IncentiveRewardsDistributor
Overview
IncentiveRewardsDistributor is a contract that builds upon an abstract RewardsDistributor to manage the distribution of incentive rewards within the EYWA ecosystem. The RewardsDistributor base contract provides fundamental logic for tracking deposits, withdrawals, reward notifications, and reward claims over discrete epochs. The IncentiveRewardsDistributor adds:
Whitelisting of Tokens: Before accepting a new token as a reward token, it checks with the escrow vote manager to ensure it is whitelisted.
Escrow Vote Manager Authorization: Restricts calls to certain functions (like
getReward
) to only the authorized vote manager.Inheritance and Extended Logic: Integrates seamlessly with the epoch-based deposit/withdraw system in
RewardsDistributor
to finalize reward amounts and calculations.
By implementing IIncentiveRewardsDistributor
, this contract conforms to a standard reward distributor interface used throughout the EYWA ecosystem.
Inherited Contracts and Interfaces
RewardsDistributor (Abstract Contract):
Manages core reward distribution functionality, such as:
Tracking how many tokens each owner has deposited during a specific epoch.
Storing how many rewards are allocated to a token for each epoch.
Calculating earned rewards for each owner at specific epochs and enabling claim logic.
Declares and implements the
IRewardsDistributor
interface.
IIncentiveRewardsDistributor:
Extends
IRewardsDistributor
with additional constraints and methods (getReward
¬ifyRewardAmount
restricted to certain checks).
Additional External References:
IEscrowVoteManagerV1:
Provides
s_isWhitelistedToken
to validate new reward tokens.Acts as an authorization gate for methods that require
msg.sender
to be the vote manager.
IEscrowManager:
Gives ownership and deposit/withdraw data for NFT-based locks.
Indirectly leveraged via
RewardsDistributor
functions for deposit/withdraw logic.
ReentrancyGuard (OpenZeppelin):
Inherited in
RewardsDistributor
to prevent re-entrant calls.
SafeERC20, IERC20 (OpenZeppelin):
Used for secure ERC20 transfers.
Contract Architecture
Inherited from RewardsDistributor
The base RewardsDistributor constructor sets immutable references for ESCROW_VOTE_MANAGER
and ESCROW_MANAGER
. It also defines the following main categories of functionality:
Epoch-Based Deposit and Withdrawal:
deposit(uint256 amount_, uint256 tokenId_)
withdraw(uint256 amount_, uint256 tokenId_)
Reward Notification and Calculation:
notifyRewardAmount(address rewardToken_, uint256 rewardAmount_)
(abstract here, implemented in the child contract)earned(address owner_, address rewardToken_)
andearnedByEpoch(address owner_, address rewardToken_, uint256 epoch_)
rewardPerToken(address rewardToken_, uint256 epoch_)
Claiming Rewards:
getReward(address owner_, address[] calldata rewardTokens_)
(abstract here, partially implemented in the child)_getReward(address owner_, address[] calldata rewardTokens_)
(internal)
Data Structures for Epoch Accounting and Balances:
Mappings storing how much each user has deposited per epoch, total supply per epoch, and how much reward is allocated per epoch.
We now detail each of these base functions.
Functions in the Base Contract: RewardsDistributor
RewardsDistributor
1. Constructor
Description: Sets
ESCROW_VOTE_MANAGER
andESCROW_MANAGER
as immutable addresses, used for authorization and lock ownership lookups.Parameters:
escrowVoteManager_
: The address of the escrow vote manager contract.escrowManager_
: The address of the escrow manager contract.
2. deposit(uint256 amount_, uint256 tokenId_)
deposit(uint256 amount_, uint256 tokenId_)
Description:
Called by the escrow vote manager to record that
amount_
of tokens have been deposited for the lock represented bytokenId_
in the current epoch.Increments the total supply and the lock ownerβs balance for the current epoch.
Checks:
msg.sender == ESCROW_VOTE_MANAGER
; otherwiseUnauthorizedAccess()
.
Logic:
Queries the current epoch start via
IEscrowVoteManagerV1(ESCROW_VOTE_MANAGER).currentEpochStart()
.Increments
s_totalSupplyByEpoch[m_currentEpochStart]
byamount_
.Retrieves lock owner via
IEscrowManager(ESCROW_MANAGER).ownerOf(tokenId_)
.Increments
s_balanceByOwnerAndEpoch[m_owner][m_currentEpochStart]
byamount_
.Emits
TokensDeposited(m_owner, tokenId_, amount_)
.
3. withdraw(uint256 amount_, uint256 tokenId_)
withdraw(uint256 amount_, uint256 tokenId_)
Description:
Called by the escrow vote manager to record that
amount_
of tokens have been removed from the lock represented bytokenId_
in the current epoch.Decrements the total supply and the lock ownerβs balance for the current epoch.
Checks:
msg.sender == ESCROW_VOTE_MANAGER
; otherwiseUnauthorizedAccess()
.
Logic:
Gets the current epoch start, as with
deposit
.Decrements
s_totalSupplyByEpoch[m_currentEpochStart]
byamount_
.Finds lock owner and decreases
s_balanceByOwnerAndEpoch[m_owner][m_currentEpochStart]
byamount_
.Emits
TokensWithdrawn(m_owner, tokenId_, amount_)
.
4. getRewardTokensCount()
getRewardTokensCount()
Description: Returns the length of the
s_rewardTokens
array, i.e., how many reward tokens the distributor currently recognizes.Return:
uint256
: number of recognized reward tokens.
5. earned(address owner_, address rewardToken_)
earned(address owner_, address rewardToken_)
Description:
Computes how many tokens of
rewardToken_
theowner_
has earned across epochs since their last claim.Iterates through epochs in weekly increments up to a maximum of 52 (1-year look-back) or until reaching the current epoch.
Returns:
(uint256 m_reward, uint256 m_lastRewardClaim)
: the total reward due and the final epoch boundary used for calculation.
Logic:
Checks if
rewardToken_
is recognized ins_isRewardToken[rewardToken_]
. If not, returns(0,0)
.Locates the last claimed epoch timestamp for
(owner_, rewardToken_)
.Repeatedly calls
earnedByEpoch(...)
for each epoch fromm_lastRewardClaim
up to but not includingcurrentEpochStart
.Summation is the total pending rewards.
6. earnedByEpoch(address owner_, address rewardToken_, uint256 epoch_)
earnedByEpoch(address owner_, address rewardToken_, uint256 epoch_)
Description:
Returns how many
rewardToken_
tokens were earned byowner_
specifically in a single epoch.Calculated as
rewardPerToken(rewardToken_, epoch_) * s_balanceByOwnerAndEpoch[owner_][epoch_] / 1e18
.
7. rewardPerToken(address rewardToken_, uint256 epoch_)
rewardPerToken(address rewardToken_, uint256 epoch_)
Description:
Calculates the distribution ratio for
rewardToken_
in a givenepoch_
.If
s_totalSupplyByEpoch[epoch_]
is zero, it simply returnss_rewardAmountByTokenAndEpoch[rewardToken_][epoch_]
.Otherwise, divides that reward amount by the epochβs total supply (scaled by
1e18
).
Return:
uint256
: The per-token reward ratio used to multiply by an ownerβs deposit amount to get their share.
8. getReward(address owner_, address[] calldata rewardTokens_)
(abstract)
getReward(address owner_, address[] calldata rewardTokens_)
(abstract)Description:
Abstract in the base RewardsDistributor. The child contract (
IncentiveRewardsDistributor
) provides the actual implementation.Childβs implementation calls
_getReward(...)
internally after verifying authorization.
9. notifyRewardAmount(address rewardToken_, uint256 rewardAmount_)
(abstract)
notifyRewardAmount(address rewardToken_, uint256 rewardAmount_)
(abstract)Description:
Abstract method for adding new reward tokens. Child contract overrides this to add whitelisting checks or additional logic.
The base logic is available in
_notifyRewardAmount(...)
(see below).
10. _getReward(address owner_, address[] calldata rewardTokens_)
(internal)
_getReward(address owner_, address[] calldata rewardTokens_)
(internal)Description:
The internal function that loops over
rewardTokens_
, calculatesearned(...)
, updatess_lastRewardClaimByOwnerAndToken
, and transfers the reward toowner_
.Finally, emits
RewardsClaimed(owner_, token, amount)
.
11. _notifyRewardAmount(address sender_, address rewardToken_, uint256 rewardAmount_)
(internal)
_notifyRewardAmount(address sender_, address rewardToken_, uint256 rewardAmount_)
(internal)Description:
Transfers
rewardAmount_
ofrewardToken_
fromsender_
to this distributor.Adds the difference in the contractβs balance to
s_rewardAmountByTokenAndEpoch[rewardToken_][currentEpochStart]
.If
s_initialIncentiveTimestamp == 0
, sets it to the current epoch start.Emits
RewardNotified(sender_, rewardToken_, epoch, difference)
.
Functions in IncentiveRewardsDistributor
Constructor
Description:
Calls the RewardsDistributor constructor to set
ESCROW_VOTE_MANAGER
andESCROW_MANAGER
.No additional logic besides inheritance.
getReward(address owner_, address[] calldata rewardTokens_)
getReward(address owner_, address[] calldata rewardTokens_)
Description:
Implementation of
getReward
from bothRewardsDistributor
(abstract) andIIncentiveRewardsDistributor
.Allows the escrow vote manager to claim rewards for
owner_
.Calls
_getReward(...)
internally after checkingmsg.sender == ESCROW_VOTE_MANAGER
.
notifyRewardAmount(address rewardToken_, uint256 rewardAmount_)
notifyRewardAmount(address rewardToken_, uint256 rewardAmount_)
Description:
Implementation of
notifyRewardAmount
from bothRewardsDistributor
(abstract) andIIncentiveRewardsDistributor
.First ensures
rewardToken_
is whitelisted vias_isWhitelistedToken
inIEscrowVoteManagerV1
.If the token is not recognized (
!s_isRewardToken[rewardToken_]
), checks the vote manager to see if itβs whitelisted; if so, itβs now added tos_rewardTokens
.If not whitelisted, reverts with
NotWhitelisted()
.
Calls
_notifyRewardAmount(msg.sender, rewardToken_, rewardAmount_)
to handle actual fund transfer and epoch reward updates.
Events and Errors
Inherited Events
TokensDeposited(from, tokenId, amount)
TokensWithdrawn(from, tokenId, amount)
RewardNotified(from, token, epoch, amount)
RewardsClaimed(from, token, amount)
Inherited Errors
InvalidRewardToken()
UnauthorizedAccess()
ZeroAmountProvided()
NotWhitelisted()
No new custom events or errors are introduced in IncentiveRewardsDistributor beyond whatβs inherited.
Summary
IncentiveRewardsDistributor leverages the robust, epoch-based reward accounting system from RewardsDistributor to facilitate secure incentive distribution in the EYWA ecosystem, adding token whitelisting checks and limiting reward claims (getReward
) to calls from the escrow vote manager. This design ensures:
Authorized Control: Only recognized and whitelisted tokens can be notified as rewards; only the escrow vote manager can trigger claims.
Accurate Reward Calculations: Inherits deposit/withdraw logic to track each userβs epoch-based balance.
Easy Integration: Conforms to the
IIncentiveRewardsDistributor
interface, providing consistent methods for reward notifications and claims across the system.
Together with the RewardsDistributor base contract, IncentiveRewardsDistributor offers a flexible, robust means of awarding incentive tokens in a multi-lock, epoch-based environment.
Last updated