MinimalForwarderUpgradeable.sol 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v4.5.0) (metatx/MinimalForwarder.sol)
  3. pragma solidity ^0.8.0;
  4. import "../utils/cryptography/ECDSAUpgradeable.sol";
  5. import "../utils/cryptography/draft-EIP712Upgradeable.sol";
  6. import "../proxy/utils/Initializable.sol";
  7. /**
  8. * @dev Simple minimal forwarder to be used together with an ERC2771 compatible contract. See {ERC2771Context}.
  9. */
  10. contract MinimalForwarderUpgradeable is Initializable, EIP712Upgradeable {
  11. using ECDSAUpgradeable for bytes32;
  12. struct ForwardRequest {
  13. address from;
  14. address to;
  15. uint256 value;
  16. uint256 gas;
  17. uint256 nonce;
  18. bytes data;
  19. }
  20. bytes32 private constant _TYPEHASH =
  21. keccak256("ForwardRequest(address from,address to,uint256 value,uint256 gas,uint256 nonce,bytes data)");
  22. mapping(address => uint256) private _nonces;
  23. function __MinimalForwarder_init() internal onlyInitializing {
  24. __EIP712_init_unchained("MinimalForwarder", "0.0.1");
  25. }
  26. function __MinimalForwarder_init_unchained() internal onlyInitializing {}
  27. function getNonce(address from) public view returns (uint256) {
  28. return _nonces[from];
  29. }
  30. function verify(ForwardRequest calldata req, bytes calldata signature) public view returns (bool) {
  31. address signer = _hashTypedDataV4(
  32. keccak256(abi.encode(_TYPEHASH, req.from, req.to, req.value, req.gas, req.nonce, 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)
  37. public
  38. payable
  39. returns (bool, bytes memory)
  40. {
  41. require(verify(req, signature), "MinimalForwarder: signature does not match request");
  42. _nonces[req.from] = req.nonce + 1;
  43. (bool success, bytes memory returndata) = req.to.call{gas: req.gas, value: req.value}(
  44. abi.encodePacked(req.data, req.from)
  45. );
  46. // Validate that the relayer has sent enough gas for the call.
  47. // See https://ronan.eth.link/blog/ethereum-gas-dangers/
  48. if (gasleft() <= req.gas / 63) {
  49. // We explicitly trigger invalid opcode to consume all gas and bubble-up the effects, since
  50. // neither revert or assert consume all gas since Solidity 0.8.0
  51. // https://docs.soliditylang.org/en/v0.8.0/control-structures.html#panic-via-assert-and-error-via-require
  52. assembly {
  53. invalid()
  54. }
  55. }
  56. return (success, returndata);
  57. }
  58. /**
  59. * @dev This empty reserved space is put in place to allow future versions to add new
  60. * variables without shifting down storage in the inheritance chain.
  61. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
  62. */
  63. uint256[49] private __gap;
  64. }