.skr domain resolution
domains are AllDomains names on Solana mainnet. Seeker users get one by default, which
makes them a good substitute for truncated addresses in a UI.
Two directions:
- Forward — to a wallet address
- Reverse — a wallet address to the names it owns
Both live on mainnet, regardless of which cluster the rest of the app targets. An app on
devnet still resolves names against mainnet.
Decide where resolution runs
Resolution reads public on-chain data, so a client can do it directly. Proxy it through a
backend when you want:
- RPC key protection. A key in is readable by anyone with the APK. If you
use a paid RPC, it has to be server-side.
- Shared caching. Names change rarely. One server-side cache beats every client
re-resolving the same addresses.
- Batch lookups. Resolving a whole friend list in one request beats N round trips from a
phone.
Direct client-side resolution against a public RPC is reasonable for a prototype or a
low-traffic app. Public endpoints are rate-limited, so it will not survive a list view that
resolves dozens of addresses.
Ask which the user wants if it is not obvious from the project. Default to the proxy for
anything heading to production.
Integrating with an existing backend
Check what exists before writing a new server. Adding an Express app beside someone's
NestJS service is a mess to maintain.
- Look for backend dependencies in every — , , ,
, , or a Next.js app with API routes.
- Look for entry points: , , , .
- Look for route organisation: , , .
- Ask if it is still ambiguous — "I see a Fastify server in ; should the
endpoints go there?"
Add routes to what exists, matching its conventions for routing, validation, and error
handling. Only scaffold a minimal server when there is genuinely no backend.
Core resolution logic
The library is framework-agnostic; only the routing around it changes.
bash
npm install @onsol/tldparser @solana/web3.js
ts
import { TldParser } from '@onsol/tldparser'
import { Connection } from '@solana/web3.js'
const connection = new Connection(process.env.SOLANA_MAINNET_RPC_URL, 'confirmed')
const parser = new TldParser(connection)
// Forward: name to address. Pass the name WITHOUT the .skr suffix.
const owner = await parser.getOwnerFromDomainTld('alice')
// Reverse: address to names.
const domains = await parser.getParsedAllUserDomainsFromTld(publicKey, 'skr')
Two things to get right:
- takes the bare name, not . Passing the full domain
returns nothing, which reads as "unregistered" rather than as a bug.
- Reverse lookup returns an array. An address can own several names, and the order
is not a ranking. Pick deterministically — sort and take the first — or the displayed name
will change between calls.
API shape
Two endpoints, adapted to whatever framework is in use:
| Route | Body | Success | Not found |
|---|
| | | 404 |
POST /api/resolve-address
| | | 404 |
Validate input before touching RPC: reject a malformed base58 address or a domain that does
not end in
with a 400, so bad input does not consume RPC quota.
Distinguish "no domain registered" (404) from "RPC failed" (503). Collapsing both into 404
makes an outage look like every user having no name.
Full Express implementation, plus notes for Fastify, NestJS, Hono, and Next.js route
handlers: references/server.md.
Client integration
ts
const { data: domain } = useResolveAddress(account?.address)
const label = domain ?? ellipsify(account?.address)
Always fall back to a truncated address. A name that fails to resolve should degrade to
something usable, never to a blank space or a spinner that never resolves.
Cache results —
with a long
is enough, since names change
rarely.
For an Android emulator,
is the emulator itself. Reach the host machine at
. On a physical device use the host's LAN IP. Hard-coding either into
source is what breaks the app for the next person — read it from
.
Hook, components, and the truncation helper: references/client.md.
Reference material
- references/server.md — Express implementation, other frameworks,
validation and error handling
- references/client.md — resolution hook, display components,
emulator networking
Related skills
- — the wallet connection supplying the address to resolve
- — verifying Seeker ownership
Links