- Stored keys: Registry ownership epochs and Registrar configuration, reservations, usage and receipts.
- Request types: the complete intent authorized for a claim, reserved assignment, transfer or renewal.
- Return values: quotes and destination previews, which are not additional stored records.
Encoding conventions
The XDR conventions also apply here. A named struct is a map keyed by field-name symbols. Enum variants are symbol vectors with their exact payload arity, not integer ordinals.BytesN<32> is raw 32-byte SCV_BYTES; u64 and i128 must retain their full
precision. Labels use canonical lowercase ASCII and are stored as Bytes.
Contract field names use snake_case. The SDK exposes equivalent
camelCase fields, bigint numbers and lowercase 64-character hex identifiers.
Do not hash a JSON serialization when reproducing a contract commitment.
Registry additions
The current namespace record is:
Config retain their documented shapes. The ownership
sequence is Registry-wide, so a particular namespace’s epochs can skip numbers.
An absent sequence is an error, not a reset to zero. Increment overflow also errors.
The required namespace record carries its epoch through ordinary writes. A transfer
back to a former owner receives a new epoch.
owner_epoch(node) reads this field. template_hashes() returns Registrar then
Resolver Wasm hashes for new deployments. In governed mode, native_contracts(node) verifies the existing namespace against its NativeV1(node) code pins and attestations. Approved upgrades update those pins atomically.
This extra required field changes the Registry record schema. An old four-field
record is not a native-claim record with an implied epoch. Use the old schema only
for its matching deployment. Existing owner/resolver pointers and namespace
transfer proposals keep their original meanings.
Registrar keys
The existingDataKey::Config, Name(node) and PendingTransfer(node) shapes remain
unchanged. In particular, the name still stores holder, built-in address, expiry
and ownership generation. Claim state uses a separate ClaimKey enum:
Instance policy and counters
Persistent claim records
For example, a receipt key encodes as:
V1 belongs to the key name. It is not an
integer schema-version record. No new application state uses temporary storage;
native authorization nonce entries belong to the Soroban runtime separately.
Configuration and usage types
These types defineConfigV1, UsageV1 and ApprovalUsageV1.
fee_token must be the current network’s native XLM asset contract. fee_amount
is nonnegative; 0 means free. fee_recipient must be G. Approval mode requires
a G approver distinct from the namespace owner, fee recipient and claimant, plus nonzero explicit allowance, rate limit, window and lifetime. Outside Approval mode, all four approval-specific numeric settings are
zero. wallet_limit = 0 means unlimited cumulative public claims.
Configuration stamps the current owner epoch. Configure and enable/pause operations
advance both policy and grant epochs. Reservations and renewal-grace changes advance the policy version,
including when changed before public claiming is first configured.
Grace is an additive policy, not a field appended to ClaimConfig or Name. RenewalGraceV1 accepts 0–7,776,000 seconds. Enabling stores the current ledger timestamp in RenewalGraceEffectiveFromV1; only expiries at or after that timestamp qualify. Positive duration changes retain the cutoff. Disabling removes it, and re-enabling starts a new activation. A legacy nonzero duration without the cutoff does not protect expired names. Grace prevents ordinary reissue while leaving the ownership expiry and resolution rules unchanged.
An ownership transfer does not rewrite this stored configuration. Its enabled
flag may remain true, but it is ineffective when ClaimConfig.owner_epoch differs
from Registry’s current epoch. A new owner must configure explicitly. SDKs and
interfaces must compare the epochs when displaying whether claiming is usable.
public_claims counts lifetime ordinary claims, including expired-name reissues.
reserved_issues counts privileged reserved assignments. Neither count decreases
on transfer, expiry, reclaim, mode change or ownership change. The approval total
and active window likewise survive policy and key changes. An allowance is an
absolute lifetime ceiling, not a balance automatically replenished by rotation.
Request types
Payment destination
These types represent the complete receiving instructions included in an intent:Direct supports G with None/ID/Text/Hash or C with None. Muxed requires a G
base account and an exact u64 ID. It does not carry a transaction memo. The
public SDK displays a canonical M string with memo: { type: "none" }.
Shared request context
Every intent includes the same network, contract, request-ID and execution-window context:Public claim
A public claim binds the label, claimant, destination, current policy and exact fee. Registrarcontract_claim_version() == 1 adds G and C claimant support without changing this intent’s shape or the original claim_version() == 1. A C claimant authorizes through its contract wallet; the approver and fee recipient remain G identities under the current configuration rules.
Reserved assignment
A reserved assignment binds its holder and destination without a username fee.Transfer acceptance
Transfer acceptance binds the current proposal and the recipient’s chosen destination.Holder renewal
Renewal binds the current name record and the permitted range for its new expiry.expected_generation = None and expected_expiry = None.
Reissue binds both previous values. First issuance creates generation 0; reissue,
accepted transfer and reclaim advance it with checked arithmetic. Renewal preserves
it. An active record is not available for ordinary issuance.
term_secs must equal the namespace’s immutable default term. The public claim
intent also binds all fee fields and current policy/owner/grant epochs. An atomic
reserved assignment uses the current owner and policy epochs but has no username
fee. Transfer and renewal do not depend on claim policy or approval epochs.
Transfer binds the exact pending sender/recipient, original generation, name expiry
and proposal deadline. Renewal binds the holder/generation/current expiry and
permitted result range. For an expired name, the renewal result is based on actual
execution time, so the signed range accommodates the reviewed timing window.
Quote and receipt types
Quote
A quote is a read result, not a reservation or additional stored key.Receipt and result
ClaimReceipt is stored under ReceiptV1; ClaimResult wraps it in an operation response.
ClaimQuote.config is an explicit enum: [Symbol("Unconfigured")] or
[Symbol("Configured"), ClaimConfig]. This differs from the standalone
claim_config() getter’s Option<ClaimConfig>, whose absence is SCV_VOID.
The SDK converts either absence representation to null at its respective API.
Quote availability, reservation and enablement are separate facts. An expired
record still supplies its prior generation/expiry, and applicable grace can keep it unavailable for reissue. A quote’s available flag
is not proof that the requesting wallet satisfies admission or quota rules.
Receipts are stored under the receiving holder’s identity for reserved assignment,
transfer and renewal, and the claimant for a public claim. The key spans operation
types: a holder cannot reuse the same request ID for a different operation.
The commitment is:
claim, issue_reserved_with_destination,
accept_transfer_with_destination or renew_holder. Merkle proof bytes and native
credential nonce/signatures are excluded. A different business deadline or epoch
changes the commitment; refreshing only credentials does not.
A matching receipt yields historical Replayed without writes or renewed
business authorization. It never reinitializes records after transfer/reissue.
An unmatched commitment is an error. Receipt expiry/generation are historical,
not a replacement for current Lookup state. Free operations have fee_amount = 0
and fee_recipient = None; fee_token still identifies native XLM.
Resolver behavior
The Resolver exposesinitialization_version() = 1, restricted initialize_destination and preview_destination. These methods use the existing payment-version-2 record encodings and add no storage keys.
Initialization writes the existing generation-bound Addr(node),
Text(node, Symbol("payment")) and PaymentConfigured(node, generation) records
together. It refuses an existing marker for that generation or address/payment
records from the same or a newer generation. Old-generation records can be
replaced when the trusted Registrar creates a new ownership generation.
The caller must be the bound, currently clean native Registrar, and the exact
holder must consent. The Registrar creates the generation internally; callers
cannot use this helper as an arbitrary generation or owner-setting API. The
initializer does not call back into the active Registrar. It writes no reverse
or Primary identity automatically.
Destination preview
Preview returns a read-only value, not another stored record:active = false for an expired name. Ordinary payment reads remain strict:
expired names do not resolve. Renewal leaves the existing generation and records
intact, so the holder should review this preview before reactivating them.
TTL, restoration and events
Ownership expiry and storage lifetime remain independent. An archived receipt, reservation, usage entry or name must restore or fail. An application must not replace an unavailable read with zero usage, an unreserved label or a fresh request. No admin action deletes usage or receipts to reset these values.Maintaining stored entries
Registrar TTL extensions use a threshold of2,500,000 ledgers and a target of 3,000,000 ledgers, clamped to the network maximum. Policy and configuration writes extend the instance lifetime. Receipt, usage and reservation writes extend their persistent entries. Name writes extend the name entry and instance. Keeping entries live costs
network resources even when there is no username renewal fee.
touch_claim_state(holder, request_ids, labels) is permissionless. It extends the instance, that holder’s existing usage and the supplied existing receipt and reservation entries. The combined supplied request/label count is at most 23;
the return count excludes the instance. It skips keys that were never created.
It does not enumerate every wallet, request or reservation. Keep a discovery list
or use indexed events to select entries; verify values against the contracts.
Events
The existing
issued, transfer, renewed and name_v1 lifecycle events remain.
The renewed payload remains (label, name_node, new_expiry). Destination writes
retain the native Resolver payment events. Replaying a receipt emits no new claim
event because it performs no business mutation.
Native username claims add no storage keys to Allocator, Primary or Lookup. Earlier deployments retain their own records and namespace escrow liabilities.