frontend-apps について
現行の dApp Kit API を使った Sui フロントエンド dApp 開発向けのスキルです。React、Vue などの実装を案内し、非推奨 API からの移行やトランザクションでの注意点も扱います。
主な機能
- 01dApp Kit のセットアップと初期化
- 02React のウォレット接続と状態管理
- 03Vue、Svelte、Vanilla JS の実装パターン
- 04TanStack Query によるオンチェーン照会
- 05トランザクションの署名・実行・状態確認
- 06旧 API からの移行とコードレビュー
活用シーン
- 01新しい Sui React dApp の構築
- 02Vue や Svelte でのウォレット UI 実装
- 03残高の照会とトランザクションの送信
- 04古いチュートリアルの API を点検
MCP 対応
利用可能な場合、最新情報の検証や参考ファイルにない詳細の確認に Sui ドキュメント MCP サーバーを使います。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mystenlabs/ skills --skill frontend-appsインストール後、Claude Code で/frontend-appsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
limitations.mdnon-react.mdqueries.mdreact.mdsetup.mdtransactions.mdevals/code-evals.jsonevals.json詳細
Sui フロントエンド/dApp Kit
MCP ツール: 環境で利用できる場合は、最新の情報を得るために Sui ドキュメント MCP サーバー(
https://sui.mcp.kapa.ai)にも問い合わせてください。検証や、これらのリファレンスファイルに記載されていない詳細の確認に利用してください。
ブラウザー上の Sui アプリで問題が発生する原因は、次のようなものに集約されます。
- パッケージが間違っています。
@mysten/dapp-kit(サフィックスなし)は、JSON-RPC のみをサポートするレガシーパッケージで、非推奨です。新しいコードでは@mysten/dapp-kit-reactまたは@mysten/dapp-kit-coreを使用します。 - クライアントが間違っています。 dApp Kit では、
createDAppKitのcreateClientにSuiGrpcClient(推奨)を指定します。SuiJsonRpcClientは渡さないでください。JSON-RPC は非推奨です。 - プロバイダースタックが古いです。 コードで v1 のパターン、つまり
QueryClientProvider→SuiClientProvider→WalletProviderが使われていることがよくあります。この方式は廃止されています。新しいパターンは、createDAppKitファクトリーとDAppKitProvider(または React を使わない同等の方式)です。 - フックが廃止されています。
useSuiClientQuery、useSuiClientInfiniteQuery、useSignAndExecuteTransaction(ミューテーションフック)、useConnectWallet、useDisconnectWallet、useSuiClient、useSuiClientContextは削除されました。これらはuseCurrentClient/useCurrentNetwork/useDAppKit()(命令型メソッド)と、独自の TanStack Query ラッパーに置き換えられています。 - 実行後、再取得の前に
waitForTransactionを呼び出していません。 フルノードはトランザクションを非同期でインデックス化するため、signAndExecuteTransactionの直後に TanStack のキャッシュを無効化すると、古いデータが再取得されます。 - ウォレットに渡す前に、アプリのコードで
tx.build()を使って PTB を構築しています。 これではウォレットによるガス選択が機能しなくなります。必ずTransactionインスタンスをウォレットに渡してください。
このスキルのパターンはすべて、次の情報をもとにしています。
- https://sdk.mystenlabs.com/dapp-kit (ランディングページ)
- https://sdk.mystenlabs.com/dapp-kit/getting-started/react
- https://sdk.mystenlabs.com/dapp-kit/getting-started/next-js
- https://sdk.mystenlabs.com/dapp-kit/getting-started/vue
- https://docs.sui.io/standards/wallet-standard
API に不明な点があれば、該当するページから情報を取得してください。レガシーの @mysten/dapp-kit や v2 より前のフック API から推測してはいけません。古いチュートリアルが多数存在します。
リファレンスファイル
setup — インストール、ファクトリー、プロバイダー
パス: setup.md
読み込むタイミング: 新しい dApp プロジェクトを始めるとき、React/Next.js/Vue のセットアップを構成するとき、または従来の 3 つのプロバイダーを使うパターンから移行するとき。パッケージの選択、createDAppKit({ networks, createClient })、DAppKitProvider(React)、declare module による TypeScript の拡張を扱います。
react — React フックとパターン
パス: react.md
読み込むタイミング: React コンポーネントを作成するとき。現在のすべてのフック(useCurrentAccount、useCurrentWallet、useCurrentNetwork、useCurrentClient、useDAppKit、useWallets、useWalletConnection)、標準コンポーネント(ConnectButton)、ウォレット接続を条件とする UI の定型パターンを扱います。
non-react — Vue、バニラ JS、Web Components
パス: non-react.md
読み込むタイミング: Vue/Svelte/バニラ JS の dApp を構築するとき。@mysten/dapp-kit-core、nanostores のリアクティブな状態(dAppKit.stores.$connection など)、Web Components の登録、@nanostores/vue による Vue バインディングを扱います。
queries — TanStack Query のパターン
パス: queries.md
読み込むタイミング: dApp でオンチェーンデータ(残高、所有オブジェクト、コイン、動的フィールド、トランザクション)を取得するとき。useQuery と useCurrentClient の組み合わせ、ページ分割された結果に使う useInfiniteQuery、enabled によるガード、書き込み後のキャッシュ無効化を扱います。
transactions — 署名と実行
パス: transactions.md
読み込むタイミング: dApp からトランザクションを送信するとき。dAppKit.signAndExecuteTransaction、$kind に基づく結果の判別、signTransaction(ウォレットで署名するが実行はしないため、スポンサー付きフローに使用)、signPersonalMessage、waitForTransaction と invalidateQueries の手順、ウォレットの UX でよくある問題を扱います。
limitations — フロントエンドでできないこと、すべきでないこと
パス: limitations.md
読み込むタイミング: ブラウザー環境の境界を越えるような設計を検討している場合です。対象:バックエンド専用機能(ガスステーションの内部処理、バリデーターキー)、ブラウザー/SSR の注意点、自動接続の信頼性、「シークレットをブラウザーに置かない」というルール。
ルーティングガイド
| タスク | 読み込むファイル |
|---|---|
| React dApp をゼロから作成する | setup + react + queries + transactions |
| Vue/vanilla/Svelte dApp を新規作成する | setup + non-react |
| 「ウォレットを接続するには?」 | react(または non-react) |
| 「残高/所有オブジェクトをクエリするには?」 | queries |
| 「トランザクションを送信するには?」 | transactions +(PTB の構築には sui-sdks) |
| スポンサー付き tx のフロー | transactions(フロントエンド側)+ ptbs(PTB 側) |
@mysten/dapp-kit(サフィックスなし)からの移行 | setup + limitations + 必要に応じてすべて |
| tx の後に UI が古いままなのはなぜ? | transactions + queries |
| SSR/Next.js への対応 | setup + limitations |
| dApp のコードレビュー全般 | すべてのリファレンスファイル + 以下のコードレビュー用チェックリスト |
| 「このコードをレビューして」/「このスニペットの問題点は?」 | 以下のコードレビュー用チェックリスト + 関連するリファレンスファイル |
スキルの内容
主な概念
- 2 つのパッケージ、1 つの API。
@mysten/dapp-kit-reactは@mysten/dapp-kit-coreをラップしています。createDAppKitは両方にあります。アクション(signAndExecuteTransaction、signTransaction、switchNetwork、connectWallet、disconnectWallet)は同一です。異なるのはリアクティブな状態の読み取り方法です。React ではフックを使い、non-React では nanostores のストアを読み取ります。 - 1 つのインスタンスで複数のネットワークに対応。
createDAppKit({ networks: [...], createClient })は、複数のネットワークに対応する dApp Kit インスタンスを 1 つ作成します。dAppKit.switchNetwork(name)でアクティブなネットワークを切り替えます。createClientファクトリーはネットワークごとに遅延呼び出しされます。 - デフォルトは gRPC。 新しい dApp Kit は
SuiGrpcClient向けに構築されています。JSON-RPC は非推奨です。createClientではSuiGrpcClientを使用してください。 - ウォレットはブラウザー専用です。 ウォレットの検出には
window.navigator.walletsと CustomEvents を使用します。ウォレットの状態を扱うコンポーネントは、クライアント側でレンダリングする必要があります。Next.js/SSR フレームワークでは、ウォレットを扱うコンポーネントに'use client'を指定します。 - ガスはウォレットが管理します。 アプリは
Transactionを構築し、ウォレットに渡します。ウォレットがガスコインを選択し(ドライランを通じて)予算を設定して、署名します。スポンサー付きフローの場合を除き、tx.build()を呼び出してバイト列を渡してはいけません。詳しくはtransactions.mdを参照してください。 - フルノードのデータ反映には時間がかかります。
signAndExecuteTransactionは、データをクエリできるようになる前にダイジェストを返します。再取得する前に、必ずwaitForTransactionを実行してください。
ルール
- 新しいコードでは
@mysten/dapp-kit-reactまたは@mysten/dapp-kit-coreを使用してください — 以前の@mysten/dapp-kitは使用しないでください。このパッケージは JSON-RPC 専用であり、非推奨です。 createClientではSuiGrpcClientを使用してください。SuiClientは使用しないでください —SuiClientは v2 で削除されています。@mysten/sui/grpcのSuiGrpcClientを使用してください。createDAppKit+DAppKitProviderを使用してください。 3 つのプロバイダーを組み合わせる構成(QueryClientProvider+SuiClientProvider+WalletProvider)は使用しないでください。データ取得に TanStack Query を使用する場合は、引き続きQueryClientProviderでラップしますが、dApp Kit 自体には必要ありません。declare moduleの TypeScript 拡張を含めてください。 これにより、インスタンスを手動で渡さなくてもフックで適切な型が使用されます。- 削除されたフックは使用しないでください。
useSuiClientQuery/useSuiClientInfiniteQuery/useSuiClientContext/useSuiClient/useSignAndExecuteTransaction(ミューテーションフック) /useConnectWallet/useDisconnectWalletは削除されています。代わりに、useCurrentClient+useQuery/useInfiniteQuery+useDAppKit()の命令型メソッドを使用してください。 - 現在のアカウントが
nullかどうか確認してください。useCurrentAccount()は接続前にnullを返します。常にif (!account) returnを使用するか、クエリでenabled: !!accountを指定してください。 - キャッシュを無効化する前に
waitForTransactionを実行してください。await client.waitForTransaction({ digest: result.Transaction.digest })を実行してからqueryClient.invalidateQueries(...)を呼び出してください。順序を逆にすると、古いデータが取得されます。 await tx.build(...)のバイト列ではなく、Transactionインスタンスをウォレットに渡してください。 ガスの選択はウォレットに任せる必要があります。例外は、tx.build({ client, onlyTransactionKind: true })を使用するスポンサー付きフローです —ptbsスキルを参照してください。result.$kind === 'FailedTransaction'(またはresult.FailedTransaction)を確認してください。 成功を前提にしないでください。v1 のresult.effects?.status?.statusは使用しないでください。- ウォレットで制御する UI はクライアント側でレンダリングしてください。 クライアント側のガードなしで SSR を行うと、ウォレットを検出できる前にウォレットボタンがレンダリングされます。
'use client'/ 動的インポート / effect ベースのハイドレーションを使用してください。 - Vue:
useStoreは Vue の ref を返します — スクリプト内のコードでは.valueを使用してください。const connection = useStore(dAppKit.stores.$connection)は ref を返します。<script setup>ではconnection.value.accountとして状態にアクセスしてください。Vue はテンプレート内の ref を自動的にアンラップしますが、スクリプトの例では常に.valueのパターンを示してください。
コードレビューのチェックリスト
ユーザーからコードスニペットのレビューを依頼されたら、最初に見つけた2~3件の問題だけで終わらせないでください。このチェックリストを明示的に確認し、該当する項目をすべて指摘してください。Browser Sui のコードは、v1 のチュートリアルからコピーされたものが多く、1つのコンポーネントに通常5~10件の問題が重なっています。
インポート/パッケージ
@mysten/sui.js(どこで使われていても)— 凍結された v1 パッケージです。@mysten/suiに置き換えてください。@mysten/dapp-kit(サフィックスなし)— 非推奨の JSON-RPC 専用パッケージです。@mysten/dapp-kit-react(React)または@mysten/dapp-kit-core(その他のフレームワーク)に置き換えてください。import { ConnectButton } from '@mysten/dapp-kit-react'— パスが間違っています。ConnectButtonとConnectModalは@mysten/dapp-kit-react/uiからエクスポートされています。間違ったパスを使うと、何も表示されない白い画面になります。import { SuiClient }—SuiClientは v2 で削除されました。@mysten/sui/grpcのSuiGrpcClient(またはコンポーネント内のuseCurrentClient())を使ってください。import { TransactionBlock }— v2 ではTransactionに改名されました。
削除されたフック(いずれかがあればバグ)
useSuiClientQuery、useSuiClientInfiniteQuery、useSuiClientContext、useSuiClient—useCurrentClient()と TanStack のuseQuery/useInfiniteQueryに置き換えてください。useSignAndExecuteTransaction(ミューテーションフック)— イベントハンドラー内で命令的に呼び出すuseDAppKit().signAndExecuteTransaction(...)に置き換えてください。useConnectWallet、useDisconnectWallet—useDAppKit().connectWallet()/disconnectWallet()に置き換えてください。
プロバイダースタック
SuiClientProvider+WalletProvider(v1 の3プロバイダースタック)—createDAppKit(...)+<DAppKitProvider>に置き換えてください。TanStack のQueryClientProviderは引き続き使用できます。
コンポーネント内でのクライアント構築
- コンポーネント本体内の
new SuiClient(...)/new SuiGrpcClient(...)— ネットワークの切り替えに対応できず、レンダーのたびにクライアントを作り直します。useCurrentClient()を使ってください。 - 接続済みウォレットが必要なクエリで
enabled: !!accountが指定されていない — owner が未定義のまま実行され、エラーになります。
トランザクションの構築
tx.pure(value)(型指定なし)— Move の型に合った型付きヘルパーに置き換えてください:tx.pure.u64(n)、tx.pure.address(addr)、tx.pure.string(s)など。- ウォレットに渡す前の
tx.build()— ウォレットによるガス選択を無効にしてしまいます。Transactionインスタンスをそのまま渡してください。
実行/待機/ステータス
signAndExecuteTransactionBlock(...)(v1 のメソッド)—signAndExecuteTransaction(...)に置き換えてください。{ transactionBlock: tx }というパラメーター形式 —{ transaction: tx }に置き換えてください。result.effects?.status?.status === 'success'— v1 の形式です。result.$kind !== 'FailedTransaction'に置き換えるか、result.FailedTransactionを確認してください。result.digestへの直接アクセス — 成功時のダイジェストはresult.Transaction.digestにあります。失敗時にはダイジェストはありません。- 実行直後のキャッシュ無効化 — まず
await client.waitForTransaction({ digest })を実行してから、queryClient.invalidateQueries(...)を実行する必要があります。
SSR/Next.js
'use client'のない、ウォレット対応コンポーネント — ウォレットの検出にはブラウザー専用 API が使われます。
チェックリストを確認したら、見つかった個別の問題の数を数えてください。古いチュートリアルから取得した一般的な複数行のスニペットで5件未満の場合は、スニペットをもう一度確認してください。見落としがある可能性が非常に高いです。
よくある間違い
- 接続済みのウォレットが必要なクエリで、
enabled: !!accountを指定せずに@tanstack/react-queryのuseQueryを使うことです。owner が未定義の状態でクエリが実行され、エラーになります。 - React-Query の
queryFnからTransactionを返すことです。トランザクションはクエリではありません。useDAppKit()を使って、ミューテーションまたはイベントハンドラー内で使用してください。 dAppKit.signAndExecuteTransaction({ transactionBlock: tx })とすることです。新しい API では{ transaction: tx }です。result.digestを直接読み取ることです。成功時の digest はresult.Transaction.digestにあります。失敗時は digest がないため、まずresult.FailedTransactionを確認してください。waitForTransactionの前にクエリを無効化することです。これは典型的な UI の古い状態を引き起こすバグです。必ず先に待機してください。- コンポーネント内で
new SuiGrpcClient(...)を呼び出すことです。ネットワーク切り替えが機能しなくなります。useCurrentClient()を使用してください。 SuinsClient/DeepBookClientを直接インスタンス化することです。createClientから返されたクライアントで、client.$extend(suins(), deepbook({ address }))を使用してください。- わかりにくい UX のまま
autoConnect: trueにしておくことです。自動再接続は、読み込み時に最後に使用したウォレットを復元します。アプリで権限や nonce を扱う場合は、この復元が非同期であることを考慮してください(保留中/再接続中の状態)。 - testnet/mainnet の URL を複数箇所にハードコードすることです。ネットワーク名をキーとする単一の
GRPC_URLSマップにまとめ、createClientから参照してください。 - wallet-standard API を直接使用することです。dApp Kit は wallet standard をラップしています。自分で
window.navigator.walletsを呼び出さず、useWallets()/dAppKit.stores.$walletsを使用してください。 - 秘密鍵やシークレットをブラウザーに保存することです。絶対にしないでください。dApp はウォレット経由で署名し、バックエンドで鍵を保持します。