LogoLogo
  • CrossCurve MetaLayer
    • ⚙️What is CrossCurve MetaLayer
      • CrossCurve Consensus bridge
      • CrossCurve Pools v2
    • 🗺️Roadmap
      • 2024
  • 🏢CrossCurve DAO
    • Overview of CrossCurve DAO
    • Voting
    • Obtaining veEYWA and Calculating the Boost
    • Staking mechanics
    • NFTs
      • CrossCurve DAO NFT
      • EYWA NFT Collection
  • 💼Earn with CrossCurve
    • Staking in CrossCurve
    • Providing Liquidity to CrossCurve Pools
    • Voting for Incentives
  • 📖user documentation
    • 🛸Migration to Sonic
      • Why are we moving to Sonic
      • Sonic Upgrade Stages
      • Liquidity transfer from Fantom to Sonic
      • Sonic Incentives on CrossCurve MetaLayer
    • 🔃Swap interface
      • How to trade
      • Slippage settings
      • Routing
    • 🌊Liquidity Interface
      • Easy mode
      • via Curve (Balanced)
      • Liquidity provision use cases
        • Deposit
          • Easy mode (Imbalanced)
          • via Curve (Balanced)
        • Withdraw
          • Easy mode (Imbalanced)
          • via Curve (Balanced)
        • Curve Knowledge Database
          • Balanced liquidity provision
          • Guide to transferring CRV from Fantom chain to Ethereum mainnet
          • Disclamer
    • 🏢DAO
      • Locker Interface
      • Vote Interface
      • Incentives Interface
      • Working with the EYWA Locker contract in Arbiscan.
    • 🌾Yield
      • Farms Interface
        • Staking liquidity and earning rewards
      • APR Calculator
      • EYWA pool via Convex
    • 💼Vesting
      • Claim portal interface
      • Early farming program interface
    • EYWA NFT
      • Bridge interface in the Aurora chain
      • Merge interface in the Arbitrum chain
      • EYWA NFT Manager interface
      • Dashboard interface
    • Leaderboard
    • ❄️Outdated
      • Early farming program
  • 📖Developer documentation
    • Pools/asset contracts
      • Hubchain Pools and Assets
      • 💱Supported tokens
    • 🔗CrossCurve smart contracts
    • 💻Guide for Developers
      • Technical Documentation for CrossCurve DAO Smart Contracts
        • CalldataHelperV1
        • DelegationManagerV1
        • DelegationConditionValidatorV1
        • EmissionManagerV1
        • EscrowManager
        • EscrowVoteManagerV1
        • GaugeFactoryV1
        • GaugeV1
        • IncentiveRewardsDistributor
        • LockHolderFactoryV1
        • LockHolderV1
        • ProposalManager
        • RebaseRewardsDistributorV1
        • RewardsDistributorFactoryV1
        • Treasury
      • 🔃Make cross-chain swap
      • 🔦Tracking cross-chain swap
      • 📔Pusher API Reference
      • 📝Glossary
      • API Specification
  • 📣About CrossCurve
    • 🛡️Security audits
    • 🧠Team
    • Project History
    • Website
    • Telegram
    • Twitter
    • Medium
    • Discord
    • YouTube
    • LinkedIn
    • GitHub
Powered by GitBook
On this page
  • Overview
  • Inherited Contracts and Interfaces
  • Contract Architecture
  • Functions in the Base Contract: RewardsDistributor
  • Functions in IncentiveRewardsDistributor
  • Events and Errors
  • Summary
Export as PDF
  1. Developer documentation
  2. Guide for Developers
  3. Technical Documentation for CrossCurve DAO Smart Contracts

IncentiveRewardsDistributor

Overview

IncentiveRewardsDistributor is a contract that builds upon an abstract RewardsDistributor to manage the distribution of incentive rewards within the CrossCurve ecosystem. The RewardsDistributor base contract provides fundamental logic for tracking deposits, withdrawals, reward notifications, and reward claims over discrete epochs. The IncentiveRewardsDistributor adds:

  1. Whitelisting of Tokens: Before accepting a new token as a reward token, it checks with the escrow vote manager to ensure it is whitelisted.

  2. Escrow Vote Manager Authorization: Restricts calls to certain functions (like getReward) to only the authorized vote manager.

  3. 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 CrossCurve 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 & notifyRewardAmount 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

IncentiveRewardsDistributor (Concrete)
 └── RewardsDistributor (Abstract)
      └── IRewardsDistributor (Interface)

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:

  1. Epoch-Based Deposit and Withdrawal:

    • deposit(uint256 amount_, uint256 tokenId_)

    • withdraw(uint256 amount_, uint256 tokenId_)

  2. Reward Notification and Calculation:

    • notifyRewardAmount(address rewardToken_, uint256 rewardAmount_) (abstract here, implemented in the child contract)

    • earned(address owner_, address rewardToken_) and earnedByEpoch(address owner_, address rewardToken_, uint256 epoch_)

    • rewardPerToken(address rewardToken_, uint256 epoch_)

  3. Claiming Rewards:

    • getReward(address owner_, address[] calldata rewardTokens_) (abstract here, partially implemented in the child)

    • _getReward(address owner_, address[] calldata rewardTokens_) (internal)

  4. 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

1. Constructor

constructor(address escrowVoteManager_, address escrowManager_) {
    ESCROW_VOTE_MANAGER = escrowVoteManager_;
    ESCROW_MANAGER = escrowManager_;
}
  • Description: Sets ESCROW_VOTE_MANAGER and ESCROW_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_)

function deposit(uint256 amount_, uint256 tokenId_) external
  • Description:

    • Called by the escrow vote manager to record that amount_ of tokens have been deposited for the lock represented by tokenId_ in the current epoch.

    • Increments the total supply and the lock owner’s balance for the current epoch.

  • Checks:

    • msg.sender == ESCROW_VOTE_MANAGER; otherwise UnauthorizedAccess().

  • Logic:

    1. Queries the current epoch start via IEscrowVoteManagerV1(ESCROW_VOTE_MANAGER).currentEpochStart().

    2. Increments s_totalSupplyByEpoch[m_currentEpochStart] by amount_.

    3. Retrieves lock owner via IEscrowManager(ESCROW_MANAGER).ownerOf(tokenId_).

    4. Increments s_balanceByOwnerAndEpoch[m_owner][m_currentEpochStart] by amount_.

    5. Emits TokensDeposited(m_owner, tokenId_, amount_).


3. withdraw(uint256 amount_, uint256 tokenId_)

function withdraw(uint256 amount_, uint256 tokenId_) external
  • Description:

    • Called by the escrow vote manager to record that amount_ of tokens have been removed from the lock represented by tokenId_ in the current epoch.

    • Decrements the total supply and the lock owner’s balance for the current epoch.

  • Checks:

    • msg.sender == ESCROW_VOTE_MANAGER; otherwise UnauthorizedAccess().

  • Logic:

    1. Gets the current epoch start, as with deposit.

    2. Decrements s_totalSupplyByEpoch[m_currentEpochStart] by amount_.

    3. Finds lock owner and decreases s_balanceByOwnerAndEpoch[m_owner][m_currentEpochStart] by amount_.

    4. Emits TokensWithdrawn(m_owner, tokenId_, amount_).


4. getRewardTokensCount()

function getRewardTokensCount() external view returns (uint256)
  • 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_)

function earned(address owner_, address rewardToken_) public view returns (uint256, uint256)
  • Description:

    • Computes how many tokens of rewardToken_ the owner_ 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:

    1. Checks if rewardToken_ is recognized in s_isRewardToken[rewardToken_]. If not, returns (0,0).

    2. Locates the last claimed epoch timestamp for (owner_, rewardToken_).

    3. Repeatedly calls earnedByEpoch(...) for each epoch from m_lastRewardClaim up to but not including currentEpochStart.

    4. Summation is the total pending rewards.


6. earnedByEpoch(address owner_, address rewardToken_, uint256 epoch_)

function earnedByEpoch(address owner_, address rewardToken_, uint256 epoch_) public view returns (uint256)
  • Description:

    • Returns how many rewardToken_ tokens were earned by owner_ specifically in a single epoch.

    • Calculated as rewardPerToken(rewardToken_, epoch_) * s_balanceByOwnerAndEpoch[owner_][epoch_] / 1e18.


7. rewardPerToken(address rewardToken_, uint256 epoch_)

function rewardPerToken(address rewardToken_, uint256 epoch_) public view returns (uint256)
  • Description:

    • Calculates the distribution ratio for rewardToken_ in a given epoch_.

    • If s_totalSupplyByEpoch[epoch_] is zero, it simply returns s_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)

function getReward(address owner_, address[] calldata rewardTokens_) external virtual;
  • 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)

function notifyRewardAmount(address rewardToken_, uint256 rewardAmount_) external virtual;
  • 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)

function _getReward(address owner_, address[] calldata rewardTokens_) internal
  • Description:

    • The internal function that loops over rewardTokens_, calculates earned(...), updates s_lastRewardClaimByOwnerAndToken, and transfers the reward to owner_.

    • Finally, emits RewardsClaimed(owner_, token, amount).


11. _notifyRewardAmount(address sender_, address rewardToken_, uint256 rewardAmount_) (internal)

function _notifyRewardAmount(address sender_, address rewardToken_, uint256 rewardAmount_) internal
  • Description:

    • Transfers rewardAmount_ of rewardToken_ from sender_ 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

constructor(address escrowVoteManager_, address escrowManager_) 
    RewardsDistributor(escrowVoteManager_, escrowManager_)
{}
  • Description:

    • Calls the RewardsDistributor constructor to set ESCROW_VOTE_MANAGER and ESCROW_MANAGER.

    • No additional logic besides inheritance.


getReward(address owner_, address[] calldata rewardTokens_)

function getReward(
    address owner_, 
    address[] calldata rewardTokens_
)
    external
    override (RewardsDistributor, IIncentiveRewardsDistributor)
    nonReentrant
  • Description:

    • Implementation of getReward from both RewardsDistributor (abstract) and IIncentiveRewardsDistributor.

    • Allows the escrow vote manager to claim rewards for owner_.

    • Calls _getReward(...) internally after checking msg.sender == ESCROW_VOTE_MANAGER.


notifyRewardAmount(address rewardToken_, uint256 rewardAmount_)

function notifyRewardAmount(
    address rewardToken_, 
    uint256 rewardAmount_
)
    external
    override (RewardsDistributor, IIncentiveRewardsDistributor)
    nonReentrant
  • Description:

    • Implementation of notifyRewardAmount from both RewardsDistributor (abstract) and IIncentiveRewardsDistributor.

    • First ensures rewardToken_ is whitelisted via s_isWhitelistedToken in IEscrowVoteManagerV1.

      • 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 to s_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

  1. TokensDeposited(from, tokenId, amount)

  2. TokensWithdrawn(from, tokenId, amount)

  3. RewardNotified(from, token, epoch, amount)

  4. 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 CrossCurve 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.

PreviousGaugeV1NextLockHolderFactoryV1

Last updated 1 month ago

📖
💻