Meta交易 - OpenZeppelin 文档

本文档介绍了Meta Transactions,即从交易发起者抽象执行上下文的能力,遵循ERC-2771规范。主要介绍了ERC2771Context和ERC2771Forwarder两个合约,分别用于重写执行上下文的发送者和calldata,以及实现一个生产级别的转发器,用于转发由EOA离线签名的操作请求。文档还详细说明了每个合约的函数、事件、错误以及安全考虑。

Meta Transactions (元交易)

建议在 https://docs.openzeppelin.com/contracts/api/metatx 上查看此文档

此目录包含用于添加元交易功能(即,从交易发起方抽象执行上下文)的合约,遵循 ERC-2771 规范

  • ERC2771Context: 提供一种机制,通过受信任的转发器指定的自定义值来覆盖执行上下文的发送者和calldata(msg.sendermsg.data)。

  • ERC2771Forwarder: 一个生产就绪的转发器,它转发由 EOA 链下签名的操作请求。

Core (核心)

ERC2771Context

import "@openzeppelin/contracts/metatx/ERC2771Context.sol";

具有 ERC-2771 支持的上下文变体。

避免在依赖于特定calldata长度的合约中使用此模式,因为它们会受到任何转发器的影响,转发器的 msg.data 根据 ERC-2771 规范以 from 地址作为后缀,将地址大小(以字节为单位,20)添加到calldata大小。 一个意想不到的行为的例子可能是尝试调用 receive 函数时,意外地调用了回退函数(或其他函数),只有当 msg.data.length == 0 时才能访问 receive 函数。
在此合约中使用 delegatecall 是危险的,可能会导致上下文损坏。<br>转发到此合约的任何请求触发对自身的 delegatecall,都将导致无效的 _msgSender<br>恢复。

函数

constructor(address trustedForwarder_) internal
trustedForwarder() → address public

返回受信任转发器的地址。

isTrustedForwarder(address forwarder) → bool public

指示任何特定地址是否为受信任的转发器。

_msgSender() → address internal

msg.sender 的覆盖。 只要调用不是由受信任的转发器执行的,或者calldata长度小于 20 字节(地址长度),则默认为原始 msg.sender

_msgData() → bytes internal

msg.data 的覆盖。 只要调用不是由受信任的转发器执行的,或者calldata长度小于 20 字节(地址长度),则默认为原始 msg.data

_contextSuffixLength() → uint256 internal

ERC-2771 指定上下文作为单个地址(20 字节)。

Utils (实用工具)

ERC2771Forwarder

import "@openzeppelin/contracts/metatx/ERC2771Forwarder.sol";

与 ERC-2771 合约兼容的转发器。 参见 ERC2771Context

此转发器对包含以下内容的转发请求进行操作:

  • from: 代表其进行操作的地址。 它必须等于请求签名者。

  • to: 应该调用的地址。

  • value: 要附加到请求调用的原生代币的数量。

  • gas: 将随请求的调用一起转发的 gas 限制量。

  • nonce: 唯一的交易排序标识符,用于避免重放性和请求失效。

  • deadline: 请求不再可执行的时间戳。

  • data: 要随请求的调用一起发送的编码 msg.data

如果 Relayer 正在处理大量请求,则能够提交批处理。 通过高 吞吐量,Relayer 可能会遇到链的限制,例如mempool中交易数量的限制。 在这些情况下,建议在多个帐户之间分配负载。

批处理请求包括一个可选的未使用 msg.value 的退款,这是通过调用空calldata实现的。 虽然这在 ERC-2771 合规性的范围内,但如果退款接收者碰巧认为转发器是受信任的转发器,则它必须正确处理 msg.data.length == 0。 OpenZeppelin Contracts 4.9.3 之前的版本中的 ERC2771Context 无法正确处理此问题。
Security Considerations (安全注意事项)

如果 Relayer 提交转发请求,它应该愿意支付请求中指定的 gas 量的 100%。 此合约未对此 gas 实施任何形式的补偿,并且假定存在链外激励,鼓励 Relayer 代表签名者支付执行费用。 通常,Relayer 由一个项目运营,该项目将这视为用户获取成本。

通过提供 gas 费用支付,Relayer 有可能让攻击者将 gas 用于与预期链外激励不符的其他目的。 如果你运行 Relayer,请考虑将目标合约和函数选择器列入白名单。 在专门转发 ERC-721 或 ERC-1155 时,请考虑拒绝使用 data 字段,因为它可用于执行任意代码。

函数

Nonces (随机数)

EIP712

Events (事件)

IERC5267

Errors (错误)

Nonces (随机数)

Internal Variables (内部变量)

constructor(string name) public

参见 EIP712.constructor

verify(struct ERC2771Forwarder.ForwardRequestData request) → bool public

如果在当前块时间戳下,请求对于提供的 signature 有效,则返回 true

当目标信任此转发器、请求未过期(未达到deadline),并且签名者与签名请求的 from 参数匹配时,交易被认为是有效的。

请求可能在此处返回 false,但如果提供退款接收者,则不会导致 executeBatch 还原。
execute(struct ERC2771Forwarder.ForwardRequestData request) public

使用 ERC-2771 协议代表 `signature’s signer 执行 request。 提供给请求调用的 gas 可能不完全是请求的量,但调用不会耗尽 gas。 如果请求无效或调用还原,则将还原,在这种情况下,不会消耗nonce。

要求:

  • 请求值应等于提供的 msg.value

  • 根据 verify,请求应有效。

executeBatch(struct ERC2771Forwarder.ForwardRequestData[] requests, address payable refundReceiver) public

具有可选退款和原子执行的 execute 的批量版本。

如果批处理包含至少一个无效请求(参见 verify), 将跳过该请求,并且 refundReceiver 参数将在执行结束时收到未使用的请求值。 这样做是为了防止在请求无效或已提交时还原整个批处理。

如果 refundReceiveraddress(0),则当至少一个请求无效时,此函数将还原,而不是跳过它。 如果需要以原子方式执行批处理(至少在顶层),这可能很有用。 例如,如果 Relayer 正在使用一种避免包含已还原交易的服务,则可以opt-out退款(因此原子性)。

要求:

  • 请求的值的总和应等于提供的 msg.value

  • refundReceiver 为零地址时,所有请求都应有效(参见 verify)。

仅对于第一级转发调用,设置零 refundReceiver 保证了全有或全无的请求执行。 如果转发的请求通过另一个子调用调用合约,则第二级调用可能会在没有顶层调用还原的情况下还原。
_validate(struct ERC2771Forwarder.ForwardRequestData request) → bool isTrustedForwarder, bool active, bool signerMatch, address signer internal

验证是否可以在当前块时间戳下,代表 request.signer 使用给定的 request.signature 执行所提供的请求。

_recoverForwardRequestSigner(struct ERC2771Forwarder.ForwardRequestData request) → bool isValid, address signer internal

返回一个元组,其中包含 EIP712 转发请求消息哈希的已恢复签名者和一个布尔值,指示签名是否有效。

如果 ECDSA.tryRecover 指示没有恢复错误,则认为签名有效。
_execute(struct ERC2771Forwarder.ForwardRequestData request, bool requireValidRequest) → bool success internal

验证并执行签名请求,返回请求调用的 success 值。

没有 msg.value 验证的内部函数。

要求:

  • 调用者必须提供足够的 gas 才能通过调用进行转发。

  • 如果 requireValidRequest 为 true,则请求必须有效(参见 verify)。

发出 ExecutedForwardRequest 事件。

使用此函数不会检查是否已发送所有 msg.value,可能会导致 value 卡在合约中。
_isTrustedByTarget(address target) → bool internal

返回目标是否信任此转发器。

此函数对目标合约执行静态调用,调用 ERC2771Context.isTrustedForwarder 函数。

请考虑此转发器的执行是免许可的。 如果没有此检查,任何人都可以转移由此转发器拥有或批准的资产。
ExecutedForwardRequest(address indexed signer, uint256 nonce, bool success) event

当执行 ForwardRequest 时发出。

转发请求不成功可能是由于签名无效、deadline 过期,或者只是请求的调用还原。 合约保证 Relayer 无法强制请求的调用耗尽 gas。
ERC2771ForwarderInvalidSigner(address signer, address from) error

请求的 from 与恢复的 signer 不匹配。

ERC2771ForwarderMismatchedValue(uint256 requestedValue, uint256 msgValue) error

requestedValue 与可用的 msgValue 不匹配。

ERC2771ForwarderExpiredRequest(uint48 deadline) error

请求的 deadline 已过期。

ERC2771UntrustfulTarget(address target, address forwarder) error

请求目标不信任 forwarder

bytes32 _FORWARD_REQUEST_TYPEHASH internal constant

← 接口

Proxy →

  • 原文链接: docs.openzeppelin.com/co...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
OpenZeppelin
OpenZeppelin
江湖只有他的大名,没有他的介绍。