Vault

The Vault is the core module responsible for the storage, issuance, and redemption of cUSD, and for managing the underlying collateral assets. It plays a pivotal role as the protocol's liquidity backbone by enabling minting and burning of cUSD, facilitating liquidity for borrowers, and ensuring capital efficiency through the Fractional Reserves.

Overview of operations

  • Mint/Burn: cUSD can be minted/burned ~1:1 for any of the supported backing assets. Fees are dynamically calculated according to the allocation ratio of the asset.

  • Redeem: cUSD can be redeemed for a proportional amount of the basket of assets for a fixed fee.

  • Fractional Reserves: Idle capital in the Vault is deployed into yield-generating strategies (US T-bill yield, crypto lending markets) until borrowed or withdrawn.

  • Borrow/Repay: When operators borrow/repays assets, the Vault tracks utilization of the pool

Mechanics

Mint/Burn

The Vault is the main interface for liquidity providers to mint and burn cUSD. cUSD can be minted/burned at Oracle value for any of the assets. Fees are calculated in the Minter contract according to the allocation of the assets.

When a user mints/burns, the flow is as follows:

  1. User Call: User calls Vault.mint() (or burn) with asset and amount

  2. Fee Calculation: Vault calls Minter.getMintAmount() (or getBurnAmount) to calculate fees

  3. Logic Processing: MinterLogic calculates amount out and fees at current Oracle value

  4. State Update: VaultLogic handles asset transfer and state updates

  5. Token Minting: cUSD is minted/burned in exchange for underlying assets

Mint and burn functions are disabled if Oracle prices are stale, until Oracles are back in sync

Redeem

A depeg event of any of the underlying assets can result in a last man standing problem where the last to withdraw will be left with the depegged asset. When such events occur, the protocol incentivizes users to withdraw proportionally to the ratio of the assets, effectively socializing the losses. Redeem fees are charged at a fixed percentage, whereas burn fees are dynamic, making it economically infeasible to burn for USDT beyond the burn kink ratio. For instance, if the basket contains 50% of USDC valued at $0.9 and 50% of USDT valued at $1, then the redeem request for $100 cUSD should withdraw $45 worth of USDC and $50 worth of USDT minus fees.

When a user redeems, the flow is as follows:

  1. User Call: User calls Vault.redeem() with cUSD

  2. Fee Calculation: Vault calls Minter.getRedeemAmount() to calculate proportional amounts

  3. State Update: cUSD is burned from user, assets are divested from strategies

  4. Asset Transfer: All underlying assets are transferred to user

Borrow Operations

Registered Operators can borrow assets from the Vault via the Lender, provided they are sufficiently collateralized by delegated assets from shared security networks. While assets are lent out from the Vault, the core borrow logic is implemented in the Lender contract. When the Operator requests to borrow via the Lender, the Lender calls Vault.borrow() to transfer assets to the Lender, updating the utilization and reserve state of the Vault.

Similarly, Operators can repay via the Lender, which transfers borrowed assets back to the Vault.

Vault Management

Assets must first be whitelisted in order to be used in Cap. Only regulated dollar-denominated crypto assets are accepted as a backing assets.

Interest rates for borrowing each asset of the reserve is a function of the utilization rate of the asset. The current utilization rate of each asset can be queried in the Vault contract.

Configurations

  • Whitelist minters: Supports fee bypass for privileged users

  • Pause mechanisms:

    • Asset-Level Pause: Individual assets can be paused while others remain active

    • Protocol-Level Pause: Complete protocol shutdown capability

Key Vault Parameters

  • Total Supplies: Total amount of each asset deposited in the vault

  • Total Borrows: Total amount of each asset borrowed from the vault

  • Utilization Rate: Ratio of borrowed assets to total supplies, calculated as (Total Borrows / Total Supplies) * 100%

  • Available Balance: Amount of asset available for borrowing, calculated as Total Supplies - Total Borrows

  • Utilization Index: Cumulative utilization tracking for interest rate calculations

  • Insurance Fund: Address that receives fees from mint/burn operations

  • Pause States: Individual asset pause states and protocol-wide pause capability

Architecture

The Vault module inherits from the Fractional Reserve and Minter contracts

  1. Vault - Manages asset storage, accounting, and cUSD minting/burning

  2. Fractional Reserve - Manages idle capital deployment

  3. Minter - Handles dynamic fee calculation for minting operations

Vault Contract

The Vault Contract is the main user-facing contract that enables minting and borrowing, as well as reserve asset management.

Core Functions

mint: Allows users to deposit approved assets and receive cUSD in return

function mint(address _asset, uint256 _amountIn, uint256 _minAmountOut, address _receiver, uint256 _deadline)
    external
    returns (uint256 amountOut)
  • _asset: Whitelisted asset to deposit

  • _amountIn: Amount of asset to use in the minting

  • _minAmountOut: Minimum amount to mint (slippage protection)

  • _receiver: Receiver of the minting

  • _deadline: Deadline of the transaction

Key features:

  • Slippage Protection: _minAmountOut parameter

  • Deadline Protection: Transaction deadline validation

  • Dynamic Fees: Fees based on asset allocation ratios

burn: Burns cUSD in exchange for one of the underlying assets.

function burn(address _asset, uint256 _amountIn, uint256 _minAmountOut, address _receiver, uint256 _deadline)
    external
    returns (uint256 amountOut)
  • _asset: Asset to withdraw

  • _amountIn: Amount of cap token to burn

  • _minAmountOut: Minimum amount out to receive

  • _receiver: Receiver of the withdrawal

  • _deadline: Deadline of the transaction

redeem: Allows users to burn cUSD in exchange for multi-collateral withdrawal, proportional to the ratio of the underlying assets.

function redeem(uint256 _amountIn, uint256[] calldata _minAmountsOut, address _receiver, uint256 _deadline)
    external
    returns (uint256[] memory amountsOut)
  • _amountIn: Amount of Cap token to burn

  • _minAmountsOut: Minimum amounts of assets to withdraw

  • _receiver: Receiver of the withdrawal

  • _deadline: Deadline of the transaction

Key features:

  • Proportional Withdrawal: Withdraws assets proportional to current ratios

  • Fee Avoidance: Avoids dynamic fees by withdrawing proportionally

borrow: Allows whitelisted agents to borrow assets from the vault

function borrow(address _asset, uint256 _amount, address _receiver) external
  • _asset: Asset to borrow

  • _amount: Amount of asset to borrow

  • _receiver: Receiver of the borrow

repay: Allows repayment of borrowed assets

function repay(address _asset, uint256 _amount) external
  • _asset: Asset to repay

  • _amount: Amount of asset to repay

Admin Functions

  • addAsset: Adds new assets to the vault

  • removeAsset: Removes assets from the vault (only if no supplies)

  • pauseAsset: Pauses operations for specific assets

  • unpauseAsset: Resumes operations for specific assets

  • pauseProtocol: Pauses all protocol operations

  • unpauseProtocol: Resumes all protocol operations

  • setInsuranceFund: Sets the insurance fund address

  • rescueERC20: Rescues unsupported tokens from the vault

View Functions

  • assets: Get the list of assets supported by the vault

  • totalSupplies: Get the total supplies of an asset

  • totalBorrows: Get the total borrows of an asset

  • utilization: Get the utilization rate of an asset

  • availableBalance: Get available balance to borrow an asset

  • paused: Get the pause state of an asset

  • currentUtilizationIndex: Get up-to-date cumulative utilization index

  • insuranceFund: Get the insurance fund address

Data Structures

VaultStorage

The VaultStorage stores all vault configuration and state information.

struct VaultStorage {
    EnumerableSet.AddressSet assets;           // List of supported assets
    mapping(address => uint256) totalSupplies; // Total supplies per asset
    mapping(address => uint256) totalBorrows;  // Total borrows per asset
    mapping(address => uint256) utilizationIndex; // Utilization index per asset
    mapping(address => uint256) lastUpdate;    // Last update time per asset
    mapping(address => bool) paused;           // Pause state per asset
    address insuranceFund;                     // Insurance fund address
}

MintBurnParams

Parameters for minting or burning operations.

struct MintBurnParams {
    address asset;        // Asset to mint or burn
    uint256 amountIn;     // Amount of asset to use
    uint256 amountOut;    // Amount of cap token to mint or burn
    uint256 minAmountOut; // Minimum amount to mint or burn
    address receiver;     // Receiver of the operation
    uint256 deadline;     // Deadline of the transaction
    uint256 fee;          // Fee paid to insurance fund
}

RedeemParams

Parameters for redemption operations.

struct RedeemParams {
    uint256 amountIn;        // Amount of cap token to burn
    uint256[] amountsOut;    // Amounts of assets to withdraw
    uint256[] minAmountsOut; // Minimum amounts of assets to withdraw
    address receiver;        // Receiver of the withdrawal
    uint256 deadline;        // Deadline of the transaction
    uint256[] fees;          // Fees paid to insurance fund
}

BorrowParams

Parameters for borrowing operations.

struct BorrowParams {
    address asset;    // Asset to borrow
    uint256 amount;   // Amount of asset to borrow
    address receiver; // Receiver of the borrow
}

RepayParams

Parameters for repayment operations.

struct RepayParams {
    address asset;  // Asset to repay
    uint256 amount; // Amount of asset to repay
}

Last updated