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
Summary
set_adapterrefuses to run whiletotal_shares > 0(ContractError::AdapterSwapUnsafe). The only way to move capital out of the current adapter is the adapter's ownwithdraw(shares, recipient), which is gated onvault.require_auth()and can only ever be called through the vault's own user-facingwithdraw(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.mdalready 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 normalwithdraw()flow once the adapter-share counter resets"), andscripts/redeploy-blend-adapter.shrepeats 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/Entrybookkeeping. This needs invariant checks (value-before ≈ value-after within a slippage tolerance) across two economically different adapter accounting models (Blend'saccrue()-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
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
TOTAL_SH,ADPT_SH, and per-userPrincipal/Entrybookkeeping remain correct after migration