alice.acme. For application code, start with the Owner and Holder SDK walkthrough.
A username claim issues a name within an existing namespace. It does not use the top-level namespace Allocator or its objection and refund process. Universal Lookup remains the shared read entry point.
A typical integration follows four steps:
- Check the namespace’s native contracts and claim configuration.
- Request a quote for the label and claimant.
- Build and authorize the exact claim intent, including its destination and fee.
- Submit the transaction and retain its request ID to recover the receipt.
Network fees
Network execution and storage fees are separate from any username price, including a zero price. Owner 0.12.0 and Holder 0.10.0 defaultmaxNetworkFeeStroops to 50_000_000n (5 XLM) per transaction, including storage restoration. Native operations also respect maxNativeFeeStroops; when both options are set, the lower limit applies. They reject a higher estimate before signing. See write-client fee limits.
Initial storage rent can exceed that limit. Review the estimate before explicitly choosing a higher limit; this does not change the on-chain username price.
Capability and bindings
native_contracts checks the required namespace record, Registry-deployed
attestations, clean provenance, selected Resolver pointer and current Wasm hashes
against the Registry’s per-namespace code pins in governed mode, or factory templates on historical deployments. It does not call the Registrar or
Resolver. This permits its use while either contract is already executing.
A namespace owner’s ownership epoch changes on every completed ownership
transition. Returning the namespace to a former owner does not restore old claim
settings. Epoch numbers increase but are not necessarily consecutive for one
namespace.
Verify code, provenance and version answers before using native claims. A failed or unsupported capability read does not mean public claiming is open.
Owner controls
Administrative writes require the current Registry owner. Console operator roles do not replace on-chain authorization. Unless shown otherwise, the methods below returnResult<result, Error>.
Read and configure policy
Reserve and assign labels
Read usage
Policy behavior
Before configuration, manual owner issuance is available and public claiming is unavailable. Configuration sets the mode (Manual or Public), enablement, admission rule, fee, G treasury and usage limits. It also records the current ownership epoch: the version of namespace ownership against which the settings were authorized.
A new owner must configure claiming explicitly. Old settings cannot be enabled under a different ownership epoch. Configuration, pause and re-enable advance the policy and approval-grant epochs; reservation changes advance the policy version.
Public mode blocks the manual issue and issue_batch methods even while paused.
A public label must use public rules. The explicit reserved path is the
administrative exception to public username prices and quotas. It still rejects
an active name and records separate reserved-issuance usage.
Reservation behavior
Reservation batches are atomic, contain 1–23 distinct canonical labels and reject active names when reserving them. Releasing a reservation leaves any holder unchanged. An issued reserved name stays reserved until the namespace owner releases the reservation, including after the name expires.issue_reserved uses owner authorization and the holder’s default address. The
atomic custom-destination variant requires both owner and holder authorization.
The Owner SDK exposes simple assignment. Calling the atomic reserved method for different owner and holder accounts requires an integration that collects both authorizations.
Claim and recovery
Quote
A quote reports availability, reservation, current configuration, ownership epoch, record generation/expiry and lifetime usage. It does not reserve the label. Availability respects the applicable renewal grace period, not just the expiry timestamp.available: true alone does not mean claiming is enabled or that the wallet is
eligible. Inspect all relevant fields and the current policy.
Submit a claim
Current public claims support a G or C claimant as holder and username-fee payer. Checkcontract_claim_version() == 1 before using a C claimant; claim_version() == 1 alone does not establish that support. A C claimant needs an integration with its contract wallet’s authorization rules, and a separate G transaction source pays network fees. The
receiving destination can independently be G without a memo, G with ID/Text/Hash
memo, M with its muxed ID, or C without a memo. The transaction records future
receiving instructions; it does not make a payment to that destination.
A fresh claim checks the complete signed context, current policy and owner epochs,
fixed namespace term, exact fee, expected name generation/expiry, availability,
reservation, wallet limit and admission rule. It then issues the name, transfers
any fee directly to the treasury, initializes the destination and writes usage
and a receipt in one transaction. Any failure rolls back those business effects.
Network fees are separate.
Recover a result
A matching existing receipt returnsReplayed before fresh deadline, policy and
authorization checks. It does not charge, increment usage, issue another name or
rewrite a later destination. Reusing a request ID with a different operation or
intent returns RequestIdConflict. Keep request IDs stable only for the same
immutable intent. Credential nonce/signature renewal does not change that intent.
After recovering a receipt, verify the current holder and generation through Lookup before associating a name with an app account. The receipt records a historical result.
A missing receipt or interrupted RPC read does not prove that a transaction failed.
Reconcile the original transaction before replacing it.
Exact authorization
Forclaim, claimant and optional approver each authorize the single argument
[intent] with native Soroban authorization. The Merkle proof is not part of the
signed intent; it can only demonstrate membership in the already committed root.
The claimant’s authorization has these children, in order:
- Native asset contract
transfer(claimant, fee_recipient, fee_amount)when the fee is nonzero. - Resolver
initialize_destination(label, claimant, fresh_generation, destination).
__check_auth implementation. The backend signs the approver’s authorization entry independently of the claimant’s authorization and the transaction-source signature.
An intent binds network, Registry, Registrar, namespace, request ID, execution
window, label, claimant, complete destination, Resolver, existing generation/expiry,
term, policy/owner/grant epochs and exact fee token/amount/recipient. See the
type definitions.
The business execution window is inclusive: valid_after <= now <= deadline.
Its positive span must be at most 3600 seconds. Approval mode may configure a
shorter maximum. Native credential expiration is a separate ledger-based limit;
an expired or rotated credential is not proof that a previous request never completed.
Admission rules
Allowlist proof
The leaf is SHA-256 of this Soroban XDR tuple:SHA256(0x01 || smaller || larger). Use the final value as the root. This username
allowlist is separate from the Allocator’s top-level namespace reservation proof.
Wallet and approval limits
Wallet limits count cumulative public claims, including expiry/reissue claims.wallet_limit = 0 means unlimited. They do not count current holdings or prove
one person. Reserved assignments have their own count.
The G approver must differ from the namespace owner, fee recipient and claimant. Approval requires a nonzero cumulative allowance, rate limit, window and lifetime.
The owner chooses these numbers. The window is at most 31536000 seconds; approval
lifetime is at most 3600 seconds. Counts survive mode, key, policy and owner
changes. An active window cannot be reset or shortened by reconfiguration; a longer
window may extend its end. The next approved claim starts a new window after expiry.
The lifetime allowance is an absolute ceiling; only an explicit owner increase
provides more headroom.
Transfer and renewal
Accept a transfer
Transfer acceptance requires the intended recipient. It checks the exact current holder, generation, name expiry and pending proposal expiry. It preserves the name’s expiry, advances the generation and initializes the selected destination atomically. A failed destination write leaves the existing holder and proposal unchanged. Claim pause, app admission and claim quotas do not gate this operation.Renew a name
Holder renewal uses the immutable positive default term. It checks the recorded holder, generation and expiry, then extends frommax(now, old_expiry). It preserves
the generation and existing records. It is available within the shorter of 30 days
or one policy term before expiry, subject to the resulting expiry being no more
than 100 years from execution and within the signed result bounds. Zero-expiry or
permanent names cannot use it. The legacy owner renewal method also rejects zero
extension and leases beyond the same 100-year bound.
The owner can configure renewal grace from zero (the default) through 90 days. Enabling it protects names whose expiry is at or after its activation timestamp. Changing one positive duration to another retains that cutoff; disabling and re-enabling starts a new activation. Each change advances the claim policy version. Grace prevents ordinary reissue until ledger time is strictly greater than expiry + applicable grace; it does not keep an expired name resolving or remove any owner reclaim power.
After that protection ends, an expired holder can still renew while it remains the recorded holder and no reissue has won, unless the owner has reserved the now-reissuable label. Read both grace getters and the current name state; a nonzero duration without an activation timestamp provides no protection.
preview_destination returns the exact-generation receiving instructions,
including when inactive. It rejects mismatched generations and invalid configured
payment records. Ordinary payment resolution still rejects expired names. Preview
is not a new payment destination or a bypass of live resolution.
Destination initialization
The initializer is restricted to the bound native Registrar and exact holder consent. It accepts only a destination for a generation freshly created by claim, reserved assignment or accepted transfer. It derives the node from its bound namespace, checks native bindings, rejects already initialized/same-or-newer data, and makes no callback into the active Registrar. It is not a general owner record setter, and renewal does not call it.Errors and compatibility
Existing Registrar error codes1–20 retain their values. The native claim methods add the codes below.
Configuration and reservations
Admission and limits
Request and execution errors
These are the claim and renewal-related codes, not the full Registrar error catalogue. Code
37 remains in the ABI; current contract-claim capability 1 permits both G and C claimants.
Related contract errors
Registry additionally reportsOwnershipEpochUnavailable (29) and
OwnershipEpochOverflow (30). Resolver adds InitializationContextMismatch
(22), DestinationAlreadyInitialized (23) and GenerationMismatch (24).
An atomic Registrar call maps a failed initializer to Registrar error 41 and
aborts the whole operation.
A contract rejection does not authorize changing the destination, dropping a memo,
opening admission or charging different terms on a retry. Changing a Registry deployment template affects future contracts. Existing governed testnet contracts can receive compatible authorized upgrades at the same address; neither operation automatically changes their stored lifecycle policies. Choose those rules during namespace activation.