Gas Station Network (GSN) - OpenZeppelin 文档

本文档介绍了 OpenZeppelin Gas Station Network (GSN) 库,它提供了一组合约,允许合约通过 GSN 被调用,实现 gasless 交易。

你当前阅读的不是此文档的最新版本。5.x 是当前版本。

Gas Station Network (GSN)

更好的阅读方式:https://docs.openzeppelin.com/contracts/api/gsn

这组合约提供了通过 Gas Station Network 使合约可调用的所有必要工具。

如果你是 GSN 的新手,请前往我们的系统概述创建支持 GSN 的合约的基本指南。

接收者必须继承的核心合约是 GSNRecipient:它包括所有必要的接口,以及一些辅助方法,使与 GSN 的交互更容易。

GSNRecipient 中提供了使编写 GSN 策略 变得简单的实用程序,或者你可以简单地使用我们预先构建的策略之一:

你还可以查看构成 GSN 协议的两个合约接口:IRelayRecipientIRelayHub,但你不需要直接使用它们。

接收者

GSNRecipient

基础 GSN 接收者合约:包括 IRelayRecipient 接口,并在继承树中的所有合约上启用 GSN 支持。

这个合约是抽象的。函数 IRelayRecipient.acceptRelayedCall,<br> _preRelayedCall, 和 _postRelayedCall 没有实现,必须由派生合约提供。有关如何使用预构建的 GSNRecipientSignature 和<br>GSNRecipientERC20Fee,或如何编写你自己的,请参阅<br>GSN 策略

函数

IRelayRecipient

事件

getHubAddr() → address public

返回此接收者的 IRelayHub 合约的地址。

_upgradeRelayHub(address newRelayHub) internal

切换到新的 IRelayHub 实例。添加此方法是为了面向未来:没有理由不使用默认实例。

升级后,GSNRecipient 将无法再从旧的<br>IRelayHub 实例接收中继调用。此外,所有资金应事先通过 _withdrawDeposits 提取。
relayHubVersion() → string public

返回构建此接收者实现的 IRelayHub 的版本字符串。如果使用了 _upgradeRelayHub,则新的 IRelayHub 实例应与此版本兼容。

_withdrawDeposits(uint256 amount, address payable payee) internal

提取接收者在 RelayHub 中的存款。

派生合约应在具有适当访问控制的外部接口中公开此功能。

_msgSender() → address payable internal

替换 msg.sender。返回交易的实际发送者:常规交易的 msg.sender,GSN 中继调用的最终用户(其中 msg.sender 实际上是 RelayHub)。

GSNRecipient 派生的合约永远不应使用 msg.sender,而应使用 _msgSender 代替。
_msgData() → bytes internal

替换 msg.data。返回交易的实际 calldata:常规交易的 msg.data,GSN 中继调用的简化版本(其中 msg.data 包含附加信息)。

GSNRecipient 派生的合约永远不应使用 msg.data,而应使用 _msgData 代替。
preRelayedCall(bytes context) → bytes32 public

参见 IRelayRecipient.preRelayedCall

不应直接覆盖此函数,而应使用 _preRelayedCall 代替。

  • 要求:

  • 调用者必须是 RelayHub 合约。

_preRelayedCall(bytes context) → bytes32 internal

参见 IRelayRecipient.preRelayedCall

GSNRecipient.preRelayedCall 调用,后者断言调用者是 RelayHub 合约。派生合约必须实现此函数,并执行它们可能希望执行的任何中继调用预处理。

postRelayedCall(bytes context, bool success, uint256 actualCharge, bytes32 preRetVal) public

参见 IRelayRecipient.postRelayedCall

不应直接覆盖此函数,而应使用 _postRelayedCall 代替。

  • 要求:

  • 调用者必须是 RelayHub 合约。

_postRelayedCall(bytes context, bool success, uint256 actualCharge, bytes32 preRetVal) internal

参见 IRelayRecipient.postRelayedCall

GSNRecipient.postRelayedCall 调用,后者断言调用者是 RelayHub 合约。派生合约必须实现此函数,并执行它们可能希望执行的任何中继调用后处理。

_approveRelayedCall() → uint256, bytes internal

在 acceptRelayedCall 中返回此值以继续执行中继调用。请注意,此合约将被 RelayHub 收取费用

_approveRelayedCall(bytes context) → uint256, bytes internal

参见 GSNRecipient._approveRelayedCall

此重载将 context 转发到 _preRelayedCall 和 _postRelayedCall。

_rejectRelayedCall(uint256 errorCode) → uint256, bytes internal

在 acceptRelayedCall 中返回此值以阻止执行中继调用。不会收取任何费用。

_computeCharge(uint256 gas, uint256 gasPrice, uint256 serviceFee) → uint256 internal
RelayHubChanged(address oldRelayHub, address newRelayHub) event

当合约将其 IRelayHub 合约更改为新合约时发出。

策略

GSNRecipientSignature

GSN 策略 随附受信任签名者的签名时,允许通过中继交易。目的是让此签名由在链下执行验证的服务器生成。请注意,在此方案中不会向用户收取任何费用。因此,服务器应确保在其经济和威胁模型中考虑这一点。

函数

GSNRecipient

事件

GSNRecipient

constructor(address trustedSigner) public

设置将生成签名以批准中继调用的受信任签名者。

acceptRelayedCall(address relay, address from, bytes encodedFunction, uint256 transactionFee, uint256 gasPrice, uint256 gasLimit, uint256 nonce, bytes approvalData, uint256) → uint256, bytes public

确保只有具有受信任签名的交易才能通过 GSN 中继。

_preRelayedCall(bytes) → bytes32 internal
_postRelayedCall(bytes, bool, uint256, bytes32) internal

GSNRecipientERC20Fee

GSN 策略 以特殊用途的 ERC20 token 收取交易费用,我们将其称为 gas 支付 token。收取的金额恰好是向接收者收取的以太币金额。这意味着 token 本质上与以太币的价值Hook。

gas 支付 token 向用户分发的策略不是由本合约定义的。它是一个可铸造的 token,其唯一的铸币者是接收者,因此必须在派生合约中实现该策略,并利用内部 _mint 函数。

函数

GSNRecipient

事件

GSNRecipient

constructor(string name, string symbol) public

构造函数的参数是 gas 支付 token 将具有的详细信息:namesymboldecimals 硬编码为 18。

token() → contract __unstable__ERC20Owned public

返回 gas 支付 token

_mint(address account, uint256 amount) internal

铸造 gas 支付 token 的内部函数。派生合约应在其公共 API 中公开此函数,并具有适当的访问控制机制。

acceptRelayedCall(address, address from, bytes, uint256 transactionFee, uint256 gasPrice, uint256, uint256, bytes, uint256 maxPossibleCharge) → uint256, bytes public

确保只有具有足够 gas 支付 token 余额的用户才能通过 GSN 中继交易。

_preRelayedCall(bytes context) → bytes32 internal

实现对用户的预收费。最大可能的费用(取决于 gas 限制、gas 价格和费用)将从 gas 支付 token 的用户余额中扣除。请注意,这是对实际费用的高估,这是必要的,因为我们无法预测执行实际需要多少 gas。剩余部分将在 _postRelayedCall 中返回给用户。

_postRelayedCall(bytes context, bool, uint256 actualCharge, bytes32) internal

一旦知道实际执行成本,就会将先前收取的额外金额退还给用户。

协议

IRelayRecipient

将通过来自 IRelayHub 的 GSN 调用的合约的基本接口。

你不需要自己编写实现!改为从 GSNRecipient 继承。

函数

getHubAddr() → address external

返回此接收者与之交互的 IRelayHub 实例的地址。

acceptRelayedCall(address relay, address from, bytes encodedFunction, uint256 transactionFee, uint256 gasPrice, uint256 gasLimit, uint256 nonce, bytes approvalData, uint256 maxPossibleCharge) → uint256, bytes external

IRelayHub 调用以验证此接收者是否接受为中继调用付费。请注意,无论中继调用的执行结果如何(即,如果它恢复与否),都将向接收者收费。

中继请求由 from 发起,并将由 relay 提供服务。encodedFunction 是中继调用的 calldata,因此它的前四个字节是函数选择器。中继调用将转发 gasLimit gas,并且交易将以至少 gasPrice 的 gas 价格执行。relay 的费用是 transactionFee,接收者将被收取最多 maxPossibleCharge(以 wei 为单位)。nonce 是发件人(from)的 nonce,用于在 IRelayHub 中防止重放攻击,approvalData 是一个可选参数,可用于保存对所有或部分先前值的签名。

返回一个元组,其中第一个值用于指示批准 (0) 或拒绝(自定义非零错误代码,保留值 1 到 10),第二个值是要传递给其他 IRelayRecipient 函数的数据。

acceptRelayedCall 被调用时有 50k gas:如果执行期间耗尽,则该请求将被视为拒绝。常规恢复也会触发拒绝。

preRelayedCall(bytes context) → bytes32 external

IRelayHub 在批准的中继调用请求上调用,在中继调用执行之前。这允许例如预先向交易发送者收费。

contextacceptRelayedCall 的元组返回的第二个值。

返回要传递给 postRelayedCall 的值。

preRelayedCall 被调用时有 100k gas:如果执行期间耗尽或以其他方式恢复,则不会执行中继调用,但接收者仍将被收取交易成本。

postRelayedCall(bytes context, bool success, uint256 actualCharge, bytes32 preRetVal) external

IRelayHub 在批准的中继调用请求上调用,在中继调用执行之后。这允许例如向用户收取中继调用成本,从 preRelayedCall 返回任何多收费用,或执行特定于合约的记账。

contextacceptRelayedCall 的元组返回的第二个值。success 是中继调用的执行状态。actualCharge 是对接收者将为交易支付多少费用的估计,不包括 postRelayedCall 本身使用的任何 gas。preRetValpreRelayedCall 的返回值。

postRelayedCall 被调用时有 100k gas:如果执行期间耗尽或以其他方式恢复,则中继调用和对 preRelayedCall 的调用将被追溯恢复,但接收者仍将被收取交易成本。

IRelayHub

RelayHub 的接口,GSN 的核心合约。用户不应需要直接与此合约交互。

有关如何在本地测试网络上部署 RelayHub 实例的更多信息,请参阅 OpenZeppelin GSN helpers

函数

事件

stake(address relayaddr, uint256 unstakeDelay) external

向一个 relay 添加 stake 并设置它的 unstakeDelay。如果该 relay 不存在,则创建它,并且此函数的调用者成为其所有者。如果该 relay 已经存在,则只有所有者可以调用此函数。一个 relay 不能是它自己的所有者。

此函数调用中的所有 Ether 都将被添加到 relay 的 stake 中。 它的 unstake delay 将被分配给 unstakeDelay,但新值必须大于或等于当前值。

发出一个 Staked 事件。

registerRelay(uint256 transactionFee, string url) external

将调用者注册为一个 relay。 该 relay 必须已经 stake,并且不能是合约(即,此函数必须直接从一个 EOA 调用)。

此函数可以被多次调用,发出新的 RelayAdded 事件。请注意,接收到的 transactionFee 不会被 relayCall 强制执行。

发出一个 RelayAdded 事件。

removeRelayByOwner(address relay) external

移除(注销)一个 relay。未注册(但已 stake)的 relay 也可以被移除。

只能由该 relay 的所有者调用。在该 relay 的 unstakeDelay 经过后,可以调用 unstake

发出一个 RelayRemoved 事件。

unstake(address relay) external
getRelay(address relay) → uint256 totalStake, uint256 unstakeDelay, uint256 unstakeTime, address payable owner, enum IRelayHub.RelayState state external

返回一个 relay 的状态。请注意,relay 可以在 unstake 或受到惩罚时被删除,导致此函数返回一个空条目。

depositFor(address target) external

为一个合约存入 Ether,以便它可以接收(并支付)中继的交易。

未使用的余额只能由合约本身通过调用 withdraw 来提取。

发出一个 Deposited 事件。

balanceOf(address target) → uint256 external

返回一个账户的存款。这些可以是合约的资金,也可以是 relay 所有者的收入。

withdraw(uint256 amount, address payable dest) external
canRelay(address relay, address from, address to, bytes encodedFunction, uint256 transactionFee, uint256 gasPrice, uint256 gasLimit, uint256 nonce, bytes signature, bytes approvalData) → uint256 status, bytes recipientContext external

检查 RelayHub 是否会接受一个中继的操作。 要发生这种情况,必须满足多个条件: - 所有参数必须由发送者(from)签名 - 发送者的 nonce 必须是当前的 nonce - 接收者必须接受此交易(通过 acceptRelayedCall

返回一个 PreconditionCheck 值(当交易可以被中继时返回 OK),或者,如果它在 acceptRelayedCall 中返回一个接收者特定的错误代码。

relayCall(address from, address to, bytes encodedFunction, uint256 transactionFee, uint256 gasPrice, uint256 gasLimit, uint256 nonce, bytes signature, bytes approvalData) external

中继一个交易。

为了使其成功,必须满足多个条件: - canRelay 必须 return PreconditionCheck.OK - 发送者必须是一个已注册的 relay - 交易的 gas 价格必须大于或等于发送者所请求的价格 - 交易必须有足够的 gas,以防止所有内部交易(对接收者的调用)使用所有可用 gas 时耗尽 gas - 接收者必须有足够的余额来支付 relay 最坏情况下的费用(即,当所有 gas 都被消耗时)

如果满足所有条件,则调用将被中继,并且接收者将被收费。 preRelayedCall、编码的函数和 postRelayedCall 将按该顺序被调用。

参数: - from:发起请求的客户端 - to:目标 IRelayRecipient 合约 - encodedFunction:要中继的函数调用,包括数据 - transactionFee:relay 收取的超过实际 gas 成本的费用(%) - gasPrice:客户端愿意支付的 gas 价格 - gasLimit:调用编码函数时转发的 gas - nonce:客户端的 nonce - signature:客户端对所有先前参数以及 relay 和 RelayHub 地址的签名 - approvalData:dapp 特定的数据,转发到 acceptRelayedCall。此值RelayHub 验证,但它仍然可以用于例如签名。

发出一个 TransactionRelayed 事件。

requiredGas(uint256 relayedCallStipend) → uint256 external

返回应该转发给 relayCall 调用的 gas 数量,以便中继一个将花费最多 relayedCallStipend gas 的交易。

maxPossibleCharge(uint256 relayedCallStipend, uint256 gasPrice, uint256 transactionFee) → uint256 external

返回最大接收者费用,给定转发的 gas 数量、gas 价格和 relay 费用。

penalizeRepeatedNonce(bytes unsignedTx1, bytes signature1, bytes unsignedTx2, bytes signature2) external

惩罚一个使用相同 nonce(仅使第一个有效)和不同数据(gas 价格、gas 限制等可能不同)签署两个交易的 relay。

必须提供两个交易的(未签名)交易数据和签名。

penalizeIllegalTransaction(bytes unsignedTx, bytes signature) external

惩罚一个发送未以 RelayHubregisterRelayrelayCall 为目标的交易的 relay。

getNonce(address from) → uint256 external

返回 RelayHub 中一个账户的 nonce。

Staked(address relay, uint256 stake, uint256 unstakeDelay) event

当一个 relay 的 stake 或 unstakeDelay 增加时发出

RelayAdded(address relay, address owner, uint256 transactionFee, uint256 stake, uint256 unstakeDelay, string url) event

当一个 relay 被注册或重新注册时发出。查看这些事件(并过滤掉 RelayRemoved 事件)可以让客户端发现可用的 relay 列表。

RelayRemoved(address relay, uint256 unstakeTime) event

当一个 relay 被移除(注销)时发出。unstakeTime 是可以调用 unstake 的时间。

Unstaked(address relay, uint256 stake) event

当一个 relay 被解除 stake 时发出,包括返回的 stake。

Deposited(address recipient, address from, uint256 amount) event

depositFor 被调用时发出,包括被资助的金额和账户。

Withdrawn(address account, address dest, uint256 amount) event

当一个账户从 RelayHub 提取资金时发出。

CanRelayFailed(address relay, address from, address to, bytes4 selector, uint256 reason) event

当试图中继一个调用失败时发出。

这可能是由于不正确的 relayCall 参数,或者接收者不接受该中继的调用。实际的中继调用没有被执行,并且接收者没有被收费。

reason 参数包含一个错误代码:值 1-10 对应于 PreconditionCheck 条目,并且大于 10 的值是从 acceptRelayedCall 返回的自定义接收者错误代码。

TransactionRelayed(address relay, address from, address to, bytes4 selector, enum IRelayHub.RelayCallStatus status, uint256 charge) event

当一个交易被中继时发出。 在监视 relay 的操作和对合约的中继调用时很有用

请注意,实际的编码函数可能会被回滚:这在 status 参数中指示。

charge 是从接收者余额中扣除的 Ether 值,支付给 relay 的所有者。

Penalized(address relay, address sender, uint256 amount) event

当一个 relay 受到惩罚时发出。

← ERC 1155

Introspection →

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

0 条评论

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