Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
b425a72
Replace revert strings with custom errors (#4261)
ernestognw Jun 12, 2023
4c1cd22
Minimal Forwarder
ernestognw Jun 13, 2023
fe08f58
Update README.md (#4335)
zackrw Jun 13, 2023
2432d0d
Add changeset
ernestognw Jun 13, 2023
d6c7cee
Update index.adoc (#4336)
zackrw Jun 13, 2023
6a87cec
Fix ERC2771 tests
ernestognw Jun 14, 2023
6040254
Add EIP-712 `name` and `version` getters (#4303)
RenanSouza2 Jun 14, 2023
7cc2cbf
Cleanup the structure of GovernorTimelockControl.test.js (#4302)
Amxx Jun 14, 2023
5cc1ea0
Add `GUIDELINES.md` for marking `abstract` contracts (#4010)
ernestognw Jun 14, 2023
ef103f3
Replace some uses of abi.encodePacked with more explicit alternatives…
Amxx Jun 14, 2023
ac5480e
Merge release-v4.9 branch (#4352)
ernestognw Jun 14, 2023
2477534
Change behavior of ceilDiv(0, 0) and improve test coverage (#4348)
ernestognw Jun 14, 2023
05ef692
Optimize array access in ERC1155 (#4300)
clauBv23 Jun 15, 2023
ff85c7b
Make ERC1967Upgrades a library instead of an abstract contract (#4325)
Amxx Jun 15, 2023
c014c8f
Use ERC721Holder & ERC1155Holder in the TimelockController (#4284)
Amxx Jun 15, 2023
6724873
Output contract name where storage inconsistency was found (#4357)
Amxx Jun 15, 2023
cd48b3e
Add validation in Governor on ERC-721 or ERC-1155 received (#4314)
clauBv23 Jun 16, 2023
002a7c8
Remove automatic conflict resolution for merge from release branch (#…
frangio Jun 16, 2023
1a77a50
Move upgradeToAndCallUUPS to UUPSUpgradeable (#4356)
Amxx Jun 17, 2023
c95a445
Detect MerkleProof multiproof invariant violation (#4367)
frangio Jun 19, 2023
fc19a79
Change release cycle `prBackExists` definition (#4365)
ernestognw Jun 19, 2023
1f4e33f
Add toStringSigned to Strings.sol (#4330)
balajipachai Jun 19, 2023
1d0dbcf
Make `TransparentUpgradeableProxy` admin immutable (#4354)
ernestognw Jun 20, 2023
365aca6
Improve tests for ERC1155 and ERC721 error handling (#3781)
Amxx Jun 20, 2023
2271e2c
Use clones for testing non ERC1967 proxies (#4371)
Amxx Jun 20, 2023
9fa550c
Fix attempt to delete nonexistent npm tag (#4374)
frangio Jun 20, 2023
b66c77a
Merge branch 'release-v4.9' into master (#4373)
frangio Jun 20, 2023
dac2457
Improve customError testing (#4376)
Amxx Jun 20, 2023
6ddacdb
Cleanup timelockId on execution for gas refund (#4118)
Amxx Jun 20, 2023
16b9ea8
Add batching and better explain gas forwarding check
ernestognw Jun 20, 2023
7c5d038
Lint
ernestognw Jun 20, 2023
5662e35
Applied suggestions
ernestognw Jun 20, 2023
d1c75c8
Fix test
ernestognw Jun 20, 2023
dff9998
Complete tests
ernestognw Jun 21, 2023
8da57ef
Improve testing
ernestognw Jun 21, 2023
1e0e4e2
Do not emit Approval event when calling transferFrom (#4370)
Amxx Jun 22, 2023
a7a94c7
Update comment to reflect code logic in Ownable.sol (#4369)
s-tikhomirov Jun 22, 2023
5978b7e
Rename MinimalForwarder to ERC2771Forwarder
ernestognw Jun 23, 2023
3d5fe68
Avoid revert on nonce mismatch
ernestognw Jun 23, 2023
c781b6b
Use _validate in _execute
ernestognw Jun 23, 2023
da89c43
Pack Governor's ProposalCore into a single slot (#4268)
Amxx Jun 23, 2023
f5987eb
Use timestamp instead of block number
ernestognw Jun 23, 2023
c44c220
Update Ownable2Step docs (#4384)
RenanSouza2 Jun 23, 2023
e59d707
Merge branch 'master' into lib-643-production-ready-minimal-forwarder-2
ernestognw Jun 24, 2023
87e77b1
Apply suggestions
ernestognw Jun 24, 2023
bdd061d
Pack signature into request
ernestognw Jun 24, 2023
376f3b2
Fix ERC2771Context tests
ernestognw Jun 24, 2023
cb4bf95
Add unreleased disclaimer in readme
frangio Jun 24, 2023
8cab922
Rename `ERC1155InsufficientApprovalForAll` to `ERC1155MissingApproval…
ernestognw Jun 26, 2023
f29307c
Add Foundry installation instructions with required warnings (#4389)
frangio Jun 26, 2023
1ba8173
Merge branch 'master' into lib-643-production-ready-minimal-forwarder-2
ernestognw Jun 26, 2023
b94a100
Improve comments in _checkForwardedGas
ernestognw Jun 27, 2023
85acfdf
Remove returndata
ernestognw Jun 27, 2023
74d5961
Fix ETH left
ernestognw Jun 27, 2023
c62d927
Changed note
ernestognw Jun 27, 2023
daafff8
Fix codespell
ernestognw Jun 27, 2023
f3d5b44
Fix ETH left in the contract
ernestognw Jun 27, 2023
cb8690e
Fix nonces
ernestognw Jun 27, 2023
68ce4eb
Avoid reentrancy
ernestognw Jun 27, 2023
99a26c4
Apply suggestion
ernestognw Jun 27, 2023
be93a80
Apply suggestion
ernestognw Jun 27, 2023
5c039ea
Improve tests
ernestognw Jun 28, 2023
b7b985e
Remove flaky test
ernestognw Jun 28, 2023
8f84f4e
Hardcode slither version to 0.9.3
ernestognw Jun 28, 2023
8a03cad
Revert on unsuccessful execute
ernestognw Jun 28, 2023
95bcb57
Implement suggestions
ernestognw Jun 29, 2023
8b7e961
tweak proof wording
frangio Jun 29, 2023
f72c2d5
change ETH -> value
frangio Jun 29, 2023
62d2342
adjust comment after recent change
frangio Jun 29, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Complete tests
  • Loading branch information
ernestognw committed Jun 21, 2023
commit dff99985e65d9029f16423fd42e6f46f989521ac
57 changes: 31 additions & 26 deletions contracts/metatx/MinimalForwarder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ contract MinimalForwarder is EIP712, Nonces {
"ForwardRequest(address from,address to,uint256 value,uint256 gas,uint256 nonce,uint48 deadline,bytes data)"
);

/**
* @dev Emitted when a `ForwardRequest` is executed.
*/
event ExecutedForwardRequest(address indexed signer, uint256 nonce, bool success, bytes returndata);

/**
* @dev The request `from` doesn't match with the recovered `signer`.
*/
Expand Down Expand Up @@ -81,8 +86,6 @@ contract MinimalForwarder is EIP712, Nonces {
) public payable virtual returns (bool, bytes memory) {
(bool success, bytes memory returndata) = _execute(request, signature);

_checkForwardedGas(gasleft(), request);

if (msg.value != request.value) {
revert MinimalForwarderMismatchedValue(request.value, msg.value);
}
Expand All @@ -93,34 +96,21 @@ contract MinimalForwarder is EIP712, Nonces {
/**
* @dev Batch version of {execute}.
*/
function executeBatch(
ForwardRequest[] calldata requests,
bytes[] calldata signatures
) public payable virtual returns (bool[] memory, bytes[] memory) {
function executeBatch(ForwardRequest[] calldata requests, bytes[] calldata signatures) public payable virtual {
if (requests.length != signatures.length) {
revert MinimalForwarderInvalidBatchLength(requests.length, signatures.length);
}

uint256 requestsValue = 0;
bool[] memory successes = new bool[](requests.length);
bytes[] memory returndatas = new bytes[](requests.length);
uint256 requestsValue;

for (uint256 i; i < requests.length; ++i) {
(bool success, bytes memory returndata) = _execute(requests[i], signatures[i]);
requestsValue += requests[i].value;
successes[i] = success;
returndatas[i] = returndata;
_execute(requests[i], signatures[i]);
}

// Only check the last request because if the batch didn't go out-of-gas at this point,
// only the last call can be provided with less gas than requested.
_checkForwardedGas(gasleft(), requests[requests.length - 1]);

if (msg.value != requestsValue) {
revert MinimalForwarderMismatchedValue(requestsValue, msg.value);
}

return (successes, returndatas);
}

/**
Expand All @@ -141,7 +131,7 @@ contract MinimalForwarder is EIP712, Nonces {
function _recoverForwardRequestSigner(
ForwardRequest calldata request,
bytes calldata signature
) internal view returns (address) {
) internal view virtual returns (address) {
return
_hashTypedDataV4(
keccak256(
Expand All @@ -167,11 +157,17 @@ contract MinimalForwarder is EIP712, Nonces {
* - The request's deadline must have not passed.
* - The request's from must be the request's signer.
* - The request's nonce must match the sender's nonce.
* - The caller must have provided enough gas to forward with the call.
*
* Emits an {ExecutedForwardRequest} event.
*
* IMPORTANT: Using this function does not guarantee the forwarded call will receive enough gas to complete.
* Similarly, it doesn't check that all the `msg.value` was sent, potentially leaving ETH stuck in the contract.
* IMPORTANT: Using this function doesn't check that all the `msg.value` was sent, potentially leaving
* ETH stuck in the contract.
*/
function _execute(ForwardRequest calldata request, bytes calldata signature) private returns (bool, bytes memory) {
function _execute(
ForwardRequest calldata request,
bytes calldata signature
) internal virtual returns (bool success, bytes memory returndata) {
// The _validate function is intentionally avoided to keep the signer argument and the nonce check

if (request.deadline < block.number) {
Expand All @@ -185,7 +181,13 @@ contract MinimalForwarder is EIP712, Nonces {

_useCheckedNonce(request.from, request.nonce);

return request.to.call{gas: request.gas, value: request.value}(abi.encodePacked(request.data, request.from));
(success, returndata) = request.to.call{gas: request.gas, value: request.value}(
abi.encodePacked(request.data, request.from)
);

_checkForwardedGas(request);

emit ExecutedForwardRequest(signer, request.nonce, success, returndata);
}

/**
Expand All @@ -196,8 +198,11 @@ contract MinimalForwarder is EIP712, Nonces {
* - At least `floor(gasleft() / 64)` is kept in the caller.
*
* It reverts consuming all the available gas if the forwarded gas is not the requested gas.
*
* IMPORTANT: This function should be called exactly the end of the forwarded call. Any gas consumed
* in between will make room for bypassing this check.
*/
function _checkForwardedGas(uint256 gasLeft, ForwardRequest calldata request) private pure {
function _checkForwardedGas(ForwardRequest calldata request) private view {
// To avoid insufficient gas griefing attacks, as referenced in https://ronan.eth.limo/blog/ethereum-gas-dangers/
// A malicious relayer can attempt to shrink the gas forwarded so that the underlying call reverts out-of-gas
// and the top-level call still passes, so in order to make sure that the subcall received the requested gas,
Expand All @@ -209,10 +214,10 @@ contract MinimalForwarder is EIP712, Nonces {
// - (X - req.gas) >= req.gas/63
//
// Although we can't access X, we let Y be the actual gas used in the subcall so that `gasleft() == X - Y`, then
// we know that `X - req.gas <= X - Y`, thus `req.gas <= Y` and `X - req.gas <= gasleft()`.
// we know that `X - req.gas <= X - Y`, thus `Y <= req.gas` and finally `X - req.gas <= gasleft()`.
// Therefore, any attempt to manipulate X to reduce the gas provided to the callee will result in the following
// invariant violated:
if (gasLeft < request.gas / 63) {
if (gasleft() < request.gas / 63) {
// We explicitly trigger invalid opcode to consume all gas and bubble-up the effects, since
// neither revert or assert consume all gas since Solidity 0.8.0
// https://docs.soliditylang.org/en/v0.8.0/control-structures.html#panic-via-assert-and-error-via-require
Expand Down
Loading