Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

使用 Gas 代付中继

使用 @stablechain/enterprise 赞助您用户的 gas。白名单中的代付账户会包装用户的零 gas 交易(内部交易),并将其广播,这样用户就可以在不持有任何 USDT0 的情况下进行交易。gasWaiver 模块在一个调用中构建、签名和中继,因此您每个操作只需调用一个方法。

每个方法都返回 H_inner,即用户交易的哈希,而不是携带它的包装器。

先决条件

  • Node.js 20 或更高版本,并安装了 @stablechain/enterpriseviem。请参阅 Enterprise SDK 参考
  • 治理注册的代付密钥。Enterprise SDK 在 Stable 主网和 Stable 测试网上运行,访问受限:联系 Stable 获取白名单代付密钥。

1. 使用 Gas 代付模块创建客户端

gasWaiver: { account } 传递给 createStableEnterprise,其中 account 是您的白名单代付密钥。只有在配置后,模块才会在客户端上出现。

import { createStableEnterprise, stable } from "@stablechain/enterprise";
import { privateKeyToAccount } from "viem/accounts";
 
const enterprise = createStableEnterprise({
  chain: stable,
  gasWaiver: { account: privateKeyToAccount(process.env.WAIVER_PRIVATE_KEY as `0x${string}`) },
});
 
const gw = enterprise.gasWaiver;
StableEnterpriseClient { gasWaiver, guaranteedBlock: undefined, guaranteedWaiver: undefined }

rpcEndpoints 选项是可选的。如果不设置,客户端将使用链的内置 RPC。

2. 中继单个交易

使用用户账户和变化的字段调用 sendgasPrice: 0、遗留类型、chainId 和待处理 nonce 都已为您处理,因此您只需传递 to,以及可选的 datavaluegas

const user = privateKeyToAccount(process.env.USER_PRIVATE_KEY as `0x${string}`);
 
const { txHash } = await gw.send(user, { to: token, data, gas: 150_000n });
console.log("H_inner:", txHash);
H_inner: 0x8f3a...2d41

用户不需要 USDT0:代付账户赞助 gas。gas 默认为 150_000n (DEFAULT_INNER_GAS),足以覆盖代币转账或批准。对于更繁重的调用,请传递明确的 gas

3. 中继批处理

调用 sendBatch 中继来自一个账户的多个交易。Nonce 会从账户的待处理 nonce 自动排序,并且您会按照输入顺序获得每个输入的单个结果。

const results = await gw.sendBatch(user, [
  { to: token, data: dataA, gas: 150_000n },
  { to: token, data: dataB, gas: 150_000n },
]);
 
for (const r of results) {
  console.log(r.success ? `[${r.index}] ✔ ${r.txHash}` : `[${r.index}] ✖ ${r.error?.code}`);
}
[0] ✔ 0x8f3a...2d41
[1] ✔ 0x2b7c...9e04

批处理会根据 result.error 报告每个项目的失败,而不是抛出异常,因此一个糟糕的交易不会导致其余交易失败。

4. 执行每个合作伙伴的策略限制

通过在配置中添加策略限制来限制代付密钥可以赞助的内容。违反限制的内部交易会在广播前被拒绝。

const enterprise = createStableEnterprise({
  chain: stable,
  gasWaiver: {
    account: privateKeyToAccount(process.env.WAIVER_PRIVATE_KEY as `0x${string}`),
    maxGasLimit: 500_000n,
    maxDataLength: 4_096,
    allowedTargets: [
      { address: token, selectors: ["0xa9059cbb"] }, // 仅限 ERC-20 传输
    ],
  },
});

目标合约不在 allowedTargets 中的交易将因 TARGET_NOT_ALLOWED 而失败;超过 maxGasLimit 的交易将因 GAS_LIMIT_EXCEEDED 而失败。使用 "*" 作为 address 允许任何合约,省略 selectors 允许任何方法。

5. 中继预签名交易

对于非托管流程,用户在其自己的环境中签署内部交易,并只将签名的十六进制字符串交给您,因此您永远不会看到他们的密钥。使用 buildWaiverInnerTx 构建它,然后使用 relay 中继它。

import { buildWaiverInnerTx, toSigner } from "@stablechain/enterprise";
 
// 在用户端 — buildWaiverInnerTx 通过 Signer 签名;toSigner 适配 viem 账户
const signed = await buildWaiverInnerTx(toSigner(user), stable.id, { to: token, data, gas: 150_000n, nonce });
 
// 在您的后端
const { txHash } = await gw.relay(signed);
console.log("H_inner:", txHash);
H_inner: 0x8f3a...2d41

对于多个预签名交易,请使用 relayBatch,它会像 sendBatch 一样为每个输入返回一个结果。

处理拒绝

sendrelay 在拒绝时会抛出 StableEnterpriseRelayError,其中包含一个您可以进行分支判断的 code

import { StableEnterpriseRelayError } from "@stablechain/enterprise";
 
try {
  await gw.send(user, { to: token, data });
} catch (err) {
  if (err instanceof StableEnterpriseRelayError && err.code === "TARGET_NOT_ALLOWED") {
    // 内部交易目标不在配置的允许列表中
  }
  throw err;
}
StableEnterpriseRelayError: relay failed [TARGET_NOT_ALLOWED]: target 0x... not allowed

有关所有拒绝原因的完整信息,请参阅完整的 ErrorCode 表。

后续步骤