# Yield Vault Staking Contract Manual

***

**Contents of Contract Manual**

[#id-1.-overview](#id-1.-overview "mention")

[#id-2.-key-concepts-and-terminology](#id-2.-key-concepts-and-terminology "mention")

[#id-3.-contract-lifecycle-and-epoch-logic](#id-3.-contract-lifecycle-and-epoch-logic "mention")\
[#id-3.1.-epoch-duration-and-alignment-with-flare](#id-3.1.-epoch-duration-and-alignment-with-flare "mention")\
[#id-3.2.-chunk-based-activation-pending-active](#id-3.2.-chunk-based-activation-pending-active "mention")\
[#id-3.3.-multi-token-fee-distribution-and-finalization](#id-3.3.-multi-token-fee-distribution-and-finalization "mention")\
[#id-3.4.-foton-as-the-staked-token-and-optional-reward-token](#id-3.4.-foton-as-the-staked-token-and-optional-reward-token "mention")\
[#id-3.5.-reward-retention-and-data-pruning](#id-3.5.-reward-retention-and-data-pruning "mention")

[#id-4.-user-actions](#id-4.-user-actions "mention")\
[#id-4.1.-staking-foton](#id-4.1.-staking-foton "mention")\
[#id-4.2.-withdrawing-pending-stake](#id-4.2.-withdrawing-pending-stake "mention")\
[#id-4.3.-unstaking-active-stake](#id-4.3.-unstaking-active-stake "mention")\
[#id-4.4.-claiming-rewards](#id-4.4.-claiming-rewards "mention")\
[#id-4.5.-additional-utility-functions](#id-4.5.-additional-utility-functions "mention")

[#id-5.-admin-and-owner-only-actions](#id-5.-admin-and-owner-only-actions "mention")\
[#id-5.1.-adding-and-removing-reward-tokens](#id-5.1.-adding-and-removing-reward-tokens "mention")\
[#id-5.2.-setting-the-minimum-stake-amount](#id-5.2.-setting-the-minimum-stake-amount "mention")\
[#id-5.3.-timelocked-emergency-withdrawals](#id-5.3.-timelocked-emergency-withdrawals "mention")\
[#id-5.4.-pausing-and-unpausing-the-vault](#id-5.4.-pausing-and-unpausing-the-vault "mention")

[#id-6.-pausable-feature](#id-6.-pausable-feature "mention")

[#id-7.-data-structures-and-storage](#id-7.-data-structures-and-storage "mention")\
[#id-7.1.-epoch-tracking](#id-7.1.-epoch-tracking "mention")\
[#id-7.2.-stakes](#id-7.2.-stakes "mention")\
[#id-7.3.-rewards](#id-7.3.-rewards "mention")\
[#id-7.4.-timelock-mechanism](#id-7.4.-timelock-mechanism "mention")\
[#id-7.5.-additional-aggregator-structures](#id-7.5.-additional-aggregator-structures "mention")

[#id-8.-deployment-and-initialization](#id-8.-deployment-and-initialization "mention")\
[#id-8.1.-constructor-logic](#id-8.1.-constructor-logic "mention")\
[#id-8.2.-external-address-setup](#id-8.2.-external-address-setup "mention")

[#id-9.-example-user-journeys](#id-9.-example-user-journeys "mention")\
[#id-9.1.-a-single-users-process-for-token-allocation-and-fee-distribution](#id-9.1.-a-single-users-process-for-token-allocation-and-fee-distribution "mention")\
[#id-9.2.-multiple-users-and-chunk-based-activation](#id-9.2.-multiple-users-and-chunk-based-activation "mention")\
[#id-9.3.-unstaking-mid-epoch](#id-9.3.-unstaking-mid-epoch "mention")\
[#id-9.4.-claiming-all-rewards](#id-9.4.-claiming-all-rewards "mention")\
[#id-9.5.-emergency-withdrawal-process](#id-9.5.-emergency-withdrawal-process "mention")

[#id-10.-error-conditions-and-reverts](#id-10.-error-conditions-and-reverts "mention")

[#id-11.-security-and-best-practices](#id-11.-security-and-best-practices "mention")

***

### Yield Vault Contract on [Routescan](https://routescan.io/address/0x00d5081E8B0e4a5f936A3f037F9f7BAE960cd545/contract/14/code) & [Flarescan](https://flarescan.com/address/0x00d5081E8B0e4a5f936A3f037F9f7BAE960cd545/contract/14/code)

***

### 1. Overview

**Yield Vault** is a mechanism within the Flareporium ecosystem that allows **FOTON** holders to deposit tokens. Participants may receive a share of platform-generated fees in the form of ERC-20 tokens, which are distributed according to platform activity. The vault aligns its internal epoch system with an external epoch provider (via the `IFlareEpoch` interface) and finalizes **fee distributions every epoch**. Key features include:

* **Pending-to-Active Stake Activation:** New deposits enter a pending state and become active on the next epoch boundary.
* **Multi-Token Fee Distributions:** The vault supports the redistribution of platform-generated fees across multiple ERC-20 tokens.
* **Epoch Synchronization & Finalization:** The vault monitors external epochs, finalizes epochs when new epochs are detected, and properly allocates newly arrived rewards.
* **Emergency Controls & Pausability:** Owner-only timelocked emergency withdrawal functions and pausable operations provide security and control.
* **Auto-Wrapping:** Incoming native FLR is automatically wrapped into WNAT.

***

### 2. Key Concepts & Terminology

* **Epoch:** A discrete period synchronized with the external epoch provider. Each epoch finalizes fee distributions based on the active stake.
* **Pending Stake:** Newly deposited FOTON enters a pending state. Pending stakes do not earn rewards until activated in the following epoch.
* **Active Stake:** Once pending stakes are activated, they become active and participate in the fee distribution until unstaked.
* **Reward Tokens:** Tokens distributed as rewards each epoch. WNAT is added by default, but the owner can add additional tokens.
* **Forfeiture:** When a user unstakes active FOTON mid-epoch, that portion is forfeited for the current epoch’s rewards.
* **Epoch Finalization:** The process that locks in reward parameters (such as the accumulated reward per share) for an epoch.
* **Data Pruning:** To conserve storage, epoch data older than a set depth (26 epochs) is pruned. Any leftover rewards from pruned epochs are reallocated if applicable.
* **Timelock:** A security delay (2 days) enforced on emergency withdrawals to allow community oversight.

***

### 3. Contract Lifecycle & Epoch Logic

#### 3.1. Epoch Duration & Alignment with Flare

* The vault does not manage time-based epochs internally. Instead, it continuously polls an external epoch provider (via the `IFlareEpoch.getCurrentRewardEpochId()` function).
* On detecting a new external epoch, the vault finalizes the previous epoch and advances its internal epoch counters:
  * `currentEpochId` is updated to match the external epoch.
  * `lastFinalizedEpochId` records the most recent epoch that has been finalized.

#### 3.2. Chunk-Based Activation (Pending → Active)

* Newly staked FOTON is initially recorded in the `pendingStake` mapping.
* On an epoch transition, the internal function `_activatePendingStakers()` processes pending stakers in manageable batches (up to a constant `MAX_ACTIVATIONS`, currently 250) to convert pending stakes into active stakes.
* Once activated, a user’s active stake is recorded and will participate in the epoch’s fee distribution.

#### 3.3. Multi-Token Fee Distribution & Finalization

* At the end of each epoch, the vault calculates the newly arrived rewards for each recognized token by comparing the current balance (after exclusions) with a previously recorded value.
* For each reward token:
  * The contract determines the distribution rate of collected platform fees per participant (`epochAccRewardPerShare`) based on the total active stake.
  * It records any leftover tokens in `epochTokenLeftover` for adjustments and reallocation.
* **Exclusion of Staked FOTON from Reward Calculations:**
  * To prevent double counting, the contract excludes the total staked FOTON from the available balance when FOTON is considered as a reward token.
  * The function `_getCurrentBalanceExcludingStake(address token)` handles this:
    * If the token is not FOTON, it simply returns the entire balance of that token held by the contract.
    * If the token is FOTON, it subtracts the total staked FOTON (both active and pending) from the contract’s balance.
  * Only any "surplus" FOTON (i.e., FOTON not already allocated as a stake) is considered as newly arrived reward, ensuring that staked tokens aren’t inadvertently counted as rewards.
* Reward calculations also account for any forfeited stake (from mid-epoch unstaking) using dedicated functions.

#### 3.4. FOTON as the Staked Token and Optional Reward Token

* FOTON is the token that users stake. It does not automatically function as a reward token.
* However, if desired, the owner may add FOTON to the recognized reward tokens list via the `addRewardToken` function.
* By default, only WNAT is pre-added as a reward token in the constructor.
* **Note:** When FOTON is optionally added as a reward token, its reward calculation follows the mechanism detailed in Section 3.3, where the contract excludes any staked FOTON from the balance used to calculate rewards.

#### 3.5. Reward Retention & Data Pruning

* The vault retains detailed epoch data for a fixed number of epochs. In this version, epochs older than **26** (defined by `EPOCH_PRUNE_DEPTH`) are pruned.
* During pruning, any unclaimed or leftover rewards are reallocated to the most recent finalizable epoch (typically `flareEpoch - 1`), ensuring that stale rewards are not lost.

***

### 4. User Actions

#### 4.1. Staking FOTON

* **Function:** `stake(uint256 amount)`
* **Process:**
  * The user must approve the vault to spend their FOTON.
  * Upon calling `stake`, the specified amount (which must be nonzero and, if a minimum stake is set, at least `minStakeAmount`) is transferred from the user to the vault.
  * The deposited FOTON is recorded in the user’s `pendingStake` balance and the user is added to the `pendingStakers` list if not already present.

#### 4.2. Withdrawing Pending Stake

* **Function:** `withdrawPendingStake(uint256 amount)`
* **Process:**
  * If a user decides not to wait for activation, they may withdraw any portion (or the entirety) of their pending stake.
  * If withdrawing a partial amount results in a remaining balance below `minStakeAmount`, the entire pending stake may be withdrawn to avoid unusable leftovers.

#### 4.3. Unstaking Active Stake

* **Function:** `unstake(uint256 amount)`
* **Process:**
  * Active staked FOTON can be withdrawn by calling `unstake` with a positive amount.
  * The function deducts the unstaked amount from the user’s active stake and the global total.
  * The unstaked amount is immediately transferred back to the user.
  * Importantly, any amount unstaked during an epoch forfeits its share of rewards for that epoch; the corresponding forfeiture is recorded against the user’s epoch info.

#### 4.4. Claiming Rewards

* **Function:** `claimAll()`
* **Process:**
  * This function claims all rewards for the caller across all epochs that have been finalized (and not pruned).
  * The rewards for each recognized token are calculated based on the user’s effective stake (active stake minus any forfeited portion).
  * Upon a successful claim, the appropriate reward token amounts are transferred to the user.
  * Claiming also marks the user’s epoch stake as claimed to prevent double claims.

#### 4.5. Additional Utility Functions

The contract includes several read-only functions to aid in data retrieval and aggregation:

* **Aggregators:**
  * `getUserDataAcrossEpochs`, `getGlobalDataAcrossEpochs`, `getEverything`, and `getEpochDetails` return detailed views of a user’s staking data and epoch-by-epoch reward information.
* **Balances & Rewards:**
  * `getRewardTokens` returns the list of recognized reward tokens.
  * `getUserTotalUnclaimed` provides an aggregated view of pending rewards across epochs.

***

### 5. Admin & Owner-Only Actions

#### 5.1. Adding & Removing Reward Tokens

* **Adding Reward Tokens:**
  * **Function:** `addRewardToken(address token)`
  * The owner can designate additional ERC-20 tokens for fee distribution.
* **Removing Reward Tokens:**
  * **Function:** `removeRewardToken(address token)`
  * Tokens may be removed from the recognized list except for WNAT, which is permanently retained.

#### 5.2. Setting the Minimum Stake Amount

* **Function:** `setMinStakeAmount(uint256 _amount)`
* The owner may update the minimum FOTON deposit required from users. This ensures that very small stakes are avoided.

#### 5.3. Timelocked Emergency Withdrawals

* **Functions:**
  * `scheduleEmergencyWithdraw(address token, address to, uint256 amount, bool isNative)`
  * `cancelEmergencyWithdraw()`
  * `executeEmergencyWithdraw()`
* **Process:**
  * The owner can schedule an emergency withdrawal by specifying the token, recipient address, amount, and whether the token is native (the parameter is named `isNative`).
  * A timelock delay of **2 days** is imposed before the withdrawal can be executed, allowing time for oversight.
  * The owner may cancel a pending request before execution.

#### 5.4. Pausing and Unpausing the Vault

* **Functions:** `pause()` and `unpause()`
* The owner can pause user-facing operations (staking, unstaking, claiming) during emergencies while retaining the ability to execute administrative functions.

***

### 6. Pausable Feature

* The contract inherits from OpenZeppelin’s Pausable.
* When paused, functions related to staking, unstaking, and reward claiming will revert.
* The pause mechanism provides an important safety valve during unforeseen issues or attacks.

***

### 7. Data Structures & Storage

#### 7.1. Epoch Tracking

* **Variables:**
  * `currentEpochId`: The current internal epoch, synchronized with the external provider.
  * `lastFinalizedEpochId`: The most recently finalized epoch.
  * `epochs`: A mapping where each epoch record contains:
    * A boolean `finalized` flag.
    * `totalActiveStake` for that epoch.
* **Pruning:**
  * The constant `EPOCH_PRUNE_DEPTH` (set to 26) defines how many epochs are retained. Epochs older than this depth are pruned and their leftover rewards reallocated if necessary.

#### 7.2. Stakes

* **Mappings:**
  * `pendingStake`: Records FOTON amounts deposited by users but not yet activated.
  * `activeStake`: Tracks the user’s active stake which participates in rewards.
* **Global Variables:**
  * `totalActiveStake` and `totalPendingFotonStake` aggregate user stakes.
* **Activation Queue:**
  * `pendingStakers` (an array) and the `inPendingList` mapping are used to manage and process pending stakers in batches.

#### 7.3. Rewards

* **Reward Tokens:**
  * The array `rewardTokens` and the mapping `isRewardToken` manage the list of tokens eligible for rewards.
* **Reward Accounting:**
  * `totalRecognizedForToken` tracks the cumulative rewards recognized for each token.
  * `epochAccRewardPerShare` stores the accumulated reward per share for each token and epoch.
  * `userRewardDebt` tracks the reward debt for each user per token and epoch.
  * `epochTokenLeftover` maintains any leftover reward tokens for reallocation.

#### 7.4. Timelock Mechanism

* **Structure:**
  * `TimelockRequest` records the parameters for an emergency withdrawal (token, recipient, amount, whether native, and the earliest execution time).
* **Delay:**
  * A constant `TIMELOCK_DELAY` of 2 days is enforced.

#### 7.5. Additional Aggregator Structures

* The contract defines several structs (such as `TokenRewardEpochData`, `UserEpochData`, `TokenBalances`, `VaultGlobalData`, and others) to facilitate comprehensive data retrieval via its view functions.

***

### 8. Deployment & Initialization

#### 8.1. Constructor Logic

* The constructor accepts three addresses:
  * The external epoch provider (conforming to `IFlareEpoch`).
  * The wrapped native token (WNAT).
  * The FOTON token.
* It initializes the epoch counters by querying the external epoch provider.
* WNAT is added by default to the recognized reward tokens.

#### 8.2. External Address Setup

* Unlike previous versions that hard-coded addresses, the current contract receives all key external addresses (epoch provider, WNAT, and FOTON) via the constructor parameters.
* This design improves flexibility and reusability across different network environments.

***

### 9. Example User Journeys

#### 9.1. A Single User's Process for Token Allocation and Fee Distribution

1. **Approval & Deposit:**
   * The user approves the vault to deposit their FOTON and calls `stake(amount)`.
2. **Pending State:**
   * The deposited amount is recorded in the user’s pending stake.
3. **Epoch Transition:**
   * On the next epoch boundary (triggered by any function call that synchronizes epochs), the pending stake is activated.
4. **Reward Accrual & Claim:**
   * The user’s active stake may receive a proportional share of collected platform fees during the epoch. The `claimAll()` function allows users to retrieve their calculated share.

#### 9.2. Multiple Users & Chunk-Based Activation

* Numerous users deposit FOTON concurrently, populating the `pendingStakers` list.
* During epoch synchronization, up to 250 pending stakers are processed in a single batch, converting their pending stakes to active stakes.
* Remaining pending stakers will be processed in subsequent activations.

#### 9.3. Unstaking Mid-Epoch

* A user calls `unstake(amount)` to withdraw part of their active stake.
* The specified amount is removed from their active stake, and the user immediately receives the tokens.
* The withdrawn amount forfeits its share of rewards for the current epoch.

#### 9.4. Claiming All Rewards

* A user can call `claimAll()` at any time to retrieve their share of platform fee distributions from finalized epochs (subject to pruning limits).
* The function iterates over eligible epochs, calculates pending rewards (accounting for any forfeitures), and transfers the tokens.

#### 9.5. Emergency Withdrawal Process

1. **Scheduling:**
   * The owner calls `scheduleEmergencyWithdraw` with the target token, recipient, amount, and whether the token is native.
   * A timelock is set (2 days delay).
2. **Cancellation (Optional):**
   * The owner may cancel the scheduled withdrawal via `cancelEmergencyWithdraw` before execution.
3. **Execution:**
   * After the delay, `executeEmergencyWithdraw` can be called by the owner to complete the transfer.

***

### 10. Error Conditions & Reverts

* **Zero Amounts:**
  * Functions revert if the provided amount is zero (e.g., `"Zero stake"` or `"Zero unstake"`).
* **Minimum Stake:**
  * Deposits below the `minStakeAmount` (when set) will revert with an error (e.g., `"Below minStake"`).
* **Insufficient Balance:**
  * Withdrawals of pending or active stake will revert if the user does not have sufficient balance.
* **Pausable State:**
  * When the vault is paused, calls to stake, unstake, or claim will revert.
* **Timelock Violations:**
  * Emergency withdrawals cannot be executed before the timelock delay has passed, and attempts to schedule a new withdrawal while one is pending will revert.

***

### 11. Security & Best Practices

* **Reentrancy Protection:**
  * All functions that transfer tokens (e.g. stake, unstake, claim) are protected with OpenZeppelin’s ReentrancyGuard to prevent reentrancy attacks
* **Pausability:**
  * The owner can pause the contract during emergencies to prevent further deposits, withdrawals, or claims.
* **Timelock on Critical Functions:**
  * Emergency withdrawals are subject to a 2-day timelock, providing a window for community oversight.
* **Data Pruning:**
  * By limiting the number of retained epochs (26), the contract reduces long-term storage growth and potential performance issues.
* **Auto-Wrapping of Native Tokens:**
  * Incoming native FLR is automatically wrapped into WNAT, ensuring consistency in reward token accounting.
* **Careful Reward Accounting:**
  * The fee distribution mechanism excludes staked FOTON from reward calculations, preventing accidental double-counting.
* **Administrative Controls:**
  * Owner-only functions (such as pausing, setting minimum stakes, and managing reward tokens) are secured through access control (Ownable).

***

### **Conclusion**

The Yield Vault contract provides a structured mechanism for FOTON holders to participate in platform activity and receive distributions in multiple ERC-20 tokens. It aligns with external Flare epochs, handles staker onboarding in manageable chunks to mitigate gas spikes, and allows stakers to claim rewards and withdraw any stake as they see fit.

**Remember:**

* Always stake above the `minStakeAmount`.
* Monitor the vault’s epoch transitions to know when your stake becomes active.
* Claim rewards before data pruning (26 epochs) to avoid forfeiture.
* In any emergency, watch for timelock announcements of large withdrawals.

{% hint style="info" %}
Users should carefully consider their participation. Staking is not risk-free, and distributions are based on platform activity rather than guaranteed returns.
{% endhint %}

***

**We hope this manual provides a clear and comprehensive guide for both end users and technical integrators. If you have any additional questions, please refer to the contract’s source code comments or contact the project maintainers.**
