// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "../core/HasSignature.sol"; import "../utils/TimeChecker.sol"; interface IToken { function transferFrom( address from, address to, uint256 amount ) external returns (bool); function signApprove( address spender, uint256 amount, uint256 startTime, uint256 saltNonce, bytes calldata signature ) external; } contract ExecuteRelay is HasSignature, TimeChecker { constructor() HasSignature("ExecuteRelay", "1") {} address public tokenAddress; event MethodExecuted( address indexed sender, address indexed target, bytes data, uint256 gasUsed, uint256 tokenAmount ); function execute( address sender, address target, uint256 value, bytes calldata data, uint256 startTime, uint256 saltNonce, bytes calldata signature ) external payable signatureValid(signature) timeValid(startTime) { bytes32 messageHash = getMessageHash( target, value, data, startTime, saltNonce ); uint256 gasStart = gasleft(); checkSigner712(sender, messageHash, signature); uint256 gasPrice = tx.gasprice; _call(target, value, data); uint256 gasUsed = gasStart - gasleft(); uint256 tokenAmount = gasPrice * gasUsed; // TODO:: calc real token amount IToken(tokenAddress).signApprove( sender, tokenAmount, startTime, saltNonce, signature ); IToken(tokenAddress).transferFrom(sender, address(this), tokenAmount); _useSignature(signature); emit MethodExecuted(sender, target, data, gasUsed, tokenAmount); } /** * @dev Execute an operation's call. * * Emits a {CallExecuted} event. */ function _call(address target, uint256 value, bytes calldata data) private { (bool success, ) = target.call{value: value}(data); require(success, "ExecuteRelay: underlying transaction reverted"); } function getMessageHash( address _target, uint256 _value, bytes calldata _data, uint256 _startTime, uint256 _saltNonce ) public pure returns (bytes32) { bytes memory encoded = abi.encodePacked( _target, _value, _data, _startTime, _saltNonce ); return keccak256(encoded); } }