Skip to content

feat(registry): name expiry with renewal payments and grace re-registrationΒ #2

Open

Description

@Meet-hybrid

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

Description

Names are registered forever once claimed β€” combined with free registration this means the namespace can be fully squatted. DNS/ENS convention is annual renewal: names expire unless renewed, and expired names become registrable again. Soroban's persistent-storage TTL already gives us the machinery; this issue adds the economic layer on top.

Desired outcome: each name carries an expires_at ledger timestamp; renew(name) extends it for a fee; a new reclaim(name) entrypoint lets anyone re-register a name whose expiry passed, deleting the stale record first.

Scope

  • Crate/module: crates/registry, src/lib.rs
  • API: renew(name), reclaim(name), read-only expiry_of(name) -> u64; Resolution gains expires_at
  • Storage: DataKey::Expiry(String) (persistent, TTL-extended alongside the name key)
  • Tests: renew extends by exactly one year-equivalent; renew on unregistered name β†’ NotFound; reclaim before expiry β†’ InvalidInput; reclaim after expiry resets owner/address/counter; TTL interplay between expiry key and name key
  • Docs: renewal/expiry section in docs/ and README

Non-goals

  • Auto-renewal subscriptions (needs pull-debit β€” out of scope)
  • Grace periods with premium pricing (single flat re-registration price)
  • Refunds on early reclaim
  • Pricing changes (the pricing issue owns fee levels; this uses a constant renewal price or integrates price_for if it has landed)

What "done" looks like

  • register sets expires_at = now + REGISTRATION_PERIOD (documented constant, ~1 year in ledgers)
  • resolve returns expires_at; UI-consumable
  • renew requires owner auth (or anyone, if paying β€” pick one, document, test) and extends expiry
  • reclaim deletes + re-creates the record when now > expires_at, otherwise errors
  • New error variants use the next free codes; enum test updated
  • All existing 15 tests stay green; new tests cover every branch above
  • fmt/clippy/tests/WASM-build gates pass

Implementation guidelines

  • The name and owner keys already extend TTL on write/hot-read (extend_ttl in register/resolve) β€” the expiry key must join those bumps or it will archive before the name
  • Compare set_address/transfer for the owner-check pattern (require_owner helper exists)
  • reclaim should reuse register's validation path for the new owner
  • Consider whether resolve should fail with a new Expired error when past expiry β€” design note: prefer returning the record + expires_at and letting reclaim gate re-registration, but state your choice in the PR
  • Constants belong at module top with the existing TTL constants

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 #2.
  • State before/after storage behavior explicitly (which keys changed).
  • 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 love to implement the name expiry and renewal lifecycle for the registry.

    Architecture & Implementation Plan:

    1. Expiry Metadata:
      • Store expiry_timestamp: u64 in Record in instance storage.
      • Default registration sets expiry based on configured duration parameter.
    2. Renewal Entrypoint:
      • renew_name(env, name: String, duration: u64): Requires caller payment / auth and extends expiry_timestamp.
    3. Grace Period & Re-registration Policy:
      • Define a grace window (e.g. 30 days) during which only the previous owner can renew.
      • After the grace window lapses, the domain record is available for open re-registration by any caller.
    4. Resolution Guard:
      • In resolve, check env.ledger().timestamp() > expiry_timestamp and return RegistryError::NameExpired if lapsed.
    5. Testing:
      • Unit tests with mock ledger timestamps verifying pre-expiry resolution, grace period owner renewal, and post-grace public takeover.
      • Workspace pass on clippy and unit tests.

    Track Record

    Please assign this issue to me so I can get started!

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