Usual USD0++ Investment Vault
High-Level Overview
The WrappedDollarVault contract is an upgradeable ERC4626-compliant yield-bearing vault. The contract leverages OpenZeppelin's upgradeable contracts for enhanced security and flexibility, including pausability and reentrancy protection.
The vault holds another USD-denominated ERC4626 and allows users to deposit and withdraw this token, with fees accrued in USD, and a monotonic increase in USD value per share only, rather than a monotonic increase in assets or share. The price in units of asset decreases over time due to fees accruing.
Only the registered router via the setRouter() function can call deposit, mint, withdraw, redeem . The goal of the router is to allow for swaps and permits for approvals, ensuring that arbitrary tokens are accepted as input and USD0++ is accepted as output.
The primary objective of the investment vault is to have a generic contract to allow wrapping of yield bearing token from external strategies without leaving the Usual ecosystem.
Contract Summary
The contract provides the following main functions:
pause
: Pause the vault's functionality.unpause
: Unpause the vault's functionality.setRouter
: Add or remove a router.setFeeRateBps
: Set the fee rate in basis points.harvest
: Harvest management fees by minting shares to the treasury.feeRateBps
: Returns the fee rate in basis points.getRouterState
: Returns the state of a router.decimals
: Returns the number of decimals of the vault.withdraw
/redeem
: Handles asset withdrawals and share redemptions, incorporating withdrawal fees.mint
/deposit
: Handles depositing asset and mint shares of the vaultpreviewWithdraw
/previewRedeem
: Simulates withdrawal and redemption operations for users.
Inherited Contracts
PausableUpgradeable: Enables emergency halt of contract operations.
ReentrancyGuardUpgradeable: Prevents reentrancy attacks in critical functions.
ERC20PermitUpgradeable: Extends ERC20 to support gasless transactions through signed
ERC4626Upgradable: Provide a standard implementation for ERC4626 vault.
Functionality Breakdown
Access Control and Security:
Utilizes a registry contract for role-based access control.
Implements specific role to set router
VAULT_SET_ROUTER_ROLE
, set feeVAULT_SET_FEE_ROLE
and harvestVAULT_HARVESTER_ROLE
to prevent specific addresses from interacting with the contract.Enforces router registration for all the creation and destruction of vault shares, allowing only previously set router addresses to interact with the vault.
Fee Management:
Allows admin-controlled daily harvest of fee to the treasury.
Accrues fees over time based on configurable parameters. Fees are due when withdrawing and redeeming
The number of underlying assets behind a share decreases over time due to fee accruing.
Asset Management:
Implements ERC4626 standard for standardized vault interactions.
Handles withdrawals, and redemption with consideration for accrued fees.
Asset is yield bearing so its USD value will increase overtime.
Upgradability and Pause Mechanism:
Utilizes OpenZeppelin's upgradeable contract pattern for future improvements.
Includes pause functionality for emergency situations.
Security Analysis
Method: initialize
Initializes the vault, setting up the registry contract, underlying asset, name, symbol, and initial vault state.
11-12. Ensures valid registry contract and underlying asset addresses, reverting if either is zero to prevent null references.
Initializes inherited contracts for reentrancy protection
14-15. ERC20 functionality sets the vault name, symbol and permit support.
16-17. Pausability, and ERC4626 vault standards with the underlying asset.
19-22. Sets up contract storage with the registry contract, access control from the registry.
23-26. treasury address, default fee rate, last fee update timestamp, and mints initial shares to a dead address.
Method: setRouter
Add or disable a router, updating its active state.
1. Sets the router address is only callable when the vault is not paused.
3-4. Checks that the caller has the VAULT_SET_ROUTER_ROLE
via the registry’s access control, reverting if unauthorized.
5. Ensures the router address is not zero, reverting if null to prevent invalid settings.
7-8. Verifies the router’s current state differs from the requested state, reverting if unchanged to avoid redundant updates.
9-10. Updates the router’s active state in storage and emits a RouterUpdated
event with the router address and new status.
Method: setFeeRateBps
Set the fee rate in basis points, updating the vault’s fee structure.
1-2. Sets a new fee rate in micro basis points is only callable when the vault is not paused, with a check to ensure it doesn’t exceed the maximum allowed fee rate.
5-6. Verifies the caller has the VAULT_SET_FEE_ROLE
via the registry’s access control, reverting if unauthorized.
8. Ensures the new fee rate differs from the current rate, reverting if unchanged to avoid redundant updates.
9-10. Confirms at least one week has passed since the last fee update, reverting if too frequent to maintain stability.
12-15. Stores the old fee rate, updates the fee rate and timestamp in storage, and emits a FeeRateUpdated
event with the old and new rates.
Method: harvest
Harvest management fees by minting shares to the treasury based on the current fee rate
1-5. Initiates the harvest process to mint shares for management fees, callable only when not paused and non-reentrant, returning the number of shares minted.
9-10. Verifies the caller has the VAULT_HARVESTER_ROLE
via the registry’s access control, reverting if unauthorized.
13-14. Ensures at least one day has passed since the last harvest, reverting if too frequent to prevent abuse.
17-20. Calculates the shares to mint based on the current total supply and fee rate, reverting if the result is zero to avoid empty operations.
22-28. Updates the last harvest timestamp, mints the calculated shares to the treasury, emits a Harvested
event with the caller and shares minted, and returns the shares minted.
Method: previewWithdraw
1-6. Previews the withdrawal process by calculating the shares needed to withdraw a given amount of assets, including the applicable fee, overriding the ERC4626 implementation.
8-10. Retrieves the vault’s storage and calculates the fee based on the requested assets and the current fee rate in basis points.
13. Adds the fee to the requested assets and uses the parent ERC4626 previewWithdraw
function to determine the total shares required, returning the result.
Method: previewRedeem
Previews the amount of assets that would be returned for redeeming a specified number of shares, after deducting fees
1-6. Previews the redemption process by calculating the assets returned for a given number of shares, after subtracting the applicable fee, overriding the ERC4626 implementation.
9. Uses the parent ERC4626 previewRedeem
function to convert the shares into assets.
13. Calculates the fee based on the raw asset amount and the current fee rate in basis points.
12. Returns the assets minus the calculated fee as the final redeemable amount
Method: _withdraw
Internal function to handle the withdrawal of assets, including minting fee shares to the treasury.
1-9. Executes the withdrawal process internally, taking the caller, receiver, owner, assets, and shares as inputs, overriding the parent implementation to include fee handling. 15. Calculates the fee in shares based on the raw shares being withdrawn and the current fee rate in basis points. 18. Calls the parent _withdraw function to perform the core withdrawal logic for the specified assets and shares. 21-22. Mints the calculated fee shares to the treasury if the fee is greater than zero, ensuring fees are collected.
Last updated
Was this helpful?