关于 public-relayer
该技能指导编码 Agent 集成 1Shot 公共中继器的 JSON-RPC API,以提交 Gas 抽象化的 ERC-7710 委托交易。内容涵盖单链和多链提交、费用报价、委托签名及 Webhook 验证。
主要功能
- 01发现支持的链和支付代币
- 02构建并签署 ERC-7710 委托
- 03估算费用并锁定报价
- 04提交单链或多链交易
- 05验证签名的 Webhook 事件
适用场景
- 01为钱包或应用接入中继交易
- 02将 EOA 升级为 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 公共中继服务(EIP-7710)集成
本技能介绍如何让客户端编码 Agent 集成 1Shot 公共中继服务 JSON-RPC API,以提交 Gas 抽象的 ERC-7710 委托交易。
安装此技能(使用者 / 全局)
npx skills add 1Shot-API/skills/public-relayer -g -a cursor -y
中继服务接受来自 7702StatelessDelegator 智能账户的已签名 MetaMask 委托,通过目标钱包在链上兑换该委托,并接受在同一条链(单链)或不同链(多链)上支付的 ERC-20 代币。
何时使用此技能
- 构建通过 1Shot 中继服务提交交易的客户端应用、SDK、钱包或 Agent
- 通过 EIP-7702 将 EOA 升级为 MetaMask
7702StatelessDelegator智能账户 - 创建、签名并提交 ERC-7710 委托
- 在提交交易前估算或查询中继服务费用
- 在报价有效期内锁定中继服务 Gas 价格
- 接收并验证来自中继服务的已签名 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。
- 主导出项:
viem,用于createPublicClient、encodeFunctionData、signAuthorization、privateKeyToAccount。@noble/ed25519(或任何 Ed25519 验证器),用于验证 Webhook 签名。
方法命名: 多链变体直接在基础方法名后追加 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处理每个委托,并将结果作为permissionContext传入relayer_send7710Transaction。
钱包前提条件(参阅代表 MetaMask 用户执行操作):
- ERC-20 周期性权限要求 MetaMask Flask ≥13.5 或 MetaMask 正式版 ≥13.23。
- 用户必须升级为 MetaMask Smart Account(EIP-7702)。使用
publicClient.getCode(address)检查——如果存在代码,则将委托者地址(去掉0xef0100前缀)与getSmartAccountsEnvironment(chainId).implementations.EIP7702StatelessDeleGatorImpl进行比较。如有需要,提示用户升级。
这条路径之所以重要,是因为扩展钱包负责管理密钥和权限交互体验。本地/内部签名辅助函数(如 signDelegation)适用于后端或由脚本驱动的签名者,但在扩展流程中可能会失败或造成误导。
如果 requestExecutionPermissions 不可用,请明确告知用户:已连接的钱包可能不支持 EIP-7715,应用应提示用户切换钱包。
操作顺序
进行任何新集成时,请按顺序执行以下步骤。
步骤 1 — relayer_getCapabilities:发现链、接受的代币和 targetAddress
对每条要支持的链调用一次。响应会告知你:
- 支持哪些
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" }]
}
}}
步骤 2 — 构建并签署捆绑包(客户端)
在报价或提交之前,组装完整的 ERC-7710 捆绑包:
- 初始化智能账户,使用
toMetaMaskSmartAccount({ implementation: Implementation.Stateless7702, address: <delegator EOA address>, signer })。 - **(首次使用时)**使用
account.signAuthorization({ chainId, contractAddress: getSmartAccountsEnvironment(chainId).implementations.EIP7702StatelessDeleGatorImpl, nonce })签署 EIP-7702authorizationList条目 — 在估算和发送时都要包含该条目。 - 生成权限上下文:
- 浏览器扩展路径:调用
requestExecutionPermissions(传入to: targetAddress),使用decodeDelegations解码granted[0].context,再使用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 })签署。
- 浏览器扩展路径:调用
- 编码每项执行的 calldata(对费用
transfer(转账至feeCollector)和用户的主要工作使用encodeFunctionData)。
加入一项模拟费用支付执行:向 feeCollector 转账 ERC-20,金额**≥**该代币的 minFee(使用 relayer_getFeeData,或使用保守的占位金额,例如 0.01 USDC)。中继器会解析此操作以确定支付代币。对于多链交易,只需在费用链参数中加入费用操作;工作链参数可以省略该操作。
对于用户输入的代币金额,先根据代币精度解析十进制字符串(例如,对 USDC 使用 parseUnits("0.01", 6))。切勿直接将十进制字符串传给 BigInt,因为 "0.01" 无效,会导致运行时故障。
步骤 3 — relayer_estimate7710Transaction 或 relayer_estimate7710TransactionMultichain:获取费用报价(首选)
签名后的捆绑包准备就绪后,调用对应的估算方法,使用与发送时相同的 params 结构(省略 context 和 delegationSecret;taskId、destinationUrl 和 memo 为可选项,且不影响定价):
| 需求…… | 使用此方法 |
|---|---|
| 在同一条链上支付费用并执行工作 | relayer_estimate7710Transaction |
| 在链 A 上支付费用,在链 B 上执行工作(或原子性地批量处理多条链) | relayer_estimate7710TransactionMultichain |
中继器会验证委托、运行 1Shot Gas 模拟,并同步返回结果(不会创建任务):
success(布尔值)— 验证或模拟失败时为false;请读取结果中的error(不一定是 JSON-RPC 错误)。requiredPaymentAmount(字符串,以代币最小单位计)— 以模拟支付代币支付的费用,最低为该链/代币的minFee。gasUsed— 链 ID → 累计 Gas 单位数的映射(十进制字符串)。context— 首个支付链的签名价格锁定报价;在单链发送时作为params.context传入。contextByChainId— 各链对应的签名报价;多链发送时,将每个params[i].context设为contextByChainId[params[i].chainId]。
生产环境工作流:
- 使用当前捆绑包(模拟费用 ≥
minFee)发送估算请求。 - 如果
success === false,根据error修复捆绑包(缺少支付、低于 minFee、模拟回滚、委托无效)。 - 如果
requiredPaymentAmount与模拟费用不同,则更新费用执行金额和委托的maxAmount,然后重新签署委托。 - 立即使用估算响应中的
context/contextByChainId发送,以锁定报价(有效期 30 秒)。
完整捆绑包准备就绪后,此流程可取代客户端 eth_estimateGas 加手动费用计算。
步骤 2b(备用方案)— relayer_getFeeData:在 bundle 尚不存在时获取粗略报价
当 bundle 尚未构建时使用 — 例如,浏览器权限体验需要在用户签名之前获取粗略费用,或快速显示价格。每个 (chainId, paymentToken) 调用一次。响应包含:
gasPrice(十六进制 wei)— relayer 以原生 gas 单位计价的当前 gas 价格。rate(数字)— 用于将原生 gas 成本换算为支付代币金额的汇率。minFee(字符串,以代币最小单位计)— 最低费用,相当于支付代币中的 $0.01。expiry(Unix 秒数)— 报价有效期(默认 30 秒;超过expiry的报价均视为过期)。context(字符串)— 已签名的价格锁定上下文(bundle 存在时,优先使用 estimate 返回的context)。
手动计算费用(estimate 不可用时):
- 估算工作交易的
gasUsed(使用eth_estimateGas或已知的上限值)。 nativeFee = gasPrice * gasUsed(wei)。- 使用
rate将其换算为支付代币的最小单位。 - 下限:
feeAmount = max(converted, minFee)。
委托的 caveat 范围必须允许向 feeCollector 转账至少 feeAmount。支付不足会导致 InsufficientPayment(4200)。
步骤 4 — relayer_send7710Transaction 或 relayer_send7710TransactionMultichain:提交交易包
首先选择签名路径:
- 浏览器扩展路径(UI 应用推荐): 使用
requestExecutionPermissions请求权限,使用decodeDelegations解码,并在permissionContext中发送解码后的委托。 - 本地签名器路径(后端/脚本): 使用
createDelegation+smartAccount.signDelegation构建并签署委托(参见步骤 2)。
POST 在步骤 2–3 中构建的 JSON-RPC 请求体。params.context 字段必须是对应估算响应中的已签名价格锁定 context(单链使用 result.context;多链则每个参数使用 result.contextByChainId[chainId]),不能是自由格式字符串。
选择合适的方法:
| 你的需求 … | 使用此方法 |
|---|---|
| 在同一条链上支付费用并执行任务 | relayer_send7710Transaction |
| 在 A 链上支付费用,在 B 链上执行任务(或原子性地批处理多条链) | relayer_send7710TransactionMultichain |
两种方法都接受可选的 destinationUrl(≤256 个字符)。设置后,每当状态发生变化,relayer 都会向该 URL POST 已签名的 Ed25519 webhook 事件。建议使用 destinationUrl,而不是轮询——它的扩展性更好,且能提供亚秒级更新。
两种方法还都接受可选的 memo(≤256 个字符):不透明的客户端关联字符串(订单 ID、内部引用等)。它不会影响执行、定价或链上 calldata——relayer 会存储该值,并在设置后通过 relayer_getStatus 和 webhook 负载将其回传。估算时省略(同一参数类型也可接受,但会像 taskId / destinationUrl 一样被忽略,不影响定价)。对于多链,每个数组条目都可以携带自己的 memo(每个条目会成为一个单独的任务)。
发送时建议提供: delegationSecret(提供时长度为 10–1024 个字符)。为每个客户端或应用选择一个密钥(而不是每份委托一个):生成一次,将其存储在应用配置或安全的客户端存储中,并在来自该来源的每次发送中传入相同的值。你无需为每份委托使用不同的密钥,也无需维护委托→密钥映射——relayer 会在首次提交某份委托且提供密钥时,将其绑定到你使用的密钥;之后重新提交该委托时必须使用相同的密钥。第三方若没有你的应用密钥却重放你的链上委托,将被拒绝(4216)。省略该值时,尚未绑定的委托仍可使用(旧行为);已绑定的委托若未提供密钥,则会被拒绝。估算时省略。对于多链,你可以在每个链条目中重复使用相同的应用密钥。
结果为 TaskId(单链)或 TaskId[](多链,顺序与提交顺序一致)。
步骤 5 — relayer_getStatus:检查状态(或使用 Webhook)
如果设置了 destinationUrl,优先使用 Webhook——中继器会在每次状态变更时 POST 已签名的 JSON。出站 Webhook 正文使用数字 type 字段(而非字符串事件名称):
type | 含义 |
|---|---|
4 | 已提交(链上交易哈希可用) |
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 字节的分离式签名。
如果无法避免轮询,每隔 2–3 秒使用 { id: <TaskId>, logs: true|false } 调用 relayer_getStatus,并在状态变为终态时停止。如果发送了 params.memo,则每种状态码对应的状态对象都包含 memo;如果发送时省略了该参数,则字段也会缺失(而非 null)。状态码:
| 代码 | 标签 | 是否为终态 |
|---|---|---|
| 100 | 待处理 | 否 |
| 110 | 已提交 | 否(包含 hash) |
| 200 | 已确认 | 是(包含 receipt) |
| 400 | 已拒绝 | 是(包含 message) |
| 500 | 已回滚 | 是(包含 data) |
决策速查表
- 如何报价?:签名后的 bundle 已准备好时,优先使用
relayer_estimate7710Transaction(单链)或relayer_estimate7710TransactionMultichain(多链)——中继器会模拟 Gas,并返回requiredPaymentAmount和已签名的context。仅在 bundle 尚未构建、需要粗略报价时(例如浏览器权限 UX),或无法使用 estimate 时,才使用relayer_getFeeData。 - 未签名的 estimate(签名前报价):仅在 estimate 时,将每个 delegation 的
signature设为""、bytes32(0)(0x+ 64 个零十六进制数字),或推荐的 65 字节全零占位符;中继器会通过 GethstateOverride,在每个 delegator 处注入仅用于 estimate 的 DelegatorEstimateShim 代码(包括链上尚未完成 EIP-7702 升级的 EOA)。真实的链上代币余额和授权仍会生效,不会伪造。对于首次 EIP-7702 升级,你也可以发送包含正确address、chainId和nonce,但使用占位符r/s(32 字节零十六进制)和yParity0的authorizationList——仅当 delegation 签名为占位符时才这样做;中继器会在报价中加入固定的授权 Gas(默认 40100 Gas),且不会将无效授权转发给模拟。发送时必须使用真实的 delegation 和授权签名——relayer_send7710Transaction*会拒绝占位符。 - 自行支付 vs. 赞助支付:如果同一账户既支付费用又执行工作,则签署一个 delegation,其范围涵盖
feeAmount + workAmount,并在 bundle 中包含两个executions(费用转账 + 工作)。如果由单独的 sponsor 支付费用,则签署两个 delegation(分别来自 sponsor 和 delegator),并提交两个带有各自permissionContext的transactions[]条目。中继器会将它们合并到单个redeemDelegations批次中。 - 选择
ScopeType:ScopeType.Erc20TransferAmount最简单,适用于费用和工作转账。当你需要在一个批次中覆盖更广泛的函数时,使用ScopeType.FunctionCall(代币 + selector)——对于某些批量调用模式,Erc20TransferAmountenforcer 可能会以CaveatEnforcer:invalid-call-type回滚。 - EIP-7702 授权:每个请求只允许有一个
authorizationList条目。如果 delegator 和 sponsor 都需要升级,则分两次单独调用(或先在其他地方升级其中一个)。 - Salt:调用
createDelegation时,始终传入新的随机 32 字节十六进制salt,以避免重放冲突。 memo、context、taskId和delegationSecret的区别:context会锁定 estimate 中的费用报价;taskId是由中继器分配(或由客户端提供)的任务标识符;memo是不透明标签,会在状态和 webhook 中原样返回,用于关联;delegationSecret是一个应用级密钥,可在所有发送操作中重复使用(不是每个 delegation 一个密钥),用于防止公开重放开放的 delegation(仅发送时使用)。- 将 BigInt 转换为 JSON:中继器 JSON-RPC 要求使用普通 JSON。发送前,将已签名 delegation 结构中的
bigint值转换为带0x前缀的十六进制字符串。使用viem/utils中的bytesToHex转换Uint8Array。
最简端到端结构
// 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、Gas 估算回滚)时,会返回 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 条目最多只能有一个;确认 nonce 是最新值。 |
| 4211 | 模拟失败 | 中继器会预先模拟;检查 data 中的回滚原因。 |
| 4212 | 不支持多链 | 改为按链调用 relayer_send7710Transaction。 |
| 4214 | 任务 ID 重复 | 省略 taskId,由中继器分配一个,或发送新的随机十六进制值。 |
| 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":先根据代币精度解析十进制输入,再进行转换。
完整的错误目录和请求/响应架构请参阅 references/schemas.md。
与 1shot-wallet 集成的路径
共有三种不同路径——编写代码前请选择一种:
| 路径 | 技能 | 宿主是否调用 relayer_*? |
|---|---|---|
| A — 仅嵌入 | 1shot-wallet | 否 |
| B — 嵌入并执行委托 | 1shot-wallet + public-relayer | 是(兑换授权) |
| C — 不嵌入钱包 | public-relayer | 是 |
路径 A — 仅嵌入(最常见)
仅安装 1shot-wallet。接入 OWSProxy,调用 eth_sendTransaction——钱包会在内部签署委托并提交给中继器。无需编写宿主中继器 JSON-RPC 代码。无 Gas 抽象的交易发送以及可选的 configure.destinationUrl Webhook,无需此技能即可使用。
路径 B — 嵌入 + 执行委托(两项技能)
当宿主或后端使用用户授予的委托(会话密钥、离线执行、定期 ERC-20 授权)执行工作时使用。安装两项技能;阅读 1shot-wallet/SKILL.md 了解 OWSProxy 设置。从 relayer_getCapabilities 开始,并记下 targetAddress(该链上的中继器赎回钱包)。
| 子路径 | 授权 to | 宿主是否重新委托? | 示例 |
|---|---|---|---|
| B1 — 直接 | targetAddress | 否 | 示例 0b |
| B2 — 会话密钥(推荐) | 宿主会话账户 | 是 → targetAddress | 示例 0c |
路径 B1 — 直接授权给中继器
更简单的原型路径:用户直接授权中继器。
- 使用
to: targetAddress和定期 ERC-20 范围(预算 ≥ 费用 + 工作量)调用wallet_requestExecutionPermissions。 - 钱包返回
response.context(单个已签名委托);宿主使用decodeDelegations+toRelayerJson解码,构建executions[],然后调用relayer_estimate7710Transaction/relayer_send7710Transaction。
用户直接委托给中继器地址——适用于演示;生产环境建议使用 B2 会话密钥。
路径 B2 — 会话密钥 + 重新委托(推荐)
生产环境的会话密钥路径:用户授权一个由宿主控制的会话账户;宿主在提交前,将权限重新委托给中继器,并采用范围更窄、针对具体执行的授权条件。
- 宿主生成或加载一个会话账户(本地签名者;私钥保留在宿主内存中,不是用户的通行密钥)。
- 使用
to: sessionAccountAddress和定期 ERC-20 范围(离线/Agent 预算)调用wallet_requestExecutionPermissions。 - 钱包返回
response.context(父级授权)。宿主解码后,会话账户将权限重新委托给targetAddress,并针对本次执行采用范围更窄的限制条件(FunctionCall+exactCalldata,或将Erc20TransferAmount限定为费用 + 工作量上限——与钱包内发送采用相同的权限收窄思路)。 - 通过
encodeDelegations将委托链(父级委托 + 已签名的重新委托)编码为permissionContext;估算后调用relayer_send7710Transaction,并在permissionContext中包含完整委托链。 - 首次使用时,会话账户可能需要采用 EIP-7702 智能账户形式;升级时发送请求应包含
authorizationList(与本技能其他部分的限制相同)。
重新委托只能收窄父级授权范围(限制条件会叠加)。请参阅 MetaMask kit 的创建重新委托(redelegatePermissionContext 或 createDelegation({ parentDelegation }))。
钱包也会在钱包内发送和 wallet_revokeExecutionPermission 取消操作中使用中继器;这与路径 B 无关。
当开发者要求在离线时代表用户执行操作、通过中继器兑现定期 ERC-20 授权,或使用来自嵌入式钱包、由通行密钥签名的委托提交中继器捆绑交易时,选择路径 B——不要将其用于一般性的“嵌入通行密钥钱包”。会话密钥和 Agent 执行场景优先选择 B2。
公共中继器是开放的 JSON-RPC 服务(无需 API 密钥)。任何人都可以运行一个支持相同 relayer_* 方法的备用中继器。
路径 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 浏览器流程(示例 0)、嵌入式钱包直接授权(示例 0b,路径 B1)、嵌入式钱包会话密钥与重新委托(示例 0c,路径 B2)、先估算费用的单链和多链流程、自行赞助、赞助,以及使用 Ed25519 验证的 webhook 接收器。即将编写客户端代码或想要复制经过验证的集成模式时,请阅读此文档。
1shot-wallet技能 — 嵌入 1Shot Wallet(OWS Host Layer)。路径 A 和路径 B 必需;仅用于路径 B 委托执行的配套技能(仅嵌入后直接发送时不需要)。webauthn-prf-wallet技能 — 用于在隔离的 iframe 中持有客户端通行密钥派生 EVM 密钥的配套技能。与此技能搭配使用,可实现完全非托管的设置。- MetaMask Smart Accounts Kit — 安装、浏览器/EIP-7715 流程、本地签名器/委托流程、Advanced Permissions 钱包客户端参考。