Adapter changes and look-alike accounts

Download Markdown

The adapter is the small program that connects the vault to a protocol. The vault trusts it to report values and move money. So the vault checks two things on every call: that the adapter is exactly the version it approved, and that the adapter is talking to exactly the protocol accounts it approved.

Each vault position in a protocol is called a leg, and each leg has its own adapter. The behaviour below is checked by automated tests.

Pinning: the adapter must not change

What. When a leg is added, the vault records which deployment of the adapter program it uses. On Solana, an upgradeable program stores its code in a separate program-data account, and that account records the slot in which the code was last deployed. The leg stores both: Leg.adapter_program_data and Leg.adapter_slot. This is called a pin.

Why. If an adapter's upgrade authority is compromised, an attacker could deploy new code that reports fake values or sends money elsewhere. A pin makes the vault refuse any code it did not approve.

How. Every call to the adapter checks that its program-data account still records the pinned slot. If not, the call fails with AdapterPinMismatch.

Example. The adapter is redeployed, so its program-data account now records a later slot than the pinned one. Bob, a new investor, wants to deposit 100 USDC.

ActionResult
refresh_legAdapterPinMismatch
The executor (the service that moves the vault's cash) takes 100 USDC out of the legAdapterPinMismatch
Bob deposits 100 USDC, after the leg goes stale (not valued for about a minute)StaleValuation

Table: until governance accepts the new code, the leg cannot be valued or moved.

To accept the new code, the admin queues a RepinAdapter change with the new slot. It waits for the add-leg delay, which the curator sets; the program's default is 172,800 seconds, which is 2 days. After the delay, anyone executes it, the leg is refreshed, and Bob's deposit succeeds.

The 2-day delay gives holders time to read the new code and leave if they disagree. While the leg is stale, the guardian can suspend it so the rest of the vault keeps running (A protocol stops working).

Binding: the accounts must not change

What. Each leg stores the list of protocol accounts its adapter may use (its bound accounts, up to 64, the most the program allows). For each adapter instruction, the leg also records which of those accounts it passes.

Why. Without this check, a caller could pass a fake market account that looks like the real one and reports a different price.

How. The vault builds the account list for each adapter call from the leg's stored list, and refuses any transaction whose accounts differ (LegAccountsMismatch). This happens before the adapter runs.

Example.

  • A keeper (anyone who sends the vault's maintenance instructions) refreshes the leg with a look-alike market account in place of the real one. The vault refuses with LegAccountsMismatch.
  • The executor tries to allocate through a swapped account. The vault refuses with LegAccountsMismatch.

The takeaway: neither a changed adapter nor a changed account can reach the vault's money without going through the governance timelock.

Advanced details

  • Adapters are also approved at the protocol level: GlobalConfig keeps a list of approved adapter programs (up to 16, the most the program allows). Approving a new adapter waits for the registry delay before anyone can complete it with execute_adapter_approval. Removing an approval takes effect at once. The delay starts at 0, is set with set_registry_delay, can only be increased, and the program allows at most 30 days.
  • A new leg (an AddLeg change) uses the same add-leg delay as a repin.
  • A queued change must be executed within 7 days after its delay ends, a window set by the program, otherwise it fails with ChangeExpired.
  • An adapter upgrade that fixes a bug therefore reaches each vault only after its admin queues a RepinAdapter and the delay passes.

On this page