USD0++
High-Level Overview
This smart contract manages a staking-like financial instrument for the UsualDAO ecosystem. It provides functionality for minting, transferring, and unstaking the liquid token. The contract complies with ERC20 standards and allows users to stake USD0 to mint USD0++ or acquire it on the secondary market.
USD0 Liquid Staking Token (USD0++) is issued when a user stakes their USD0 for up to 4 years. In return, they receive a composable, transferable, and yield-bearing* USD0++.
Minting USD0++
Users can stake their USD0 to convert them into USD0++. The issuance of USD0++ follows a 1:1 ratio with the staked USD0. Once staked, the assets remain immobilized for the maturity period of the USD0++ liquid stake, ensuring stability and predictability.
Staking and Issuance
Locking USD0: Users stake their USD0 to mint USD0++.
1:1 Issuance: USD0++ is issued on a 1:1 basis with the locked USD0.
Locked Duration: Assets are locked for the maturity period of the USD0++ liquid staking token.
Floor Price Mechanism
USD0++ includes a floor price mechanism, allowing users to unstake their USD0++ for USD0 at a guaranteed minimum rate.
updateFloorPrice(uint256 newFloorPrice)
: Allows authorized admins to update the floor price. Only callable by theFLOOR_PRICE_UPDATER_ROLE
role.unlockUsd0ppFloorPrice(uint256 usd0ppAmount)
: Allows users to unstake their USD0++ at the current floor price.
USUAL Burn Mechanism
USD0++ includes an early redemption mechanism that allows users to unlock their USD0++ before maturity by burning USUAL tokens. The amount of USUAL required for redemption is dynamically calculated based on several factors:
Key Functions
unlockUSD0ppWithUsual(uint256 usd0ppAmount, uint256 maxUsualAmount)
: Allows users to redeem USD0++ by burning USUAL tokensunlockUSD0ppWithUsualWithPermit(...)
: Same as above but includes permit functionality for gasless approvalscalculateRequiredUsual(uint256 usd0ppAmount)
: Calculates the amount of USUAL needed to redeem a given amount of USD0++
Calculation Factors
The required USUAL amount is determined by:
Base Distribution Rate: Amount of USUAL distributed per USD0++ per day
Duration Cost: Adjusts cost based on time window
Net Outflows: Considers weekly redemption volume
Treasury Allocation: A portion of burned USUAL is sent to treasury instead of being burned
Parameters (Configurable by governance)
usualDistributionPerUsd0pp
: Base USUAL distribution ratedurationCostFactor
: Multiplier for time-based cost adjustmenttreasuryAllocationRate
: Percentage of USUAL sent to treasury (in basis points)targetRedemptionRate
: Target weekly redemption rate (in basis points of total supply)
Example Flow
User calls
calculateRequiredUsual()
to determine USUAL costUser approves USUAL spend (or uses permit)
User calls
unlockUSD0ppWithUsual()
with desired USD0++ amount and maximum USUAL willing to burnContract burns portion of USUAL, sends portion to treasury, and returns USD0 to user
The mechanism helps maintain protocol stability by adjusting costs based on redemption volume and ensuring controlled unwinding of USD0++ positions.
Peg Maintainer
unwrapPegMaintainer(uint256 amount)
: Allows peg maintainers to unwrap liquid staking tokens at any time. Only callable by thePEG_MAINTAINER_ROLE
role.
Early Unlock Period
The contract includes functionality for a temporary early unlock period, allowing users to unwrap their liquid staking tokens before the full maturity period under certain conditions. This is a temporary mechanism specifically related to the airdrop
setupEarlyUnlockPeriod(uint256 bondEarlyUnlockStart, uint256 bondEarlyUnlockEnd)
: Sets up the early unlock period. Only callable by theEARLY_BOND_UNLOCK_ROLE
role.temporaryOneToOneExitUnwrap(uint256 amountToUnwrap)
: Allows users to unwrap their bonds during the early unlock period. This voids any USUAL airdrop that they are entitled toallocateEarlyUnlockBalance(address[] calldata addressesToAllocateTo, uint256[] calldata balancesToAllocate)
: Allocates early unlock balances to specific addresses that have accumulated potential airdrop rewards. Only callable by theEARLY_BOND_UNLOCK_ROLE
role.
Regulatory Compliance
The contract includes a blacklist feature to ensure regulatory compliance. Sanctioned addresses are prevented from interacting with the contract and are kept up to date.
Functionality Breakdown
The contract flow begins with the initialization of liquid staking token parameters and related registry and token information. Liquid staking tokens can be minted, transferred, and unstaked. The contract also allows for emergency withdrawals of the underlying token.
Functions Description
Public/External Functions (non-view / non-pure)
pause()
: Pauses all token transfer operations; callable only by thePAUSING_CONTRACTS_ROLE
.unpause()
: Resumes all token transfer operations; callable only by theDEFAULT_ADMIN_ROLE
.setupEarlyUnlockPeriod(uint256 bondEarlyUnlockStart, uint256 bondEarlyUnlockEnd)
: Sets up the early unlock period. Only callable by theEARLY_BOND_UNLOCK_ROLE
role.mint(uint256 amountUsd0)
: Mints new bonds by locking the specified amount of collateral token.mintWithPermit(uint256 amountUsd0, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
: Mints new bonds with a permit signature.unwrap()
: Unwraps the bonds and transfers the underlying collateral token to the user.temporaryOneToOneExitUnwrap(uint256 amountToUnwrap)
: Allows users to unwrap their bonds during the early unlock period.allocateEarlyUnlockBalance(address[] calldata addressesToAllocateTo, uint256[] calldata balancesToAllocate)
: Allocates early unlock balances to specific addresses. Only callable by theEARLY_BOND_UNLOCK_ROLE
role.unwrapPegMaintainer(uint256 amount)
: Allows peg maintainers to unwrap bonds at any time. Only callable by thePEG_MAINTAINER_ROLE
role.triggerPARMechanismCurvepool(uint256 parUsd0Amount, uint256 minimumPARMechanismGainedAmount)
: Triggers the PAR mechanism in the Curve pool.emergencyWithdraw(address safeAccount)
: Allows for the emergency withdrawal of the underlying collateral token.updateFloorPrice(uint256 newFloorPrice)
: Allows authorized users to update the floor price. Only callable by theFLOOR_PRICE_UPDATER_ROLE
role.unlockUsd0ppFloorPrice(uint256 usd0ppAmount)
: Allows users to unlock their USD0++ at the current floor price.transfer(address recipient, uint256 amount)
: Transfers bonds from the sender to the recipient.transferFrom(address sender, address recipient, uint256 amount)
: Transfers bonds from the sender to the recipient on behalf of the sender.
View Functions
totalBondTimes()
: Returns the total staking duration.getBondEarlyUnlockDisabled(address user)
: Checks if early unlock is disabled for a user.getStartTime()
: Returns the start time of the staking period.getEndTime()
: Returns the end time of the staking period.getFloorPrice()
: Returns the current floor price.getTemporaryUnlockStartTime()
: Returns the start time of the temporary unstaking period.getTemporaryUnlockEndTime()
: Returns the end time of the temporary unstaking period.getAllocationEarlyUnlock(address addressToCheck)
: Returns the early unstaking allocation for an address.
Last updated