Skip to content

feat(registry): upgradeable admin with two-step ownership handoverΒ #8

Open

Description

@Meet-hybrid

πŸ’  Sidera β€” Stellar Name Service. Contribute via Drips Wave / GrantFox. Comment with your approach and wait for assignment before starting.

Description

The pricing tranche introduces an admin (fee config authority), and the protocol will need more admin-gated knobs over time. But admin-style authorities that can be set by a single call are the classic rug handle for a name service. The house pattern for this ecosystem is a two-step handover: the current admin proposes a new admin, the proposed admin accepts.

Desired outcome: an Admin record with propose_admin(new) / accept_admin() two-step transfer, used by all admin-gated functionality going forward.

Scope

  • Crate/module: crates/registry, src/lib.rs
  • API: propose_admin(env, new_admin), accept_admin(env), read-only admin() and pending_admin()
  • Storage: DataKey::Admin + DataKey::PendingAdmin (instance storage β€” small hot config)
  • Tests: first-initialization behavior; propose requires current admin; accept requires the proposed address; pending cleared after accept; re-propose flow; accept with no pending β†’ error
  • Docs: admin section in docs/ + README note

Non-goals

  • Multisig admin (a future integration β€” the admin CAN be a multisig contract address)
  • Upgradeability of the contract WASM itself (out of scope; immutability is a feature)
  • Time-locked admin actions
  • Migration tooling

What "done" looks like

  • propose_admin requires current-admin auth; stores pending
  • accept_admin requires the PROPOSED address's auth; promotes and clears pending
  • admin() before any proposal β†’ NotFound or an explicit uninitialized variant (pick, document, test)
  • Re-propose while a pending exists overwrites the pending (documented)
  • Old admin retains no power after acceptance (proven by a test that their next admin call fails)
  • All gates pass

Implementation guidelines

  • If the pricing tranche (separate issue) has already introduced an admin, REFACTOR it onto this two-step module rather than duplicating authority logic β€” note the dependency in your PR
  • Initialization decision to document: lazy init on first propose_admin when unset (the first proposer becomes admin) vs an explicit initialize β€” lazy init is simpler; either is acceptable if tested
  • Error discipline: reuse Unauthorized; add NoPendingAdmin at the next free code if needed
  • Instance storage for both keys; TTL extension follows the house pattern

Verification

cargo fmt --all -- --check
cargo clippy --workspace --all-targets --locked -- -D warnings
cargo test -p sidera-registry --all-targets --locked

PR guidelines

  • Get assigned before starting; do not start work on a reserved issue.
  • Work in a fork; branch off upstream/main; open the PR against Sidera-Protocol/sidera-contracts:main.
  • PR description must include Closes #8.
  • All CI checks must pass; human maintainer review required.

Metadata

  • Affected crates/files: contracts/registry/src/lib.rs, docs/
  • Complexity label: complexity: medium (150 base points)
  • Type labels: enhancement

Activity

  1. Rodrigoue9 commented on Oct 7, 2026

    @Rodrigoue9

    Hi @maintainer! I would like to implement the two-step admin ownership handover.

    Architectural Plan:

    1. Storage Keys:
      • Define DataKey::Admin and DataKey::PendingAdmin in instance storage with appropriate TTL extension matching existing house patterns.
    2. API Entrypoints in contracts/registry/src/lib.rs:
      • propose_admin(env, new_admin: Address): Enforces current_admin.require_auth(), stores DataKey::PendingAdmin. Re-proposing overwrites pending.
      • accept_admin(env): Enforces pending_admin.require_auth(), promotes to DataKey::Admin, and purges DataKey::PendingAdmin. Returns error if no pending admin exists.
      • View functions: admin(env) -> Option<Address> and pending_admin(env) -> Option<Address>.
    3. Security Invariants & Tests:
      • Prove old admin loses all privileges immediately after accept_admin.
      • Prevent self-takeover without explicit two-step completion.
      • First-run initialization test (lazy initialization or explicit admin check).
    4. Verification:
      • Clean clippy (-D warnings), formatting, and test coverage across all handover paths.

    Track Record

    Please assign this issue to me to begin implementation!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    complexity: mediumStandard features or involved bug fixes (150 pts)enhancementNew feature or requestexternal-contributorsSuitable for contributors outside the maintainer team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions