Skip to content

Commit

Permalink
added comment so ChefIncentivesMultiRewarder
Browse files Browse the repository at this point in the history
  • Loading branch information
gas-limit committed Nov 21, 2024
1 parent a6f2f3a commit fe58b04
Showing 1 changed file with 132 additions and 32 deletions.
164 changes: 132 additions & 32 deletions src/ChefIncentivesController/ChefIncentivesMultiRewarder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,88 @@ pragma solidity 0.7.6;
import { SafeMath} from "../dependencies/openzeppelin/contracts/SafeMath.sol";
import { IERC20 } from "../dependencies/openzeppelin/contracts/IERC20.sol";

/**
* @title ChefIncentivesMultiRewarder
* @dev Enables multi-token reward distribution for users staking aTokens or LP tokens.
* Supports diverse and flexible incentive mechanisms with accurate reward accounting.
*/
contract ChefIncentivesMultiRewarder {

using SafeMath for uint256;

address multiIncentiveAdmin;
/// @notice Address of the admin responsible for managing incentives
address public multiIncentiveAdmin;

// aToken address => total staked amount
//// @notice Maps aToken addresses to the total staked amount
mapping(address => uint256) public multiTotalStaked;
// aToken address => staked amount

/// @notice Maps aToken and user addresses to the user's staked amount
mapping(address => mapping(address => uint256)) public multiUserStaked;
// aToken address => rewardToken array

/// @notice Maps aToken addresses to an array of reward tokens
mapping(address => address[]) public multiRewardTokens;
// rewardToken address => isMultiRewardToken

/// @notice Maps reward token addresses to a boolean indicating if it is a multi-reward token
mapping(address => bool) public isMultiRewardToken;
// aTokenAddress => rewardTokenAddress => multiRewardPerToken

/// @notice Maps aToken and reward token addresses to the reward per token value
mapping(address => mapping(address => uint256)) public multiRewardPerToken;
// user address => aToken address => reward address => multiRewardPerTokenOffsetScaled
mapping(address => mapping(address => mapping(address => uint256)))
public multiUserRewardOffset;
// user address => rewardToken address => accumulated rewards

/// @notice Tracks user-specific reward offsets to ensure accurate reward calculations
mapping(address => mapping(address => mapping(address => uint256))) public multiUserRewardOffset;

/// @notice Tracks accumulated pending rewards for users per reward token
mapping(address => mapping(address => uint256)) public multiUserPendingRewards;
// aToken address => rewardToken address => rewardPerSecond

/// @notice Tracks reward distribution rates per aToken and reward token
mapping(address => mapping(address => uint256)) public multiRewardPerSecond;
// aToken address => rewardToken address => lastMultiUpdateTime

/// @notice Tracks the last time rewards were updated per aToken and reward token
mapping(address => mapping(address => uint256)) public lastMultiUpdateTime;

uint256 internal constant SCALE = 1e24;

event multiStakeRecorded(address user, address aToken, uint256 amount);
event multiUnstakeRecorded(address user, address aToken, uint256 amount);
/// @dev Emitted when a user stakes aTokens
event multiStakeRecorded(address indexed user, address indexed aToken, uint256 amount);
/// @dev Emitted when a user unstakes aTokens
event multiUnstakeRecorded(address indexed user, address indexed aToken, uint256 amount);
/// @dev Emitted when a user claims rewards
event multiRewardHarvested(
address user,
address aToken,
address rewardToken,
address indexed user,
address indexed aToken,
address indexed rewardToken,
uint256 amount
);
/// @dev Emitted when a new reward token is added
event multiRewardAdded(
address aToken,
address rewardToken,
address indexed aToken,
address indexed rewardToken,
uint256 rewardsPerSecond
);
event multiRewardRemoved(address aToken, address rewardToken);
/// @dev Emitted when a reward token is removed
event multiRewardRemoved(address indexed aToken, address indexed rewardToken);
/// @dev Emitted when a reward rate is updated
event multiRewardUpdated(
address aToken,
address rewardToken,
address indexed aToken,
address indexed rewardToken,
uint256 rewardsPerSecond
);
event multiRewardDeposited(address rewardToken, uint256 amount);
event multiRewardWithdrawn(address rewardToken, uint256 amount);

/// @dev Emitted when reward tokens are deposited
event multiRewardDeposited(address indexed rewardToken, uint256 amount);
/// @dev Emitted when reward tokens are withdrawn
event multiRewardWithdrawn(address indexed rewardToken, uint256 amount);

/**
* @dev Restricts access to the multiIncentiveAdmin.
*/
modifier onlyIncentiveAdmin() {
require(msg.sender == multiIncentiveAdmin, "caller is not the multiIncentiveAdmin");
_;
}

/**
* @dev Initializes the contract and sets the deployer as the multiIncentiveAdmin.
*/
constructor() {
multiIncentiveAdmin = msg.sender;
}
Expand All @@ -67,7 +94,13 @@ contract ChefIncentivesMultiRewarder {
// USER FUNCTIONS
// °✰════════════════════╛

// Stake aToken
/**
* @notice Stakes aTokens to participate in rewards.
* @dev Internal function called by the parent contract.
* @param _aToken The aToken being staked.
* @param _amount The amount of aTokens to stake.
* @param _user The address of the user staking the tokens.
*/
function _stakeIncentiveTokens(address _aToken, uint256 _amount, address _user) internal {
require(_amount > 0, "amount must be greater than 0");
calculateUserPending(_user, _aToken);
Expand All @@ -90,7 +123,13 @@ contract ChefIncentivesMultiRewarder {
emit multiStakeRecorded(_user, _aToken, _amount);
}

// Withdraw aToken
/**
* @notice Stakes aTokens to participate in rewards.
* @dev Internal function called by the parent contract.
* @param _aToken The aToken being staked.
* @param _amount The amount of aTokens to stake.
* @param _user The address of the user staking the tokens.
*/
function _unstakeIncentiveTokens(address _aToken, uint256 _amount, address _user) internal {
require(_amount > 0, "amount must be greater than 0");
// assume check for sufficient staked amount is done in parent contract
Expand All @@ -103,7 +142,12 @@ contract ChefIncentivesMultiRewarder {
emit multiUnstakeRecorded(_user, _aToken, _amount);
}

// Harvest rewards
/**
* @notice Claims all pending rewards for a user.
* @dev Internal function called by the parent contract.
* @param _aToken The aToken for which rewards are claimed.
* @param _user The address of the user claiming rewards.
*/
function _claimMultiRewards(address _aToken, address _user) internal {
updateMultiRewardAccounting(_aToken);
address[] memory rewardTokenList = multiRewardTokens[_aToken];
Expand Down Expand Up @@ -131,7 +175,11 @@ contract ChefIncentivesMultiRewarder {
// INTERNAL ACCOUNTING
// °✰════════════════════════╛

// Update reward accounting
/**
* @notice Updates the reward accounting for a specific aToken.
* @dev Ensures that reward tokens are accurately accounted for over time.
* @param _aToken The aToken whose rewards need to be updated.
*/
function updateMultiRewardAccounting(address _aToken) internal {
if(multiTotalStaked[_aToken] == 0) {
return;
Expand All @@ -153,6 +201,11 @@ contract ChefIncentivesMultiRewarder {
}
}

/**
* @notice Calculates pending rewards for a user and updates their pending rewards.
* @param _user The address of the user.
* @param _aToken The aToken for which pending rewards are calculated.
*/
function calculateUserPending(address _user, address _aToken) internal {
(address[] memory rewardTokenList, uint256[] memory earnedAmounts) = previewEarned(
_user,
Expand All @@ -169,7 +222,12 @@ contract ChefIncentivesMultiRewarder {
// ADMIN FUNCTIONS
// °✰════════════════════════╛

// Add a new reward to a specific aToken
/**
* @notice Adds a new reward token to a specific aToken with a defined rate.
* @param _aToken The aToken to associate with the reward token.
* @param _rewardToken The reward token to add.
* @param _rewardsPerSecond The rate at which rewards are distributed.
*/
function addIncentiveReward(
address _aToken,
address _rewardToken,
Expand All @@ -192,7 +250,11 @@ contract ChefIncentivesMultiRewarder {
emit multiRewardAdded(_aToken, _rewardToken, _rewardsPerSecond);
}

// Remove a reward from a specific aToken
/**
* @notice Removes an existing reward token from a specific aToken.
* @param _aToken The aToken from which the reward token is removed.
* @param _rewardToken The reward token to remove.
*/
function removeIncentiveReward(
address _aToken,
address _rewardToken
Expand All @@ -207,19 +269,34 @@ contract ChefIncentivesMultiRewarder {
}


// Update reward per second for a specific aToken
/**
* @notice Updates the reward rate for a specific aToken and reward token.
* @param _aToken The aToken whose reward rate is updated.
* @param _rewardToken The reward token whose rate is updated.
* @param _rewardsPerSecond The new reward rate.
*/
function adjustRewardRate(address _aToken, address _rewardToken, uint256 _rewardsPerSecond) external onlyIncentiveAdmin {
require(multiRewardPerSecond[_aToken][_rewardToken] != 0, "reward token does not exist");
updateMultiRewardAccounting(_aToken);
multiRewardPerSecond[_aToken][_rewardToken] = _rewardsPerSecond;
emit multiRewardUpdated(_aToken, _rewardToken, _rewardsPerSecond);
}

/**
* @notice Deposits reward tokens into the contract for distribution.
* @param _rewardAddress The address of the reward token.
* @param _amount The amount of reward tokens to deposit.
*/
function depositReward(address _rewardAddress, uint256 _amount) external onlyIncentiveAdmin {
IERC20(_rewardAddress).transferFrom(msg.sender, address(this), _amount);
emit multiRewardDeposited(_rewardAddress, _amount);
}

/**
* @notice Withdraws reward tokens from the contract.
* @param _rewardAddress The address of the reward token.
* @param _amount The amount of reward tokens to withdraw.
*/
function withdrawReward(address _rewardAddress, uint256 _amount) external onlyIncentiveAdmin {
IERC20(_rewardAddress).transfer(msg.sender, _amount);
emit multiRewardWithdrawn(_rewardAddress, _amount);
Expand All @@ -229,6 +306,13 @@ contract ChefIncentivesMultiRewarder {
// USER PREVIEW REWARDS
// °✰════════════════════════╛

/**
* @notice Previews the rewards earned by a user for a specific aToken.
* @param _user The address of the user.
* @param _aToken The aToken for which rewards are previewed.
* @return multiRewardTokens_ The list of reward tokens.
* @return earnedAmounts_ The amounts of rewards earned for each token.
*/
function previewEarned(address _user, address _aToken)
public
view
Expand Down Expand Up @@ -265,6 +349,13 @@ contract ChefIncentivesMultiRewarder {
}
}

/**
* @notice Simulates the reward per token for a specific aToken and reward token.
* @param _aToken The aToken for which the simulation is performed.
* @param _rewardToken The reward token for which the simulation is performed.
* @param totalStakedAmount The total amount of aTokens staked.
* @return simulatedRewardPerToken The simulated reward per token value.
*/
function _simulateRewardPerToken(
address _aToken,
address _rewardToken,
Expand All @@ -282,6 +373,15 @@ contract ChefIncentivesMultiRewarder {
return simulatedRewardPerToken;
}

/**
* @notice Calculates the earned amount of rewards for a user based on their staked amount and reward offsets.
* @param _user The address of the user earning rewards.
* @param _aToken The aToken associated with the rewards.
* @param _rewardToken The reward token to calculate earned rewards for.
* @param simulatedRewardPerToken The simulated reward per token value.
* @param userStakedAmount The amount of aTokens staked by the user.
* @return earnedAmountActual The actual amount of rewards earned by the user.
*/
function _calculateEarnedAmount(
address _user,
address _aToken,
Expand Down

0 comments on commit fe58b04

Please sign in to comment.