seeker-domains

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

.skr domain resolution

.skr域名解析

.skr
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
    alice.skr
    to a wallet address
  • Reverse — a wallet address to the
    .skr
    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.
.skr
域名是Solana主网上的AllDomains域名。Seeker用户默认会获得一个,非常适合在UI中替代截断显示的钱包地址。
双向解析:
  • 正向解析 — 将
    alice.skr
    转换为钱包地址
  • 反向解析 — 将钱包地址转换为其拥有的
    .skr
    域名
无论应用的其余部分针对哪个集群,这两种解析都在主网上进行。即使是部署在devnet的应用,仍会基于主网解析域名。

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
    EXPO_PUBLIC_*
    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.
解析操作读取链上公开数据,因此客户端可以直接执行。在以下场景中,建议通过后端代理执行:
  • RPC密钥保护
    EXPO_PUBLIC_*
    中的密钥对任何拥有APK文件的人都可见。如果使用付费RPC服务,必须在服务器端执行。
  • 共享缓存:域名很少变更。单台服务器端缓存的效率远高于每个客户端重复解析相同地址。
  • 批量查询:一次请求解析整个好友列表,比手机发起N次往返请求更高效。
对于原型或低流量应用,直接通过公共RPC进行客户端解析是可行的。但公共端点有速率限制,因此无法支持需要解析数十个地址的列表视图。
如果从项目中无法明确判断用户需求,可询问用户。对于任何面向生产环境的项目,默认使用代理方案。

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.
  1. Look for backend dependencies in every
    package.json
    express
    ,
    fastify
    ,
    hono
    ,
    @nestjs/core
    ,
    koa
    , or a Next.js app with API routes.
  2. Look for entry points:
    server.ts
    ,
    app.ts
    ,
    main.ts
    ,
    index.ts
    .
  3. Look for route organisation:
    routes/
    ,
    api/
    ,
    controllers/
    .
  4. Ask if it is still ambiguous — "I see a Fastify server in
    apps/api
    ; should the
    .skr
    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.
在编写新服务器前先检查现有资源。在已有NestJS服务的旁边新增Express应用会增加维护难度。
  1. 查看所有
    package.json
    中的后端依赖——
    express
    fastify
    hono
    @nestjs/core
    koa
    ,或带有API路由的Next.js应用。
  2. 查找入口文件:
    server.ts
    app.ts
    main.ts
    index.ts
  3. 查找路由组织方式:
    routes/
    api/
    controllers/
  4. 如果仍有疑问,可询问:“我在
    apps/api
    中看到一个Fastify服务器,.skr的端点应该放在这里吗?”
将路由添加到现有后端中,匹配其路由、验证和错误处理的约定。只有当确实没有后端时,才搭建最小化服务器。

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:
  • getOwnerFromDomainTld
    takes the bare name
    , not
    alice.skr
    . 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
    .skr
    names, and the order is not a ranking. Pick deterministically — sort and take the first — or the displayed name will change between calls.
该库与框架无关,仅围绕它的路由会有所不同。
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)

// 正向解析:名称转地址。传入不带.skr后缀的名称。
const owner = await parser.getOwnerFromDomainTld('alice')

// 反向解析:地址转名称。
const domains = await parser.getParsedAllUserDomainsFromTld(publicKey, 'skr')
需要注意两点:
  • getOwnerFromDomainTld
    接收纯名称
    ,而非
    alice.skr
    。传入完整域名会返回空结果,这会被视为“未注册”而非bug。
  • 反向查询返回数组。一个地址可以拥有多个.skr域名,且顺序不代表优先级。需确定性选择——排序后取第一个——否则显示的名称会在不同调用间变化。

API shape

API接口设计

Two endpoints, adapted to whatever framework is in use:
RouteBodySuccessNot found
POST /api/resolve-domain
{ domain: "alice.skr" }
{ address }
404
POST /api/resolve-address
{ address: "5FHw..." }
{ domain }
404
Validate input before touching RPC: reject a malformed base58 address or a domain that does not end in
.skr
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.
两个端点,可根据使用的框架调整:
路由请求体成功响应未找到响应
POST /api/resolve-domain
{ domain: "alice.skr" }
{ address }
404
POST /api/resolve-address
{ address: "5FHw..." }
{ domain }
404
在调用RPC前验证输入:拒绝格式错误的base58地址或不以.skr结尾的域名,返回400状态码,避免错误输入消耗RPC配额。
区分“无注册域名”(404)和“RPC请求失败”(503)。如果将两者都归为404,会导致服务中断时看起来像是所有用户都没有域名。
完整的Express实现,以及Fastify、NestJS、Hono和Next.js路由处理的说明: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 —
@tanstack/react-query
with a long
staleTime
is enough, since names change rarely.
For an Android emulator,
localhost
is the emulator itself. Reach the host machine at
http://10.0.2.2:3000
. 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
EXPO_PUBLIC_API_URL
.
Hook, components, and the truncation helper: references/client.md.
ts
const { data: domain } = useResolveAddress(account?.address)
const label = domain ?? ellipsify(account?.address)
始终回退到截断显示的地址。解析失败的名称应降级为可用内容,绝不能显示空白或无限加载的加载动画。
缓存结果——使用
@tanstack/react-query
并设置较长的
staleTime
即可,因为域名很少变更。
对于Android模拟器,
localhost
指模拟器本身。要访问主机,需使用
http://10.0.2.2:3000
。在物理设备上使用主机的LAN IP。将任何一种地址硬编码到源码中都会导致后续开发者无法正常使用应用——应从
EXPO_PUBLIC_API_URL
读取地址。
Hook、组件和截断工具的说明: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
  • references/server.md — Express实现、其他框架、验证与错误处理
  • references/client.md — 解析Hook、显示组件、模拟器网络配置

Related skills

相关技能

  • solana-mobile-wallet
    — the wallet connection supplying the address to resolve
  • seeker-genesis-token
    — verifying Seeker ownership
  • solana-mobile-wallet
    — 提供待解析地址的钱包连接功能
  • seeker-genesis-token
    — 验证Seeker所有权

Links

链接