ERC-2770: 元交易转发器合约
Authors | Alex Forshtat (@forshtat), Dror Tirosh (@drortirosh) |
---|---|
Created | 2020-07-01 |
Discussion Link | https://ethereum-magicians.org/t/erc-2770-meta-transactions-forwarder-contract/5391 |
Requires | EIP-712, EIP-2771 |
简述
用于可扩展的元交易转发的标准合约接口。
摘要
本提案定义了一个可扩展的转发器的外部 API,其职责是在链上验证交易签名,并将签名者暴露给目标合约,该合约有望适应所有用例。 转发请求的 ERC-712 结构可以扩展,允许钱包显示可读数据,即使对于在转发器合约部署期间未知的类型。
动机
人们越来越有兴趣使以太坊合约能够接受来自没有 ETH 支付 gas 费用的外部账户的调用。
这可以通过元交易来实现,元交易是由一个外部账户首先签名作为普通数据,然后由另一个账户将其包装到以太坊交易中的交易。
msg.sender
是一个交易参数,合约可以检查该参数以确定谁签署了交易。该参数的完整性由以太坊 EVM 保证,但对于元交易,验证 msg.sender
是不够的,并且还必须恢复签名者地址。
此处描述的转发器合约允许多个 Gas Relays 和 Relay Recipient 合约依赖于签名验证代码的单个实例,从而提高任何参与的元交易框架的可靠性和安全性,并避免链上代码重复。
规范
转发器合约通过接受带签名的类型化数据及其 ERC-712 签名来运行,对传入数据执行签名验证,将签名者地址附加到数据字段并执行对目标的调用。
转发器数据类型注册
请求结构必须按照以下确切顺序包含以下字段:
struct ForwardRequest {
address from;
address to;
uint256 value;
uint256 gas;
uint256 nonce;
bytes data;
uint256 validUntil;
}
from
- 发出请求的外部账户
to
- 目标地址,通常是智能合约
value
- 要转移到目标的以太币数量
gas
- 为执行设置的 gas 限制量
nonce
- 链上跟踪的交易 nonce
data
- 要发送到目标的数据
validUntil
- 可以在其中转发请求的最高区块号,如果请求有效期不受时间限制,则为 0
如果需要,请求结构可以包含任何其他字段,包括嵌套结构。 为了使转发器能够强制执行此结构的字段名称,仅允许注册类型。
注册必须通过调用以下方法提前执行:
function registerRequestType(string typeName, string typeSuffix)
typeName
- 要注册的类型的名称
typeSuffix
- 类型的 ERC-712 兼容描述
例如,在调用
registerRequestType("ExtendedRequest", "uint256 x,bytes z,ExtraData extraData)ExtraData(uint256 a,uint256 b,uint256 c)")
之后,以下 ERC-712 类型将注册到转发器:
/* primary type */
struct ExtendedRequest {
address from;
address to;
uint256 value;
uint256 gas;
uint256 nonce;
bytes data;
uint256 validUntil;
uint256 x;
bytes z;
ExtraData extraData;
}
/* subtype */
struct ExtraData {
uint256 a;
uint256 b;
uint256 c;
}
签名验证
以下方法对请求执行 ERC-712 签名检查:
function verify(
ForwardRequest forwardRequest,
bytes32 domainSeparator,
bytes32 requestTypeHash,
bytes suffixData,
bytes signature
) view;
forwardRequest
- ForwardRequest
结构的实例
domainSeparator
- 调用者提供的域分隔符,以防止跨 dapps 重用签名(请参阅 ERC-712)
requestTypeHash
- 注册的中继请求类型的哈希
suffixData
- 请求结构其余部分的 RLP 编码
signature
- forwardRequest
和 suffixData
连接的 ERC-712 签名
命令执行
为了使转发器执行操作,需要调用以下方法:
function execute(
ForwardRequest forwardRequest,
bytes32 domainSeparator,
bytes32 requestTypeHash,
bytes suffixData,
bytes signature
)
public
payable
returns (
bool success,
bytes memory ret
)
在内部执行 “verify”,如果成功,则执行以下调用:
bytes memory data = abi.encodePacked(forwardRequest.data, forwardRequest.from);
...
(success, ret) = forwardRequest.to.call{gas: forwardRequest.gas, value: forwardRequest.value}(data);
无论内部调用成功还是回退,nonce 都会递增,使签名无效并防止重放请求。
请注意,gas
参数的行为符合 EVM 规则,特别是 EIP-150。转发器在内部验证是否有足够的 gas 用于内部调用。如果 forwardRequest
指定了非零值,则会保留额外的 40000 gas
,以防内部调用恢复或有剩余的以太币,因此需要从 Forwarder
转移价值:
uint gasForTransfer = 0;
if ( req.value != 0 ) {
gasForTransfer = 40000; // buffer in case we need to move Ether after the transaction.
}
...
require(gasleft()*63/64 >= req.gas + gasForTransfer, "FWD: insufficient gas");
如果转发器中没有足够的 value
,则内部调用的执行将失败。
请注意,如果内部调用最终将以太币转移到最初没有 value
的 Forwarder
,则在交易完成后,此以太币将保留在 Forwarder
内部。
ERC-712 和 ‘suffixData’ 参数
suffixData
字段必须提供有效的 ERC-712 类型化数据的“尾部”。
例如,为了对 ExtendedRequest
结构进行签名,数据将是以下块的串联:
forwardRequest
字段将按原样进行 RLP 编码,并且可变长度的data
字段将被哈希uint256 x
将完全按原样附加bytes z
将首先被哈希ExtraData extraData
将被哈希为类型化数据
因此,有效的 suffixData
计算如下:
function calculateSuffixData(ExtendedRequest request) internal pure returns (bytes) {
return abi.encode(request.x, keccak256(request.z), hashExtraData(request.extraData));
}
function hashExtraData(ExtraData extraData) internal pure returns (bytes32) {
return keccak256(abi.encode(
keccak256("ExtraData(uint256 a,uint256 b,uint256 c)"),
extraData.a,
extraData.b,
extraData.c
));
}
接受转发的调用
为了支持通过转发器执行的调用,接收者合约必须从 msg.data
的最后 20 个字节读取签名者地址,如 ERC-2771 中所述。
理由
进一步依赖 msg.sender
通过其外部账户对最终用户进行身份验证正在将以太坊 dapp 生态系统带入死胡同。
用户在可以与任何合约交互之前需要拥有以太币的需求使智能合约的绝大部分用例不可行, 这反过来又限制了大规模采用并强制执行这种恶性循环。
validUntil
字段使用区块号而不是时间戳,以便更好地与其他基于区块的常见计时器进行精确和集成。
安全注意事项
所有引入对转发的请求支持的合约,从而授权此合约在任何帐户下执行任何操作。 至关重要的是,此合约没有漏洞或中心化问题。
版权
版权和相关权利通过 CC0 放弃。
Citation
Please cite this document as:
Alex Forshtat (@forshtat), Dror Tirosh (@drortirosh), "ERC-2770: 元交易转发器合约 [DRAFT]," Ethereum Improvement Proposals, no. 2770, July 2020. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-2770.