关键词:ERC-20 元交易、无 Gas 费交易、以太坊转账、EIP-712、permit 函数、Forwarder 合约、链下签名、重放保护
还在为新钱包光秃秃没有 ETH 而望“空投”兴叹?本指南带你拆解 ERC-20 元交易(也俗称“无 Gas 交易”),手把手说明为什么你无需持有以太币,也能把代币转给别人。
1. Gas 困境:为什么没 ETH 什么都做不了?
在以太坊网络,Gas 费就像汽车的燃油,任何写入型操作都必须付费。
- Gas 单位 = 计算量
- 单价 = gwei(1 gwei = 0.000000001 ETH)
- 每一次 approve、transfer 都会先问你要 ETH
问题在于:空投猎人、DeFi 新手、游戏玩家常常只有代币、没有 ETH——卡在这一步非常痛苦。
2. 元交易是什么?
元交易 = 用户链下签名 + Relay 代付 Gas
- 用户:在本地离线生成一条包含目标动作(如转账)的交易,并用私钥签名,但不广播。
- Relay(运营商):把这条签名消息包装成第二层交易,送到链上并支付实际 Gas。
- 转发合约:验证签名无误后,才真正执行用户的原始指令。
整个过程无需用户拥有 ETH,Relay 会垫付,后续再向用户或项目方结算。
3. ERC-20 的双刃剑:approve + transferFrom
ERC-20 代币之所以流行,是因为它抽象了 授权—转移 两步:
- 用户先调用
approve(spender, amount)授权; - spender 再调用
transferFrom(holder, recipient, amount)实际转账。
然而 approve 本身是 EOA 交易,仍旧需要 ETH。于是「持无 ETH 账号」连第一步都迈不出去。
4. 引入 EIP-2612:permit 一步到位的链下授权
EIP-2612 给标准 ERC-20 增加了 permit(owner, spender, amount, deadline, v, r, s) 函数:
- 用户链下签名授权
- spender 使用链上提交的签名即可一键过户
- 代币持有者 不需再付出任何 Gas
实现要素:
- 签名遵循 EIP-712 结构化哈希标准,MetaMask 与主流钱包 API 原生支持。
- 合约必须实现
_domainSeparator与_hashTypedDataV4,确保不同链、不同合约之间签名不可重放。
5. 实战案例:Forwarder.sol 设计方案
下面给出一套最小可运行的“转发合约”思路:
function verify(ForwardRequest calldata req, bytes calldata sig) public view returns (bool) {
address signer = _hashTypedDataV4(keccak256(abi.encode(
_TYPEHASH,
req.from,
req.to,
req.value,
req.gas,
req.nonce,
keccak256(req.data)
))).recover(sig);
return _nonces[req.from] == req.nonce && signer == req.from;
}
function execute(ForwardRequest calldata req, bytes calldata sig) public payable whenNotPaused {
require(_senderWhitelist[msg.sender], "Forwarder: relayer not whitelisted");
require(verify(req, sig), "Forwarder: invalid signature");
_nonces[req.from]++;
(bool success,) = req.to.call{gas: req.gas, value: req.value}(
abi.encodePacked(req.data, req.from)
);
require(success);
emit MetaTransactionExecuted(req.from, req.to, req.data);
}安全细节:
- nonce 映射:防止同一条签名被二次利用。
- 白名单:项目方可控 Relay 地址,避免恶意机器人滥用。
- 可暂停:紧急事件下冻结转发通道。
- 自毁(killForwarder):合约所有者可在极端情况下销毁合约并退回余额。
👉 想亲自部署测试?这里提供开箱即用脚本与测试网水龙头一键对接。
6. JavaScript 示例:为数据签名
借助 ethers.js + eip-712 库,只需三步完成链下签名:
- 准备域分隔符(Domain & types)。
- 构造 ForwardRequest 数据(from、to、value、gas、nonce、data)。
- 调用
_signTypedData生成 v,r,s 三值,附在permit或execute调用里。
7. 注意事项 & 风险揭底
- 合约尚未审计:主网使用前,务必于 Goerli 或 Sepolia 做全流程测试。
- 100 % 测试覆盖率 ≠ 无漏洞;测试“范围”和“逻辑边界”更关键。
- Relay 中心化:谁来报销 Gas?可考虑引入去中继化的Gas Station Network(GSN)。
8. 常见问题(FAQ)
Q1:如果没有 ETH,矿工或验证者区块打包不就失败了吗?
A:失败的是用户“原始转账”交易,Meta-Transaction 中 Relay 支付 Gas 的那笔父交易正常被打包,所以机制成立。
Q2:签名数据会不会过期?
A:可以在数据里设置 deadline,超过时间窗口前端即可拒绝提交,合约层面同样会校验。
Q3:怎么防止别人盗用我的签名重放?
A:每一次调用 Forwarder 都会让 nonce++,重复用同一 nonce 必定失败。
Q4:permit 适合所有代币吗?
A:必须该代币合约显式植入 permit 方法并遵循 EIP-2612;USDC、DAI 等新版已内置,老合约需手动升级。
Q5:Relay 收费机制怎么做?
A:可在 Forwarder 里加转支付逻辑(用户代币直接扣)。也可项目方补贴,用体验换取留存。GSN 协议提供去中心化的竞价市场。
Q6:跨链、Layer2 也可以用同样的签名吗?
A:EIP-712 会带上 chainId,跨链后域分隔符变化,签名天然失效,确保安全。
9. 下一步行动清单
- 本地仓库 fork 现成 Forwarder 模板,先跑测试网。
- 在 WETH、DAI 等已支持 EIP-2612 的代币上试验
permit消费场景。 - 加入 GSN 或自建中继节点,探索白名单 + 聚合费用的规模化运营。
零 ETH 以太坊转账,已经触手可及。与其等待空投变现,不如今天就把 ERC-20 元交易 玩法装进你的工具箱。