# IncentiveRewardsDistributor

### Overview <a href="#overview" id="overview"></a>

**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 <a href="#inherited-contracts-and-interfaces" id="inherited-contracts-and-interfaces"></a>

* **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 <a href="#contract-architecture" id="contract-architecture"></a>

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

#### Inherited from **RewardsDistributor** <a href="#inherited-from-rewardsdistributor" id="inherited-from-rewardsdistributor"></a>

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` <a href="#functions-in-the-base-contract-rewardsdistributor" id="functions-in-the-base-contract-rewardsdistributor"></a>

#### 1. **Constructor** <a href="#id-1-constructor" id="id-1-constructor"></a>

```solidity
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_)`** <a href="#id-2-deposit-uint256-amount_-uint256-tokenid" id="id-2-deposit-uint256-amount_-uint256-tokenid"></a>

```solidity
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_)`** <a href="#id-3-withdraw-uint256-amount_-uint256-tokenid" id="id-3-withdraw-uint256-amount_-uint256-tokenid"></a>

```solidity
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()`** <a href="#id-4-getrewardtokenscount" id="id-4-getrewardtokenscount"></a>

```solidity
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_)`** <a href="#id-5-earned-address-owner_-address-rewardtoken" id="id-5-earned-address-owner_-address-rewardtoken"></a>

```solidity
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_)`** <a href="#id-6-earnedbyepoch-address-owner_-address-rewardtoken_-uint256-epoch" id="id-6-earnedbyepoch-address-owner_-address-rewardtoken_-uint256-epoch"></a>

```solidity
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_)`** <a href="#id-7-rewardpertoken-address-rewardtoken_-uint256-epoch" id="id-7-rewardpertoken-address-rewardtoken_-uint256-epoch"></a>

```solidity
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)** <a href="#id-8-getreward-address-owner_-address-calldata-rewardtokens_-abstract" id="id-8-getreward-address-owner_-address-calldata-rewardtokens_-abstract"></a>

```solidity
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)** <a href="#id-9-notifyrewardamount-address-rewardtoken_-uint256-rewardamount_-abstract" id="id-9-notifyrewardamount-address-rewardtoken_-uint256-rewardamount_-abstract"></a>

```solidity
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)** <a href="#id-10-_getreward-address-owner_-address-calldata-rewardtokens_-internal" id="id-10-_getreward-address-owner_-address-calldata-rewardtokens_-internal"></a>

```solidity
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)** <a href="#id-11-_notifyrewardamount-address-sender_-address-rewardtoken_-uint256-rewardamount_-internal" id="id-11-_notifyrewardamount-address-sender_-address-rewardtoken_-uint256-rewardamount_-internal"></a>

```solidity
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** <a href="#functions-in-incentiverewardsdistributor" id="functions-in-incentiverewardsdistributor"></a>

#### Constructor <a href="#constructor" id="constructor"></a>

```solidity
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_)` <a href="#getreward-address-owner_-address-calldata-rewardtokens" id="getreward-address-owner_-address-calldata-rewardtokens"></a>

```solidity
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_)` <a href="#notifyrewardamount-address-rewardtoken_-uint256-rewardamount" id="notifyrewardamount-address-rewardtoken_-uint256-rewardamount"></a>

```solidity
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 <a href="#events-and-errors" id="events-and-errors"></a>

#### Inherited Events <a href="#inherited-events" id="inherited-events"></a>

1. **`TokensDeposited(from, tokenId, amount)`**
2. **`TokensWithdrawn(from, tokenId, amount)`**
3. **`RewardNotified(from, token, epoch, amount)`**
4. **`RewardsClaimed(from, token, amount)`**

#### Inherited Errors <a href="#inherited-errors" id="inherited-errors"></a>

* **`InvalidRewardToken()`**
* **`UnauthorizedAccess()`**
* **`ZeroAmountProvided()`**
* **`NotWhitelisted()`**

No new custom events or errors are introduced in **IncentiveRewardsDistributor** beyond what’s inherited.

***

### Summary <a href="#summary" id="summary"></a>

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.crosscurve.fi/developer-documentation/guide-for-developers/technical-documentation-for-crosscurve-dao-smart-contracts/incentiverewardsdistributor.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
