Contract
0x69015912aa33720b842dcd6ac059ed623f28d9f7
1
Contract Overview
Balance:
0 MATIC
Token:
My Name Tag:
Not Available
[ Download CSV Export ]
Contract Name:
BiconomyForwarderV2
Compiler Version
v0.8.4+commit.c7e474f2
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "./ForwardRequestTypesV2.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; /** * * @title BiconomyForwarder * * @notice A trusted forwarder for Biconomy relayed meta transactions * * @dev - Inherits Forward Request structs from Forward Request Types * @dev - Verifies EIP712 signatures * @dev - Verifies traditional personalSign signatures * @dev - Implements 2D nonces... each Tx has a BatchId and a BatchNonce * @dev - Keeps track of highest BatchId used by a given address, to assist in encoding of transactions client-side * @dev - maintains a list of verified domain seperators * */ contract BiconomyForwarderV2 is ForwardRequestTypesV2, Ownable { using ECDSA for bytes32; mapping(bytes32 => bool) public domains; uint256 chainId; string public constant EIP712_DOMAIN_TYPE = "EIP712Domain(string name,string version,address verifyingContract,bytes32 salt)"; //@review bytes32 public constant REQUEST_TYPEHASH = keccak256(bytes("ForwardRequest(address from,address to,uint256 txGas,uint256 batchId,uint256 batchNonce,uint256 deadline,bytes data)")); //@review and rename bytes32 public constant FORWARD_REQUEST_TYPEHASH = keccak256(bytes("ERC20ForwardRequest(address from,address to,address token,uint256 txGas,uint256 tokenGasPrice,uint256 batchId,uint256 batchNonce,uint256 deadline,bytes data)")); //Sandbox use case bytes32 public constant CUSTOM_FORWARD_REQUEST_TYPEHASH = keccak256(bytes("CustomForwardRequest(string warning,string info,string action,ERC20ForwardRequest request)ERC20ForwardRequest(address from,address to,address token,uint256 txGas,uint256 tokenGasPrice,uint256 batchId,uint256 batchNonce,uint256 deadline,bytes data)")); mapping(address => mapping(uint256 => uint256)) nonces; constructor( ) public { uint256 id; assembly { id := chainid() } chainId = id; } /** * @dev registers domain seperators, maintaining that all domain seperators used for EIP712 forward requests use... * ... the address of this contract and the chainId of the chain this contract is deployed to * @param name : name of dApp/dApp fee proxy * @param version : version of dApp/dApp fee proxy */ function registerDomainSeparator(string calldata name, string calldata version) external onlyOwner{ uint256 id; /* solhint-disable-next-line no-inline-assembly */ assembly { id := chainid() } bytes memory domainValue = abi.encode( keccak256(bytes(EIP712_DOMAIN_TYPE)), keccak256(bytes(name)), keccak256(bytes(version)), address(this), bytes32(id)); bytes32 domainHash = keccak256(domainValue); domains[domainHash] = true; emit DomainRegistered(domainHash, domainValue); } event DomainRegistered(bytes32 indexed domainSeparator, bytes domainValue); event MetaTransactionExecuted(address indexed userAddress, address indexed relayerAddress, bytes indexed functionSignature); /** * @dev returns a value from the nonces 2d mapping * @param from : the user address * @param batchId : the key of the user's batch being queried * @return nonce : the number of transaction made within said batch */ function getNonce(address from, uint256 batchId) public view returns (uint256) { return nonces[from][batchId]; } //TODO //@review if new read method is needed for Custom /** * @dev an external function which exposes the internal _verifySigEIP712 method * @param req : request being verified * @param domainSeparator : the domain separator presented to the user when signing * @param sig : the signature generated by the user's wallet */ function verifyEIP712( ERC20ForwardRequest calldata req, bytes32 domainSeparator, bytes calldata sig) external view { _verifySigEIP712(req, domainSeparator, sig); } /** * @dev verifies the call is valid by calling _verifySigEIP712 * @dev executes the forwarded call if valid * @dev updates the nonce after * @param req : ERC20 forward request being executed * @param domainSeparator : the domain separator presented to the user when signing * @param sig : the signature generated by the user's wallet * @return success : false if call fails. true otherwise * @return ret : any return data from the call */ function executeEIP712( ERC20ForwardRequest calldata req, bytes32 domainSeparator, bytes calldata sig ) external returns (bool success, bytes memory ret) { _verifySigEIP712(req,domainSeparator,sig); _updateNonce(req); /* solhint-disable-next-line avoid-low-level-calls */ (success,ret) = req.to.call{gas : req.txGas}(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.txGas / 63); _verifyCallResult(success,ret,"Forwarded call to destination did not succeed"); emit MetaTransactionExecuted(req.from, msg.sender, req.data); } /** * @dev verifies the call is valid by calling _verifySigEIP712Custom * @dev executes the forwarded call if valid * @dev updates the nonce after * @param req : Custom ERC20 forward request being executed * @param domainSeparator : the domain separator presented to the user when signing * @param sig : the signature generated by the user's wallet * @return success : false if call fails. true otherwise * @return ret : any return data from the call */ function executeEIP712Custom( CustomForwardRequest calldata req, bytes32 domainSeparator, bytes calldata sig ) external returns (bool success, bytes memory ret) { _verifySigEIP712Custom(req,domainSeparator,sig); _updateNonceCustom(req); /* solhint-disable-next-line avoid-low-level-calls */ (success,ret) = req.request.to.call{gas : req.request.txGas}(abi.encodePacked(req.request.data, req.request.from)); // Validate that the relayer has sent enough gas for the call. // See https://ronan.eth.link/blog/ethereum-gas-dangers/ assert(gasleft() > req.request.txGas / 63); _verifyCallResult(success,ret,"Forwarded call to destination did not succeed"); emit MetaTransactionExecuted(req.request.from, msg.sender, req.request.data); } /** * @dev an external function which exposes the internal _verifySigPersonSign method * @param req : request being verified * @param sig : the signature generated by the user's wallet */ function verifyPersonalSign( ERC20ForwardRequest calldata req, bytes calldata sig) external view { _verifySigPersonalSign(req, sig); } /** * @dev verifies the call is valid by calling _verifySigPersonalSign * @dev executes the forwarded call if valid * @dev updates the nonce after * @param req : ERC20 forward request being executed * @param sig : the signature generated by the user's wallet * @return success : false if call fails. true otherwise * @return ret : any return data from the call */ function executePersonalSign(ERC20ForwardRequest calldata req,bytes calldata sig) external returns(bool success, bytes memory ret){ _verifySigPersonalSign(req, sig); _updateNonce(req); (success,ret) = req.to.call{gas : req.txGas}(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.txGas / 63); _verifyCallResult(success,ret,"Forwarded call to destination did not succeed"); emit MetaTransactionExecuted(req.from, msg.sender, req.data); } /** * @dev Increments the nonce of given user/batch pair * @dev Updates the highestBatchId of the given user if the request's batchId > current highest * @dev only intended to be called post call execution * @param req : ERC20 forward request that was executed */ function _updateNonce(ERC20ForwardRequest calldata req) internal { nonces[req.from][req.batchId]++; } /** * @dev Increments the nonce of given user/batch pair * @dev Updates the highestBatchId of the given user if the request's batchId > current highest * @dev only intended to be called post call execution * @param req : ERC20 custom forward request that was executed */ function _updateNonceCustom(CustomForwardRequest calldata req) internal { nonces[req.request.from][req.request.batchId]++; } /** * @dev verifies the domain separator used has been registered via registerDomainSeparator() * @dev recreates the 32 byte hash signed by the user's wallet (as per EIP712 specifications) * @dev verifies the signature using Open Zeppelin's ECDSA library * @dev signature valid if call doesn't throw * * @param req : ERC20 forward request being executed * @param domainSeparator : the domain separator presented to the user when signing * @param sig : the signature generated by the user's wallet * */ function _verifySigEIP712( ERC20ForwardRequest calldata req, bytes32 domainSeparator, bytes memory sig) internal view { uint256 id; /* solhint-disable-next-line no-inline-assembly */ assembly { id := chainid() } require(req.deadline == 0 || block.timestamp + 20 <= req.deadline, "request expired"); require(domains[domainSeparator], "unregistered domain separator"); require(chainId == id, "potential replay attack on the fork"); bytes32 digest = keccak256(abi.encodePacked( "\x19\x01", domainSeparator, hashERC20ForwardRequest(req) )); require(digest.recover(sig) == req.from, "signature mismatch"); } /** * @dev verifies the domain separator used has been registered via registerDomainSeparator() * @dev recreates the 32 byte hash signed by the user's wallet (as per EIP712 specifications) * @dev verifies the signature using Open Zeppelin's ECDSA library * @dev signature valid if call doesn't throw * * @param req : Custom ERC20 forward request being executed * @param domainSeparator : the domain separator presented to the user when signing * @param sig : the signature generated by the user's wallet * */ function _verifySigEIP712Custom( CustomForwardRequest calldata req, bytes32 domainSeparator, bytes memory sig) internal view { uint256 id; /* solhint-disable-next-line no-inline-assembly */ assembly { id := chainid() } require(req.request.deadline == 0 || block.timestamp + 20 <= req.request.deadline, "request expired"); require(domains[domainSeparator], "unregistered domain separator"); require(chainId == id, "potential replay attack on the fork"); bytes32 digest = keccak256(abi.encodePacked( "\x19\x01", domainSeparator, hashCustomForwardRequest(req) )); require(digest.recover(sig) == req.request.from, "signature mismatch"); } function hashERC20ForwardRequest(ERC20ForwardRequest calldata request) internal view returns (bytes32) { return keccak256(abi.encode( FORWARD_REQUEST_TYPEHASH, request.from, request.to, request.token, request.txGas, request.tokenGasPrice, request.batchId, nonces[request.from][request.batchId], request.deadline, keccak256(request.data) )); } function hashCustomForwardRequest(CustomForwardRequest calldata req) internal view returns (bytes32) { return keccak256(abi.encode( CUSTOM_FORWARD_REQUEST_TYPEHASH, keccak256(bytes(req.warning)), keccak256(bytes(req.info)), keccak256(bytes(req.action)), hashERC20ForwardRequest(req.request) )); } /** * @dev encodes a 32 byte data string (presumably a hash of encoded data) as per eth_sign * * @param hash : hash of encoded data that signed by user's wallet using eth_sign * @return input hash encoded to matched what is signed by the user's key when using eth_sign*/ function prefixed(bytes32 hash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev recreates the 32 byte hash signed by the user's wallet * @dev verifies the signature using Open Zeppelin's ECDSA library * @dev signature valid if call doesn't throw * * @param req : ERC20 forward request being executed * @param sig : the signature generated by the user's wallet * */ function _verifySigPersonalSign( ERC20ForwardRequest calldata req, bytes memory sig) internal view { require(req.deadline == 0 || block.timestamp + 20 <= req.deadline, "request expired"); bytes32 digest = prefixed(keccak256(abi.encodePacked( req.from, req.to, req.token, req.txGas, req.tokenGasPrice, req.batchId, nonces[req.from][req.batchId], req.deadline, keccak256(req.data) ))); require(digest.recover(sig) == req.from, "signature mismatch"); } /** * @dev verifies the call result and bubbles up revert reason for failed calls * * @param success : outcome of forwarded call * @param returndata : returned data from the frowarded call * @param errorMessage : fallback error message to show */ function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure { if (!success) { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } else if (error == RecoverError.InvalidSignatureV) { revert("ECDSA: invalid signature 'v' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { // Check the signature length // - case 65: r,s,v signature (standard) // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._ if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else if (signature.length == 64) { bytes32 r; bytes32 vs; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) vs := mload(add(signature, 0x40)) } return tryRecover(hash, r, vs); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s; uint8 v; assembly { s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) v := add(shr(255, vs), 27) } return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } if (v != 27 && v != 28) { return (address(0), RecoverError.InvalidSignatureV); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; /* deadline can be removed : GSN reference https://github.com/opengsn/gsn/blob/master/contracts/forwarder/IForwarder.sol (Saves 250 more gas)*/ /** * @title ForwardRequestTypes * @notice specifies structures required by Forwarders to verify structured signatures. * @notice This contract defines a struct which both ERC20Forwarder and BiconomyForwarder inherit. ERC20ForwardRequest includes all the fields present in the GSN V2 ForwardRequest struct, * but adds the following : * address token : address of the token to pay for gas fees. For gasless transactions token address will be 0 address * uint256 tokenGasPrice : gas price in the context of fee token * uint256 txGas : gas to be supplied for recipient method call * uint256 batchNonce : used for 2D nonces * uint256 deadline * @dev Fields are placed in type order, to minimise storage used when executing transactions. */ contract ForwardRequestTypesV2 { /*allow the EVM to optimize for this, ensure that you try to order your storage variables and struct members such that they can be packed tightly*/ struct ForwardRequest { address from; address to; uint256 txGas; uint256 batchId; uint256 batchNonce; uint256 deadline; bytes data; } struct ERC20ForwardRequest { address from; address to; address token; uint256 txGas; uint256 tokenGasPrice; uint256 batchId; uint256 batchNonce; uint256 deadline; bytes data; } //@review //should be SandBox Forward Request? struct CustomForwardRequest { string warning; //optional string info; string action; ERC20ForwardRequest request; } //For DAI and EIP2612 type Permits struct PermitRequest { address holder; address spender; uint256 value; uint256 nonce; uint256 expiry; bool allowed; uint8 v; bytes32 r; bytes32 s; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _setOwner(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _setOwner(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _setOwner(newOwner); } function _setOwner(address newOwner) private { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
{ "evmVersion": "berlin", "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "libraries": {} }
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"domainValue","type":"bytes"}],"name":"DomainRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"userAddress","type":"address"},{"indexed":true,"internalType":"address","name":"relayerAddress","type":"address"},{"indexed":true,"internalType":"bytes","name":"functionSignature","type":"bytes"}],"name":"MetaTransactionExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"CUSTOM_FORWARD_REQUEST_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_DOMAIN_TYPE","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FORWARD_REQUEST_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REQUEST_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"domains","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"txGas","type":"uint256"},{"internalType":"uint256","name":"tokenGasPrice","type":"uint256"},{"internalType":"uint256","name":"batchId","type":"uint256"},{"internalType":"uint256","name":"batchNonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ForwardRequestTypesV2.ERC20ForwardRequest","name":"req","type":"tuple"},{"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"executeEIP712","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"ret","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"warning","type":"string"},{"internalType":"string","name":"info","type":"string"},{"internalType":"string","name":"action","type":"string"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"txGas","type":"uint256"},{"internalType":"uint256","name":"tokenGasPrice","type":"uint256"},{"internalType":"uint256","name":"batchId","type":"uint256"},{"internalType":"uint256","name":"batchNonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ForwardRequestTypesV2.ERC20ForwardRequest","name":"request","type":"tuple"}],"internalType":"struct ForwardRequestTypesV2.CustomForwardRequest","name":"req","type":"tuple"},{"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"executeEIP712Custom","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"ret","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"txGas","type":"uint256"},{"internalType":"uint256","name":"tokenGasPrice","type":"uint256"},{"internalType":"uint256","name":"batchId","type":"uint256"},{"internalType":"uint256","name":"batchNonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ForwardRequestTypesV2.ERC20ForwardRequest","name":"req","type":"tuple"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"executePersonalSign","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"ret","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"batchId","type":"uint256"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"}],"name":"registerDomainSeparator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"txGas","type":"uint256"},{"internalType":"uint256","name":"tokenGasPrice","type":"uint256"},{"internalType":"uint256","name":"batchId","type":"uint256"},{"internalType":"uint256","name":"batchNonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ForwardRequestTypesV2.ERC20ForwardRequest","name":"req","type":"tuple"},{"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"verifyEIP712","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"txGas","type":"uint256"},{"internalType":"uint256","name":"tokenGasPrice","type":"uint256"},{"internalType":"uint256","name":"batchId","type":"uint256"},{"internalType":"uint256","name":"batchNonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ForwardRequestTypesV2.ERC20ForwardRequest","name":"req","type":"tuple"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"verifyPersonalSign","outputs":[],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5061001a33610023565b46600255610073565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611dbf806100826000396000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c80639563096811610097578063c3f28abd11610066578063c3f28abd146101fc578063c722f17714610211578063e630543314610244578063f2fde38b1461024c57600080fd5b806395630968146101c65780639c7b4592146101ce5780639e39b73e146101e1578063a41a03f2146101e957600080fd5b8063715018a6116100d3578063715018a61461014c5780638171e6321461015457806389535803146101675780638da5cb5b146101ab57600080fd5b806341706c4e146100fa5780634abec93d146101245780636e4cb07514610137575b600080fd5b61010d6101083660046117f0565b61025f565b60405161011b929190611928565b60405180910390f35b61010d610132366004611795565b61041a565b61014a610145366004611844565b6105fa565b005b61014a61063f565b61010d610162366004611844565b61067e565b61019d6101753660046116eb565b6001600160a01b03919091166000908152600360209081526040808320938352929052205490565b60405190815260200161011b565b6000546040516001600160a01b03909116815260200161011b565b61019d610837565b61014a6101dc36600461172c565b61085a565b61019d61097b565b61014a6101f73660046117f0565b61099e565b6102046109e5565b60405161011b919061194b565b61023461021f366004611714565b60016020526000908152604090205460ff1681565b604051901515815260200161011b565b61019d610a01565b61014a61025a3660046116ca565b610a25565b600060606102a4868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ac092505050565b6102ad86610c30565b6102bd60408701602088016116ca565b6001600160a01b031660608701356102d96101008901896119ff565b6102e660208b018b6116ca565b6040516020016102f8939291906118e6565b60408051601f19818403018152908290526103129161190c565b60006040518083038160008787f1925050503d8060008114610350576040519150601f19603f3d011682016040523d82523d6000602084013e610355565b606091505b50909250905061036a603f6060880135611a88565b5a1161038657634e487b7160e01b600052600160045260246000fd5b6103a982826040518060600160405280602d8152602001611c66602d9139610c7f565b6103b76101008701876119ff565b6040516103c59291906118d6565b604051908190039020336103dc60208901896116ca565b6001600160a01b03167f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b60405160405180910390a494509492505050565b6000606061045f868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610cae92505050565b61046886610de0565b6104756060870187611a5a565b6104869060408101906020016116ca565b6001600160a01b031661049c6060880188611a5a565b606001358780606001906104b09190611a5a565b6104bf906101008101906119ff565b6104cc60608b018b611a5a565b6104da9060208101906116ca565b6040516020016104ec939291906118e6565b60408051601f19818403018152908290526105069161190c565b60006040518083038160008787f1925050503d8060008114610544576040519150601f19603f3d011682016040523d82523d6000602084013e610549565b606091505b509092509050603f61055e6060880188611a5a565b6060013561056c9190611a88565b5a1161058857634e487b7160e01b600052600160045260246000fd5b6105ab82826040518060600160405280602d8152602001611c66602d9139610c7f565b6105b86060870187611a5a565b6105c7906101008101906119ff565b6040516105d59291906118d6565b604051908190039020336105ec6060890189611a5a565b6103dc9060208101906116ca565b61063a8383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e4b92505050565b505050565b6000546001600160a01b031633146106725760405162461bcd60e51b815260040161066990611987565b60405180910390fd5b61067c6000611010565b565b600060606106c28585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e4b92505050565b6106cb85610c30565b6106db60408601602087016116ca565b6001600160a01b031660608601356106f76101008801886119ff565b61070460208a018a6116ca565b604051602001610716939291906118e6565b60408051601f19818403018152908290526107309161190c565b60006040518083038160008787f1925050503d806000811461076e576040519150601f19603f3d011682016040523d82523d6000602084013e610773565b606091505b509092509050610788603f6060870135611a88565b5a116107a457634e487b7160e01b600052600160045260246000fd5b6107c782826040518060600160405280602d8152602001611c66602d9139610c7f565b6107d56101008601866119ff565b6040516107e39291906118d6565b604051908190039020336107fa60208801886116ca565b6001600160a01b03167f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b60405160405180910390a4935093915050565b6040518060c00160405280609d8152602001611bc9609d91398051906020012081565b6000546001600160a01b031633146108845760405162461bcd60e51b815260040161066990611987565b600046905060006040518060800160405280604f8152602001611b06604f91398051906020012086866040516108bb9291906118d6565b604051809103902085856040516108d39291906118d6565b604080519182900382206020830194909452810191909152606081019190915230608082015260a0810183905260c00160408051601f198184030181528282528051602080830191909120600081815260019283905293909320805460ff1916909117905592509081907f4bc68689cbe89a4a6333a3ab0a70093874da3e5bfb71e93102027f3f073687d89061096a90859061194b565b60405180910390a250505050505050565b6040518060a0016040528060748152602001611b55607491398051906020012081565b6109df848484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ac092505050565b50505050565b6040518060800160405280604f8152602001611b06604f913981565b60405180610120016040528060f78152602001611c9360f791398051906020012081565b6000546001600160a01b03163314610a4f5760405162461bcd60e51b815260040161066990611987565b6001600160a01b038116610ab45760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610669565b610abd81611010565b50565b4660e08401351580610ae0575060e0840135610add426014611a70565b11155b610afc5760405162461bcd60e51b81526004016106699061195e565b60008381526001602052604090205460ff16610b5a5760405162461bcd60e51b815260206004820152601d60248201527f756e7265676973746572656420646f6d61696e20736570617261746f720000006044820152606401610669565b8060025414610b7b5760405162461bcd60e51b8152600401610669906119bc565b600083610b8786611060565b60405161190160f01b60208201526022810192909252604282015260620160408051601f1981840301815291905280516020918201209150610bcb908601866116ca565b6001600160a01b0316610bde828561119a565b6001600160a01b031614610c295760405162461bcd60e51b81526020600482015260126024820152710e6d2cedcc2e8eae4ca40dad2e6dac2e8c6d60731b6044820152606401610669565b5050505050565b60036000610c4160208401846116ca565b6001600160a01b031681526020808201929092526040908101600090812060a085013582529092528120805491610c7783611ad4565b919050555050565b8261063a57815115610c945781518083602001fd5b8060405162461bcd60e51b8152600401610669919061194b565b46610cbc6060850185611a5a565b60e001351580610ce65750610cd46060850185611a5a565b60e00135610ce3426014611a70565b11155b610d025760405162461bcd60e51b81526004016106699061195e565b60008381526001602052604090205460ff16610d605760405162461bcd60e51b815260206004820152601d60248201527f756e7265676973746572656420646f6d61696e20736570617261746f720000006044820152606401610669565b8060025414610d815760405162461bcd60e51b8152600401610669906119bc565b600083610d8d866111be565b60405161190160f01b60208201526022810192909252604282015260620160408051601f1981840301815291905280516020909101209050610dd26060860186611a5a565b610bcb9060208101906116ca565b60036000610df16060840184611a5a565b610dff9060208101906116ca565b6001600160a01b031681526020810191909152604001600090812090610e286060840184611a5a565b60a0013581526020019081526020016000206000815480929190610c7790611ad4565b60e08201351580610e6a575060e0820135610e67426014611a70565b11155b610e865760405162461bcd60e51b81526004016106699061195e565b6000610fa3610e9860208501856116ca565b610ea860408601602087016116ca565b610eb860608701604088016116ca565b6060870135608088013560a089013560036000610ed860208d018d6116ca565b6001600160a01b031681526020808201929092526040908101600090812060a08e0135825290925290205460e08b0135610f166101008d018d6119ff565b604051610f249291906118d6565b6040519081900381206bffffffffffffffffffffffff1960609a8b1b81166020840152988a1b891660348301529690981b9096166048880152605c870193909352607c860191909152609c85015260bc84015260dc83019190915260fc82015261011c016040516020818303038152906040528051906020012061128e565b9050610fb260208401846116ca565b6001600160a01b0316610fc5828461119a565b6001600160a01b03161461063a5760405162461bcd60e51b81526020600482015260126024820152710e6d2cedcc2e8eae4ca40dad2e6dac2e8c6d60731b6044820152606401610669565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006040518060c00160405280609d8152602001611bc9609d9139805160209182012090611090908401846116ca565b6110a060408501602086016116ca565b6110b060608601604087016116ca565b6060860135608087013560a0880135600360006110d060208c018c6116ca565b6001600160a01b031681526020808201929092526040908101600090812060a08d0135825290925290205460e08a013561110e6101008c018c6119ff565b60405161111c9291906118d6565b60408051918290038220602083019b909b526001600160a01b03998a1690820152968816606088015296909416608086015260a085019290925260c084015260e0830152610100820152610120810191909152610140810191909152610160015b604051602081830303815290604052805190602001209050919050565b60008060006111a985856112c9565b915091506111b681611339565b509392505050565b600060405180610120016040528060f78152602001611c9360f7913980516020909101206111ec8380611a44565b6040516111fa9291906118d6565b6040519081900390206112106020850185611a44565b60405161121e9291906118d6565b60405180910390208480604001906112369190611a44565b6040516112449291906118d6565b60405190819003902061126261125d6060880188611a5a565b611060565b6040805160208101969096528501939093526060840191909152608083015260a082015260c00161117d565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c0161117d565b6000808251604114156113005760208301516040840151606085015160001a6112f48782858561153a565b94509450505050611332565b82516040141561132a576020830151604084015161131f868383611627565b935093505050611332565b506000905060025b9250929050565b600081600481111561135b57634e487b7160e01b600052602160045260246000fd5b14156113645750565b600181600481111561138657634e487b7160e01b600052602160045260246000fd5b14156113d45760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610669565b60028160048111156113f657634e487b7160e01b600052602160045260246000fd5b14156114445760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610669565b600381600481111561146657634e487b7160e01b600052602160045260246000fd5b14156114bf5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610669565b60048160048111156114e157634e487b7160e01b600052602160045260246000fd5b1415610abd5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610669565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611571575060009050600361161e565b8460ff16601b1415801561158957508460ff16601c14155b1561159a575060009050600461161e565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156115ee573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166116175760006001925092505061161e565b9150600090505b94509492505050565b6000806001600160ff1b03831660ff84901c601b016116488782888561153a565b935093505050935093915050565b80356001600160a01b038116811461166d57600080fd5b919050565b60008083601f840112611683578182fd5b50813567ffffffffffffffff81111561169a578182fd5b60208301915083602082850101111561133257600080fd5b600061012082840312156116c4578081fd5b50919050565b6000602082840312156116db578081fd5b6116e482611656565b9392505050565b600080604083850312156116fd578081fd5b61170683611656565b946020939093013593505050565b600060208284031215611725578081fd5b5035919050565b60008060008060408587031215611741578182fd5b843567ffffffffffffffff80821115611758578384fd5b61176488838901611672565b9096509450602087013591508082111561177c578384fd5b5061178987828801611672565b95989497509550505050565b600080600080606085870312156117aa578384fd5b843567ffffffffffffffff808211156117c1578586fd5b90860190608082890312156117d4578586fd5b909450602086013593506040860135908082111561177c578384fd5b60008060008060608587031215611805578384fd5b843567ffffffffffffffff8082111561181c578586fd5b611828888389016116b2565b955060208701359450604087013591508082111561177c578384fd5b600080600060408486031215611858578283fd5b833567ffffffffffffffff8082111561186f578485fd5b61187b878388016116b2565b94506020860135915080821115611890578384fd5b5061189d86828701611672565b9497909650939450505050565b600081518084526118c2816020860160208601611aa8565b601f01601f19169290920160200192915050565b8183823760009101908152919050565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b6000825161191e818460208701611aa8565b9190910192915050565b821515815260406020820152600061194360408301846118aa565b949350505050565b6020815260006116e460208301846118aa565b6020808252600f908201526e1c995c5d595cdd08195e1c1a5c9959608a1b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526023908201527f706f74656e7469616c207265706c61792061747461636b206f6e2074686520666040820152626f726b60e81b606082015260800190565b6000808335601e19843603018112611a15578283fd5b83018035915067ffffffffffffffff821115611a2f578283fd5b60200191503681900382131561133257600080fd5b6000808335601e19843603018112611a15578182fd5b6000823561011e1983360301811261191e578182fd5b60008219821115611a8357611a83611aef565b500190565b600082611aa357634e487b7160e01b81526012600452602481fd5b500490565b60005b83811015611ac3578181015183820152602001611aab565b838111156109df5750506000910152565b6000600019821415611ae857611ae8611aef565b5060010190565b634e487b7160e01b600052601160045260246000fdfe454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c6164647265737320766572696679696e67436f6e74726163742c627974657333322073616c7429466f72776172645265717565737428616464726573732066726f6d2c6164647265737320746f2c75696e743235362074784761732c75696e7432353620626174636849642c75696e743235362062617463684e6f6e63652c75696e7432353620646561646c696e652c62797465732064617461294552433230466f72776172645265717565737428616464726573732066726f6d2c6164647265737320746f2c6164647265737320746f6b656e2c75696e743235362074784761732c75696e7432353620746f6b656e47617350726963652c75696e7432353620626174636849642c75696e743235362062617463684e6f6e63652c75696e7432353620646561646c696e652c6279746573206461746129466f727761726465642063616c6c20746f2064657374696e6174696f6e20646964206e6f742073756363656564437573746f6d466f72776172645265717565737428737472696e67207761726e696e672c737472696e6720696e666f2c737472696e6720616374696f6e2c4552433230466f7277617264526571756573742072657175657374294552433230466f72776172645265717565737428616464726573732066726f6d2c6164647265737320746f2c6164647265737320746f6b656e2c75696e743235362074784761732c75696e7432353620746f6b656e47617350726963652c75696e7432353620626174636849642c75696e743235362062617463684e6f6e63652c75696e7432353620646561646c696e652c6279746573206461746129a26469706673582212205fbc05e07af55f4c17f97fd5da997389fe94192a5be1e03a1620cd754a89d82a64736f6c63430008040033
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|