USUAL staking
High-Level Overview
The AbstractYieldBearingVault contract is an abstract contract that extends the ERC4626Upgradeable contract and provides functionality for a vault where shares appreciate in value due to yield accrual. The contract tracks total assets deposited and accrues yield over time based on a configurable yield rate and distribution period.
Inherited by:
USUALxContract Summary
The contract provides the following main functions:
totalAssets: Calculates the total assets in the vault, including accrued yield.
_deposit: Internal function to handle 4626 deposits and mints, updates yield, and tracks total deposits explicitly to avoid vault donation attacks.
_withdraw: Internal function to handle 4626 withdrawals and mints, updates yield, and updates total deposits.
_calculateEarnedYield: Calculates the amount of yield earned since the last update.
_updateYield: Updates the yield state by calculating yield earned and adding it to total deposits.
_startYieldDistribution: Starts a new yield distribution period.
The contract uses a separate internal storage structure (YieldDataStorage) to store yield-related state variables, including total deposits, yield rate, period start and finish times, last update time, and maximum period length.
Inherited Contracts
ERC4626Upgradeable : The contract inherits from the ERC4626Upgradeable contract, which provides the standard implementation for tokenized vaults.
Functionality Breakdown
The contract's main functionality is to provide a foundation for implementing yield-bearing vaults that follow the ERC4626 standard. The contract handles the calculation and distribution of yield, updating the total assets in the vault based on the accrued yield.
Yield Calculation and Distribution:
The contract tracks the total assets deposited and accrues yield over time based on a configurable yield rate and distribution period.
The _calculateEarnedYield function calculates the amount of yield earned since the last update, taking into account the active yield period and the yield rate.
The _updateYield function updates the yield state by calculating the earned yield and adding it to the total deposits. It also updates the last update timestamp and deactivates the yield period if it has finished.
The _startYieldDistribution function starts a new yield distribution period with a specified yield amount, start time, and end time.
Deposits and Withdrawals:
The contract overrides the internal _deposit and _withdraw functions from the ERC4626Upgradeable contract to handle deposits and withdrawals while considering the yield accrual.
The _deposit function updates the yield, takes the deposited assets, mints shares, and updates the total deposits.
The _withdraw function updates the yield, burns shares, transfers the withdrawn assets, and updates the total deposits.
Total Assets Calculation:
The totalAssets function calculates the total assets in the vault, including the accrued yield, by adding the total deposits and the earned yield.
Security Analysis
Method: totalAssets
Calculates the total assets in the vault, including accrued yield since the last time totalDeposits was updated. This effectively allows yield to accrue uniformly over time.
Function is declared as
public view
, allowing external calls without state modifications.Retrieves the YieldDataStorage struct from storage.
Calculates current assets by adding total deposits and earned yield since the last time total deposits was updated if there is an active yield period.
Returns the calculated current assets as the total assets in the vault.
Method: _deposit
Internal function to handle deposits, update yield, and track total deposits explicitly to only count the yield that has accrued so far. Addresses the vault donation attack. Can be overridden in the concrete implementation to allow for fees.
1-5. Function is internal, virtual, overrides the parent contract's _deposit function.
Retrieves the YieldDataStorage struct from storage.
Updates the yield accrued by the vault before processing the deposit.
Calls the ERC4626Upgradeable contract's _deposit function to take assets and mint.
Finally updates the totalDeposits by adding the deposited assets.
Method: _withdraw
Internal function to handle withdrawals, update yield, and adjust total deposits explicitly. Can be overriden in the concrete implementation to allow for withdraw fees.
1-7. Function is internal, virtual, overrides the parent contract's deposit function.
Retrieves the YieldDataStorage struct from storage.
Updates the yield before processing the withdrawal.
Calls the parent contract's _withdraw function to burn shares then transfer assets.
Updates the totalDeposits by subtracting the withdrawn assets.
Method: _calculateEarnedYield
Calculates the amount of yield earned since the last update without updating state.
Function is declared as internal view, allowing only internal calls without state modifications.
Retrieves the YieldDataStorage struct from storage.
Returns 0 if there's no active yield period.
Calculates the end time as the minimum of current time and period finish time.
Calculates the duration since the last update capped at the current yield period finish time.
Calculates and returns the earned yield by multiplying by yield rate as tokens/second allowing for high decimal precision and rounding down.
Method: _updateYield
Updates the yield storage by calculating earned yield at the current time stamp and adding it to total deposits, then updates the last update time capped at the end of the current yield period. No-op if there is active yield period because the contract was just deployed or the previous yield period has finished.
Function is declared as internal virtual, allowing internal calls and potential overrides.
Retrieves the YieldDataStorage struct from storage.
Returns early if there's no active yield period.
Calculates the new yield earned since the lastUpdateTime.
Adds the new yield to total deposits.
Updates the last update time, capped at the period finish time. 10-12. Deactivates the yield period if it has finished.
Method: _startYieldDistribution
This method is left abstract and needs to be implemented in the derived contract. It's crucial for setting up the variables needed for calculating and updating yield. When implementing this method, consider the following:
Set the
yieldRate
based on theyieldAmount
and the duration (endTime - startTime
) times the YIELD_PRECISION.Update
periodStart
,periodFinish
, andlastUpdateTime
.Set
isActive
to true to enable yield calculations.Implement proper access control to prevent unauthorized yield distributions.
Ensure that the new distribution period doesn't overlap with an existing active period.
Last updated