The trustless core
The Registry is immutable. It ships with no upgrade path at all — not timelocked, not multisig-gated: absent. No admin override, no force-transfer, no pause, no platform revocation. The guarantee is verifiable from the bytecode, not trusted to an operator. The cost — a Registry bug can never be patched — is why the Registry is deliberately tiny: namespace ownership, resolver pointers, and the handful of one-way facts that certify permanence. Who can do what is fixed by the absence of code paths:
The one power the platform retains — deciding who receives unclaimed namespaces — is bounded by the public claim window and ends permanently the moment a namespace is allocated.
Resolution is readable by anyone. Every resolve, reverse lookup, and policy read is on-chain state, answerable by any Soroban RPC node — including yours. No API key, no allowlist, no Soran server required.
The hosted layer
Everything else Soran runs is convenience, not authority:- The console — a UI over transactions your wallet signs. It never holds your keys or your namespace.
- The public API — a read mirror of on-chain state: fast and cacheable, but never the source of truth.
- Webhooks and the directory — indexed projections of chain events.
- Billing and the marketplace — subscription billing and the escrow marketplace, when enabled on a deployment. Subscription pricing is operator-set per deployment. Even here the asset stays sovereign: a lapsed subscription can cost you the conveniences, never the namespace.
The SDK verifies everything
The SDK is built so Soran’s servers are never in the trust path:- Every call is a read-only Soroban RPC simulation against the deployed contracts. Point
rpcUrlat any node you trust. - Forward resolution is verified by the contracts themselves: records are bound to a name’s ownership generation, so expired, reissued, or transferred names stop resolving on chain — the SDK never guesses.
- Reverse resolution is contract-verified end to end: the Resolver answers a reverse lookup only while the name is live and its forward record points back at the address. No client-side re-check needed, nothing to spoof.
- Hints are liveness-only. The optional
hintUrl(backed by the public API) supplies only a list of namespaces to probe for reverse lookup. A lying hint can hide a name by omission; it can never forge one. - Errors are never answers. A failed chain read throws — it is never silently reported as “unregistered” or “no address.” One documented exception: the optional primary-name step inside
reverseLookupdegrades to the namespace probes on failure rather than failing the whole lookup — callprimaryOfdirectly when you must distinguish “no primary” from “primary unreadable.”
If you consume the HTTP API directly from a backend, apply the SDK’s discipline yourself: treat mirror answers as hints and confirm anything that gates money on chain. See what the API is and isn’t.
Residual trust, stated plainly
Honesty about the edges is part of the model:- Namespace policy is the issuer’s. A ◔ reclaimable name is genuinely reclaimable by its issuer — the guarantee is that this is disclosed on chain, not that it can’t happen. Render the glyphs.
- Allocation governance is trusted once, briefly, publicly. Awarding unclaimed namespaces involves human adjudication, bounded by a public window, bonded objections, and hard caps in code — but it is a governed process, not a theorem. After allocation, the trust relationship is over, permanently.
- Your RPC is your oracle. Trustless reads are only as honest as the node answering them. For high-value flows, use an RPC you operate or have reason to trust.