Skip to content
Open app

Vaults and shares

A vault holds one tier's USDC, split between an idle account and whitelisted strategies. Depositors own it through an SPL share token whose price rises as the strategies earn.

On this page

What a vault is#

Each tier is one vault account owned by the Aqueduct program, derived from the asset mint and the tier number. A vault holds no tokens itself. Its USDC sits in two places:

  • The idle account, a token account owned by the vault. Deposits land here and withdrawals are paid from here.
  • Strategies, up to eight whitelisted venues per vault. Each strategy records how much of its venue's position belongs to the vault. The keeper moves USDC between idle and strategies; nothing else can.

The vault's total assets are the idle balance plus the current value of every strategy position. Every instruction that touches a vault first accrues interest on all of its strategies, so total assets are always up to date when shares are priced.

Shares#

When you deposit, the vault mints you shares: an ordinary SPL token with 6 decimals, one mint per vault. The share mint's authority is the vault itself, so only the program can mint or burn them. Shares sit in your wallet like any other token; you can hold them, transfer them or redeem them. Whoever holds shares can withdraw them.

Shares never rebase. Your number of shares only changes when you deposit or withdraw. What changes is the price of each share, so your position is simply shares × share price.

Share price#

share price = (total assets + 0.001) ÷ (share supply + pending fee shares + 0.001)
Both sides include a virtual offset of 1,000 base units (0.001 USDC and 0.001 shares).

The price started at 1.0 USDC per share. It rises as the strategies earn interest and only falls if a strategy loses value. The denominator counts pending fee shares: the performance fee owed to the treasury but not yet minted (see Fees). The price you see is therefore already after fees, and it is exactly the price a deposit or withdrawal gets.

The virtual offset is the ERC-4626 defence against the first-depositor inflation attack. Without it, an attacker could deposit a tiny amount into an empty vault, donate a large amount to inflate the price, and round the next depositor's shares down to zero. With it, a donation is shared with a phantom 0.001 shares and the attack costs more than it can earn. Its effect on normal prices is below a millionth.

A worked example#

A vault holds 1,050,000 USDC and 1,000,000 shares, so a share is worth 1.05 USDC.

  1. Deposit 2,100 USDC

    You receive 2,100 ÷ 1.05 = 2,000 shares. Total assets become 1,052,100 and supply 1,002,000; the price is still 1.05.

  2. The strategies earn

    Interest raises total assets by about 1%. After the performance fee, the price is 1.06. Your 2,000 shares are now worth 2,120 USDC.

  3. Withdraw everything

    Burning 2,000 shares pays 2,000 × 1.06 = 2,120 USDC. You never interact with a strategy directly.

Amounts are rounded down in the vault's favour, by at most one base unit (0.000001), so rounding can never be used to drain other depositors.

Depositing#

A deposit accrues every strategy, accrues the vault's fees, computes your shares at the current price, transfers your USDC to the idle account and mints the shares. The program creates your share token account if it does not exist yet. A deposit fails when:

ConditionError
The protocol is pausedPaused
The amount is zero, or so small it would mint zero sharesZeroAmount
Total assets plus the deposit would exceed the vault's deposit cap (5,000,000 USDC per vault on devnet; 0 means no cap)DepositCapExceeded

New USDC waits in idle until the keeper deploys it. The keeper keeps about 5% of each vault idle as a buffer for withdrawals and deploys the rest in steps once the excess is worth a transaction. See Rebalancer.

Withdrawing#

A withdrawal burns your shares and pays their value at the current price, in the same transaction. There is no queue, lock-up or withdrawal fee, and the pause switch does not apply to it.

If the idle account holds less than you are owed, the program pulls the shortfall from strategies first, in this order:

  1. Solana strategies before cross-chain ones.
  2. Within each group, the lowest risk score first.

If the strategies together cannot cover the withdrawal, it fails with InsufficientLiquidity and nothing changes. On devnet every simulated reserve is fully backed, so this cannot happen there. On mainnet it could if a venue's liquidity were locked up by high utilisation.

Cross-chain liquidity

On devnet a cross-chain strategy can be pulled from inside a withdrawal like any other, because its reserve lives in the program. A mainnet position on another chain cannot be redeemed atomically from Solana, which is one reason withdrawals use Solana venues first and each vault keeps an idle buffer. See Devnet and mainnet.

Vault parameters#

Each vault stores its own settings. The admin can change some of them within hard limits written into the program.

Tier
0 = Bedrock, 1 = Rapids. Part of the vault's address, so it never changes.
Deposit cap
Maximum total assets in USDC. 5,000,000 on both devnet vaults.
Performance fee
500 bps on Bedrock, 1,000 bps on Rapids. The program caps it at 3,000 bps (30%).
Management fee
0. Supported by the program up to 200 bps (2%) a year, but not used.
High-water mark
The share price on which the performance fee was last charged.
Strategies
Up to 8, each with a hard cap in bps of total assets, a risk score from 1 to 10 and an enabled flag.
Lifetime deposits and withdrawals
Running totals in USDC, for analytics.

The full account layout is in the program reference, and the venues behind each vault's strategies are listed under Tiers and venues.

Written against programs/aqueduct/src/state.rs, programs/aqueduct/src/instructions/user.rs and programs/aqueduct/src/instructions/common.rs. If the code and this page disagree, the code wins.