seeker-domains について
Solana Mobile アプリで `.skr` ドメインを解決するスキルです。`@solana-mobile/skr-domain` による名前とウォレットアドレスの双方向検索に加え、クライアントとバックエンドの選択、キャッシュ、入力検証、表示上の注意点を案内します。
主な機能
- 01`.skr` 名とアドレスの双方向検索
- 02メインネット検索と期限切れ処理
- 03クライアントとバックエンドプロキシの構成
- 04入力検証とエラー分類
- 05逆引きのキャッシュと信頼性に関する指針
活用シーン
- 01ウォレットアドレスを`.skr`名で表示
- 02`.skr`名を支払い先アドレスに解決
- 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 で省略表示されたアドレスの代わりに使うのに適しています。
解決には 2 つの方向があります。
- 順方向 —
alice.skrからウォレットアドレスへ - 逆方向 — ウォレットアドレスから
.skr名へ。プライマリ名があればそれを、なければ所有している名前を返します
どちらも、アプリの他の部分がどのクラスターを対象にしているかにかかわらず、メインネット上で解決されます。devnet 上のアプリでも、名前はメインネットに対して解決されます。
解決を実行する場所を決める
解決には公開されているオンチェーンデータを読み取るため、クライアントから直接実行できます。次のような場合はバックエンド経由にしてください。
- RPC キーの保護。
EXPO_PUBLIC_*に含まれるキーは、APK を持つ人なら誰でも読み取れます。有料 RPC を使う場合、キーはサーバー側に置く必要があります。 - キャッシュの共有。 名前が変更されることはまれです。各クライアントが同じアドレスを何度も解決するより、サーバー側のキャッシュを 1 つ用意するほうが効率的です。
- 一括検索。 友人リスト全体を 1 回のリクエストで解決するほうが、スマートフォンから N 回往復するより効率的です。
getProgramAccountsへのアクセス。 逆引きにはこのメソッドが必要ですが、多くのプロバイダーが無効化しているか、厳しくレート制限しています。ユーザーのデバイスで制限に気づくより、確認済みのプロバイダーに対してサーバー側のエンドポイントを 1 つ用意するほうが確実です。
プロトタイプやトラフィックの少ないアプリなら、公開 RPC に対してクライアント側で直接解決しても問題ありません。公開エンドポイントにはレート制限があるため、数十件のアドレスを解決するリスト表示には耐えられません。
プロジェクトからどちらが適切か明らかでない場合は、ユーザーに確認してください。本番環境を想定したものには、プロキシ方式をデフォルトとして使ってください。
既存のバックエンドとの統合
新しいサーバーを書く前に、既存の構成を確認してください。 誰かの NestJS サービスの隣に Express アプリを追加すると、保守が難しくなります。
- すべての
package.jsonでバックエンドの依存関係(express、fastify、hono、@nestjs/core、koa、または API ルートを持つ Next.js アプリ)を探します。 - エントリーポイントを探します。
server.ts、app.ts、main.ts、index.tsなどです。 - ルートの構成を探します。
routes/、api/、controllers/などです。 - まだ判断がつかない場合は確認します。「
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 のクォータを消費する前に、不正な入力を 400 に変換できるよう、try/catch内で呼び出してください。 - 期限切れの名前は、猶予期間なしで、どちらの方向でも未登録として解決されます。
getPrimarySkrDomainは所有権を再確認します。MainDomainアカウントは譲渡時に更新されないため、このパッケージは名前を逆方向に解決し、ウォレットが現在も所有している場合にのみ返します。getSkrDomainsはgetProgramAccountsを使用します。 多くのプロバイダーはこれを無効化またはレート制限しています。この関数はラベルを 100 件ずつ、一度に 1 リクエストで読み取るため、名前を大量に持つウォレットがクォータに対するリクエストの集中を引き起こすことはありません。- NFT でラップされた名前は対象外です。 現在
.skrには存在せず、存在した場合、resolveSkrDomainは例外を投げます。
React Native には WebCrypto ポリフィルが必要です。 名前アドレスの導出では crypto.subtle.digest を呼び出しますが、Hermes にはこれがありません。react-native-quick-crypto をインストールし、パッケージをインポートする前に、起動時にその install() を呼び出してください。Node 20.18 以降、Bun、ブラウザーでは何も必要ありません。
このパッケージは ESM のみです。 CommonJS サーバーでは "type": "module" が必要です(または、ES モジュールを require() できる Node 22.12 以降を使用してください)。
パッケージが対応していない ANS レコードやアバターには、AllDomains SDK を使用してください。以下のリンクを参照してください。
API の形式
使用中のフレームワークに合わせた 2 つのエンドポイントです。
| ルート | ボディ | 成功時 | 見つからない場合 |
|---|---|---|---|
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 キーを保護するためのプロキシが、それを介したオープンリレーになってはいけません。逆方向のルートでは最大 2 回の getAccountInfo 呼び出し、1 回の getProgramAccounts 呼び出し、およびそのアドレスが所有するすべての名前の一括読み取りが発生します。そのため、エンドポイントにはオリジンの許可リスト、IP ごとのレート制限、ボディサイズ制限、否定的な結果も保存するキャッシュが必要です。パブリックエンドポイントやオープン CORS にフォールバックするのではなく、起動時に RPC URL とオリジンリストを必須にしてください。
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 でアクセスしてください。実機ではホストの LAN IP を使います。これらのいずれかをソースにハードコードすると、次に使う人の環境でアプリが動かなくなります。EXPO_PUBLIC_API_URL から読み込み、エミュレーター向けのフォールバックは __DEV__ で制御してください。EXPO_PUBLIC_* はビルド時にインライン化されるため、条件を付けずにデフォルト値を設定すると、リリース APK に機能しないクリアテキスト URL が含まれます。Android はそもそもデフォルトでこれをブロックします。RPC キーを含む情報は、いかなる場合も EXPO_PUBLIC_* 変数に入れてはいけません。そのためにプロキシがあります。
上記のスニペットはプロキシを前提としています。アプリから直接解決する場合は、WebCrypto ポリフィルをインストールすれば、このパッケージは Hermes 上で動作します。fetch の代わりに、同じフックから呼び出してください。
フック、コンポーネント、省略表示用ヘルパーについては、references/client.md を参照してください。
逆引きした名前を信頼する際の注意
プライマリ名はウォレットが選んだ名前です。getSkrDomains から取得した名前はそうではありません。.skr の譲渡には受取人からの操作が不要なため、誰でも任意のウォレットに名前を割り当てられます。また、プライマリ名を持たないユーザーについて、ソート順が早い名前を送ることで、見知らぬ人が UI 上の表示名を決められてしまいます。
getPrimarySkrDomainを優先し、getSkrDomainsは表示用途に限ってフォールバックとして使ってください。- 名前は省略表示したアドレスの代わりではなく、横に表示してください。 ユーザー自身が確認できるのはアドレスです。
- ラベルが本人確認の代わりになる場面 — 支払先、取引相手、モデレーション画面など — では、プライマリ名のみを使い、取得できない場合はアドレスにフォールバックしてください。
方向別のキャッシュ
| 方向 | 対象 | キャッシュ |
|---|---|---|
| 順引き(名前 → アドレス) | 支払い先 | なし。送信時に再解決します。 |
| 逆引き(アドレス → 名前) | 表示ラベル | staleTime を長く設定します。1 時間で問題ありません。 |
名前が変わることはまれなので、逆引き結果のキャッシュはほぼコストがかかりません。順引き結果は異なります。.skr 名は譲渡や再登録が可能なため、1 時間キャッシュした順引き結果を使って送金を作成すると、UI 上は何もおかしく見えないまま、1 時間前にその名前を所有していた人に支払うことになります。署名の直前に再解決し、実際の送金先をユーザーが確認できるよう、確認手順に解決後のアドレスを表示してください。
これはクライアントとサーバーの両方で守る必要があります。送信時に再解決するクライアントでも、プロキシが独自の順引きキャッシュから応答すると意味がありません。そのため、サーバーがキャッシュするのは順引きの未検出結果のみとし、解決済みのアドレスは決してキャッシュしないでください。
参考資料
- references/server.md — Express および Hono の実装、その他のフレームワーク、バリデーション、エラー処理
- references/client.md — 解決フック、表示コンポーネント、エミュレーターのネットワーク設定
関連スキル
solana-mobile-wallet— 解決対象のアドレスを提供するウォレット接続seeker-genesis-token— Seeker の所有権を検証
リンク
@solana-mobile/skr-domain:https://www.npmjs.com/package/@solana-mobile/skr-domain@solana-mobile/skr-domainのソースと README:https://github.com/solana-mobile/skr-js/tree/main/packages/skr-domain- AllDomains 開発者ガイド:https://docs.alldomains.id/protocol/developer-guide/ad-sdks/svm-sdks/solana-mainnet-sdk
@solana/kit:https://www.npmjs.com/package/@solana/kit