MetavaultsGuides

Depositing and Redeeming

MetaVaults follow the ERC-7540 asynchronous vault standard. Unlike standard ERC-4626 vaults where deposits and redeems are instant, MetaVaults use a request → settle → share mint / share burn flow.

Deposit flow

Step 1: Request a deposit

function requestDeposit(
    uint256 assets,
    address controller,
    address owner
) external returns (uint256 requestId)

The depositor transfers assets (underlying token, e.g. USDC) to the wrapper. The assets are forwarded to the infrastructure vault.

msg.sender must approve the MetaVaultWrapper to spend the underlying asset before calling requestDeposit.

Requirements:

  • assets > 0
  • owner == msg.sender or msg.sender is an approved operator of owner
  • The vault must not be paused

What happens internally:

  1. If the controller has a claimable deposit from a previous epoch, it is automatically claimed first.
  2. Assets are transferred from owner to the wrapper, then forwarded to the infrastructure vault.
  3. The request is recorded in the current epoch's deposit request balance.

Step 2: Wait for settlement

The accountant calls settle() on the infrastructure vault to end the current epoch. During settlement:

  • Pending deposit assets are converted to shares using the epoch's total supply and total assets snapshot.
  • Shares are minted and made available for claiming.

Step 3: Mint shares

function deposit(
    uint256 assets,     // not used — all claimable shares are minted
    address receiver,
    address controller
) external returns (uint256 shares)

The assets parameter is not used in the MetaVaultWrapper implementation. Calling deposit always mints all claimable shares for the controller.

Requirements:

  • controller == msg.sender or msg.sender is an approved operator of controller
  • The controller must have a claimable deposit from a settled epoch

Returns: The number of wrapper shares minted to receiver.

Complete deposit example

// 1. Approve the wrapper to spend USDC
IERC20(usdc).approve(address(wrapper), 1000e6);

// 2. Request deposit
wrapper.requestDeposit(1000e6, msg.sender, msg.sender);

// ... wait for settle() ...

// 3. Claim shares
uint256 shares = wrapper.deposit(0, msg.sender, msg.sender);

Redeem flow

Step 1: Request a redeem

function requestRedeem(
    uint256 shares,
    address controller,
    address owner
) external returns (uint256 requestId)

The depositor's wrapper shares are burned and the equivalent infrastructure vault shares are queued for redemption.

Requirements:

  • shares > 0
  • owner == msg.sender or msg.sender is an approved operator of owner
  • The vault must not be paused

What happens internally:

  1. If the controller has a claimable redeem from a previous epoch, it is automatically claimed first.
  2. Wrapper shares are burned from owner.
  3. The corresponding infrastructure vault shares are queued for redemption.
  4. The request is recorded in the current epoch's redeem request balance.

Step 2: Wait for settlement

During settle(), pending redeem shares are converted to assets using the epoch's snapshot values. Assets are made available for claiming.

Step 3: Burn shares for assets

function redeem(
    uint256 shares,     // not used — all claimable assets are returned
    address receiver,
    address controller
) public returns (uint256 assets)

Like deposit, the shares parameter is not used. Calling redeem always returns all claimable assets for the controller.

Returns: The amount of underlying assets transferred to receiver.

Complete redeem example

// 1. Request redeem of 500 shares
wrapper.requestRedeem(500e6, msg.sender, msg.sender);

// ... wait for settle() ...

// 2. Claim assets
uint256 assets = wrapper.redeem(0, msg.sender, msg.sender);

Decreasing a request

If a depositor changes their mind before settlement, they can decrease their pending request:

// Decrease a deposit request (get assets back)
wrapper.decreaseDepositRequest(500e6);

// Decrease a redeem request (get shares back)
wrapper.decreaseRedeemRequest(250e6);

These functions can only be called by the original requester (msg.sender). The refunded assets or shares are returned directly to msg.sender.

Operator model

MetaVaults support the ERC-7540 operator pattern. A controller can approve an operator to act on their behalf:

wrapper.setOperator(operatorAddress, true);

Once approved, the operator can call requestDeposit, deposit, requestRedeem, and redeem on behalf of the controller.

View functions for integrators

FunctionReturns
pendingDepositRequest(requestId, controller)Assets queued in the current epoch
claimableDepositRequest(requestId, controller)Assets claimable from a settled epoch
pendingRedeemRequest(requestId, controller)Shares queued in the current epoch
claimableRedeemRequest(requestId, controller)Shares claimable from a settled epoch
maxDeposit(receiver)Maximum claimable deposit amount (0 if paused or current epoch)
maxRedeem(owner)Maximum claimable redeem amount (0 if paused or current epoch)
convertToShares(assets)Convert assets to shares using the last settled epoch rate
convertToAssets(shares)Convert shares to assets using the last settled epoch rate
convertToShares(assets, epochId)Convert using a specific epoch's rate
convertToAssets(shares, epochId)Convert using a specific epoch's rate
totalAssets()Estimated total assets of the wrapper
epochId()Current epoch ID from the infrastructure vault

previewDeposit, previewRedeem, previewWithdraw, and previewMint are not implemented on the MetaVaultWrapper, as specified by ERC-7540 for asynchronous vaults. Calling them will revert.

On this page