MinimalForwarder.sol 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.0;
  3. import "../cryptography/ECDSA.sol";
  4. import "../drafts/EIP712.sol";
  5. /*
  6. * @dev Simple minimal forwarder to be used together with an ERC2771 compatible contract. See {ERC2771Context}.
  7. */
  8. contract MinimalForwarder is EIP712 {
  9. using ECDSA for bytes32;
  10. struct ForwardRequest {
  11. address from;
  12. address to;
  13. uint256 value;
  14. uint256 gas;
  15. uint256 nonce;
  16. bytes data;
  17. }
  18. bytes32 private constant TYPEHASH = keccak256("ForwardRequest(address from,address to,uint256 value,uint256 gas,uint256 nonce,bytes data)");
  19. mapping(address => uint256) private _nonces;
  20. constructor() EIP712("MinimalForwarder", "0.0.1") {}
  21. function getNonce(address from) public view returns (uint256) {
  22. return _nonces[from];
  23. }
  24. function verify(ForwardRequest calldata req, bytes calldata signature) public view returns (bool) {
  25. address signer = _hashTypedDataV4(keccak256(abi.encode(
  26. TYPEHASH,
  27. req.from,
  28. req.to,
  29. req.value,
  30. req.gas,
  31. req.nonce,
  32. keccak256(req.data)
  33. ))).recover(signature);
  34. return _nonces[req.from] == req.nonce && signer == req.from;
  35. }
  36. function execute(ForwardRequest calldata req, bytes calldata signature) public payable returns (bool, bytes memory) {
  37. require(verify(req, signature), "MinimalForwarder: signature does not match request");
  38. _nonces[req.from] = req.nonce + 1;
  39. // solhint-disable-next-line avoid-low-level-calls
  40. (bool success, bytes memory returndata) = req.to.call{gas: req.gas, value: req.value}(abi.encodePacked(req.data, req.from));
  41. // Validate that the relayer has sent enough gas for the call.
  42. // See https://ronan.eth.link/blog/ethereum-gas-dangers/
  43. assert(gasleft() > req.gas / 63);
  44. return (success, returndata);
  45. }
  46. }