Architecture
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
| Part | What it is | What it can do | What it cannot do |
|---|---|---|---|
akashi_vault | The core program | Holds USDC in PDAs, mints and burns share tokens, books gains and losses, enforces every rule on this site | Call a protocol without an adapter |
| Adapters | One program per protocol type | Move a leg's USDC into and out of a protocol, report its value | Touch the vault's idle cash or shares |
| Holder wallet | You | Deposit, request, cancel and claim withdrawals, settle shares | Move anyone else's funds |
| Admin | The curator's key | Configure a Draft vault, queue timelocked changes, unpause, resume, start settlement | Skip the timelock for risk-increasing changes |
| Guardian | A safety key set per vault | Pause, lower limits, mark a leg, suspend a leg, cancel a queued change | Unpause, raise limits, move money |
| Executor | An off-chain service with a key set per vault | Allocate and deallocate between idle cash and legs, run trades on token legs | Withdraw to any address outside the vault |
| Anyone (keeper) | Any wallet | Refresh legs, sync, fund and claim eligible withdrawals, execute matured changes | Change any setting |
| Global authority | The protocol-level key | Approve adapters and vault creators in GlobalConfig | Change a vault's settings |
Table: the roles and their limits; the full permission list is in Instructions.
Program IDs
| Program | Mainnet | Devnet |
|---|---|---|
akashi_vault | 11pvmug4MazGHegPLFYn7RxSwoV7AkFF1LSbbNJ1QyF | 12x9k4Ruw5wdzCW3bYZiQ47t2DqoGtVYTMKRhz5zxmWd |
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:
- 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_tradeandend_tradeinside one transaction). - 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.
- 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_vaultruns on its own. - Price. Shares are priced from the tranche values, using the cautious band (see NAV and share pricing).
- Move tokens. USDC and shares move through the SPL Token program, signed by the vault's PDAs.
- Emit an event. For example
DepositedorWithdrawalFunded, 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_withdrawandaai_value, each returning aValuationReport. 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 (
MissingReturnDataotherwise).