A hack the protocol has not reported
Sometimes a protocol is hacked but its own records do not show it yet. The adapter keeps reporting full value, so the vault cannot see the loss by itself. Someone has to tell it. That someone is the guardian, a role the curator assigns to react quickly to emergencies (see Who controls what).
The examples start from the example vault: Alice holds 4,000 USDC of Senior, June holds 1,000 USDC of Junior, 3,000 USDC is invested in the leg and 2,000 USDC is idle cash. Each share is worth 1 USDC at the start.
What a mark is
A mark is a ceiling the guardian puts on a leg's value. The guardian calls mark_leg_impaired with a value in USDC. From then on:
- The leg counts at most at the mark, even if the protocol reports more. The mark is stored in the
Vaultaccount. - The leg's mode becomes
Impaired, so no new money can go into it. - The leg's low value, the cautious end of its value range, is 0. Withdrawals are priced as if the leg were worth nothing until cash actually comes back.
- The difference between the old value and the mark is booked as a loss at once, Junior first. If the loss reaches Senior, the part Senior loses is recorded as Senior's impairment, a loss tracked so it can be repaid later.
- The vault enters Recovery, the state in which new deposits and investments stop while an incident is handled.
- An impaired leg no longer has to be refreshed. Its protocol can go silent without blocking the vault.
Why it exists
Without a mark, the people who leave first would be paid at the old, inflated value, and the people who stay would carry the whole hidden loss (see A hack nobody has noticed yet). A mark lets one trusted role book a realistic value within one transaction, before anyone else exits.
The guardian can only lower a value. A second mark that is higher than the current one fails with LimitNotLower. Raising a mark is a governance change that waits behind the timelock, a delay that gives holders time to react, so a compromised guardian key cannot inflate a leg.
How it works
sequenceDiagram
participant G as Guardian wallet
participant V as akashi_vault program
participant E as Executor
participant A as Leg adapter
participant P as Protocol
G->>V: mark_leg_impaired(leg, mark)
V->>V: leg mode = Impaired, leg value = min(value, mark)
V->>V: book the loss (Junior first), state = Recovery
Note over V: The leg's low value is 0, so withdrawals are cautious
E->>V: deallocate (take whatever is still there)
V->>A: CPI aai_withdraw
A->>P: withdraw
P-->>A: USDC
A-->>V: USDC into idle
V->>V: cash above the marked value is recovery: Senior first, then Junior
Figure: a mark books the loss in one guardian transaction, and every dollar that later comes back repays Senior before Junior.
The takeaway is that the guardian's job ends with the mark. Getting money back is ordinary work for the executor (the service that moves the vault's cash into and out of legs), and the vault decides on its own who is repaid first.
Example 1: a mark Junior can cover
Suppose the leg holds only 800 USDC, and the guardian marks it at 0.
| Before | After | |
|---|---|---|
| Leg value | 800 | 0 |
| Junior | 1,000 | 1,000 − 800 = 200 |
| Senior | 4,000 | 4,000 |
| Vault state | Active | Recovery, not frozen |
Table: the 800 USDC loss is taken entirely from Junior, so Senior can still leave.
Senior lost nothing, so Alice can withdraw 1,000 Senior shares and receive 1,000 USDC.
Example 2: a mark larger than Junior
The 3,000 USDC leg is marked at 0, a loss of 3,000. Junior loses all of its 1,000, and Senior loses the remaining 3,000 − 1,000 = 2,000 and falls to 2,000. Senior's impairment becomes 2,000. Because Senior is impaired, the vault is frozen: no withdrawal can be funded until the impairment is repaid.
Example 3: a mark can be lowered again
The guardian first marks the 3,000 USDC leg at 1,500, a loss of 1,500. Junior takes 1,000 and Senior the other 500, so Senior falls to 3,500 with an impairment of 500. News gets worse, and the guardian marks the leg again at 500. Only the extra loss of 1,500 − 500 = 1,000 is booked, all on Senior: Senior falls to 2,500 and its impairment rises to 1,500.
Example 4: the money comes back
After the mark at 0 in Example 2, the protocol turns out to be fine. The executor takes all 3,000 USDC out of the leg.
- The 3,000 USDC is above the leg's marked value of 0, so it counts as recovery.
- Recovery repays Senior first: Senior goes from 2,000 back to 4,000 and its impairment to 0. That uses 2,000.
- Then it repays Junior with the remaining 1,000: Junior goes from 0 back to 1,000 and its impairment to 0.
- The admin calls
retire_leg(the leg is now empty), thenresume. The vault is Active again.
Example 5: the protocol repays victims
Some protocols compensate users after a hack. After the mark at 0 in Example 2, the protocol sends 2,500 USDC back to the leg's own token account. The executor moves it into the vault with sweep_leg_transit.
- Senior's 2,000 impairment is repaid first: Senior is back to 4,000.
- The remaining 2,500 − 2,000 = 500 goes to Junior: Junior is 500, with 1,000 − 500 = 500 of Junior impairment still open.
Example 6: repayment after settlement started
After the mark at 0 in Example 2, the admin starts Settlement, the final wind-down in which all cash is paid out and the vault closes. Senior is entitled to its value plus its impairment, 2,000 + 2,000 = 4,000, and Junior to 0 + 1,000 = 1,000. Cash is paid Senior first.
- Alice converts her Senior shares with
settle_sharesand receives 2,000 USDC, all the idle cash there is. - Months later, the protocol pays the full 3,000 back.
- Alice calls
settle_sharesagain with 0 shares. HerSettlementClaimaccount stays open, so this collects what has accrued since her last collection: the 2,000 USDC still owed to Senior. She has now received her full 4,000. - June converts her Junior shares only now. She receives the remaining 3,000 − 2,000 = 1,000, Junior's full entitlement.
The takeaway is that settlement never closes the door on late money. A holder who converts early is not penalised, and one who converts late loses nothing.
Example 7: a precautionary mark
The guardian is worried but does not know the size of the loss. They mark the 3,000 USDC leg at its current value of 3,000.
- No loss is booked: Junior stays at 1,000 and Senior at 4,000.
- But the leg's low value is now 0. At the cautious low end the vault is worth only its 2,000 USDC of idle cash, less than Senior's 4,000. The vault is frozen, and not even Senior can leave.
- When the worry is over, the admin queues a
RaiseMarkchange with a mark at or above the leg's real position. After the governance delay (by default 86,400 seconds, which is 1 day; the curator can set another delay), anyone callsexecute_change. The impairment is lifted and the leg becomesCloseOnly: money can be taken out of it but not added. The admin then callsresume, and the vault is Active with the leg still open.
The takeaway: a mark is a strong tool even at full value, because it removes the leg from the cautious withdrawal price.
Example 8: only the guardian or admin can mark
A stranger who calls mark_leg_impaired gets NotGuardian, and nothing changes.
The mark's life cycle
stateDiagram-v2
[*] --> Active: leg added
Active --> Impaired: mark_leg_impaired
CloseOnly --> Impaired: mark_leg_impaired
Suspended --> Impaired: mark_leg_impaired
Impaired --> Impaired: mark_leg_impaired (lower only)
Impaired --> CloseOnly: RaiseMark to the position or above
Impaired --> Retired: retire_leg (value 0)
CloseOnly --> Active: UpdateLeg (governance)
Retired --> [*]
Figure: the modes a leg passes through after a mark; only governance can lift it, and only to close-only.
Advanced details
- Any leg that is not
Retiredcan be marked, including a suspended one; the mark replaces the suspension. A mark is refused during Settlement (VaultNotActive). It also lowers the leg's high value to the mark. mark_leg_impairedrecords the leg as impaired in theVaultaccount.resumerequires that no leg is impaired and that Senior's impairment is 0 (RecoveryNotFinishedotherwise).- An impaired leg is valued at the lower of its reported book value and its mark, with a low value of 0. A reported value above the mark is ignored, and cash above the marked value counts as recovery.
- A
RaiseMarkto a mark that is not higher than the current one fails withMarkNotHigherwhen it executes. A raise to less than the leg's reported position keeps the leg impaired at the new mark, and the difference between the new and the old mark counts as recovery. resumeclears Junior's impairment. Any Junior loss not yet repaid at that moment becomes permanent.- Tests on copies of every real protocol check the same behaviour: after a mark, the protocol still answers, so the leg is valued again but stays capped at its mark.