Velocity ProtocolDevelopers
Vault Managers

Trusted Vaults

A normal vault is a box the manager can trade inside but cannot take assets out of. Deposits go into the vault's own Velocity account, the manager holds delegate authority to place orders with them, and the only paths out are the depositor withdrawal flow and the manager's own shares. That is what makes the redeem period and the share accounting meaningful: they are the whole of the manager's exit.

A Trusted vault removes that box. The manager can move assets out of the vault to an address it controls, and the program tracks the amount as a number on the vault account rather than as a position it can see. Some strategies need this, for example running part of the book on a venue Velocity has no CPI into. It is a different security model, not a feature toggle, and both the manager and the depositors should treat it that way.

Approval required

Trusted vaults must be approved by the Velocity team before they can be used in production. Promotion is an admin instruction; a manager cannot self-promote.

What the class actually gates

Vault.vault_class is a single byte: 0 for Normal, 1 for Trusted. It gates exactly three instructions, manager_borrow, manager_repay, and manager_update_borrow. Calling any of them on a Normal vault fails with InvalidVaultClass. Nothing else in the vaults program reads the class.

Margin trading is not part of the Trusted class, despite often being enabled alongside it. update_margin_trading_enabled works on a Normal vault too, and is gated only on the vault not being in liquidation (OngoingLiquidation). See Quickstart for the command.

An admin promotes a vault after it is created; there is no way to initialize one as Trusted:

bun run cli -- admin-update-vault-class \
  --vault-address <VAULT_ADDRESS> \
  --vault-class trusted

The instruction rejects a class equal to the current one with InvalidVaultUpdate, so re-running it is an error rather than a no-op.

Borrowing

manager_borrow withdraws from the vault's Velocity account and forwards the tokens to a token account owned by the manager. The amount must be greater than zero (InvalidBorrowAmount), and the destination account is constrained to token::authority = manager, so it has to belong to whoever vault.manager is. If the manager is a multisig, pass --manager-token-account explicitly: see Multisig manager.

bun run cli -- manager-borrow \
  --vault-address <VAULT_ADDRESS> \
  --borrow-spot-market-index 0 \
  --borrow-amount <AMOUNT>

The vaults program sets no ceiling of its own. The bound is the Velocity withdrawal underneath it: the CPI runs with reduce_only false, so the vault's account has to end the instruction within its own margin requirement, and if margin trading is enabled the borrow can carry the account into a spot borrow rather than stopping at its deposits. A borrow that would leave the vault under-margined fails inside the Velocity program, not the vaults program.

The borrowed asset does not have to be the one the vault takes deposits in. The borrowed amount is priced into the deposit asset through both oracles at the moment of the borrow, and it is that value, not the token amount, that is recorded.

How the borrow shows up in share price

Vault equity is the value of the vault's Velocity account plus manager_borrowed_value. Share price is equity divided by total shares, so a borrow does not move it: value leaves the account and an equal claim appears in its place. Depositors see a flat share price at the moment of the borrow, and a moving one afterwards only through whatever the manager reports.

That is the whole of the accounting, and it is worth being precise about what it does not do. The program never verifies that manager_borrowed_value corresponds to anything. It cannot: the assets are outside its view.

Repaying and marking

Repay sends tokens back into the vault and reduces the recorded claim:

bun run cli -- manager-repay \
  --vault-address <VAULT_ADDRESS> \
  --repay-spot-market-index <INDEX> \
  --repay-amount <AMOUNT> \
  --repay-value <VALUE_IN_DEPOSIT_ASSET>

--repay-amount is the token transfer and must be greater than zero (InvalidRepayAmount). --repay-value is how much to subtract from manager_borrowed_value, in the deposit asset. The two are independent: the program does not check that the value claimed matches the tokens sent. Omitting --repay-value zeroes the entire outstanding claim no matter how small the transfer was.

Update borrow moves the recorded claim without moving any tokens, which is how a manager marks an outside position to market:

bun run cli -- manager-update-borrow \
  --vault-address <VAULT_ADDRESS> \
  --new-borrow-value <VALUE>

It sets manager_borrowed_value to whatever the manager passes, up or down, with no reference to anything the program can check.

Both emit a ManagerUpdateBorrowRecord carrying the previous and new values and the vault equity on each side, so the full history of what the manager declared is onchain and auditable after the fact. Publishing it is a reasonable thing to promise depositors.

What a depositor is trusting

Trust and risk

In a Trusted vault the manager can withdraw depositor capital to an address of its own and then set the value of the outstanding claim to any number, including zero, with a single instruction and no proof. The redeem period and share accounting that constrain a Normal vault's manager do not constrain this path. Depositors have no onchain recourse. A Trusted vault is appropriate only where a depositor would accept an unsecured loan to the manager.

The mitigations are all offchain: who the manager is, whether the manager role sits behind a multisig, what they publish, and whether the declared borrow value can be reconciled against a venue anyone can check. See Multisig manager for the first of those, and Vault Managers for the guardrails that do apply to every vault regardless of class.