Instructions

Download Markdown

An instruction is one call to a Solana program. A transaction can contain several. This page lists every instruction of akashi_vault, groups them by who may call them, and walks through the three flows that matter most: depositing, withdrawing and investing.

This page is reference material for developers and for readers who want to check exactly what the program allows. Instruction, argument and account names are exactly as they appear in the program's public interface. Amounts are in USDC base units, where 1 USDC = 1,000,000 base units, because USDC and the share mints have 6 decimals. Argument types such as u8, u16 and u64 are unsigned whole numbers of 1, 2 and 8 bytes; i64 is a signed one; bps means basis points, where 10,000 is 100%.

Who can call what

CallerInstructions
Holder (signs for their own funds)deposit, request_withdrawal, cancel_withdrawal, settle_shares
Anyone (permissionless)refresh_leg, sync_vault, fund_withdrawal, claim_withdrawal, settle_async, refresh_pending, execute_change, execute_adapter_approval, distribute_settlement_cash, sweep_leg_transit, seed_junior (Draft only)
Executorallocate, deallocate, allocate_v2, deallocate_v2, begin_async, cancel_async, begin_trade, end_trade
Guardian or adminpause, lower_leg_limits, set_leg_close_only, lower_vault_cap, remove_executor, mark_leg_impaired, suspend_leg, unsuspend_leg, cancel_change, lower_cost_budget
Admin onlyunpause, set_executor and set_guardian (Draft only), propose_admin, configure_vault (Draft), add_leg, configure_v2_leg, init_token_leg, init_cost_budget (Draft), activate_vault, retire_leg, resume, begin_settlement, queue_change, set_share_metadata, close_draft_vault
Proposed adminaccept_admin
Allowed vault creatorcreate_vault, init_vault_accounts
Global authorityinit_global, resize_global, set_adapter_approval, set_vault_creator, set_registry_delay, propose_global_authority, cancel_global_authority
Proposed global authorityaccept_global_authority

Table: the roles that may sign each instruction; guardian-or-admin actions can only reduce risk, so they take effect at once.

The rule behind the table: anything that can only make a vault safer is instant, and anything that can make it riskier waits for the timelock (see Governance changes).

Holder instructions

InstructionArgumentsWhat it does
deposittranche: Tranche, amount: u64, min_shares: u64Moves amount USDC from your wallet into idle and mints shares of the chosen tranche. Fails if you would receive fewer than min_shares.
request_withdrawaltranche: Tranche, shares: u64, min_usdc_out: u64Moves your shares into escrow and creates a WithdrawalRequest. It becomes eligible after the tranche's notice period: the Senior delay or the Junior notice.
cancel_withdrawalnoneReturns the shares not yet funded to you. A partly funded request keeps its funded part for claiming.
settle_sharestranche: Tranche, shares: u64In Settlement only: converts shares into a claim on the vault's cash and pays what is due. Call again with 0 shares to collect later cash.

Table: the four instructions a holder signs.

Tranche is an enum: Senior (0) or Junior (1).

Deposit: accounts

#AccountWritableSignerCheck
1userYesYour wallet
2vaultYesMust have this usdc_mint
3vault_authorityPDA ["auth", vault]
4usdc_mint
5user_usdcYesYour USDC token account
6idle_accountYesMust equal vault.idle_account
7share_mintYesMust be the chosen tranche's mint (InvalidMint)
8user_sharesYesYour token account for that share mint
9token_programSPL Token

Table: the accounts of deposit, in the order the instruction expects them.

Deposit: checks, in order

  1. No trade bracket is open (TradeOpen).
  2. The vault is Active (VaultNotActive).
  3. Every pending queued action has been re-valued (PendingClaim).
  4. Deposits are not paused (Paused).
  5. amount > 0 and amount is at least the vault's minimum deposit (AmountTooSmall).
  6. Every leg is fresh (StaleValuation). The vault then books gains and losses since the last update (the same step as sync_vault) and checks it is still Active.
  7. NAV plus amount stays within the vault's deposit cap (VaultCapExceeded).
  8. Shares to mint are above 0 (ZeroShares) and at least min_shares (MinSharesNotMet).
  9. Coverage after the deposit is valid (CoverageViolation): a Senior deposit must keep Junior at least the vault's minimum coverage of the total; a Junior deposit must keep it at most the vault's maximum coverage, where 0 means no maximum.

Then the USDC moves into idle, the shares are minted, and the Deposited event is emitted.

sequenceDiagram
    participant W as Holder wallet
    participant C as Akashi app (client)
    participant K as Akashi API
    participant V as akashi_vault
    participant T as SPL Token
    C->>K: refresh request (warm-up; the app sends at most one every 20 seconds)
    K->>V: refresh_leg for each leg
    C->>W: ask to sign deposit(tranche, amount, min_shares)
    W->>V: deposit
    V->>V: checks, legs fresh, book gains and losses, price at the high band
    V->>T: CPI transfer amount: user_usdc to idle_account (signed by user)
    V->>T: CPI mint_to shares: share_mint to user_shares (signed by vault authority)
    V-->>W: Deposited event

Figure: the app first makes sure every leg is fresh, then one deposit instruction moves the USDC and mints the shares.

The takeaway: the app's warm-up call is a convenience, not a requirement. If a leg is stale, the deposit fails with StaleValuation and can simply be retried after a refresh.

Withdrawal flow

A withdrawal has three steps, and only the first needs your signature.

sequenceDiagram
    participant W as Holder wallet
    participant V as akashi_vault
    participant T as SPL Token
    participant K as Anyone (executor, app or you)
    W->>V: request_withdrawal(tranche, shares, min_usdc_out)
    V->>T: CPI transfer shares: owner_shares to escrow
    V->>V: create WithdrawalRequest, eligible_at = now + delay
    Note over V: wait until eligible_at
    K->>V: fund_withdrawal
    V->>V: checks, legs fresh, book gains and losses, price at the low band
    V->>T: CPI burn shares from escrow
    V->>T: CPI transfer USDC: idle_account to payout_account
    K->>V: claim_withdrawal
    V->>T: CPI transfer USDC: payout_account to owner_usdc
    V->>V: close the request when fully funded and paid

Figure: shares are escrowed when you request, burned and priced when the request is funded, and the USDC is paid to you when anyone claims it.

Request states

stateDiagram-v2
    [*] --> Waiting: request_withdrawal
    Waiting --> Eligible: eligible_at passes
    Eligible --> PartlyFunded: fund_withdrawal (not enough idle, brake or coverage)
    PartlyFunded --> PartlyFunded: fund_withdrawal again
    Eligible --> Funded: fund_withdrawal (all shares)
    PartlyFunded --> Funded: fund_withdrawal (rest)
    Waiting --> Closed: cancel_withdrawal
    Eligible --> Closed: cancel_withdrawal
    PartlyFunded --> FundedPart: cancel_withdrawal returns unfunded shares
    FundedPart --> Closed: claim_withdrawal
    Funded --> Closed: claim_withdrawal pays everything

Figure: a request can be funded in several parts and cancelled at any time before it is fully funded; USDC already funded always stays claimable.

Fund: checks, in order

  1. No trade bracket is open, and withdrawals are open: the vault is Active or Recovery and not frozen (VaultFrozen, VaultNotActive).
  2. Pending queued actions are re-valued (PendingClaim), and funding is not paused (Paused).
  3. The request is eligible (NotEligibleYet) and not already funded (AlreadyFunded).
  4. Every leg is fresh, gains and losses are booked, and withdrawals are still open.
  5. The price is the tranche's value at the cautious low band.
  6. The amount is limited by the vault's idle cash. For Senior, also by the outflow brake when it is on (OutflowLimitReached). For Junior, also by the USDC that waiting Senior requests need (InsufficientIdle) and by the coverage floor (CoverageViolation).
  7. If not everything fits, the request is funded in part. The part must still meet min_usdc_out pro rata (BelowMinUsdcOut).

Then the shares are burned, the USDC moves from idle to the payout account, and the vault's reserved payouts grow by that amount.

Withdraw: accounts

InstructionAccounts (in order)
request_withdrawalowner (signer, writable), vault, request (new PDA ["request", vault, next_request_id]), share_mint, owner_shares, escrow, token_program, system_program
fund_withdrawalvault, vault_authority, request, usdc_mint, share_mint, escrow, idle_account, payout_account, senior_mint, token_program
claim_withdrawalvault, vault_authority, usdc_mint, request (must have unclaimed funded USDC, else NotFunded), owner, owner_usdc, payout_account, token_program
cancel_withdrawalowner (signer), vault, vault_authority, request (not fully funded, else AlreadyFunded), share_mint, escrow, owner_shares, token_program

Table: the accounts of each withdrawal instruction; fund_withdrawal and claim_withdrawal need no signer from the vault's side, so anyone can send them.

Investing flow (executor)

InstructionArgumentsWhat it does
allocate / allocate_v2amount: u64, min_value_increase: u64Moves USDC from idle into a leg's protocol through its adapter.
deallocate / deallocate_v2usdc_target: u64, min_usdc_out: u64Takes USDC out of a leg back into idle.
begin_asyncdirection, amount: u64, min_claim_value: u64, deadline: i64Starts a queued deposit or exit on an AAI v2 leg.
settle_asyncmin_return_units: u64Completes a queued action once the adapter proves the protocol paid. Anyone may call.
cancel_asyncnoneTakes back a queued action.
begin_trade / end_tradedirection, amount: u64, min_out: u64 / noneBrackets a swap on a token leg, in the same transaction.

Table: the executor's instructions; the _v2 versions are for legs configured with configure_v2_leg.

sequenceDiagram
    participant E as Executor
    participant V as akashi_vault
    participant T as SPL Token
    participant A as Adapter
    participant P as Protocol
    E->>V: allocate(amount, min_value_increase) + bound accounts
    V->>V: Active, not paused, leg Active, legs fresh, book gains and losses
    V->>T: CPI transfer amount: idle_account to leg_transit (signed by vault authority)
    V->>A: CPI aai_deposit(amount) (signed by leg authority)
    A->>P: CPI deposit into the protocol
    A-->>V: ValuationReport
    V->>V: leg_transit back to its old balance? (TransitBalanceMismatch)
    V->>V: value grew by amount minus the leg's slippage allowance? (ValueIncreaseTooLow)
    V->>V: leg cap, leg weight, idle minimum (LegCapExceeded, LegWeightExceeded, IdleBelowMinimum)
    V->>V: book gains and losses

Figure: an allocation passes USDC through the leg's own transit account, and the vault checks afterwards that exactly that amount left and the leg's value grew by it.

The takeaway: the executor chooses when and how much to invest, but it cannot choose where the money goes. It can only reach the leg's adapter and the accounts bound to it, and every allocation is checked against the leg's limits.

Token flows

flowchart LR
    U[Holder USDC account] -->|deposit| I[Idle account PDA]
    I -->|allocate| TR[Leg transit account]
    TR -->|aai_deposit| P[Protocol position]
    P -->|aai_withdraw| TR
    TR -->|deallocate| I
    I -->|fund_withdrawal| PO[Payout account PDA]
    PO -->|claim_withdrawal| U
    PO -->|settle_shares| U
    S[Holder share account] -->|request_withdrawal| ES[Escrow PDA]
    ES -->|fund_withdrawal: burn| X[Burned]
    ES -->|cancel_withdrawal| S
    M[Share mint PDA] -->|deposit: mint| S

Figure: USDC moves from your wallet to idle, out to legs and back, then through the payout account to you; shares move from your wallet to escrow and are burned when funded.

The key point is the payout account. Once a request is funded, its USDC is moved out of idle into the payout account and recorded as a reserved payout. From then on it cannot be invested or used to absorb losses. It belongs to the request owner.

Maintenance (anyone)

InstructionArgumentsWhat it does
refresh_legnone, plus the leg's bound accountsAsks the adapter for a ValuationReport and records the leg's value.
sync_vaultnoneBooks gains and losses since the last sync into Senior and Junior.
refresh_pendingnoneRe-values a queued action's claim. It may only go down.
sweep_leg_transitnoneMoves USDC that arrived in a leg's transit account into idle, for example a protocol's compensation.
distribute_settlement_cashnoneIn Settlement: adds new idle cash to the settlement book.
execute_changenoneApplies a queued change after its delay.

Table: instructions anyone can send to keep a vault's numbers current.

Guardian and admin actions

InstructionArgumentsEffect
pause / unpausescopes: u8Stops or restarts deposits (1), funding (2) and allocation (4). The numbers can be added to combine scopes, so 3 means deposits and funding and 7 means all three. Anything else is InvalidPauseScope. Only the admin can unpause.
lower_leg_limitscap: u64, max_bps: u16Lowers a leg's cap and maximum weight. A higher value fails with LimitNotLower.
set_leg_close_onlynoneThe leg takes no new money; it can still be emptied.
lower_vault_capvault_cap: u64Lowers the vault's deposit cap.
remove_executornoneRemoves the executor at once.
mark_leg_impairedmark: u64Caps a leg's value and starts Recovery (details).
suspend_leg / unsuspend_legnoneSets a leg aside while it cannot be valued (details).
cancel_changenoneCancels a queued change.
lower_cost_budgetbudget_bps: u16Lowers the token-leg trading cost budget.
retire_legnoneAdmin: closes an empty leg for good (LegNotEmpty otherwise).
resumenoneAdmin: Recovery back to Active (RecoveryNotFinished if a leg is still impaired or Senior is not repaid).
begin_settlementnoneAdmin: starts the final wind-down. Cannot be undone.

Table: the safety and incident instructions.

Governance changes

Changes that could increase risk on a live vault go through queue_change(change: ConfigChange). Each creates a PendingChange that anyone can execute with execute_change once its delay has passed, within a 7-day window set by the program. During the delay, the guardian or admin can cancel it.

ConfigChange variantFieldsDelay
UpdateLegleg_index: u8, params (the leg's limits and settings)Governance delay
SetIdleTargetsidle_target_bps: u16, idle_min_bps: u16Governance delay
SetVaultCapvault_cap: u64Governance delay
SetMinDepositmin_deposit: u64Governance delay
SetMaxValuationAgeslots: u64Governance delay
SetRiskSettingsmax_leg_growth_apr_bps: u16, senior_outflow_limit_bps: u16, incident_loss_bps: u16Governance delay
RaiseMarkleg_index: u8, mark: u64Governance delay
SetExecutorexecutor: PubkeyGovernance delay
SetGuardianguardian: PubkeyGovernance delay
RepinAdapterleg_index: u8, adapter_slot: u64Add-leg delay
AddLegadapter_program: Pubkey, params (the leg's limits and settings), accounts_hash: [u8; 32]Add-leg delay

Table: every timelocked change; by default the governance delay is 86,400 seconds (1 day) and the add-leg delay is 172,800 seconds (2 days).

The program caps both delays at 30 days. AddLeg is not applied by execute_change; it authorises the admin's add_leg for exactly that adapter, those parameters and that account list.

In Recovery and Settlement, only role changes (SetExecutor, SetGuardian), RepinAdapter and, in Recovery only, RaiseMark can be executed. Anything else fails with VaultNotActive.

Parameters and limits

SettingLimit
Minimum coverage500 to 9,000 basis points (5% to 90%)
Maximum coverage0 (no maximum), or above the minimum coverage and at most 10,000 basis points
Premium curveup to 4 points with increasing coverage; each premium at most 9,000 basis points (90%)
Senior delayup to 3,600 seconds (1 hour)
Junior noticeup to 2,592,000 seconds (30 days)
Maximum valuation ageup to 150 slots (about one minute)
A leg's slippage allowanceup to 1,000 basis points (10%)
Token-leg cost budgetup to 500 basis points (5%) over 7 days
A leg's maximum growth rateup to 60,000 basis points (600% a year); default 3,000 (30%)
Profit unlock periodup to 7 days; default 0
Senior outflow brakeup to 10,000 basis points; default 0 (off)
Incident thresholdup to 10,000 basis points; default 25 (0.25%)
Governance delay, add-leg delayup to 30 days; defaults 1 and 2 days
Legs per vault8
Bound accounts per leg64

Table: the limits the program enforces on every setting, and the program's defaults where it has them.

The program has no fee setting: no vault setting is a fee, and no instruction pays a fee to the curator or to Akashi. See Fees and execution costs.

Advanced details

  • The program adds a tolerance of 2 base units to the slippage allowance on allocations, to absorb protocol rounding.
  • Share math uses virtual offsets of 1,000,000 shares and 1,000,000 base units, which stops the first depositor from manipulating the share price. See NAV and share pricing.
  • An instruction that would leave a trade bracket open fails: begin_trade must be followed by end_trade in the same transaction (MissingEndTrade), and must be a top-level instruction (NotTopLevel).

On this page