12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 |
- // SPDX-License-Identifier: MIT
- pragma solidity ^0.8.0;
- import "../utils/cryptography/ECDSA.sol";
- import "../utils/cryptography/draft-EIP712.sol";
- /*
- * @dev Simple minimal forwarder to be used together with an ERC2771 compatible contract. See {ERC2771Context}.
- */
- contract MinimalForwarder 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("MinimalForwarder", "0.0.1") {}
- 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;
- // solhint-disable-next-line avoid-low-level-calls
- (bool success, bytes memory returndata) = req.to.call{gas: req.gas, value: req.value}(abi.encodePacked(req.data, req.from));
- // Validate that the relayer has sent enough gas for the call.
- // See https://ronan.eth.link/blog/ethereum-gas-dangers/
- assert(gasleft() > req.gas / 63);
- return (success, returndata);
- }
- }
|