public-relayer について
このスキルは、ガス抽象化されたERC-7710委任トランザクションを送信するため、コーディングエージェントによる1Shot Public Relayer JSON-RPC APIの統合を支援します。シングルチェーンとマルチチェーンの送信、手数料見積もり、委任署名、Webhook検証を扱います。
主な機能
- 01対応チェーンと決済トークンの確認
- 02ERC-7710委任の構築と署名
- 03手数料見積もりと価格ロック
- 04シングル/マルチチェーン取引の送信
- 05署名付きWebhookイベントの検証
活用シーン
- 01ウォレットやアプリへの中継取引の追加
- 02EOAからMetaMaskスマートアカウントへの移行
- 03ユーザー承認前の取引手数料見積もり
- 04リレーヤーのWebhook通知の検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ 1shot-api/ skills --skill public-relayerインストール後、Claude Code で/public-relayerを入力して読み込まれたか確認します。
同梱ファイルreferences/examples.mdreferences/schemas.md
詳細
1Shot Public Relayer(EIP-7710)統合
このスキルでは、クライアント側のコーディングエージェントが1Shot public relayerのJSON-RPC APIと統合し、ガス代を抽象化したERC-7710委任トランザクションを送信する方法を説明します。
このスキルのインストール(利用者向け/グローバル)
npx skills add 1Shot-API/skills/public-relayer -g -a cursor -y
リレイヤーは、7702StatelessDelegatorスマートアカウントから署名済みのMetaMask委任を受け取り、対象ウォレットを介してオンチェーンで引き換えます。また、同一チェーン(シングルチェーン)または別のチェーン(マルチチェーン)上のERC-20トークンで支払いを受け付けます。
このスキルを使用する場合
- 1Shotリレイヤー経由でトランザクションを送信するクライアントアプリ/SDK/ウォレット/エージェントを構築する場合
- EIP-7702を使用してEOAをMetaMaskの
7702StatelessDelegatorスマートアカウントにアップグレードする場合 - ERC-7710委任を作成、署名、送信する場合
- 送信前にトランザクションのリレイヤー手数料を見積もる、または取得する場合
- 見積もり期間中のリレイヤーのガス価格を固定する場合
- リレイヤーから署名済みWebhookイベントを受信して検証する場合
- 埋め込み1Shot Wallet(
wallet_requestExecutionPermissions)またはMetaMask(requestExecutionPermissions)から返された署名済み委任contextを引き換える場合
このスキルを使用しない場合
- 標準的な送信で1Shot Walletを埋め込む場合 — OWSProxy経由の
eth_sendTransactionでは、ウォレットが内部でrelayer_*を呼び出します。**1shot-wallet**スキルのみを使用してください。 - テーマ設定、接続、認証情報、分析 —
configure、eth_requestAccounts、OID4、proxy.analyticsの場合は、**1shot-wallet**のみを使用してください。 - 埋め込みウォレットからの任意のトランザクションステータスWebhook —
configure.destinationUrlを設定すると、ウォレットが送信時にこれをリレイヤーへ渡します。ホスト側にリレイヤークライアントを用意する必要はありません。
エンドポイントとパッケージ
- リレイヤーJSON-RPC URL:
relayer_getCapabilities、relayer_getFeeData、relayer_estimate7710Transaction、relayer_estimate7710TransactionMultichain、relayer_send7710Transaction、relayer_send7710TransactionMultichain、またはrelayer_getStatusを呼び出す前に、チェーンに応じたエンドポイントを選択してください。- メインネット:
https://relayer.1shotapi.com/relayers - Sepolia(
11155111)およびBase Sepolia(84532):https://relayer.1shotapi.dev/relayers
- メインネット:
- Webhook検証用JWKS:
GET https://relayer.1shotapi.com/.well-known/jwks.json(Ed25519、kty: "OKP"、crv: "Ed25519")。 - クライアントパッケージ:
@metamask/smart-accounts-kit(^2.0.0を推奨。Arc TestnetおよびRobinhood Chainでは必須)— 委任およびスマートアカウントのすべてのフローに対応する単一パッケージです。- メインエクスポート:
toMetaMaskSmartAccount、createDelegation、ScopeType、Implementation.Stateless7702、getSmartAccountsEnvironment。 @metamask/smart-accounts-kit/actions:ブラウザーでのEIP-7715フロー用のerc7715ProviderActions。@metamask/smart-accounts-kit/utils:ウォレットから取得した権限コンテキストをデコードするdecodeDelegations。
- メインエクスポート:
createPublicClient、encodeFunctionData、signAuthorization、privateKeyToAccount用のviem。- Webhook署名の検証用の
@noble/ed25519(または任意のEd25519検証ツール)。
**メソッド名について:**マルチチェーン版は、ベースメソッド名にMultichainをアンダースコアなしで直接付加します。例:relayer_send7710Transaction → relayer_send7710TransactionMultichain。
移行に関する注意:@metamask/delegation-toolkitは非推奨です。クライアントのpackage.jsonから削除し、上記のサブパスインポートを使って@metamask/smart-accounts-kitを使用してください。
ブラウザー拡張機能との統合(UI アプリに推奨)
ユーザーが MetaMask(または別の拡張機能ウォレット)を使ってブラウザーでサインインする場合は、拡張機能を優先するフローを使用してください。
window.ethereumを使用して、createWalletClient({ transport: custom(window.ethereum) })でウォレットクライアントを作成します。@metamask/smart-accounts-kit/actionsのerc7715ProviderActions()で拡張します。- (任意)
getSupportedExecutionPermissions()を呼び出し、ウォレットが必要な権限タイプをサポートしているか確認します。 - 拡張機能を通じて
requestExecutionPermissions(...)で権限をリクエストします。toには、ステップ 1 のリレイヤーのtargetAddressを設定してください。dapp のセッションアカウントではありません。リレイヤーは、リレイヤーの償還ウォレットに直接付与された委任を償還します。 @metamask/smart-accounts-kit/utilsのdecodeDelegations(context)でcontextをデコードし、各委任に対してtoRelayerJsonを実行して、その結果をrelayer_send7710TransactionのpermissionContextとして渡します。
ウォレットの前提条件(MetaMask ユーザーに代わって実行するを参照):
- ERC-20 の定期的な権限には、MetaMask Flask ≥13.5 または MetaMask 本番版 ≥13.23 が必要です。
- ユーザーは MetaMask Smart Account(EIP-7702)にアップグレードされている必要があります。
publicClient.getCode(address)で確認してください。コードがある場合は、委任者のアドレス(0xef0100のプレフィックスを除去)をgetSmartAccountsEnvironment(chainId).implementations.EIP7702StatelessDeleGatorImplと比較します。必要に応じて、ユーザーにアップグレードを促してください。
この方法が重要な理由:拡張機能ウォレットは鍵と権限 UX を管理します。signDelegation のようなローカル/内部の署名ヘルパーは、バックエンドやスクリプト駆動の署名者に適していますが、拡張機能を使うフローでは失敗したり、誤解を招いたりする可能性があります。
requestExecutionPermissions が利用できない場合は、その旨を明確に表示してください。接続中のウォレットは EIP-7715 をサポートしていない可能性が高いため、アプリはユーザーにウォレットの切り替えを促す必要があります。
操作の順序
新しい統合では、次の手順を順番どおりに実行してください。
ステップ 1 — relayer_getCapabilities:チェーン、受け入れ可能なトークン、targetAddress を確認する
サポートするチェーンごとに 1 回呼び出します。レスポンスには次の情報が含まれます。
- サポートされている
chainId。 - チェーンごとの 受け入れ可能な ERC-20 支払いトークンの一覧(
address、symbol、decimals)。 feeCollectorアドレス(手数料の送金先)。targetAddress— これは、クライアントが委任のtoとして署名する必要のあるアドレスです。そのチェーン上にあるリレイヤーの償還アカウントです。このアドレスを正確に指定して委任しないと、リレイヤーは償還できません。
結果はセッション中キャッシュしてください。変更されることはほとんどありません。
// Request
{ "jsonrpc": "2.0", "id": 1, "method": "relayer_getCapabilities", "params": ["8453", "84532"] }
// Response (excerpt)
{ "result": {
"8453": {
"feeCollector": "0x1111...",
"targetAddress": "0x2222...", // ← delegate `to` this address
"tokens": [{ "address": "0x036C...", "symbol": "USDC", "decimals": "6" }]
}
}}
Step 2 — バンドルを構築して署名する(クライアント側)
見積もりまたは送信の前に、完全な ERC-7710 バンドルを組み立てます。
- スマートアカウントを初期化します。
toMetaMaskSmartAccount({ implementation: Implementation.Stateless7702, address: <delegator EOA address>, signer })を使用します。 - (初回使用時) EIP-7702 の
authorizationListエントリーに署名します。account.signAuthorization({ chainId, contractAddress: getSmartAccountsEnvironment(chainId).implementations.EIP7702StatelessDeleGatorImpl, nonce })を使用し、見積もりと送信の両方に含めます。 - 権限コンテキストを生成します。
- ブラウザー拡張機能を使用する場合:
requestExecutionPermissions(to: targetAddressを指定)を呼び出し、granted[0].contextをdecodeDelegationsでデコードして、toRelayerJsonでシリアライズします。 - ローカル署名者を使用する場合:
createDelegation({ to: targetAddress (from Step 1), from: smartAccount.address, environment: smartAccount.environment, salt, scope: { type: ScopeType.Erc20TransferAmount | ScopeType.FunctionCall, ... maxAmount: feeAmount + workAmount } })で委任を作成し、smartAccount.signDelegation({ delegation })で署名します。
- ブラウザー拡張機能を使用する場合:
- 各実行のコールデータをエンコードします(手数料用の
feeCollector宛てtransferと、ユーザーの主な処理にはencodeFunctionDataを使用します)。
モックの手数料支払い実行を含めます。これは、そのトークンの minFee 以上の金額を feeCollector に送る ERC-20 transfer です(relayer_getFeeData を使用するか、保守的な仮値として 0.01 USDC などを指定します)。リレイヤーはこの処理を解析して、支払いトークンを判定します。マルチチェーンの場合、手数料チェーンのパラメーターにのみ手数料処理が必要です。処理チェーンのパラメーターでは省略できます。
ユーザーが入力したトークン金額は、まずトークンの小数桁数を使って小数文字列を解析します(たとえば、USDC の場合は parseUnits("0.01", 6))。小数文字列を BigInt に直接渡さないでください。"0.01" は無効なため、実行時エラーが発生します。
Step 3 — relayer_estimate7710Transaction または relayer_estimate7710TransactionMultichain:手数料を見積もる(推奨)
署名済みバンドルができたら、送信と同じ params 形式で対応する見積もりメソッドを呼び出します(context と delegationSecret は省略します。taskId、destinationUrl、memo は任意で、料金計算には使用されません)。
| 必要な処理 … | 使用するメソッド |
|---|---|
| 同じチェーンで手数料を支払い、処理を実行する | relayer_estimate7710Transaction |
| チェーン A で手数料を支払い、チェーン B で処理を実行する(または複数チェーンを一括で実行する) | relayer_estimate7710TransactionMultichain |
リレイヤーは委任を検証し、1Shot のガスシミュレーションを実行して、同期的に結果を返します(タスクは作成されません)。
success(ブール値)— 検証またはシミュレーションが失敗した場合はfalseです。結果のerrorを確認してください(常に JSON-RPC エラーとは限りません)。requiredPaymentAmount(文字列、トークン最小単位)— モックの支払いトークンで支払う手数料です。チェーン/トークンのminFeeを下限とします。gasUsed— チェーン ID から合計ガス単位(10 進文字列)へのマップです。context— 最初の支払いチェーン用の署名済み価格ロック見積もりです。単一チェーンで送信する際にparams.contextとして渡します。contextByChainId— チェーンごとの署名済み見積もりです。マルチチェーンで送信する際は、各params[i].context = contextByChainId[params[i].chainId]を設定します。
本番環境でのループ:
- 現在のバンドル(モック手数料は
minFee以上)で見積もりを POST します。 success === falseの場合は、errorに基づいてバンドルを修正します(支払いの不足、minFee未満、シミュレーションのリバート、無効な委任)。requiredPaymentAmountがモック手数料と異なる場合は、手数料処理の金額と委任のmaxAmountを更新し、委任に再署名します。- 見積もりレスポンスの
context/contextByChainIdを使用して、すぐに送信し、見積もりをロックします(有効期限は30 秒)。
完全なバンドルが準備できている場合は、クライアント側の eth_estimateGas と手動の手数料計算の代わりに、この方法を使用します。
Step 2b(フォールバック)— relayer_getFeeData:バンドル作成前の概算見積もり
バンドルがまだ作成されていない場合に使用します。たとえば、ユーザーが署名する前に概算手数料が必要なブラウザー権限の UX や、簡易的な価格表示などです。(chainId, paymentToken) ごとに 1 回呼び出します。レスポンスには次の項目が含まれます。
gasPrice(16 進数の wei)— ネイティブガス単位での現在のリレイヤーのガス価格です。rate(数値)— ネイティブガスのコストを支払いトークンの額に換算する為替レートです。minFee(文字列、トークンの最小単位)— 最低手数料で、支払いトークンでの $0.01 相当額です。expiry(Unix 秒)— 見積もりの有効期限です(デフォルトは30 秒です。expiryを過ぎた見積もりは期限切れとして扱ってください)。context(文字列)— 署名済みの価格固定コンテキストです(バンドルが作成された後は、見積もりから返されるcontextを優先してください)。
手数料を手動で計算する方法(見積もりを取得できない場合):
- 実行トランザクションの
gasUsedを見積もります(eth_estimateGasを使うか、既知の上限値を使用します)。 nativeFee = gasPrice * gasUsed(wei)。rateを使用して、支払いトークンの最小単位に換算します。- 下限:
feeAmount = max(converted, minFee)。
委任の制限範囲では、少なくとも feeAmount を feeCollector に送金できる必要があります。支払いが不足すると、InsufficientPayment(4200)が発生します。
Step 4 — relayer_send7710Transaction または relayer_send7710TransactionMultichain:バンドルを送信する
まず、署名方法を選択します。
- ブラウザー拡張機能を使う方法(UI アプリに推奨):
requestExecutionPermissionsで権限をリクエストし、decodeDelegationsでデコードして、デコードした委任をpermissionContextで送信します。 - ローカル署名者を使う方法(バックエンド/スクリプト):
createDelegationとsmartAccount.signDelegationを使って委任を作成し、署名します(Step 2 を参照)。
Step 2~3 で作成した JSON-RPC ボディを POST します。params.context フィールドには、対応する見積もりレスポンスの署名済み価格ロック context(単一チェーンの場合は result.context、マルチチェーンの場合は各パラメーターに対する result.contextByChainId[chainId])を指定する必要があります。自由形式の文字列は指定しないでください。
適切なメソッドを選択します。
| 必要な処理 … | 使用するメソッド |
|---|---|
| 同じチェーンで手数料を支払い、処理を実行する | relayer_send7710Transaction |
| チェーン A で手数料を支払い、チェーン B で処理を実行する(または複数チェーンを一括でアトミックに処理する) | relayer_send7710TransactionMultichain |
どちらのメソッドも、任意の destinationUrl(256 文字以下)を受け付けます。設定すると、リレイヤーはステータスが変わるたびに、その URL に署名済み Ed25519 Webhook イベントを POST します。ポーリングよりも destinationUrl の使用を推奨してください。こちらのほうがスケーラビリティに優れ、1 秒未満で更新を受け取れます。
どちらのメソッドも、任意の memo(256 文字以下)も受け付けます。これは不透明なクライアント相関文字列(注文 ID、内部参照など)です。実行、価格、オンチェーン calldata には影響しません。リレイヤーはこれを保存し、設定されている場合は relayer_getStatus と Webhook ペイロードで返します。見積もりでは省略してください(同じパラメーター型を指定できますが、taskId/destinationUrl と同様、価格設定には無視されます)。マルチチェーンでは、各配列エントリーに独自の memo を指定できます(それぞれが個別のタスクになります)。
送信時は、 delegationSecret(指定する場合は 10~1024 文字)の使用を推奨します。クライアントまたはアプリごとに 1 つのシークレットを選択してください(委任ごとではありません)。一度生成してアプリ設定またはセキュアなクライアントストレージに保存し、その送信元から送信するたびに同じ値を渡します。委任ごとに異なるシークレットや、委任からシークレットへのマップを用意する必要はありません。リレイヤーは、シークレットが指定された初回送信時に使用されたシークレットに各委任を紐付けます。その後、同じ委任を再送信する際は、同じシークレットを使用する必要があります。アプリのシークレットを知らない第三者がオンチェーンの委任をリプレイしても、拒否されます(4216)。省略した場合、未紐付けの委任は引き続き機能します(従来の動作)。すでに紐付けられている委任は、シークレットなしでは拒否されます。見積もりでは省略してください。マルチチェーンでは、各チェーンのエントリーに同じアプリシークレットを繰り返し指定できます。
結果は TaskId(単一チェーン)または TaskId[](マルチチェーン。送信順)です。
ステップ 5 — relayer_getStatus:ステータスを確認する(または Webhook を利用する)
destinationUrl が設定されている場合は、Webhook を優先してください。リレイヤーはステータスが変わるたびに、署名付き JSON を POST します。送信される Webhook の本文では、文字列のイベント名ではなく、数値の type フィールドを使用します。
type | 意味 |
|---|---|
4 | 送信済み(オンチェーンの tx ハッシュが利用可能) |
0 | 成功を確認済み |
1 | リバート/実行失敗 |
data フィールドは、そのタスクの relayer_getStatus と同じオブジェクト構造です。送信時に params.memo を指定した場合は、data.memo に省略可能な memo も含まれます(それ以外の場合は省略され、null にはなりません)。
各 Webhook を検証するには:
GET https://relayer.1shotapi.com/.well-known/jwks.jsonを取得してキャッシュします(ローテーションの頻度は低いです)。- Webhook 本文の
keyIdにあるkidを使って公開鍵を検索します。 signatureフィールドを除外して署名対象のペイロードを再構築し、キーを安定してソートした JSON としてシリアライズします(safe-stable-stringifyなどを使用してください。リレイヤーは正規化された形式に署名します)。- UTF-8 バイト列に対する Ed25519 で検証します。base64 の
signatureは 64 バイトの分離署名として扱います。
ポーリングが避けられない場合は、{ id: <TaskId>, logs: true|false } を指定して relayer_getStatus を 2~3 秒ごとに呼び出し、終端ステータスになったら停止します。params.memo を指定して送信した場合、すべてのステータスコードでステータスオブジェクトに memo が含まれます。送信時に省略した場合、このフィールドは存在しません(null ではありません)。ステータスコード:
| コード | ラベル | 終端か? |
|---|---|---|
| 100 | 保留中 | いいえ |
| 110 | 送信済み | いいえ(hash あり) |
| 200 | 確認済み | はい(receipt あり) |
| 400 | 拒否 | はい(message あり) |
| 500 | リバート | はい(data あり) |
判断の早見表
- 手数料の見積もり方法:署名済みバンドルがある場合は、
relayer_estimate7710Transaction(単一チェーン)またはrelayer_estimate7710TransactionMultichain(マルチチェーン)を優先します。リレイヤーがガスをシミュレートし、requiredPaymentAmountと署名済みのcontextを返します。バンドルの作成前(ブラウザー権限の UX など)に概算を得る場合、または見積もりを利用できない場合に限り、relayer_getFeeDataを使用してください。 - 未署名の見積もり(署名前の見積もり):見積もり時に限り、各委任の
signatureを""、bytes32(0)(0xに 64 個のゼロの 16 進数を続けたもの)、または推奨される 65 バイトの全ゼロのプレースホルダーに設定します。リレイヤーは Geth のstateOverrideを通じて、各委任者に見積もり専用の DelegatorEstimateShim コードを挿入します(チェーン上でまだ EIP-7702 にアップグレードされていない EOA も含みます)。実際のオンチェーンのトークン残高と使用許可は引き続き適用され、偽装されることはありません。初回の EIP-7702 アップグレードでは、address、chainId、nonceが正しく、r/sがプレースホルダー(32 バイトのゼロの 16 進数)、yParityが0のauthorizationListを送信することもできます。ただし、委任署名がプレースホルダーの場合に限ります。リレイヤーは見積もりに固定の認証ガス(デフォルトで 40100 ガス)を加算し、無効な認証情報をシミュレーションには転送しません。送信には実際の委任署名と認証署名が必要です。relayer_send7710Transaction*ではプレースホルダーは拒否されます。 - 自己負担とスポンサー負担:同じアカウントが手数料を支払い、処理も実行する場合は、
feeAmount + workAmountを対象とする単一の委任に署名し、2 つのexecutions(手数料の送金と処理)をバンドルします。別のスポンサーが手数料を支払う場合は、2 つの委任(スポンサーと委任者からそれぞれ 1 つ)に署名し、それぞれ独自のpermissionContextを持つ 2 つのtransactions[]エントリーを送信します。リレイヤーはそれらを単一のredeemDelegationsバッチにまとめます。 ScopeTypeの選択:ScopeType.Erc20TransferAmountは最もシンプルで、手数料と処理の両方の送金に使えます。1 つのバッチでより幅広い関数を対象にする必要がある場合は、ScopeType.FunctionCall(トークン + セレクター)を使用してください。バッチ化された一部の呼び出しパターンでは、Erc20TransferAmountエンフォーサーがCaveatEnforcer:invalid-call-typeでリバートすることがあります。- EIP-7702 認証:リクエストごとに許可される
authorizationListエントリーは 1 つだけです。委任者とスポンサーの両方にアップグレードが必要な場合は、2 回に分けて呼び出すか、先に一方を別の方法でアップグレードしてください。 - Salt:リプレイの衝突を避けるため、
createDelegationには常に新しいランダムな 32 バイトの 16 進数saltを渡してください。 memoとcontext、taskId、delegationSecretの違い:contextは見積もりで得た手数料の見積もり額を固定します。taskIdはリレイヤーが割り当てる(またはクライアントが指定する)タスク識別子です。memoはステータスや Webhook にそのまま返される、不透明な照合用ラベルです。delegationSecretは公開リプレイを防ぐためにオープンな委任を紐付ける、アプリレベルで再利用する単一のシークレットです(委任ごとに 1 つ用意するものではなく、送信時のみ使用します)。- BigInt の JSON 変換:リレイヤーの JSON-RPC では通常の JSON が必要です。送信前に、署名済み委任構造体内の
bigint値を0xで始まる 16 進数文字列に変換してください。Uint8Arrayはviem/utilsのbytesToHexで変換します。
最小限のエンドツーエンド構成
// 1. capabilities
const caps = await rpc("relayer_getCapabilities", [chainId]);
const { targetAddress, feeCollector, tokens } = caps[chainId];
const paymentToken = tokens.find((t) => t.symbol === "USDC")!;
// 2. build + sign bundle (mock fee ≥ minFee; see examples.md)
const sendParams = {
chainId,
transactions: [
{
permissionContext: [signedDelegation],
executions: [feeTransfer, workCall],
},
],
};
// 3. estimate (same params as send, no context)
const estimate = await rpc<Estimate7710Result>(
"relayer_estimate7710Transaction",
sendParams,
);
if (!estimate.success) throw new Error(estimate.error);
const feeAmount = BigInt(estimate.requiredPaymentAmount!);
// if feeAmount changed: rebuild fee execution + delegation scope, re-sign, re-estimate
// 4. submit with price lock from estimate
const taskId = await rpc("relayer_send7710Transaction", {
...sendParams,
context: estimate.context,
destinationUrl: "https://my-app.example.com/relayer-webhook", // optional, recommended
memo: "order-abc123", // optional; echoed in relayer_getStatus and webhooks
delegationSecret: APP_DELEGATION_SECRET, // one per app/client; reuse on every send, not per delegation
});
// Multichain: estimate with params array, then send each entry with
// context: estimate.contextByChainId![param.chainId]
// 5. either consume webhooks or poll relayer_getStatus
一般的なエラーコード
見積もりの応答:relayer_estimate7710Transaction と relayer_estimate7710TransactionMultichain は、検証やシミュレーションの失敗(モック支払いがない、手数料が minFee を下回る、ガス見積もり時のリバート)に対して、result.success: false と error 文字列を返します。これらは必ずしも JSON-RPC エラーではありません。送信する前に result.success を確認してください。
| コード | 意味 | 典型的な修正方法 |
|---|---|---|
| 4200 | 支払い不足 | feeAmount を少なくとも requiredPaymentAmount / minFee まで増やし、再署名してください。 |
| 4201 | 無効な署名 | 委任に再署名してください。salt が新しいものであり、signer が from と一致することを確認してください。 |
| 4202 | 未対応の支払いトークン | そのチェーンの relayer_getCapabilities に含まれるトークンを選択してください。 |
| 4204 | 見積もりの期限切れ | 見積もりを再実行(または relayer_getFeeData を再取得)し、約30秒以内に再送信してください。 |
| 4206 | 未対応のチェーン | chainId が relayer_getCapabilities に含まれていることを確認してください。 |
| 4209 | 未対応の機能 | 委任のスコープ/ケーブアットを調整し、リレイヤーが呼び出しの種類に対応していることを確認してください。 |
| 4210 | 無効な認証リスト | authorizationList のエントリーは最大1つです。nonce が最新であることを確認してください。 |
| 4211 | シミュレーション失敗 | リレイヤーは事前にシミュレーションを実行します。リバートの理由を data で確認してください。 |
| 4212 | マルチチェーン非対応 | チェーンごとに relayer_send7710Transaction を使う方法に切り替えてください。 |
| 4214 | タスク ID の重複 | taskId を省略してリレイヤーに割り当てさせるか、新しいランダムな16進数を送信してください。 |
| 4216 | 委任シークレットの不一致 | アプリの delegationSecret(その委任に対する初回送信時に紐付けられたもの)を使用してください。まだ紐付けられていない場合に限り、省略できます。 |
ブラウザフローでの注意点と対処法
"wallet_requestExecutionPermissions does not exist":ウォレットが EIP-7715 に対応していません。対応するウォレットに切り替えるようユーザーに促してください。"External signature requests cannot sign delegations for internal accounts":署名経路が誤っています。内部アカウントによる委任署名ではなく、拡張機能の権限リクエストを使用してください。"Account does not support signMessage":署名者とアカウントが一致していません。拡張機能モードでは、ローカルアカウントを前提としないでください。"Cannot convert 0.01 to a BigInt":まずトークンの小数桁数に基づいて10進数の入力を解析し、その後に変換してください。
エラーカタログとリクエスト/レスポンスの完全なスキーマについては、references/schemas.md を参照してください。
1shot-wallet との統合方法
方法は3つあります。コードを書く前に1つ選択してください。
| 方法 | スキル | ホストは relayer_* を呼び出すか |
|---|---|---|
| A — 埋め込みのみ | 1shot-wallet | いいえ |
| B — 埋め込み+委任の実行 | 1shot-wallet + public-relayer | はい(付与を引き換え) |
| C — 埋め込みウォレットなし | public-relayer | はい |
方法 A — 埋め込みのみ(最も一般的)
1shot-wallet のみをインストールします。OWSProxy を接続し、eth_sendTransaction を呼び出すと、ウォレットが内部で委任に署名してリレイヤーに送信します。ホスト側にリレイヤーの JSON-RPC コードは不要です。ガス抽象化された送信や、任意の configure.destinationUrl ウェブフックは、このスキルなしで利用できます。
Path B — 埋め込み+実行の委任(両方のスキル)
ホストまたはバックエンドが、ユーザーから付与された委任(セッションキー、オフライン実行、定期的な ERC-20 許可)を使って処理を実行する場合に使用します。両方のスキルをインストールし、OWSProxy のセットアップについては 1shot-wallet/SKILL.md をお読みください。relayer_getCapabilities から始め、targetAddress(そのチェーン上のリレイヤーの償還用ウォレット)を確認します。
| サブパス | Grant to | ホストによる再委任 | 例 |
|---|---|---|---|
| B1 — 直接 | targetAddress | いいえ | 例 0b |
| B2 — セッションキー(推奨) | ホストのセッションアカウント | はい → targetAddress | 例 0c |
Path B1 — リレイヤーへの直接付与
よりシンプルなプロトタイプ向けの方法です。ユーザーがリレイヤーに直接許可を付与します。
wallet_requestExecutionPermissionsをto: targetAddressと定期的な ERC-20 の範囲(予算は手数料+処理費用以上)で実行します。- ウォレットが
response.context(署名済みの委任を1つ)を返します。ホストはdecodeDelegationsとtoRelayerJsonでデコードし、executions[]を構築してから、relayer_estimate7710Transaction/relayer_send7710Transactionを実行します。
ユーザーはリレイヤーアドレスに直接委任します。デモには適していますが、本番環境では B2 のセッションキーを推奨します。
Path B2 — セッションキー+再委任(推奨)
本番向けのセッションキー方式です。ユーザーはホストが制御するセッションアカウントに許可を付与し、ホストは送信前に、より限定的で実行固有の範囲を設定してリレイヤーに再委任します。
- ホストはセッションアカウントを生成するか読み込みます(ローカル署名者。秘密鍵はユーザーのパスキーではなく、ホストのメモリ内に保持されます)。
wallet_requestExecutionPermissionsをto: sessionAccountAddressと定期的な ERC-20 の範囲(オフライン/エージェント用の予算)で実行します。- ウォレットが
response.context(親の許可)を返します。ホストはこれをデコードし、セッションアカウントが今回の実行に対する、より限定的な条件(FunctionCallとexactCalldata、または手数料+処理費用を上限とするErc20TransferAmount。ウォレット内送信と同じ範囲縮小の考え方)を設定して、targetAddressに再委任します。 encodeDelegationsを使って、エンコードされた委任チェーン(親の委任+署名済みの再委任)をpermissionContextとして構築します。チェーン全体を含むpermissionContextを指定して、見積もりを取得し、relayer_send7710Transactionを実行します。- 初回使用時に、セッションアカウントを EIP-7702 スマートアカウント形式にする必要がある場合があります。アップグレード時は、送信時に
authorizationListを含めてください(このスキルの他の箇所と同じ制約です)。
再委任で親の範囲を広げることはできず、狭めることだけが可能です(条件は累積して適用されます)。MetaMask kit の再委任の作成(redelegatePermissionContext または createDelegation({ parentDelegation }))をご覧ください。
ウォレットは、ウォレット内の送信と、取り消し用の wallet_revokeExecutionPermission でも内部的にリレイヤーを使用します。これは Path B とは別の機能です。
開発者から、オフライン時にユーザーに代わって実行する、リレイヤー経由で定期的な ERC-20 許可を償還する、または埋め込みウォレットからのパスキー署名済み委任を使ってリレイヤーバンドルを送信するよう求められた場合に Path B を使用します。一般的な「パスキーウォレットの埋め込み」には使用しません。セッションキーとエージェントによる実行には B2 を推奨します。
パブリックリレイヤーはオープンな JSON-RPC サービスです(API キー不要)。同じ relayer_* メソッドに対応する別のリレイヤーは、誰でも実行できます。
Path C — 埋め込みウォレットなし
MetaMask 拡張機能(requestExecutionPermissions + window.ethereum)またはローカル/バックエンドの署名者(createDelegation + signDelegation)を使用します。このスキルの他の内容も、そのまま適用できます。references/examples.md の例 0 をご覧ください。
完全なノンカストディアルアプリのための webauthn-prf-wallet との組み合わせ
パブリックリレイヤーは、(別途インストールする)webauthn-prf-wallet スキルと自然に組み合わせることで、ベンダーロックインがなく、ビジネスアカウントも不要な、完全なノンカストディアルの web3 アプリケーションを構築できます。
webauthn-prf-walletは、WebAuthn PRF 拡張機能を介してユーザーのパスキーから EVM 秘密鍵を導出し、隔離された iframe 内に保持します。鍵が親ページやサーバーに届くことはありません。- このパスキー由来のアカウントは、このスキルのフローにおける自然な委任者です。iframe に EIP-7702 認可、
7702StatelessDelegatorのアップグレード、および各createDelegationペイロードに署名させます。 - パブリックリレイヤーはオープンな JSON-RPC サービス(API キーも Bearer トークンも不要)で、ユーザーはトランザクションごとにステーブルコインで支払います。固定される関係はありません。同じ
relayer_*メソッドに対応する代替リレイヤーは誰でも構築でき、クライアントはRELAYER_URLを変更するだけで切り替えられます。
エンドツーエンドで見ると、ユーザーは自身の鍵(パスキー)を所有し、トランザクションごとの手数料(ERC-20)のみを支払い、アプリケーションはカストディアルな領域もビジネス認証情報も持ちません。「ETH を保有せずにトランザクションを実行できるパスキーウォレット」や「管理する API キーが不要なノンカストディアルアプリ」を開発者から求められた場合は、この組み合わせを検討してください。クライアント側のウォレットパターンについては webauthn-prf-wallet/SKILL.md を読み、リレイヤーの JSON-RPC フローにはこのスキルを使用してください。
追加リソース
- references/schemas.md — JSON-RPC メソッドのシグネチャ、スキーマ、ステータス/エラーコード、JWKS の本文形式を網羅しています。正確なパラメーター形式、完全なエラーカタログ、またはワイヤー上の Webhook ペイロード形式が必要な場合に参照してください。
- references/examples.md — 実行可能な TypeScript パターン:MetaMask のブラウザーフロー(Example 0)、埋め込みウォレットの直接付与(Example 0b、Path B1)、埋め込みウォレットのセッションキーと再委任(Example 0c、Path B2)、見積もりを先に行う単一チェーンおよびマルチチェーンのフロー、自己スポンサー型、スポンサー型、Ed25519 検証を行う Webhook 受信側。クライアントコードを書くときや、実績のある統合パターンをコピーしたいときに参照してください。
1shot-walletスキル — 1Shot Wallet(OWS Host Layer)を埋め込みます。Path A と Path B では必須です。Path B の委任実行では補助的に使用します(埋め込みのみの送信では不要です)。webauthn-prf-walletスキル — 隔離された iframe 内に保持する、パスキー由来のクライアント側 EVM 鍵のための補助スキルです。完全なノンカストディアル構成では、このスキルと併用してください。- MetaMask Smart Accounts Kit — インストール、ブラウザー/EIP-7715 フロー、ローカル署名者/委任フロー、Advanced Permissions ウォレットクライアントのリファレンス。