Vault
The Vault is the core abstract contract inherited by every cUSD deployment. It holds the backing assets deposited by cUSD minters and lent out to whitelisted Operators, tracking total supplies and borrows per asset. Mint/burn/redeem operations flow through the Minter for fee calculation and through the FractionalReserve layer for liquidity management — the Vault itself only tracks principal amounts, leaving interest calculations to the Lender.
Mechanics
Minting cUSD
Depositing a backing asset in exchange for cUSD:
Deposit cap check:
_amountInis silently capped to the remaining deposit capacity for the asset.Fee calculation: The Minter computes
(amountOut, fee)based on the asset's current allocation ratio vs. its optimal ratio.Slippage / deadline check: Reverts if
amountOut < _minAmountOutor the deadline has passed.Transfer in: The asset is pulled from
msg.senderandtotalSupplies[asset]is incremented.Mint:
amountOutcUSD is minted to_receiver; if a fee applies, an additionalfeecUSD is minted to the insurance fund.
Burning cUSD
Exchanging cUSD for a single backing asset:
Fee calculation: The Minter computes the post-fee asset output and fee amount.
cUSD burn:
_amountIncUSD is burned frommsg.sender.Divest: The FractionalReserve layer divests
amountOut + feeof the asset from the active yield strategy if needed to cover the withdrawal.Transfer out:
amountOutis sent to_receiver;feeis sent to the insurance fund.totalSupplies[asset]is decremented.
Redeeming cUSD
Proportional withdrawal across every backing asset:
Amount calculation: The Minter computes proportional
amountsOutandfeesfor each asset in the vault.cUSD burn:
_amountIncUSD is burned frommsg.sender.Divest many: The FractionalReserve layer divests the required amounts across all assets.
Transfer out: For each asset,
amountsOut[i]is sent to_receiverandfees[i]to the insurance fund.
Borrowing and Repaying
These paths are access-controlled and called only by the Lender contract:
Borrow: Divests the asset from the yield strategy if needed, decrements available balance, transfers to
_receiver, incrementstotalBorrows[asset].Repay: Accepts the asset back from the Lender via
transferFrom, decrementstotalBorrows[asset].
Utilization Tracking
The vault tracks a cumulative utilization index per asset — a time-weighted integral of the utilization ratio. This is consumed by the RateOracle to compute borrow interest rates.
The index is updated on every mint, burn, borrow, and repay via the updateIndex modifier.
Architecture
Core Functions
mint(address _asset, uint256 _amountIn, uint256 _minAmountOut, address _receiver, uint256 _deadline)
mint(address _asset, uint256 _amountIn, uint256 _minAmountOut, address _receiver, uint256 _deadline)Deposit _asset and receive cUSD. Requires ERC20 approval from msg.sender to the vault. _amountIn is silently reduced to the remaining deposit cap if exceeded.
_asset
address
Whitelisted backing asset to deposit
_amountIn
uint256
Amount of asset to deposit
_minAmountOut
uint256
Minimum cUSD to receive (slippage protection)
_receiver
address
Recipient of the minted cUSD
_deadline
uint256
Unix timestamp after which the tx reverts
Returns: amountOut — cUSD minted to _receiver (excludes fee).
burn(address _asset, uint256 _amountIn, uint256 _minAmountOut, address _receiver, uint256 _deadline)
burn(address _asset, uint256 _amountIn, uint256 _minAmountOut, address _receiver, uint256 _deadline)Burn _amountIn cUSD and receive _asset. The caller must hold the cUSD.
_asset
address
Backing asset to withdraw
_amountIn
uint256
Amount of cUSD to burn
_minAmountOut
uint256
Minimum asset to receive (slippage protection)
_receiver
address
Recipient of the asset
_deadline
uint256
Unix timestamp after which the tx reverts
Returns: amountOut — asset sent to _receiver (excludes fee).
redeem(uint256 _amountIn, uint256[] calldata _minAmountsOut, address _receiver, uint256 _deadline)
redeem(uint256 _amountIn, uint256[] calldata _minAmountsOut, address _receiver, uint256 _deadline)Burn _amountIn cUSD and receive a proportional share of every backing asset. _minAmountsOut must have one entry per vault asset in the same order as assets().
Returns: amountsOut — asset amounts sent to _receiver (one per vault asset).
borrow(address _asset, uint256 _amount, address _receiver)
borrow(address _asset, uint256 _amount, address _receiver)Access-controlled. Called by the Lender to transfer assets to an Operator. Reverts with InsufficientReserves if available balance is too low.
repay(address _asset, uint256 _amount)
repay(address _asset, uint256 _amount)Access-controlled. Called by the Lender when an Operator repays. Pulls _amount from msg.sender via transferFrom.
availableBalance(address _asset)
availableBalance(address _asset)Returns totalSupplies[_asset] - totalBorrows[_asset] — the amount currently available to borrow or withdraw.
utilization(address _asset)
utilization(address _asset)Returns the current utilization ratio in ray format (1e27 = 100%). For example, 5e26 = 50% utilization.
currentUtilizationIndex(address _asset)
currentUtilizationIndex(address _asset)Returns the up-to-date cumulative utilization index including the current unsettled period. Used by the RateOracle for interest rate calculations.
getRemainingMintCapacity(address _asset)
getRemainingMintCapacity(address _asset)Returns how much more of _asset can be deposited before hitting the deposit cap. Returns 0 if the cap is already reached.
Admin Functions
addAsset(address _asset)
Add a new backing asset to the vault
removeAsset(address _asset)
Remove an asset (only if totalSupplies == 0)
pauseAsset(address _asset)
Pause minting, burning, and borrowing for a specific asset
unpauseAsset(address _asset)
Resume operations for a paused asset
pauseProtocol()
Pause all vault operations globally
unpauseProtocol()
Resume all vault operations
setInsuranceFund(address)
Update the insurance fund address
rescueERC20(address _asset, address _receiver)
Recover a non-vault, non-strategy token sent to the contract by mistake
Data Structures
VaultStorage
VaultStorageERC-7201 namespaced storage for the Vault module.
assets
EnumerableSet.AddressSet
Set of whitelisted backing assets
totalSupplies
mapping(address => uint256)
Total asset deposited (principal, not accounting for yield)
totalBorrows
mapping(address => uint256)
Total asset currently borrowed by Operators
utilizationIndex
mapping(address => uint256)
Cumulative time-weighted utilization integral per asset
lastUpdate
mapping(address => uint256)
Timestamp of the last index update per asset
paused
mapping(address => bool)
Per-asset pause state
insuranceFund
address
Address that receives minting/burning fees in cUSD
MintBurnParams
MintBurnParamsRedeemParams
RedeemParamsEvents
Mint
minter, receiver, asset, amountIn, amountOut, fee
cUSD minted
Burn
burner, receiver, asset, amountIn, amountOut, fee
cUSD burned for a single asset
Redeem
redeemer, receiver, amountIn, amountsOut, fees
cUSD redeemed across all assets
Borrow
borrower, asset, amount
Operator borrow executed
Repay
repayer, asset, amount
Operator repayment received
AddAsset
asset
New backing asset added
RemoveAsset
asset
Backing asset removed
PauseAsset
asset
Asset paused
UnpauseAsset
asset
Asset unpaused
Errors
PastDeadline
block.timestamp > deadline
Slippage
amountOut < minAmountOut
InvalidAmount
amountOut == 0
AssetPaused
Mint/burn/borrow attempted on a paused asset
AssetNotSupported
Asset is not in the vault's asset list
AssetAlreadySupported
addAsset called for an already-listed asset
AssetHasSupplies
removeAsset called while totalSupplies > 0
AssetNotRescuable
rescueERC20 called for a listed or strategy-held asset
InvalidMinAmountsOut
_minAmountsOut.length doesn't match assets().length
InsufficientReserves
Available balance is less than the amount requested
Usage Examples
1. Minting cUSD
2. Checking vault utilization before borrowing
3. Redeeming cUSD across all assets
Last updated