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 豁免协议

本文档规定了 Gas 豁免机制:交易格式、标记路由、治理控制以及 Waiver Server API。

摘要

Gas 豁免通过允许一小组经治理批准的地址(“waivers”)提交 gasPrice = 0 的交易,从而在 Stable 上实现面向最终用户的免 Gas 交易。Stable 目前运营一项 waiver 服务(“Waiver Server”),你可以与其集成,以在无需实现特定于协议的封装逻辑的情况下提供免 Gas 的用户体验。

范围

本规范涵盖:

  • gas 豁免交易的协议级规则
  • 封装交易机制和标记地址
  • 治理控制的授权与允许的目标
  • 用于提交已签名用户交易的 Waiver Server 接口

定义

  • Waiver:通过验证者治理在链上注册的以太坊地址,被授权提交 gas 豁免交易。
  • InnerTx:最终用户签名的、gasPrice = 0 的交易。
  • WrapperTx:由 waiver 签名的交易,将用户的 InnerTx 传输到链上并授权执行。
  • Marker address(标记地址):用于识别 waiver 封装交易的哨兵地址:0x000000000000000000000000000000000000f333
  • AllowedTarget:将 waiver 限制为特定合约地址和方法选择器的策略。

概述

Gas 豁免使用封装交易模式:

  1. 用户签名一笔 gasPrice = 0InnerTx
  2. waiver 将 InnerTx 封装为 WrapperTx 并广播。
  3. 验证者检测标记交易,验证 waiver 授权和策略约束,然后执行内嵌的 InnerTx

Stable 运营一项 waiver 服务(Waiver Server),它在链上注册为经授权的 waiver。你与 Waiver Server API 集成以提交已签名的 InnerTx 载荷。

协议规范

标记地址路由

当且仅当满足以下条件时,交易才被视为 waiver 封装交易:

  • to == 0x000000000000000000000000000000000000f333

协议将交易的 data 字段解释为编码后的内部交易载荷,并使用下面的 waiver 验证规则对其进行处理。

授权与策略检查

对于每个候选封装交易,验证者必须强制执行:

  1. Waiver 授权
    • WrapperTx.from 必须是通过治理在链上注册的 waiver 地址。
  2. Gas 豁免
    • WrapperTx.gasPrice 必须等于 0
    • InnerTx.gasPrice 必须等于 0
  3. 目标允许列表
    • InnerTx.to 以及从 InnerTx.data 中提取的方法选择器必须被 waiver 的 AllowedTarget 策略允许。
  4. Value 限制
    • WrapperTx.value 必须等于 0

如果任何检查失败,验证者将拒绝封装交易,且不执行内部交易。

执行语义

如果所有检查均通过:

  1. 协议以用户身份执行 InnerTx,保留用户的 fromnonce 和调用语义。
  2. Gas 计费由 waiver 机制处理:用户不支付 gas,且根据该功能的定义,waiver 交易使用 gasPrice = 0
  3. 封装交易必须提供足够的 gasLimit 以覆盖 InnerTx 的执行(包括解封装和验证的开销)。

交易格式

WrapperTx

封装交易由 waiver 签名并发送到标记地址。

WrapperTx {
  from:     waiver_address,
  to:       0x000000000000000000000000000000000000f333,
  value:    0,                          // must be zero
  data:     RLP(InnerTx),               // RLP-encoded inner transaction
  gasPrice: 0,                          // must be zero
  gasLimit: sufficient_for_inner,       // must cover inner execution + overhead
  nonce:    waiver_nonce
}

InnerTx

内部交易由最终用户签名。

InnerTx {
  from:     user_address,
  to:       target_contract,
  value:    value,
  data:     call_data,
  gasPrice: 0,                          // must be zero
  gasLimit: execution_gas,
  nonce:    user_nonce
}

治理控制的访问

Waiver 授权由验证者治理在链上管理。

治理控制提供:

  • 可审查的 waiver 地址授权
  • waiver 注册和更新的链上透明度
  • 撤销能力
  • 通过 AllowedTarget 进行的按 waiver 范围限定

安全模型

最终用户签名完整性

用户签名 InnerTx。waiver 无法在不使签名失效的情况下修改内部交易载荷。你仍必须确保用户仅签名预期的交易载荷。

信任边界

如果合作伙伴通过 Waiver Server 路由提交,则 Gas 豁免会引入一个服务依赖:

  • 服务的可用性会影响提交免 Gas 交易的能力。
  • 授权仍保留在链上;只有已注册的 waiver 地址才能产生有效的封装提交。

集成

你通过以下方式集成:

  1. 从用户处收集已签名的 InnerTxgasPrice = 0)。
  2. 将已签名的内部交易提交到 Waiver Server API。
  3. 处理流式返回的结果并向最终用户展示交易哈希。

Waiver server

概述

Waiver Server 将已签名的用户 InnerTx 载荷封装并广播为经 waiver 授权的封装交易。你无需构造封装交易或运营 waiver 地址。

端点和基础 URL

基础 URL:

  • 主网:TBD
  • 测试网:https://waiver.testnet.stable.xyz

认证

除健康检查外,所有端点都需要 bearer token 认证:

Authorization: Bearer <your-api-key>

API

GET /v1/health

健康检查端点。

认证:无。

POST /v1/submit

提交一批已签名的内部交易。

认证:必需(Bearer)。

请求体:

{
  "transactions": ["0x<signedInnerTx1>", "0x<signedInnerTx2>"]
}

响应以 NDJSON(换行分隔的 JSON)流式返回。每一行对应一个已提交交易的索引。

示例:

{"index":0,"id":"abc123","success":true,"txHash":"0x..."}
{"index":1,"id":"def456","success":false,"error":{"code":"VALIDATION_FAILED","message":"invalid signature"}}

GET /v1/submit

用于流式提交的 WebSocket 接口。

认证:必需(Bearer)。

集成示例

const WAIVER_SERVER = "https://waiver.testnet.stable.xyz";
 
async function submitGaslessTransaction(signedInnerTxHex, apiKey) {
  const response = await fetch(`${WAIVER_SERVER}/v1/submit`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${apiKey}`,
    },
    body: JSON.stringify({
      transactions: [signedInnerTxHex],
    }),
  });
 
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
 
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
 
    const lines = decoder.decode(value).trim().split("\n");
    for (const line of lines) {
      const result = JSON.parse(line);
      console.log(result);
    }
  }
}

创建用户 InnerTx

你负责构造一个 gasPrice = 0InnerTx,然后收集用户签名。

示例:

import { ethers } from "ethers";
 
async function createInnerTx(userWallet, contractAddress, callData, nonce) {
  const innerTx = {
    to: contractAddress,
    data: callData,
    value: value,
    gasPrice: 0,              // must be 0 for waiver
    gasLimit: 100000,
    nonce: nonce,
    chainId: 2201,            // 988 for mainnet, 2201 for testnet
  };
 
  return await userWallet.signTransaction(innerTx);
}

错误码

  • PARSE_ERROR:解析交易失败
  • INVALID_REQUEST:请求体格式错误
  • BATCH_SIZE_EXCEEDED:批量大小超过允许的最大值
  • VALIDATION_FAILED:交易验证失败
  • BROADCAST_FAILED:广播到链上失败
  • RATE_LIMITED:超出速率限制
  • QUEUE_FULL:服务器队列已满
  • TIMEOUT:请求超时

推荐的后续内容

  • 零 Gas 交易 — 以演示为重点的操作演练,附带显示零 Gas 费用的收据。
  • 启用免 Gas 交易 — 完整的托管 API 集成指南,包含批量提交和错误处理。
  • 自托管 Gas 豁免 — 在不使用托管 API 的情况下运行你自己的 waiver 基础设施。