零 Gas 交易
Gas Waiver 允许应用程序代表用户支付 Gas。用户使用 gasPrice = 0 签署交易,经治理注册的豁免机制会封装该交易,验证者将以零成本为用户执行调用。本指南将引导您完成一笔符合条件的转账,展示如何验证 Gas 是否已被豁免,并解释豁免所涵盖和不涵盖的范围。
您将构建什么
一个包含两个脚本的流程,通过托管的 Waiver Server 提交 USDT0 转账,获取收据,并确认 gasPrice = 0。
演示
步骤 1. 连接钱包,余额显示 0.01 USDT0
步骤 2. 通过 Gas Waiver 发送交易 → [运行]
步骤 3. 结果
交易哈希: 0x8f3a...2d41
您支付的 Gas 费用: 0.000000 USDT0
交易后余额: 0.01 USDT0豁免适用情况
当以下所有条件都满足时,交易才符合条件:
- 用户使用
gasPrice = 0签署内部交易。 - 提交者是经过治理注册的豁免地址。
- 目标
to地址和方法选择器位于豁免的AllowedTarget策略中。 - 封装交易发送到标记地址
0x000000000000000000000000000000000000f333,且value = 0和gasPrice = 0。
如果其中任何一个失败,验证者将拒绝封装交易,而不执行内部调用。未在 AllowedTarget 中列出的合约调用不受涵盖。任意的自助豁免是不可能的;每个豁免都必须通过验证者治理进行注册。
先决条件
- Stable 团队颁发的 Waiver Server API 密钥。
- 目标合约地址和方法选择器已在豁免的
AllowedTarget策略上注册。 - 测试网上拥有用户钱包,无需 USDT0 用于 Gas。
步骤 1:签署符合条件的 InnerTx
用户使用 gasPrice = 0 签署标准交易。在此示例中,调用是 USDT0 transfer,这是应用程序涵盖的 Gas 流的常见 AllowedTarget。
// config.ts
import { ethers } from "ethers";
import "dotenv/config";
export const CONFIG = {
RPC_URL: "https://rpc.testnet.stable.xyz",
CHAIN_ID: 2201, // 988 for mainnet
WAIVER_SERVER: "https://waiver.testnet.stable.xyz",
USDT0_ADDRESS: "0x78Cf24370174180738C5B8E352B6D14c83a6c9A9",
};
export const provider = new ethers.JsonRpcProvider(CONFIG.RPC_URL);
export const userWallet = new ethers.Wallet(process.env.USER_PRIVATE_KEY!, provider);// signInner.ts
import { ethers } from "ethers";
import { CONFIG, provider, userWallet } from "./config";
const usdt0 = new ethers.Contract(CONFIG.USDT0_ADDRESS, [
"function transfer(address to, uint256 amount) returns (bool)"
], provider);
const callData = usdt0.interface.encodeFunctionData("transfer", [
"0xRecipientAddress",
ethers.parseUnits("0.001", 18),
]);
const gasLimit = await provider.estimateGas({
from: userWallet.address,
to: CONFIG.USDT0_ADDRESS,
data: callData,
});
const nonce = await provider.getTransactionCount(userWallet.address);
const innerTx = {
to: CONFIG.USDT0_ADDRESS,
data: callData,
value: 0,
gasPrice: 0,
gasLimit,
nonce,
chainId: CONFIG.CHAIN_ID,
};
export const signedInnerTx = await userWallet.signTransaction(innerTx);
console.log("Signed InnerTx:", signedInnerTx);npx tsx signInner.tsSigned InnerTx: 0xf8a8...c1步骤 2:通过 Waiver Server 提交
Waiver Server 会封装签名的内部交易并广播它。您需要一个服务器颁发的 API 密钥。
// submit.ts
import { CONFIG } from "./config";
import { signedInnerTx } from "./signInner";
const response = await fetch(`${CONFIG.WAIVER_SERVER}/v1/submit`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.WAIVER_API_KEY}`,
},
body: JSON.stringify({ transactions: [signedInnerTx] }),
});
const reader = response.body!.getReader();
const decoder = new TextDecoder();
let txHash = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
for (const line of decoder.decode(value).trim().split("\n")) {
const result = JSON.parse(line);
if (result.success) {
txHash = result.txHash;
console.log(`tx confirmed: ${txHash}`);
} else {
console.error(`tx failed: ${result.error.message}`);
}
}
}
export { txHash };npx tsx submit.tstx confirmed: 0x8f3a...2d41步骤 3:验证收据显示零 Gas
获取收据并确认 effectiveGasPrice 为 0。这是用户未支付 Gas 的加密证据。
// verify.ts
import { provider } from "./config";
import { txHash } from "./submit";
const receipt = await provider.getTransactionReceipt(txHash);
const gasUsed = receipt!.gasUsed;
const effectiveGasPrice = receipt!.gasPrice;
const totalFee = gasUsed * effectiveGasPrice;
console.log("Gas used: ", gasUsed.toString());
console.log("Effective gas price:", effectiveGasPrice.toString());
console.log("Gas fee paid: ", `${totalFee.toString()} USDT0 (wei-equivalent)`);npx tsx verify.tsGas used: 21000
Effective gas price: 0
Gas fee paid: 0 USDT0 (wei-equivalent)effectiveGasPrice 为 0 确认交易是在已注册的豁免下执行的,并且未向用户收取费用。
Gas Waiver 不涵盖的范围
AllowedTarget之外的合约:任意合约调用不在此列。每个目标都通过治理按豁免范围确定。- 用户提交的封装交易:如果用户直接提交给
0x...f333,则会失败。只有注册的豁免地址才能进行封装。 - 费用提取:验证者不接受内部或封装交易中的非零
gasPrice。
有关完整的策略模型和每个豁免的范围规则,请参阅Gas 豁免协议。
下一步建议
- 集成 Waiver Server:完整的 API 参考、批量提交、错误代码和 NDJSON 流。
- 自托管 Gas Waiver:注册您自己的豁免地址,无需托管 API 即可广播封装交易。
- Gas 豁免协议:阅读完整规范:标记路由、封装格式、治理控制。

