mcpField
S
seeker-domains

seeker-domains

github.com/solana-mobile开发812.6k 次安装1 周前更新
代码仓库

关于 seeker-domains

用于 Solana Mobile 应用的 `.skr` 域名解析技能,基于 `@solana-mobile/skr-domain` 实现名称与钱包地址的双向解析。它指导开发者选择客户端或后端代理,并处理缓存、验证与身份显示风险。

主要功能

  1. 01`.skr` 名称与地址双向解析
  2. 02主网解析及过期名称处理
  3. 03客户端与后端代理方案
  4. 04输入验证和错误状态映射
  5. 05反向解析的缓存与信任建议

适用场景

  1. 01将钱包地址显示为 `.skr` 名称
  2. 02把 `.skr` 名称解析为支付地址
  3. 03批量解析地址并减少客户端请求

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/solana-mobile/solana-mobile-skills --skill seeker-domains

安装后在 Claude Code 中输入/seeker-domains确认已加载。

附带文件references/client.mdreferences/server.md

详细介绍

.skr 域名解析

.skr 域名是 Solana 主网上的 AllDomains 名称。Seeker 用户默认会获得一个,因此在 UI 中,它们很适合用来替代被截断的地址。

有两个方向:

  • 正向解析 — 将 alice.skr 解析为钱包地址
  • 反向解析 — 将钱包地址解析为 .skr 名称:其主名称,或者它拥有的其他名称

这两个方向都在主网上进行,不受应用其他部分所使用的集群影响。即使应用在 devnet 上运行,也仍会对主网上的名称进行解析。

决定在哪里执行解析

解析会读取公开的链上数据,因此客户端可以直接执行解析。以下情况适合通过后端代理:

  • 保护 RPC 密钥。 EXPO_PUBLIC_* 中的密钥可被任何拥有 APK 的人读取。如果使用付费 RPC,就必须在服务器端使用。
  • 共享缓存。 名称很少变化。由服务器端缓存一次,比每个客户端都重新解析相同的地址更好。
  • 批量查询。 一次请求解析整个好友列表,比手机发起 N 次往返请求更好。
  • getProgramAccounts 访问权限。 反向解析需要此方法,但许多提供商会禁用它,或对其施加严格的速率限制。使用经过确认的提供商,通过一个服务器端端点处理,比等到用户设备上才发现限制更好。

对于原型或低流量应用,直接通过公共 RPC 在客户端解析是合理的。公共端点有速率限制,因此无法支撑解析数十个地址的列表视图。

如果无法从项目中明确判断用户的选择,请询问用户。对于任何准备投入生产的项目,默认采用代理方式。

与现有后端集成

编写新服务器之前,先检查现有内容。 在别人的 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 端点应该加在那里吗?”

将路由添加到现有服务中,并遵循其路由、验证和错误处理约定。只有在确实没有后端时,才搭建一个最精简的服务器。

核心解析逻辑

使用 @solana-mobile/skr-domain。不要将解析器复制到项目中,也不要转而使用其他 SDK:该软件包由 Solana Mobile 维护,基于 @solana/kit 构建,并支持两个方向的解析。解析与框架无关;只有外围的路由方式会有所不同。

npm install @solana-mobile/skr-domain @solana/kit
import { getPrimarySkrDomain, getSkrDomains, normalizeSkrName, resolveSkrDomain } from '@solana-mobile/skr-domain'
import { address, createSolanaRpc } from '@solana/kit'

// Always mainnet, whatever cluster the rest of the app targets.
const rpc = createSolanaRpc(process.env.SOLANA_MAINNET_RPC_URL!)

// Forward: { owner, nameAccount, expiresAt }, or null when unregistered or expired.
const domain = await resolveSkrDomain(rpc, 'alice.skr')

// Reverse: the name the wallet chose, else the first name it owns (sorted), else null.
const wallet = address('5FHw...')
const name = (await getPrimarySkrDomain(rpc, wallet)) ?? (await getSkrDomains(rpc, wallet))[0] ?? null

该软件包的功能如下,可避免你重新实现:

  • 未找到时返回 null(或 []),绝不会抛出异常。 拒绝意味着 RPC 调用失败,因此两者可以分别映射为 404 和 503。
  • 无效输入会抛出普通的 Error。 normalizeSkrName 接受 alice、Alice.skr 和 ' alice ',但子域名、其他 TLD 或空标签会触发异常。在消耗 RPC 配额前,可在 try/catch 中调用它,将无效输入转换为 400。
  • 已过期的名称会解析为未注册状态,两个方向均如此,且没有宽限期。
  • getPrimarySkrDomain 会重新检查所有权。 转移所有权时,MainDomain 账户不会更新,因此该软件包会正向解析名称,并且只有在钱包仍拥有该名称时才返回它。
  • getSkrDomains 使用 getProgramAccounts,许多服务提供商会禁用或限制此接口的速率。它每次读取 100 个标签,每次只发出一个请求,因此即使某个钱包拥有大量名称,也无法一次性耗尽你的配额。
  • NFT 封装名称不在支持范围内。 目前 .skr 下不存在此类名称;如果出现,resolveSkrDomain 会抛出异常。

React Native 需要 WebCrypto polyfill。 派生名称地址时会调用 crypto.subtle.digest,而 Hermes 不支持此接口。安装 react-native-quick-crypto,并在启动时、导入该软件包之前调用它的 install()。Node 20.18+、Bun 和浏览器则无需额外配置。

该软件包仅支持 ESM。 CommonJS 服务端需要设置 "type": "module"(或使用 Node 22.12+,该版本可以 require() ES 模块)。

对于该软件包未涵盖的 ANS 记录或头像,请使用 AllDomains SDK,参见下方链接。

API 形式

两个端点,可根据所用框架进行调整:

路由请求正文成功未找到
POST /api/resolve-domain{ domain: "alice.skr" }{ address }404
POST /api/resolve-address{ address: "5FHw..." }{ domain }404

访问 RPC 前先验证输入:如果 base58 地址格式错误,或名称被 normalizeSkrName 拒绝,则返回 400,避免无效输入消耗 RPC 配额。

区分“未注册域名”(404)和“RPC 调用失败”(503)。将两者都折叠为 404,会让服务中断看起来像是每个用户都没有域名。

用于保护 RPC 密钥的代理不能成为面向该密钥的开放中继。反向路由最多会调用两次 getAccountInfo、一次 getProgramAccounts,并批量读取该地址拥有的所有名称,因此端点需要设置来源允许列表、每 IP 速率限制、请求正文大小限制,以及能够缓存否定结果的缓存。启动时必须要求提供 RPC URL 和来源列表,不要回退到公共端点或开放式 CORS。

完整的 Express 和 Hono 实现,以及有关 Fastify、NestJS、Koa 和 Next.js 路由处理程序的说明:references/server.md。

客户端集成

const { data: domain } = useResolveAddress(account?.address)
const label = domain ?? ellipsify(account?.address)

始终回退到截断后的地址。名称解析失败时,应降级为可用内容,绝不能显示为空白或永远无法消失的加载动画。

对于 Android 模拟器,localhost 指的是模拟器本身。请通过 http://10.0.2.2:3000 访问主机。在实体设备上,请使用主机的局域网 IP。将任一地址硬编码到源代码中会导致下一个使用者的应用出问题——请从 EXPO_PUBLIC_API_URL 读取,并通过 __DEV__ 控制任何模拟器回退逻辑:EXPO_PUBLIC_* 会在构建时内联,因此未经限制的默认值会将一个失效的明文 HTTP URL 打包进发布版 APK,而 Android 默认也会阻止这种连接。任何包含 RPC 密钥的内容都不应放进 EXPO_PUBLIC_* 变量——这正是设置代理的原因。

上面的代码片段假定使用代理。如果改为直接在应用中解析,安装 WebCrypto polyfill 后,该软件包便可在 Hermes 下运行——请在同一个 hook 中调用它来代替 fetch。

Hook、组件和截断辅助函数:references/client.md。

信任反向解析的名称

主名称由钱包持有者选择,而 getSkrDomains 返回的名称不是:.skr 转让不需要接收方进行任何操作,因此任何人都能把名称推送到任意钱包,陌生人可以通过发送一个排序靠前的名称,决定没有主名称的用户在你的 UI 中显示什么名称。

  • 优先使用 getPrimarySkrDomain,仅在显示时才回退到 getSkrDomains。
  • 将名称显示在截断后的地址旁边,而不要用名称取代地址。 用户真正能够核实的是地址。
  • 当标签代替身份标识时——例如收款人、交易对手或审核界面——只使用主名称,并在没有主名称时回退到地址。
按方向缓存
方向用途缓存
正向(名称 → 地址)付款目的地不缓存。发送时重新解析。
反向(地址 → 名称)显示标签较长的 staleTime;缓存一小时即可。

名称很少变更,因此缓存反向解析结果几乎没有代价。正向解析则不同:.skr 名称可以转让和重新注册,因此,缓存一小时的正向解析结果随后被用于构建转账时,款项会支付给一小时前拥有该名称的人,而 UI 看起来却一切正常。请在签名前立即重新解析,并在确认步骤中显示解析出的地址,让用户看到资金实际将转往何处。

这一点在两端都必须成立。如果代理使用自己的正向缓存作答,那么客户端即使在发送时重新解析也毫无意义,因此服务器只能缓存正向解析未命中的结果,绝不缓存已解析出的地址。

参考资料

相关技能

  • solana-mobile-wallet — 提供待解析地址的钱包连接
  • seeker-genesis-token — 验证 Seeker 所有权

链接

评论

支持 Markdown