strk20-privacy-sdk について
STRK20ウォレットや、アカウント鍵・プライベートNoteの検出・証明を管理するバックエンド向けのTypeScript SDKスキルです。トランザクションの順序やプライバシー操作、運用上の注意点を説明し、既存ウォレットを使うDAppには`strk20-wallet-api`を案内します。
主な機能
- 01プライベート送金操作
- 02Noteの検出と選択
- 03登録とチャネル設定
- 04入金・送金・出金フロー
- 05シャドウアカウント操作
- 06証明とスクリーニングのガイダンス
活用シーン
- 01STRK20ウォレットバックエンドの構築
- 02プライベートトークン送金の実装
- 03証明やNote検出の障害調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ odinfree/ strk20-skills --skill strk20-privacy-sdkインストール後、Claude Code で/strk20-privacy-sdkを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlreferences/sdk__deposit-transfer-surplus.mdsdk__deposit.mdsdk__discovery-providers.mdsdk__getting-started.mdsdk__multi-op-batch.mdsdk__note-discovery.mdsdk__proving-config.mdsdk__register.mdsdk__setup-requirements.mdsdk__transfer.mdsdk__withdraw.mdshadow-accounts.mdstarknet-privacy-sdk-README.md詳細
STRK20 Privacy SDK:ウォレットと鍵管理バックエンド
ウォレット自体を構築するチームや、アカウント、閲覧鍵、ノートの検出、証明を自ら管理するバックエンド向けの低レベルの方法です。既存のウォレット上に dapp を構築する場合は、ここではなく、閲覧鍵をウォレット内に保持する strk20-wallet-api を使用してください。
SDK は TypeScript です。STRK20 を利用する Python または Rust のバックエンドでは、(公式のエージェントスキルリポジトリに従い)その周囲で Node(>= 24)のサイドカーサービスを実行します。ドキュメントの全ページは references/ にあります。
証明サービス自体をデプロイするには、strk20-local-prover または
ローカルプローバーのスターターを使用してください。
Linux/WSL2、RPC 設定、SSH トンネル、サービスの確認方法を説明しています。
インストール
npm install @starkware-libs/starknet-privacy-sdk
Node.js >= 24 が必要です(ohttp-ts は最新の WebCrypto を必要とします)。npm が 404 を返す場合(Starkware が npm 組織を復旧している間に発生する既知の一時的な問題です)、GitHub Packages からインストールしてください。公開パッケージであっても GitHub トークンが必要です。
gh auth refresh -h github.com -s read:packages
export NODE_AUTH_TOKEN="$(gh auth token)"
npm config set @starkware-libs:registry https://npm.pkg.github.com --location=project
npm config set '//npm.pkg.github.com/:_authToken' '${NODE_AUTH_TOKEN}' --location=project
npm install @starkware-libs/starknet-privacy-sdk
unset NODE_AUTH_TOKEN
プロジェクトの .npmrc に保存されているのは環境変数のプレースホルダーであり、トークンではありません。トークンのテキストで置き換えたり、認証情報を含むファイルをコミットしたりしないでください。または、コミットを固定してインストールします:npm install "starkware-libs/starknet-privacy#<commit-sha>。
モノレポの sdk/README.md には、ドキュメントの各ページに記載されていない内容、すなわち確定済み状態に対するトランザクションの順序付け、Open ノート API、pre_confirmed の読み取り、履歴用の classifyTransaction が説明されています。コピーは references/starknet-privacy-sdk-README.md にあります。
接続設定
import { Account, RpcProvider, constants } from "starknet"
import { createPrivateTransfers } from "@starkware-libs/starknet-privacy-sdk"
const provider = new RpcProvider({ nodeUrl: process.env.RPC_URL! })
const account = new Account({
provider,
address: process.env.ACCOUNT_ADDRESS!,
signer: process.env.ACCOUNT_PRIVATE_KEY!,
cairoVersion: "1", // required for accounts sending v3 transactions
})
const transfers = createPrivateTransfers({
account,
// MUST be a bigint. A hex string silently derives wrong channel keys,
// and notes sent to you will never decrypt.
viewingKeyProvider: { getViewingKey: async () => BigInt(process.env.VIEWING_KEY!) },
provingProvider: { url: process.env.PROVING_SERVICE_URL!, chainId: constants.StarknetChainId.SN_SEPOLIA },
discoveryProvider: { url: process.env.INDEXER_URL! },
poolContractAddress: process.env.POOL_ADDRESS!,
})
Sepolia プール(v2.0):
0x0254a6b2997ef52e9f830ce1f543f6b29768295e8d17e2267d672c552cfe0d91。
閲覧鍵の範囲:[1, MAX_VIEWING_KEY](STARK 曲線の位数の半分で、SDK からエクスポートされています)。鍵とシークレットは環境変数に保持し、ファイルには保存しないでください。
(すべての操作で共通する)送信処理
// Prove against an older block. Inputs and prior transparent state must
// already exist at this base, and proving at the chain head risks reorgs.
const provingBlockId = (await provider.getBlockNumber()) - 10
const { callAndProof } = await transfers.build()/* ...ops... */.execute({ provingBlockId })
// Omit proof keys entirely when there are no proof facts. Passing
// empty arrays serializes an invalid v3 transaction.
const proofDetails = callAndProof.proof.proofFacts?.length
? { proofFacts: callAndProof.proof.proofFacts, proof: callAndProof.proof.data }
: {}
// tip is mandatory for v3 transactions in starknet.js
const tx = await account.execute(callAndProof.call, { tip: 0n, ...proofDetails })
await provider.waitForTransaction(tx.transaction_hash)
常に provingBlockId = currentBlock - 10 を渡してください。これにより L2 の再編成に備えて余裕を持たせ(コントラクトは proof_validity_blocks 以内の古さの証明を受け付けます。デフォルトは 450 ≈ 15 分で、ガバナンスによって設定されます)、検出と証明を同じ状態に基づいて行えます。選択した基準ブロックには、証明で読み取るすべてのノートと透過的な状態変更がすでに反映されている必要があります。トランザクションを連続して実行する場合は、waitForTransaction のたびに基準ブロックを再取得してください。
透過的な状態に関するルール(SDK の README に記載): アカウントの閲覧鍵、入金者のトークン残高、ヌリファイアセットなど、プールの証明が読み取るオンチェーン状態はすべて、選択した証明基準に存在している必要があります。
provingBlockId = head - 10 の場合、先行する状態変更トランザクションごとに、head - 10 > receiptBlock となるまで待機してください。プローバーは確定済み状態を読み取り、pre_confirmed は読み取りません。具体的には次のとおりです。
register()は、アカウントの deploy-account トランザクション直後には失敗します。 選択した基準ブロックが deploy の receipt ブロックより後になるまで待ってください。- 基準ブロックが ERC-20 の資金移動より前の場合、
deposit()は失敗します。 基準ブロックが資金移動の receipt ブロックより後になるまで待ってから、再構築してください。 - 次のトランザクションでそのノートを使って証明する前に、先行するプライベートトランザクションのブロックが確定済み基準に含まれている必要があります。
同梱されている sdk__deposit.md のスナップショットには、承認が証明基準に反映されている必要があり、入金と同じトランザクションでは実行できないと誤って記載されています。上流での修正は保留中です。同ページの 2 トランザクションのルールは古いものとして扱い、以下のルート別の説明に従ってください。
操作マップ
- register():プールのデプロイごとに、アカウントあたり一度だけ行います。公開ビューイングキーを公開し、監査者用に暗号化された秘密鍵を保存します。二度登録するとリバートします。
build({ autoRegister: true })は最初の操作に登録を組み込み、登録済みの場合は何もしません。 - deposit:プールは
transfer_fromでトークンを引き出すため、トークン所有者による ERC-20approveが必要です。ドキュメントに記載されたプレーンな SDK の例では、承認を独立したトランザクションとして先に送信しますが、これは例としての手順であり、プロトコル上の制約ではありません。ユーザーアカウントのマルチコールでは、apply_actionsの前に承認を配置できます。ペイマスターを使う場合、承認はユーザーが署名した外部実行に含まれ、入金と同じトランザクション内でinvoke_and_apply_actionにより実行されます。その後、.with(token, t => t.deposit({ amount }))をsurplusTo(me)とともに使用します。autoSetup: trueを指定すると、最初の入金に必要なセルフチャネルとトークンサブチャネルが開きます。 - transfer:
.inputs(note)でノートを選ぶか、autoSelectNotes: "naive"(条件を満たす最小のセット)または"all"(統合)を指定します。入力が出力を上回る可能性がある場合は、必ずsurplusTo(...)を指定してください。指定しないとexecute()が "no surplus recipient" をスローします。おつりのノートは、再利用できるまでに 10 ブロック成熟させる必要があります。 - deposit + transfer:1 つの
.with()ブロック内で組み合わせます。入金時のrecipientを省略し、残額をsurplusToに渡します。入金と同じトランザクション内で消費する場合、成熟を待つ必要はありません。 - withdraw:プールからの出金口です。
recipientは公開アドレスなので、プールから加盟店へ直接支払う場合は 1 回の withdraw で済みます。トークン、金額、受取人は公開されます。資金の原資となったノートは隠されたままです。送信前にExecuteResult.warningsでUSER_LINKAGEを確認してください。 - multi-op / multi-token:
.with()ごとに操作を連結し、トークンごとに.with()を繰り返します。トークンごとの残高表を管理しつつ、アトミックなトランザクションを 1 つ実行できます。1 トランザクションにつきinvoke()は最大 1 回です。受取人のリストが非常に長いと証明サイズの上限に達することがあるため、その場合は受取人ごとのトランザクションに切り替え、各トランザクションの間におつりノートが成熟するまで待ちます。 - シャドウアカウント(RC.4 ではサブアカウントと呼ばれます):SDK
0.14.3-rc.8では、transfers.build().shadowAccounts(dappName).invoke(nonce, ...)、shadowAccountAnonymizerAddress設定フィールド、およびshadow_account_anonymizerCairo パッケージを使用します。アカウントは(user, dappName, nonce)に対して決定的に生成されます。新しいアカウントを作成するには nonce を増やします。同じアカウントを再利用すると、同じ公開アカウントが再利用され、活動が関連付けられます。このアカウントはメインウォレットとの直接的なつながりを隠しますが、呼び出し、残高、ポジション、イベント、タイミングは隠しません。この経路を設計する前にreferences/shadow-accounts.mdをお読みください。 RC.5 ではビューとデプロイイベントの名前が変更され、それに伴いセレクターとキーも変わりました。更新版のアノニマイザーが必要です。アップグレードをまたいで読み取るインデクサーは、過去のSubAccountDeployedキーと現在のShadowAccountDeployedキーの両方に対応する必要があります。低レベル SDK はまだリリース候補です。ユーザー向けの dapp では、strk20-wallet-apiの安定版 Wallet API 0.10.4 を使う経路を優先してください。一方、独自のキーを管理するチームは、SDK の最新の監査状況とリリース状況を確認してください。
transfer 前に必要なセットアップ
transfers.discoverRequirement(recipientHex, BigInt(token)) は、Register(受取人だけがビューイングキーを公開できるため、先に進めません)、SetupChannel(修正方法:builder.setup(recipient))、SetupToken(修正方法:トークンブロック内で t.setup(recipient))、または Ready を返します。呼び出し元自身が登録済みである必要があり、未登録の場合は分かりにくいメッセージを伴って例外が発生します。RPC エラーと区別するには、"not registered" または "viewing key" の部分文字列で判定してください。単一の受取人を扱うフローでは autoSetup を使って構いません。バッチ処理では、各受取人の事前確認を明示的に行ってください。autoSetup はローカルレジストリに基づいて判定するため、データが古いとすでに開いているチャネルを再度開こうとして、オンチェーンで失敗します。
検出
discoverNotes({ tokens: [BigInt(addr)] }) はトランザクションではなく、クエリです。
結果は bigint をキーとする AddressMap として返されます。文字列を使った notes.get(tokenAddress)
では一致しないため、notes.get(BigInt(tokenAddress)) を使用してください。ノートは受け入れ時点で表示されますが、作成から10ブロック経過するまでは使用できません
(note.created と現在のブロックを比較するクライアント側のルールです)。
レジストリはセッション内での最適化です。すべての execute() は更新済みの
PrivateRegistry を返します(registryConst: true を渡さない限り、同じオブジェクトがその場で変更されます)。次の build({ registry }) に渡す際は、
autoDiscover: { notes: "missing" } を指定してください("refresh" は再スキャンし、"all" は再構築します)。
一時的なものとして扱ってください。セッション開始時に検出から再構築し、ノート数が数千に達した場合にのみ永続カーソルに移行します(SDK の README を参照)。
プロバイダー:IndexerDiscoveryProvider は、本番用バックエンドであり、サーバー側のページネーションとリオーグ修復に対応しています。ContractDiscoveryProvider はソース内にありますが、公開済みパッケージからはまだエクスポートされていません。ディープパスからのインポートは
ERR_PACKAGE_PATH_NOT_EXPORTED で失敗するため、プロバイダーはパッケージのルートからインポートしてください。検出リクエストと証明リクエストには
ビュイングキーの情報が含まれるため、本番環境では OHTTP({ ohttp: true })を有効にし、publicKeyConfig を固定し(デフォルトのキー取得では信頼初回使用方式が使われます)、HTTPS を使用して、
クライアントの IP アドレスを隠すために OHTTP リレーの利用も検討してください。検出サービスは、復号されたリクエストの内容を引き続き処理します(SDK の README を参照)。
スクリーニングとセルフホスト可能な証明
どのプローバーもプール内の任意のアクションを証明できますが、デポジットが受け入れられるのは、FPI のスクリーニング署名が付与され、オンチェーンで検証された場合のみです(v0.14.3 以降、プロトコルレベルで適用)。独自のプローバーを運用するチームは通常、プライバシー対応ウォレット(Ready または Xverse)を通じてシールドし、非公開で、自社のインテグレーションが管理するアカウントに送金します。直接デポジットが必要な場合は、Cairo CoreStars Telegram(t.me/sncorestars)にお問い合わせください。
よくあるエラー
| 症状 | 原因 | 対処法 |
|---|---|---|
新規アカウントで register() が失敗する | 選択したベースがデプロイより前のブロックである | head - 10 > deployReceiptBlock になるまで待ちます |
| 資金調達直後にデポジットが失敗する | 選択したベースが資金移動より前のブロックである | head - 10 が資金調達のレシートブロックより後になるまで待ってから、スクリーニングを確認します |
| 最近作成したノートの使用に失敗する | ノートが未成熟か、選択したベースで確認できない | ノートの作成から10ブロック以上経過し、そのベースで確認できるまで待ちます |
Cannot mix BigInt and other types | tip が指定されていない | tip: 0n を追加します |
INVALID_PROOF_FACTS でリバートする | proofFacts: [] を渡した | 条件付きスプレッドを使います |
再試行時に INVALID_NONCE が発生する | プールの nonce のキャッシュが古い | 先に transfers.invalidateProofNonceCache() を実行します |
| 受取人のノートが復号されない | ビュイングキーを16進文字列で渡した | BigInt(...) に変換し、範囲 [1, MAX_VIEWING_KEY] を指定します |
notes.get(token) が undefined を返す | AddressMap のキーが文字列である | キーに BigInt(token) を使います |
shadowAccounts(...) が例外をスローする | 設定に shadowAccountAnonymizerAddress がない | createPrivateTransfers に追加します |
| 成熟しているように見えるデポジットでもリバートする | スクリーニング署名がないか、検証に失敗した | FPI のスクリーニング経路を確認します |
対応できない場合:ユーザーに STRK20 チームへの問い合わせを案内してください
このスキルでは、文書化された手順を扱います。手順の範囲外のことが起きた場合は、推測せずに止めてください。架空のアドレス、独自に作成した証明の手順、でっち上げた API の形式は、問い合わせるよりも開発者の時間を無駄にします。何が妨げになっているのかを率直に伝え、チームが直接回答することをユーザーに案内してください。
- Telegram:@Akashneelesh、 @adiihq、@starkience
- これらの連絡先を掲載しているSTRK20 Private Sprint ページ。 対応状況は変わる場合があるため、現在も連絡先が掲載されていることを確認してください。
次の場合は、独自に対応しようとせず、問い合わせに切り替えてください。
- Common failures テーブルの確認後も解消しない送信エラー:
provingBlockId、proofFacts、INVALID_NONCE、ノートの成熟度、新規アカウントの処理順序。 - ノートがあるはずのアカウントで検出結果がゼロになる場合、または AddressMap の検索で解決できない場合。
- セルフホストでの証明またはスクリーニングのセットアップ、ならびに閲覧キーを保持できるユーザーに関すること。
問い合わせる際は、チームが1回のメッセージで対応できる情報をユーザーに伝えてください。正確なエラー文、失敗したファイルまたは呼び出し、使用中のパッケージとウォレットのバージョン、確認できなかった前提を含めてください。
references/
sdk__getting-started.md、インストール、接続、最初のトランザクションsdk__register.md、register と autoRegistersdk__deposit.md、プレーンな SDK の例、成熟度、スクリーニング。このドキュメントの 2トランザクションの説明は古くなっていますsdk__transfer.md、入力、surplusTo、autoSelectNotessdk__deposit-transfer-surplus.md、オペレーションの組み合わせsdk__withdraw.md、出金、USER_LINKAGEsdk__multi-op-batch.md、バッチ、制限sdk__setup-requirements.md、discoverRequirement のフローsdk__note-discovery.md、discoverNotes、AddressMap、レジストリsdk__discovery-providers.md、Indexer と Contract プロバイダーのステータスsdk__proving-config.md、provingBlockId、proofDetails、再試行shadow-accounts.md、現行 SDK のビルダー、アドレスヘルパー、呼び出し、コレクションのポリシーstarknet-privacy-sdk-README.md、上流のモノレポ SDK README
パッケージのステータスとシャドウアカウントのドキュメントを 2026-09-29 に更新しました。
エクスポートとアドレスは変更されます。利用する前に
https://strk20-by-example.org と starkware-libs/starknet-privacy で確認してください。