Skip to content

Commit

Permalink
add Minter contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
ququzone committed Jan 14, 2024
1 parent 40dbc24 commit 2c721c0
Show file tree
Hide file tree
Showing 30 changed files with 5,510 additions and 17 deletions.
103 changes: 103 additions & 0 deletions contracts/Minter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {IMinter} from "./interfaces/IMinter.sol";
import {IRewardsDistributor} from "./interfaces/IRewardsDistributor.sol";
import {IVoter} from "./interfaces/IVoter.sol";
import {IVotingEscrow} from "./interfaces/IVotingEscrow.sol";

/// @title Minter
/// @author velodrome.finance, @figs999, @pegahcarter
/// @notice Controls minting of emissions and rebases for the Protocol
contract Minter is IMinter {
/// @inheritdoc IMinter
IVoter public immutable voter;
/// @inheritdoc IMinter
IVotingEscrow public immutable ve;
/// @inheritdoc IMinter
IRewardsDistributor public immutable rewardsDistributor;

/// @inheritdoc IMinter
uint256 public constant WEEK = 1 weeks;
/// @inheritdoc IMinter
uint256 public veRate = 1000; // 10%
/// @inheritdoc IMinter
uint256 public weekly = 100_000 * 1e18;
/// @inheritdoc IMinter
uint256 public activePeriod;
/// @inheritdoc IMinter
uint256 public epochCount;
/// @inheritdoc IMinter
address public team;
/// @inheritdoc IMinter
address public pendingTeam;

constructor(
address _voter, // the voting & distribution system
address _ve, // the ve(3,3) system that will be locked into
address _rewardsDistributor // the distribution system that ensures users aren't diluted
) {
voter = IVoter(_voter);
ve = IVotingEscrow(_ve);
team = msg.sender;
rewardsDistributor = IRewardsDistributor(_rewardsDistributor);
activePeriod = ((block.timestamp) / WEEK) * WEEK; // allow emissions this coming epoch
}

/// @inheritdoc IMinter
function setTeam(address _team) external {
if (msg.sender != team) revert NotTeam();
if (_team == address(0)) revert ZeroAddress();
pendingTeam = _team;
}

/// @inheritdoc IMinter
function acceptTeam() external {
if (msg.sender != pendingTeam) revert NotPendingTeam();
team = pendingTeam;
delete pendingTeam;
emit AcceptTeam(team);
}

/// @inheritdoc IMinter
function updatePeriod() external returns (uint256 _period) {
_period = activePeriod;
if (block.timestamp >= _period + WEEK) {
epochCount++;
_period = (block.timestamp / WEEK) * WEEK;
activePeriod = _period;
uint256 _emission = weekly;

uint256 _balanceOf = address(this).balance;
if (_balanceOf < _emission) {
revert InsufficientFund();
}
uint256 _veEmission = (_emission * veRate) / 10000;

payable(address(rewardsDistributor)).transfer(_veEmission);
rewardsDistributor.checkpointToken(); // checkpoint token balance that was just minted in rewards distributor

voter.notifyRewardAmount{value: _emission - _veEmission}();

emit Mint(msg.sender, _emission);
}
}

/// @inheritdoc IMinter
function changeWeekly(uint256 _weekly) external {
if (msg.sender != team) revert NotTeam();

weekly = _weekly;
emit WeeklyChanged(_weekly);
}

/// @inheritdoc IMinter
function changeVeRate(uint256 _rate) external {
if (msg.sender != team) revert NotTeam();
if (_rate > 5000) revert InvalidRate();

veRate = _rate;
emit VeRateChanged(_rate);
}
}
108 changes: 108 additions & 0 deletions contracts/interfaces/IGauge.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IGauge {
error NotAlive();
error NotAuthorized();
error NotVoter();
error NotTeam();
error RewardRateTooHigh();
error ZeroAmount();
error ZeroRewardRate();

event Deposit(address indexed from, address indexed to, uint256 amount);
event Withdraw(address indexed from, uint256 amount);
event NotifyReward(address indexed from, uint256 amount);
event ClaimFees(address indexed from, uint256 claimed0, uint256 claimed1);
event ClaimRewards(address indexed from, uint256 amount);

/// @notice Address of the pool LP token which is deposited (staked) for rewards
function stakingToken() external view returns (address);

/// @notice Address of the token (AERO) rewarded to stakers
function rewardToken() external view returns (address);

/// @notice Address of the FeesVotingReward contract linked to the gauge
function feesVotingReward() external view returns (address);

/// @notice Address of Protocol Voter
function voter() external view returns (address);

/// @notice Address of Protocol Voting Escrow
function ve() external view returns (address);

/// @notice Returns if gauge is linked to a legitimate Protocol pool
function isPool() external view returns (bool);

/// @notice Timestamp end of current rewards period
function periodFinish() external view returns (uint256);

/// @notice Current reward rate of rewardToken to distribute per second
function rewardRate() external view returns (uint256);

/// @notice Most recent timestamp contract has updated state
function lastUpdateTime() external view returns (uint256);

/// @notice Most recent stored value of rewardPerToken
function rewardPerTokenStored() external view returns (uint256);

/// @notice Amount of stakingToken deposited for rewards
function totalSupply() external view returns (uint256);

/// @notice Get the amount of stakingToken deposited by an account
function balanceOf(address) external view returns (uint256);

/// @notice Cached rewardPerTokenStored for an account based on their most recent action
function userRewardPerTokenPaid(address) external view returns (uint256);

/// @notice Cached amount of rewardToken earned for an account
function rewards(address) external view returns (uint256);

/// @notice View to see the rewardRate given the timestamp of the start of the epoch
function rewardRateByEpoch(uint256) external view returns (uint256);

/// @notice Cached amount of fees generated from the Pool linked to the Gauge of token0
function fees0() external view returns (uint256);

/// @notice Cached amount of fees generated from the Pool linked to the Gauge of token1
function fees1() external view returns (uint256);

/// @notice Get the current reward rate per unit of stakingToken deposited
function rewardPerToken() external view returns (uint256 _rewardPerToken);

/// @notice Returns the last time the reward was modified or periodFinish if the reward has ended
function lastTimeRewardApplicable() external view returns (uint256 _time);

/// @notice Returns accrued balance to date from last claim / first deposit.
function earned(address _account) external view returns (uint256 _earned);

/// @notice Total amount of rewardToken to distribute for the current rewards period
function left() external view returns (uint256 _left);

/// @notice Retrieve rewards for an address.
/// @dev Throws if not called by same address or voter.
/// @param _account .
function getReward(address _account) external;

/// @notice Deposit LP tokens into gauge for msg.sender
/// @param _amount .
function deposit(uint256 _amount) external;

/// @notice Deposit LP tokens into gauge for any user
/// @param _amount .
/// @param _recipient Recipient to give balance to
function deposit(uint256 _amount, address _recipient) external;

/// @notice Withdraw LP tokens for user
/// @param _amount .
function withdraw(uint256 _amount) external;

/// @dev Notifies gauge of gauge rewards. Assumes gauge reward tokens is 18 decimals.
/// If not 18 decimals, rewardRate may have rounding issues.
function notifyRewardAmount(uint256 amount) external;

/// @dev Notifies gauge of gauge rewards without distributing its fees.
/// Assumes gauge reward tokens is 18 decimals.
/// If not 18 decimals, rewardRate may have rounding issues.
function notifyRewardWithoutClaim(uint256 amount) external;
}
67 changes: 67 additions & 0 deletions contracts/interfaces/IMinter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IVoter} from "./IVoter.sol";
import {IVotingEscrow} from "./IVotingEscrow.sol";
import {IRewardsDistributor} from "./IRewardsDistributor.sol";

interface IMinter {
error NotTeam();
error ZeroAddress();
error InvalidRate();
error NotPendingTeam();
error InsufficientFund();

event Mint(address indexed _sender, uint256 _weekly);
event AcceptTeam(address indexed _newTeam);
event WeeklyChanged(uint256 weekly);
event VeRateChanged(uint256 rate);

/// @notice Interface of Voter.sol
function voter() external view returns (IVoter);

/// @notice Interface of IVotingEscrow.sol
function ve() external view returns (IVotingEscrow);

/// @notice Interface of RewardsDistributor.sol
function rewardsDistributor() external view returns (IRewardsDistributor);

/// @notice Duration of epoch in seconds
function WEEK() external view returns (uint256);

/// @notice Weekly emission of IOTX
function weekly() external view returns (uint256);

/// @notice VotingEscrow holder rate
function veRate() external view returns (uint256);

/// @notice Timestamp of start of epoch that updatePeriod was last called in
function activePeriod() external view returns (uint256);

/// @notice Number of epochs in which updatePeriod was called
function epochCount() external view returns (uint256);

/// @notice Current team address in charge of emissions
function team() external view returns (address);

/// @notice Possible team address pending approval of current team
function pendingTeam() external view returns (address);

/// @notice Creates a request to change the current team's address
/// @param _team Address of the new team to be chosen
function setTeam(address _team) external;

/// @notice Accepts the request to replace the current team's address
/// with the requested one, present on variable pendingTeam
function acceptTeam() external;

/// @notice Processes emissions and rebases. Callable once per epoch (1 week).
/// @return _period Start of current epoch.
function updatePeriod() external returns (uint256 _period);

/// @notice Change weekly emission.
function changeWeekly(uint256 _weekly) external;

/// @notice Change ve rate of emission.
function changeVeRate(uint256 _rate) external;
}
113 changes: 113 additions & 0 deletions contracts/interfaces/IReward.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IReward {
error InvalidReward();
error NotAuthorized();
error NotGauge();
error NotEscrowToken();
error NotSingleToken();
error NotVotingEscrow();
error NotWhitelisted();
error ZeroAmount();

event Deposit(address indexed from, uint256 indexed tokenId, uint256 amount);
event Withdraw(address indexed from, uint256 indexed tokenId, uint256 amount);
event NotifyReward(address indexed from, address indexed reward, uint256 indexed epoch, uint256 amount);
event ClaimRewards(address indexed from, address indexed reward, uint256 amount);

/// @notice A checkpoint for marking balance
struct Checkpoint {
uint256 timestamp;
uint256 balanceOf;
}

/// @notice A checkpoint for marking supply
struct SupplyCheckpoint {
uint256 timestamp;
uint256 supply;
}

/// @notice Epoch duration constant (7 days)
function DURATION() external view returns (uint256);

/// @notice Address of Voter.sol
function voter() external view returns (address);

/// @notice Address of VotingEscrow.sol
function ve() external view returns (address);

/// @dev Address which has permission to externally call _deposit() & _withdraw()
function authorized() external view returns (address);

/// @notice Total amount currently deposited via _deposit()
function totalSupply() external view returns (uint256);

/// @notice Current amount deposited by tokenId
function balanceOf(uint256 tokenId) external view returns (uint256);

/// @notice Amount of tokens to reward depositors for a given epoch
/// @param token Address of token to reward
/// @param epochStart Startime of rewards epoch
/// @return Amount of token
function tokenRewardsPerEpoch(address token, uint256 epochStart) external view returns (uint256);

/// @notice Most recent timestamp a veNFT has claimed their rewards
/// @param token Address of token rewarded
/// @param tokenId veNFT unique identifier
/// @return Timestamp
function lastEarn(address token, uint256 tokenId) external view returns (uint256);

/// @notice True if a token is or has been an active reward token, else false
function isReward(address token) external view returns (bool);

/// @notice The number of checkpoints for each tokenId deposited
function numCheckpoints(uint256 tokenId) external view returns (uint256);

/// @notice The total number of checkpoints
function supplyNumCheckpoints() external view returns (uint256);

/// @notice Deposit an amount into the rewards contract to earn future rewards associated to a veNFT
/// @dev Internal notation used as only callable internally by `authorized`.
/// @param amount Amount deposited for the veNFT
/// @param tokenId Unique identifier of the veNFT
function _deposit(uint256 amount, uint256 tokenId) external;

/// @notice Withdraw an amount from the rewards contract associated to a veNFT
/// @dev Internal notation used as only callable internally by `authorized`.
/// @param amount Amount deposited for the veNFT
/// @param tokenId Unique identifier of the veNFT
function _withdraw(uint256 amount, uint256 tokenId) external;

/// @notice Claim the rewards earned by a veNFT staker
/// @param tokenId Unique identifier of the veNFT
/// @param tokens Array of tokens to claim rewards of
function getReward(uint256 tokenId, address[] memory tokens) external;

/// @notice Add rewards for stakers to earn
/// @param token Address of token to reward
/// @param amount Amount of token to transfer to rewards
function notifyRewardAmount(address token, uint256 amount) external;

/// @notice Determine the prior balance for an account as of a block number
/// @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
/// @param tokenId The token of the NFT to check
/// @param timestamp The timestamp to get the balance at
/// @return The balance the account had as of the given block
function getPriorBalanceIndex(uint256 tokenId, uint256 timestamp) external view returns (uint256);

/// @notice Determine the prior index of supply staked by of a timestamp
/// @dev Timestamp must be <= current timestamp
/// @param timestamp The timestamp to get the index at
/// @return Index of supply checkpoint
function getPriorSupplyIndex(uint256 timestamp) external view returns (uint256);

/// @notice Get number of rewards tokens
function rewardsListLength() external view returns (uint256);

/// @notice Calculate how much in rewards are earned for a specific token and veNFT
/// @param token Address of token to fetch rewards of
/// @param tokenId Unique identifier of the veNFT
/// @return Amount of token earned in rewards
function earned(address token, uint256 tokenId) external view returns (uint256);
}
Loading

0 comments on commit 2c721c0

Please sign in to comment.