feat(vault): two-step admin handover via transfer_admin/accept_admin - #618
Conversation
set_admin's single-step, immediate transfer had no check against the new address being unreachable, mistyped, or otherwise uncontrolled. With no upgrade path and no second role, a bricked admin key is permanently unrecoverable, and the deploy script's shared admin/deployer/mUSDC-issuer key makes that slip plausible in practice. Replace it with the standard two-step handover: transfer_admin(new_admin) records a pending nominee under the current admin's signature, and a separate accept_admin() requires the nominee's own signature to complete the transfer. Admin never changes hands until the new key proves it can actually sign. get_pending_admin() exposes the outstanding nomination. Updates docs (vault-contract.md, migration-keeper.md, testnet-deployment.md, deploy-testnet.sh) that referenced set_admin.
|
@ibochielizabeth-spec is attempting to deploy a commit to the Collins' projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@ibochielizabeth-spec Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
collinsezedike
left a comment
There was a problem hiding this comment.
Solid nominate/accept handover, correct auth model (accept_admin requires the nominee's own signature, not the current admin's), correct overwrite semantics, and I confirmed no off-chain caller references the vault's set_admin anywhere so nothing else breaks. Fixed the two docs' Prettier formatting directly and pushed. Merging now.
closes #562
Summary
set_admin's single-step, immediate admin transfer with the standard nominate/accept handover pattern:transfer_admin(new_admin)records a pending nominee under the current admin's signature, and a separateaccept_admin()requires the nominee's own signature to complete the transfer.set_adminis removed entirely (breaking change, as called out in the issue).Changes
packages/contracts/vault/src/lib.rs:PEND_ADMinstance storage key andContractError::NoPendingAdmin(16).set_admin; addedtransfer_admin(new_admin)(admin-gated, sets the pending nominee, overwrites any prior unaccepted nomination),accept_admin()(nominee-gated via the nominee's ownrequire_auth(), completes the transfer and clears the pending slot, failsNoPendingAdminif nothing is pending), andget_pending_admin() -> Option<Address>.transfer_admin_then_accept_rotates_admin,accept_admin_fails_with_no_pending_nominee,transfer_admin_overwrites_a_prior_unaccepted_nomination,transfer_admin_fails_before_initialize(covers the full nominate → accept flow and rejects premature completion, per the issue's acceptance criteria).set_adminreferences:apps/docs/architecture/vault-contract.md(interface, auth section, error table, storage table),apps/docs/operations/migration-keeper.md,apps/docs/operations/testnet-deployment.md,scripts/deploy-testnet.sh(comments only — its actualset_admininvocation there targets the mUSDC Stellar Asset Contract, a separate, unrelatedset_admin, and is untouched).Test plan
cargo test --libinpackages/contracts/vault: all 58 tests pass, including the 4 new/updated ones.cargo build --workspaceinpackages/contracts: builds cleanly (blend-adapter, defindex-adapter, vault all compile against the updated interface).