-
Notifications
You must be signed in to change notification settings - Fork 12.4k
H-04: Update ERC2771Forwarder executeBatch docs removing atomicity terminology
#6415
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
28869ee
3798151
eb31b00
2bb7090
45df8cf
2f81cdd
8cd8d06
e1bbf07
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,5 @@ | ||||||
| --- | ||||||
| 'openzeppelin-solidity': patch | ||||||
| --- | ||||||
|
|
||||||
| Update `ERC2771Forwarder` `executeBatch` docs removing atomicity terminology | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree. Instead of a changeset, it should go in the |
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -76,9 +76,9 @@ contract ERC2771Forwarder is EIP712, Nonces { | |
| event ExecutedForwardRequest(address indexed signer, uint256 nonce, bool success); | ||
|
|
||
| /** | ||
| * @dev One of the calls in an atomic batch failed. | ||
| * @dev A request in the batch failed and no `refundReceiver` was set to handle the leftover value. | ||
| */ | ||
| error ERC2771ForwarderFailureInAtomicBatch(); | ||
| error ERC2771ForwarderNoRefundReceiver(); | ||
|
|
||
| /** | ||
| * @dev The request `from` doesn't match with the recovered `signer`. | ||
|
|
@@ -143,40 +143,34 @@ contract ERC2771Forwarder is EIP712, Nonces { | |
| } | ||
|
|
||
| /** | ||
| * @dev Batch version of {execute} with optional refunding and atomic execution. | ||
| * @dev Batch version of {execute} with optional refunding. | ||
| * | ||
| * In case a batch contains at least one invalid request (see {verify}), the | ||
| * request will be skipped and the `refundReceiver` parameter will receive back the | ||
| * unused requested value at the end of the execution. This is done to prevent reverting | ||
| * the entire batch when a request is invalid or has already been submitted. | ||
| * | ||
| * If the `refundReceiver` is the `address(0)`, this function will revert when at least | ||
| * one of the requests was not valid instead of skipping it. This could be useful if | ||
| * a batch is required to get executed atomically (at least at the top-level). For example, | ||
| * refunding (and thus atomicity) can be opt-out if the relayer is using a service that avoids | ||
| * including reverted transactions. | ||
| * If the `refundReceiver` is `address(0)`, the function will instead revert | ||
| * when any request is invalid or when a valid request's forwarded call fails while | ||
| * carrying value (since there is no receiver to refund the leftover ETH to). | ||
| * | ||
| * Requirements: | ||
| * | ||
| * - The sum of the requests' values should be equal to the provided `msg.value`. | ||
| * - All of the requests should be valid (see {verify}) when `refundReceiver` is the zero address. | ||
| * | ||
| * NOTE: Setting a zero `refundReceiver` guarantees an all-or-nothing requests execution only for | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should still keep a note about setting a refundReceiver to address(0). According to our discussion, developers should only do this when the operations use 0 value or when they're the operation won't revert. For example, if they use a private RPC (or their own node) The reason is that, if the relayer is not aware, they might still get a whole batch invalidated if they send an operation with value that's submitted first. Currently it's not clearly described imo |
||
| * the first-level forwarded calls. In case a forwarded request calls to a contract with another | ||
| * subcall, the second-level call may revert without the top-level call reverting. | ||
| */ | ||
| function executeBatch( | ||
| ForwardRequestData[] calldata requests, | ||
| address payable refundReceiver | ||
| ) public payable virtual { | ||
| bool atomic = refundReceiver == address(0); | ||
| bool requireValidRequests = refundReceiver == address(0); | ||
|
|
||
| uint256 requestsValue; | ||
| uint256 refundValue; | ||
|
|
||
| for (uint256 i; i < requests.length; ++i) { | ||
| requestsValue += requests[i].value; | ||
| bool success = _execute(requests[i], atomic); | ||
| bool success = _execute(requests[i], requireValidRequests); | ||
| if (!success) { | ||
| refundValue += requests[i].value; | ||
| } | ||
|
|
@@ -189,9 +183,9 @@ contract ERC2771Forwarder is EIP712, Nonces { | |
| } | ||
|
|
||
| // Some requests with value were invalid (possibly due to frontrunning). | ||
| // To avoid leaving ETH in the contract this value is refunded. | ||
| // To avoid leaving ETH in the contract, this value is refunded. | ||
| if (refundValue != 0) { | ||
|
gonzaotc marked this conversation as resolved.
|
||
| if (atomic) revert ERC2771ForwarderFailureInAtomicBatch(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We discussed internally and noticed that this line doesn't reintroduce the frontrunning vector. In that case, the Still, it would be possible that an attacker prepares a valid request that calls a contract the attacker controls, so the success of the call depends on the state of the contract. Therefore the attacker can still frontrun the forwarder and set the target contract's state to force a revert. Bottom line is that the code is currently fine but:
|
||
| if (requireValidRequests) revert ERC2771ForwarderNoRefundReceiver(); | ||
|
|
||
| // We know refundReceiver != address(0) && requestsValue == msg.value | ||
| // meaning we can ensure refundValue is not taken from the original contract's balance | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we don't need a changeset because there's no code change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CHANGELOG must indicate the custom error rename in the "breaking changes" section