Skip to Content
ProtocolReserved Names

Reserved Names

Reserved names are a policy layer on top of the protocol. The indexer has no concept of “reserved” - to it, a name is either in registrations or it isn’t. Reservation is enforced by the signing service: the admin key will not produce a CLAIM signature for a reserved name unless the requester presents a valid unlock code.

For the end-user perspective see Reserved Names (Use ZNS).

Storage

Reserved names live in a Supabase table (zn_reserved_names) queried by the web app’s server actions. The schema:

ColumnTypeDescription
nametext, primary keyLowercased normalized name
categorytextOne of brand, protocol, community, offensive
redeemedbooleanTrue once the name has been claimed by its rightful owner

The table is outside the indexer’s scope. Running your own indexer does not give you access to the reserved list - it’s a policy-layer table specific to the zcashnames.com deployment. Third-party signing services can implement their own reservation policy (or skip it entirely).

Unlock codes

An unlock code is a deterministic HMAC fingerprint that the signing service can regenerate for any reserved name. It is distributed out-of-band (Discord, email) to the rightful owner.

Properties:

  • Deterministic. Same secret + same name = same code forever (until the secret is rotated).
  • One per name. There is no per-user code - the secret is shared across the operator’s infrastructure.
  • 12 hex chars, formatted XXXX-XXXX-XXXX. Provides ~48 bits of entropy per code given the secret is unknown - enough to prevent online guessing, not enough to resist a secret leak.
  • Not a capability. The unlock code is a verifier input; it does not by itself authorize anything on-chain. The on-chain CLAIM still requires the admin Ed25519 signature.

Claim flow

  1. User types a reserved name in the web UI.
  2. Server action calls getReservedName(name) and finds a non-redeemed row.
  3. UI prompts for the unlock code.
  4. User submits code. Server calls verifyUnlockCode(name, code).
  5. If the code is valid and the category is not offensive, the server proceeds with the normal buildSignedClaimMemo flow: resolves (expects null), builds the canonical CLAIM:{name}:{address} pre-image, signs with the admin key, returns the memo to the client.
  6. Client shows the ZIP-321 URI. User sends the tx. Indexer processes the block normally - it has no idea this name was reserved.
  7. After confirmation, the server should mark redeemed = true in the reservation row so subsequent claim attempts are not gated on the unlock code. (Redemption tracking is operator-specific and not part of the protocol.)

Category semantics

CategoryClaim gated onBlocks forever?
brandValid unlock codeNo - once redeemed, the row is out of the way
protocolValid unlock codeNo
communityValid unlock codeNo
offensiveNothing can unlock itYes - the signing service will not produce a CLAIM signature, period

offensive is the one place where the web UI acts as a censor. The isBlocked helper checks for this category explicitly. Other reservation tiers are discretionary: if a brand doesn’t want their reserved name, they can simply not redeem it and it stays blocked by policy until the operator removes the row.

Security properties and weaknesses

  • Policy, not protocol. Anyone running their own signing service can implement a different reservation policy - or none. The indexer will accept any validly-signed CLAIM.
  • Admin-key trust. This scheme only works because the admin key is the sole source of CLAIM signatures. If the signing key leaks, reserved names are no longer protected.
  • Secret-rotation burden. Rotating ZNS_UNLOCK_SECRET invalidates every previously issued unlock code. Do this only in concert with re-issuing codes to holders.
  • Single point of failure. The signing service’s refusal is the entire enforcement mechanism. There is no on-chain way to distinguish a reserved name from any other name after it’s been claimed.
Last updated on