Skip to content

Commit 2c721c0

Browse files
committed
add Minter contracts
1 parent 40dbc24 commit 2c721c0

30 files changed

+5510
-17
lines changed

contracts/Minter.sol

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
5+
import {IMinter} from "./interfaces/IMinter.sol";
6+
import {IRewardsDistributor} from "./interfaces/IRewardsDistributor.sol";
7+
import {IVoter} from "./interfaces/IVoter.sol";
8+
import {IVotingEscrow} from "./interfaces/IVotingEscrow.sol";
9+
10+
/// @title Minter
11+
/// @author velodrome.finance, @figs999, @pegahcarter
12+
/// @notice Controls minting of emissions and rebases for the Protocol
13+
contract Minter is IMinter {
14+
/// @inheritdoc IMinter
15+
IVoter public immutable voter;
16+
/// @inheritdoc IMinter
17+
IVotingEscrow public immutable ve;
18+
/// @inheritdoc IMinter
19+
IRewardsDistributor public immutable rewardsDistributor;
20+
21+
/// @inheritdoc IMinter
22+
uint256 public constant WEEK = 1 weeks;
23+
/// @inheritdoc IMinter
24+
uint256 public veRate = 1000; // 10%
25+
/// @inheritdoc IMinter
26+
uint256 public weekly = 100_000 * 1e18;
27+
/// @inheritdoc IMinter
28+
uint256 public activePeriod;
29+
/// @inheritdoc IMinter
30+
uint256 public epochCount;
31+
/// @inheritdoc IMinter
32+
address public team;
33+
/// @inheritdoc IMinter
34+
address public pendingTeam;
35+
36+
constructor(
37+
address _voter, // the voting & distribution system
38+
address _ve, // the ve(3,3) system that will be locked into
39+
address _rewardsDistributor // the distribution system that ensures users aren't diluted
40+
) {
41+
voter = IVoter(_voter);
42+
ve = IVotingEscrow(_ve);
43+
team = msg.sender;
44+
rewardsDistributor = IRewardsDistributor(_rewardsDistributor);
45+
activePeriod = ((block.timestamp) / WEEK) * WEEK; // allow emissions this coming epoch
46+
}
47+
48+
/// @inheritdoc IMinter
49+
function setTeam(address _team) external {
50+
if (msg.sender != team) revert NotTeam();
51+
if (_team == address(0)) revert ZeroAddress();
52+
pendingTeam = _team;
53+
}
54+
55+
/// @inheritdoc IMinter
56+
function acceptTeam() external {
57+
if (msg.sender != pendingTeam) revert NotPendingTeam();
58+
team = pendingTeam;
59+
delete pendingTeam;
60+
emit AcceptTeam(team);
61+
}
62+
63+
/// @inheritdoc IMinter
64+
function updatePeriod() external returns (uint256 _period) {
65+
_period = activePeriod;
66+
if (block.timestamp >= _period + WEEK) {
67+
epochCount++;
68+
_period = (block.timestamp / WEEK) * WEEK;
69+
activePeriod = _period;
70+
uint256 _emission = weekly;
71+
72+
uint256 _balanceOf = address(this).balance;
73+
if (_balanceOf < _emission) {
74+
revert InsufficientFund();
75+
}
76+
uint256 _veEmission = (_emission * veRate) / 10000;
77+
78+
payable(address(rewardsDistributor)).transfer(_veEmission);
79+
rewardsDistributor.checkpointToken(); // checkpoint token balance that was just minted in rewards distributor
80+
81+
voter.notifyRewardAmount{value: _emission - _veEmission}();
82+
83+
emit Mint(msg.sender, _emission);
84+
}
85+
}
86+
87+
/// @inheritdoc IMinter
88+
function changeWeekly(uint256 _weekly) external {
89+
if (msg.sender != team) revert NotTeam();
90+
91+
weekly = _weekly;
92+
emit WeeklyChanged(_weekly);
93+
}
94+
95+
/// @inheritdoc IMinter
96+
function changeVeRate(uint256 _rate) external {
97+
if (msg.sender != team) revert NotTeam();
98+
if (_rate > 5000) revert InvalidRate();
99+
100+
veRate = _rate;
101+
emit VeRateChanged(_rate);
102+
}
103+
}

contracts/interfaces/IGauge.sol

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
interface IGauge {
5+
error NotAlive();
6+
error NotAuthorized();
7+
error NotVoter();
8+
error NotTeam();
9+
error RewardRateTooHigh();
10+
error ZeroAmount();
11+
error ZeroRewardRate();
12+
13+
event Deposit(address indexed from, address indexed to, uint256 amount);
14+
event Withdraw(address indexed from, uint256 amount);
15+
event NotifyReward(address indexed from, uint256 amount);
16+
event ClaimFees(address indexed from, uint256 claimed0, uint256 claimed1);
17+
event ClaimRewards(address indexed from, uint256 amount);
18+
19+
/// @notice Address of the pool LP token which is deposited (staked) for rewards
20+
function stakingToken() external view returns (address);
21+
22+
/// @notice Address of the token (AERO) rewarded to stakers
23+
function rewardToken() external view returns (address);
24+
25+
/// @notice Address of the FeesVotingReward contract linked to the gauge
26+
function feesVotingReward() external view returns (address);
27+
28+
/// @notice Address of Protocol Voter
29+
function voter() external view returns (address);
30+
31+
/// @notice Address of Protocol Voting Escrow
32+
function ve() external view returns (address);
33+
34+
/// @notice Returns if gauge is linked to a legitimate Protocol pool
35+
function isPool() external view returns (bool);
36+
37+
/// @notice Timestamp end of current rewards period
38+
function periodFinish() external view returns (uint256);
39+
40+
/// @notice Current reward rate of rewardToken to distribute per second
41+
function rewardRate() external view returns (uint256);
42+
43+
/// @notice Most recent timestamp contract has updated state
44+
function lastUpdateTime() external view returns (uint256);
45+
46+
/// @notice Most recent stored value of rewardPerToken
47+
function rewardPerTokenStored() external view returns (uint256);
48+
49+
/// @notice Amount of stakingToken deposited for rewards
50+
function totalSupply() external view returns (uint256);
51+
52+
/// @notice Get the amount of stakingToken deposited by an account
53+
function balanceOf(address) external view returns (uint256);
54+
55+
/// @notice Cached rewardPerTokenStored for an account based on their most recent action
56+
function userRewardPerTokenPaid(address) external view returns (uint256);
57+
58+
/// @notice Cached amount of rewardToken earned for an account
59+
function rewards(address) external view returns (uint256);
60+
61+
/// @notice View to see the rewardRate given the timestamp of the start of the epoch
62+
function rewardRateByEpoch(uint256) external view returns (uint256);
63+
64+
/// @notice Cached amount of fees generated from the Pool linked to the Gauge of token0
65+
function fees0() external view returns (uint256);
66+
67+
/// @notice Cached amount of fees generated from the Pool linked to the Gauge of token1
68+
function fees1() external view returns (uint256);
69+
70+
/// @notice Get the current reward rate per unit of stakingToken deposited
71+
function rewardPerToken() external view returns (uint256 _rewardPerToken);
72+
73+
/// @notice Returns the last time the reward was modified or periodFinish if the reward has ended
74+
function lastTimeRewardApplicable() external view returns (uint256 _time);
75+
76+
/// @notice Returns accrued balance to date from last claim / first deposit.
77+
function earned(address _account) external view returns (uint256 _earned);
78+
79+
/// @notice Total amount of rewardToken to distribute for the current rewards period
80+
function left() external view returns (uint256 _left);
81+
82+
/// @notice Retrieve rewards for an address.
83+
/// @dev Throws if not called by same address or voter.
84+
/// @param _account .
85+
function getReward(address _account) external;
86+
87+
/// @notice Deposit LP tokens into gauge for msg.sender
88+
/// @param _amount .
89+
function deposit(uint256 _amount) external;
90+
91+
/// @notice Deposit LP tokens into gauge for any user
92+
/// @param _amount .
93+
/// @param _recipient Recipient to give balance to
94+
function deposit(uint256 _amount, address _recipient) external;
95+
96+
/// @notice Withdraw LP tokens for user
97+
/// @param _amount .
98+
function withdraw(uint256 _amount) external;
99+
100+
/// @dev Notifies gauge of gauge rewards. Assumes gauge reward tokens is 18 decimals.
101+
/// If not 18 decimals, rewardRate may have rounding issues.
102+
function notifyRewardAmount(uint256 amount) external;
103+
104+
/// @dev Notifies gauge of gauge rewards without distributing its fees.
105+
/// Assumes gauge reward tokens is 18 decimals.
106+
/// If not 18 decimals, rewardRate may have rounding issues.
107+
function notifyRewardWithoutClaim(uint256 amount) external;
108+
}

contracts/interfaces/IMinter.sol

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
import {IVoter} from "./IVoter.sol";
5+
import {IVotingEscrow} from "./IVotingEscrow.sol";
6+
import {IRewardsDistributor} from "./IRewardsDistributor.sol";
7+
8+
interface IMinter {
9+
error NotTeam();
10+
error ZeroAddress();
11+
error InvalidRate();
12+
error NotPendingTeam();
13+
error InsufficientFund();
14+
15+
event Mint(address indexed _sender, uint256 _weekly);
16+
event AcceptTeam(address indexed _newTeam);
17+
event WeeklyChanged(uint256 weekly);
18+
event VeRateChanged(uint256 rate);
19+
20+
/// @notice Interface of Voter.sol
21+
function voter() external view returns (IVoter);
22+
23+
/// @notice Interface of IVotingEscrow.sol
24+
function ve() external view returns (IVotingEscrow);
25+
26+
/// @notice Interface of RewardsDistributor.sol
27+
function rewardsDistributor() external view returns (IRewardsDistributor);
28+
29+
/// @notice Duration of epoch in seconds
30+
function WEEK() external view returns (uint256);
31+
32+
/// @notice Weekly emission of IOTX
33+
function weekly() external view returns (uint256);
34+
35+
/// @notice VotingEscrow holder rate
36+
function veRate() external view returns (uint256);
37+
38+
/// @notice Timestamp of start of epoch that updatePeriod was last called in
39+
function activePeriod() external view returns (uint256);
40+
41+
/// @notice Number of epochs in which updatePeriod was called
42+
function epochCount() external view returns (uint256);
43+
44+
/// @notice Current team address in charge of emissions
45+
function team() external view returns (address);
46+
47+
/// @notice Possible team address pending approval of current team
48+
function pendingTeam() external view returns (address);
49+
50+
/// @notice Creates a request to change the current team's address
51+
/// @param _team Address of the new team to be chosen
52+
function setTeam(address _team) external;
53+
54+
/// @notice Accepts the request to replace the current team's address
55+
/// with the requested one, present on variable pendingTeam
56+
function acceptTeam() external;
57+
58+
/// @notice Processes emissions and rebases. Callable once per epoch (1 week).
59+
/// @return _period Start of current epoch.
60+
function updatePeriod() external returns (uint256 _period);
61+
62+
/// @notice Change weekly emission.
63+
function changeWeekly(uint256 _weekly) external;
64+
65+
/// @notice Change ve rate of emission.
66+
function changeVeRate(uint256 _rate) external;
67+
}

contracts/interfaces/IReward.sol

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
interface IReward {
5+
error InvalidReward();
6+
error NotAuthorized();
7+
error NotGauge();
8+
error NotEscrowToken();
9+
error NotSingleToken();
10+
error NotVotingEscrow();
11+
error NotWhitelisted();
12+
error ZeroAmount();
13+
14+
event Deposit(address indexed from, uint256 indexed tokenId, uint256 amount);
15+
event Withdraw(address indexed from, uint256 indexed tokenId, uint256 amount);
16+
event NotifyReward(address indexed from, address indexed reward, uint256 indexed epoch, uint256 amount);
17+
event ClaimRewards(address indexed from, address indexed reward, uint256 amount);
18+
19+
/// @notice A checkpoint for marking balance
20+
struct Checkpoint {
21+
uint256 timestamp;
22+
uint256 balanceOf;
23+
}
24+
25+
/// @notice A checkpoint for marking supply
26+
struct SupplyCheckpoint {
27+
uint256 timestamp;
28+
uint256 supply;
29+
}
30+
31+
/// @notice Epoch duration constant (7 days)
32+
function DURATION() external view returns (uint256);
33+
34+
/// @notice Address of Voter.sol
35+
function voter() external view returns (address);
36+
37+
/// @notice Address of VotingEscrow.sol
38+
function ve() external view returns (address);
39+
40+
/// @dev Address which has permission to externally call _deposit() & _withdraw()
41+
function authorized() external view returns (address);
42+
43+
/// @notice Total amount currently deposited via _deposit()
44+
function totalSupply() external view returns (uint256);
45+
46+
/// @notice Current amount deposited by tokenId
47+
function balanceOf(uint256 tokenId) external view returns (uint256);
48+
49+
/// @notice Amount of tokens to reward depositors for a given epoch
50+
/// @param token Address of token to reward
51+
/// @param epochStart Startime of rewards epoch
52+
/// @return Amount of token
53+
function tokenRewardsPerEpoch(address token, uint256 epochStart) external view returns (uint256);
54+
55+
/// @notice Most recent timestamp a veNFT has claimed their rewards
56+
/// @param token Address of token rewarded
57+
/// @param tokenId veNFT unique identifier
58+
/// @return Timestamp
59+
function lastEarn(address token, uint256 tokenId) external view returns (uint256);
60+
61+
/// @notice True if a token is or has been an active reward token, else false
62+
function isReward(address token) external view returns (bool);
63+
64+
/// @notice The number of checkpoints for each tokenId deposited
65+
function numCheckpoints(uint256 tokenId) external view returns (uint256);
66+
67+
/// @notice The total number of checkpoints
68+
function supplyNumCheckpoints() external view returns (uint256);
69+
70+
/// @notice Deposit an amount into the rewards contract to earn future rewards associated to a veNFT
71+
/// @dev Internal notation used as only callable internally by `authorized`.
72+
/// @param amount Amount deposited for the veNFT
73+
/// @param tokenId Unique identifier of the veNFT
74+
function _deposit(uint256 amount, uint256 tokenId) external;
75+
76+
/// @notice Withdraw an amount from the rewards contract associated to a veNFT
77+
/// @dev Internal notation used as only callable internally by `authorized`.
78+
/// @param amount Amount deposited for the veNFT
79+
/// @param tokenId Unique identifier of the veNFT
80+
function _withdraw(uint256 amount, uint256 tokenId) external;
81+
82+
/// @notice Claim the rewards earned by a veNFT staker
83+
/// @param tokenId Unique identifier of the veNFT
84+
/// @param tokens Array of tokens to claim rewards of
85+
function getReward(uint256 tokenId, address[] memory tokens) external;
86+
87+
/// @notice Add rewards for stakers to earn
88+
/// @param token Address of token to reward
89+
/// @param amount Amount of token to transfer to rewards
90+
function notifyRewardAmount(address token, uint256 amount) external;
91+
92+
/// @notice Determine the prior balance for an account as of a block number
93+
/// @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
94+
/// @param tokenId The token of the NFT to check
95+
/// @param timestamp The timestamp to get the balance at
96+
/// @return The balance the account had as of the given block
97+
function getPriorBalanceIndex(uint256 tokenId, uint256 timestamp) external view returns (uint256);
98+
99+
/// @notice Determine the prior index of supply staked by of a timestamp
100+
/// @dev Timestamp must be <= current timestamp
101+
/// @param timestamp The timestamp to get the index at
102+
/// @return Index of supply checkpoint
103+
function getPriorSupplyIndex(uint256 timestamp) external view returns (uint256);
104+
105+
/// @notice Get number of rewards tokens
106+
function rewardsListLength() external view returns (uint256);
107+
108+
/// @notice Calculate how much in rewards are earned for a specific token and veNFT
109+
/// @param token Address of token to fetch rewards of
110+
/// @param tokenId Unique identifier of the veNFT
111+
/// @return Amount of token earned in rewards
112+
function earned(address token, uint256 tokenId) external view returns (uint256);
113+
}

0 commit comments

Comments
 (0)