Skip to content

[CO-02] Implement two-step admin transfer in loyalty_token to prevent irreversible lockout #280

Description

@Leothosine

Problem

contracts/loyalty_token/src/lib.rs:151-156 - transfer_admin() immediately overwrites the Admin storage key:

env.storage().instance().set(&DataKey::Admin, &new_admin);

A single typo in new_admin permanently locks out the current admin with no recovery path. No confirmation is required from the new admin, no event is emitted, and the ability to mint, burn, and manage the loyalty token contract is permanently lost.

Proposed Solution

Implement a two-step admin transfer:

  1. transfer_admin(env, caller, new_admin) - sets DataKey::PendingAdmin, emits (symbol_short!("admin"), symbol_short!("proposed")). Does NOT change DataKey::Admin.
  2. accept_admin(env, caller) - requires caller == PendingAdmin, promotes to Admin, clears PendingAdmin, emits accepted event
  3. cancel_transfer(env, caller) - requires current admin auth, clears PendingAdmin

Acceptance Criteria

  • Calling transfer_admin() alone does NOT change the active admin
  • accept_admin() from any address other than PendingAdmin panics with "not pending admin"
  • Happy path test: propose ? accept ? old admin can no longer mint
  • Cancel test: propose ? cancel ? PendingAdmin cleared, old admin still active
  • Both proposed and accepted events emitted at the correct step

Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions