Skip to content
This repository has been archived by the owner on May 9, 2024. It is now read-only.

Commit

Permalink
Anderson/add new forwarder contract (#440)
Browse files Browse the repository at this point in the history
* add minimal forwarder

* rename test forwarder contract

* add tests for the new forwarder

* add forwarder test

* rename test

* fix comments

* fix comments

* remove responseForwarder
  • Loading branch information
andersonlee725 authored Jan 4, 2022
1 parent 2daf257 commit e2f5cda
Show file tree
Hide file tree
Showing 7 changed files with 989 additions and 5 deletions.
57 changes: 57 additions & 0 deletions contracts/Forwarder.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/drafts/EIP712.sol";

/**
@notice This contract refers to Openzeppelin's MinimalForwarder contract.
*/
contract Forwarder is EIP712 {
using ECDSA for bytes32;

struct ForwardRequest {
address from;
address to;
uint256 value;
uint256 gas;
uint256 nonce;
bytes data;
}

bytes32 private constant _TYPEHASH =
keccak256("ForwardRequest(address from,address to,uint256 value,uint256 gas,uint256 nonce,bytes data)");

mapping(address => uint256) private _nonces;

constructor() EIP712("Forwarder", "0.0.1") public {}

function getNonce(address from) public view returns (uint256) {
return _nonces[from];
}

function verify(ForwardRequest calldata req, bytes calldata signature) public view returns (bool) {
address signer = _hashTypedDataV4(
keccak256(abi.encode(_TYPEHASH, req.from, req.to, req.value, req.gas, req.nonce, keccak256(req.data)))
).recover(signature);
return _nonces[req.from] == req.nonce && signer == req.from;
}

function execute(ForwardRequest calldata req, bytes calldata signature)
public
payable
returns (bool, bytes memory)
{
require(verify(req, signature), "MinimalForwarder: signature does not match request");
_nonces[req.from] = req.nonce + 1;

(bool success, bytes memory returndata) = req.to.call{gas: req.gas, value: req.value}(
abi.encodePacked(req.data, req.from)
);

assert(gasleft() > req.gas / 63);

return (success, returndata);
}
}
22 changes: 21 additions & 1 deletion contracts/TestContracts.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import "./utils/SafeCast.sol";
import "./handlers/HandlerHelpers.sol";
Expand Down Expand Up @@ -80,10 +81,29 @@ contract HandlerRevert is HandlerHelpers {
}
}

contract Forwarder {
contract TestForwarder {
function execute(bytes memory data, address to, address sender) external {
bytes memory callData = abi.encodePacked(data, sender);
(bool success, ) = to.call(callData);
require(success, "Relay call failed");
}
}

contract TestTarget {
uint public calls = 0;
uint public gasLeft;
bytes public data;
bool public burnAllGas;
fallback() external payable {
gasLeft = gasleft();
calls++;
data = msg.data;
if (burnAllGas) {
assert(false);
}
}

function setBurnAllGas() public {
burnAllGas = true;
}
}
147 changes: 145 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@
"rollup-plugin-typescript2": "^0.30.0",
"rollup-plugin-node-polyfills": "^0.2.1",
"rollup-plugin-peer-deps-external": "^2.2.3",
"typescript": "^4.2.3"
"typescript": "^4.2.3",
"eth-sig-util": "^3.0.1",
"ethereumjs-wallet": "^1.0.2"
},
"peerDependencies": {
"ethers": ">= 5.0.0"
Expand Down
Loading

0 comments on commit e2f5cda

Please sign in to comment.