Architecture

Download Markdown

This page is the map. It shows every part of the system, what each part is allowed to do, and how they call each other. The pages after it go into detail: Accounts and PDAs, Instructions and Error codes.

Terms used on this page

  • Program. Code deployed on Solana. A program owns accounts and is the only code that can change them.
  • Account. A piece of on-chain storage with an address. Vaults, legs and withdrawal requests are all accounts.
  • PDA (program-derived address). An address computed from a program ID and a list of "seeds", such as ["vault", vault_id]. Nobody holds a private key for a PDA, so only the program that derived it can sign for it. The vault uses PDAs to hold USDC and to act as mint authority for share tokens.
  • CPI (cross-program invocation). One program calling another program inside the same transaction, for example the vault calling an adapter.
  • Adapter. A small program that implements the Akashi Adapter Interface (AAI) for one protocol, so the vault can deposit, withdraw and value a leg without knowing that protocol's details.

The parts

flowchart LR
    subgraph Users
        W[Holder wallet]
        C[Curator: admin key]
        G[Guardian key]
    end
    subgraph OffChain[Off-chain services]
        APP[Akashi app and client SDK]
        EX[Executor service]
        MON[Balance monitor in the executor]
    end
    subgraph Solana
        VP[akashi_vault program]
        AD[Adapter programs: token, Jupiter, Kamino, Maple, Solstice, Hastra, Huma, OnRe]
        PR[External protocols: Kamino, Jupiter Lend, Huma, Hastra, Solstice, Maple, OnRe]
        TK[SPL Token program]
    end
    W -->|signs deposit, request_withdrawal| APP
    APP -->|transactions| VP
    C -->|configure, queue_change, resume| VP
    G -->|pause, mark_leg_impaired, suspend_leg| VP
    EX -->|allocate, deallocate, refresh_leg, fund_withdrawal| VP
    MON -.->|warns| G
    VP -->|CPI: AAI calls| AD
    AD -->|CPI| PR
    VP -->|CPI: transfer, mint, burn| TK

Figure: holders, the curator and the guardian sign their own instructions, the executor runs routine maintenance, and the vault program reaches protocols only through adapters.

The takeaway is that the vault program never calls a protocol directly. Every protocol call goes through an adapter, and every adapter call is checked against the leg's pinned program and bound accounts (see Adapter changes).

What each part does

PartWhat it isWhat it can doWhat it cannot do
akashi_vaultThe core programHolds USDC in PDAs, mints and burns share tokens, books gains and losses, enforces every rule on this siteCall a protocol without an adapter
AdaptersOne program per protocol typeMove a leg's USDC into and out of a protocol, report its valueTouch the vault's idle cash or shares
Holder walletYouDeposit, request, cancel and claim withdrawals, settle sharesMove anyone else's funds
AdminThe curator's keyConfigure a Draft vault, queue timelocked changes, unpause, resume, start settlementSkip the timelock for risk-increasing changes
GuardianA safety key set per vaultPause, lower limits, mark a leg, suspend a leg, cancel a queued changeUnpause, raise limits, move money
ExecutorAn off-chain service with a key set per vaultAllocate and deallocate between idle cash and legs, run trades on token legsWithdraw to any address outside the vault
Anyone (keeper)Any walletRefresh legs, sync, fund and claim eligible withdrawals, execute matured changesChange any setting
Global authorityThe protocol-level keyApprove adapters and vault creators in GlobalConfigChange a vault's settings

Table: the roles and their limits; the full permission list is in Instructions.

Program IDs

ProgramMainnetDevnet
akashi_vault11pvmug4MazGHegPLFYn7RxSwoV7AkFF1LSbbNJ1QyF12x9k4Ruw5wdzCW3bYZiQ47t2DqoGtVYTMKRhz5zxmWd

Table: the vault program's addresses.

Every adapter is deployed on mainnet except the OnRe adapter. Networks and availability lists each adapter's mainnet address.

How a request travels

Every action that changes share prices follows the same pattern inside one transaction:

  1. Check the state. The vault must be in the right state (for example Active for a deposit), the action must not be paused, and no token-leg trade may be in progress (a trade is bracketed by begin_trade and end_trade inside one transaction).
  2. Check freshness. Every leg must have been valued within the vault's maximum valuation age, unless it is suspended or impaired. Each vault sets this age in Solana slots, and the program allows at most 150 slots, about one minute at roughly 400 milliseconds per slot.
  3. Sync. The vault books any gain or loss since the last update into the two tranches, so the price is current. This is the same step that sync_vault runs on its own.
  4. Price. Shares are priced from the tranche values, using the cautious band (see NAV and share pricing).
  5. Move tokens. USDC and shares move through the SPL Token program, signed by the vault's PDAs.
  6. Emit an event. For example Deposited or WithdrawalFunded, so indexers and the app can follow along.

The vault's life cycle

stateDiagram-v2
    [*] --> Draft: create_vault
    Draft --> Active: activate_vault
    Draft --> [*]: close_draft_vault
    Active --> Recovery: loss reaches Senior, loss above the incident threshold, or mark_leg_impaired
    Recovery --> Active: resume (no impaired leg, Senior repaid)
    Active --> Settlement: begin_settlement
    Recovery --> Settlement: begin_settlement
    Settlement --> [*]

Figure: a vault is configured in Draft, runs in Active, handles an incident in Recovery, and winds down in Settlement, which it never leaves.

The full meaning of each state is on Losses and recovery.

Advanced details

  • The program is built with Anchor 0.31.2, a widely used framework for Solana programs. Anchor determines the account format, the 8-byte account type prefix and the error numbering described on the next pages.
  • Version 1 of the adapter interface has aai_init_leg, aai_deposit, aai_withdraw and aai_value, each returning a ValuationReport. Version 2 adds queued actions: begin, settle, cancel and value pending.
  • The vault reads an adapter's report from the transaction's return data, and checks that the returning program is the leg's adapter (MissingReturnData otherwise).

On this page