Skip to content

[Feature] No safe way to migrate a live vault's capital to a new adapter #464

Description

@collinsezedike

Summary

set_adapter refuses to run while total_shares > 0 (ContractError::AdapterSwapUnsafe). The only way to move capital out of the current adapter is the adapter's own withdraw(shares, recipient), which is gated on vault.require_auth() and can only ever be called through the vault's own user-facing withdraw(caller, shares) entry point, scoped to that specific caller's own shares. There is no admin-authorized path to sweep remaining adapter funds and complete an adapter swap.

Motivation

apps/docs/architecture/vault-contract.md already documents this as the admin's responsibility ("migrating funds out of the old adapter before calling this: any value still sitting in the old adapter becomes unreachable through the vault's normal withdraw() flow once the adapter-share counter resets"), and scripts/redeploy-blend-adapter.sh repeats the same warning without automating it. For a vault with real depositors, moving from one adapter to another (e.g. Blend to a higher-yielding DeFindex vault, or replacing a compromised adapter) today requires every depositor to withdraw first, which isn't viable in production.

Proposed Solution

Add a privileged, non-user-auth-gated fund-movement path in the vault contract that lets the admin move remaining adapter capital during an adapter swap, while preserving TOTAL_SH/share-price/Principal/Entry bookkeeping. This needs invariant checks (value-before ≈ value-after within a slippage tolerance) across two economically different adapter accounting models (Blend's accrue()-cached total vs DeFindex's live-computed total), and a Soroban auth design for "the vault moves its own escrowed funds without any single user's signature" that doesn't open a rug-pull vector for a malicious or compromised admin key.

Scope

Field Value
Area Contracts
Protocol affected Both
Network testnet
Breaking change? No (new entrypoint, existing behavior unchanged)

Alternatives Considered

Leaving depositors to withdraw individually before an adapter swap: this is the current state. It works for a testnet/technical-preview vault with few depositors but doesn't scale and blocks any real migration once the vault holds meaningful TVL.

Acceptance Criteria

  • Admin-authorized entrypoint exists to move remaining adapter capital during an adapter swap without requiring every depositor to withdraw first
  • TOTAL_SH, ADPT_SH, and per-user Principal/Entry bookkeeping remain correct after migration
  • Value-before/value-after invariant check with an explicit slippage tolerance, covering both Blend's cached and DeFindex's live accounting models
  • Auth model reviewed so the migration path cannot be used to redirect funds to an attacker-controlled address by a compromised admin key alone (or documents the accepted trust assumption explicitly)
  • Tests cover: migration with outstanding depositor shares, migration under adapter-reported total_assets drift, and rejection when invariant checks fail

Metadata

Metadata

Assignees

Labels

contractsInvolves writing or testing Rust/Soroban contracts in packages/contractsenhancementNew feature or requesthardComplex implementation spanning multiple packages or involving Soroban contractssorobanInvolves Soroban smart contract invocations or Soroban RPC calls

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions