Mumbai Testnet

Contract

0x69015912AA33720b842dCD6aC059Ed623F28d9f7
Transaction Hash
Method
Block
From
To
Value
Execute Personal...481399482024-04-11 21:38:0749 days ago1712871487IN
0x69015912...23F28d9f7
0 MATIC0.0032817236.00000003
Execute Personal...481297442024-04-11 15:21:4749 days ago1712848907IN
0x69015912...23F28d9f7
0 MATIC0.000730158.73814801
Execute EIP712481291402024-04-11 14:58:4749 days ago1712847527IN
0x69015912...23F28d9f7
0 MATIC0.002540677.88549472
Execute EIP712481291162024-04-11 14:57:5549 days ago1712847475IN
0x69015912...23F28d9f7
0 MATIC0.002540327.88549472
Execute EIP712481290932024-04-11 14:57:0749 days ago1712847427IN
0x69015912...23F28d9f7
0 MATIC0.002369336.984
Execute EIP712481290182024-04-11 14:53:5549 days ago1712847235IN
0x69015912...23F28d9f7
0 MATIC0.001269215.82
Execute Personal...481287292024-04-11 14:42:5749 days ago1712846577IN
0x69015912...23F28d9f7
0 MATIC0.0023663510.07200001
Execute Personal...481286882024-04-11 14:41:1149 days ago1712846471IN
0x69015912...23F28d9f7
0 MATIC0.0037684810.06700001
Execute EIP712481285462024-04-11 14:35:4349 days ago1712846143IN
0x69015912...23F28d9f7
0 MATIC0.003008037.2
Execute Personal...481281452024-04-11 14:20:5349 days ago1712845253IN
0x69015912...23F28d9f7
0 MATIC0.0018424810.00000001
Execute EIP712481277232024-04-11 14:05:5549 days ago1712844355IN
0x69015912...23F28d9f7
0 MATIC0.001084281.80000001
Execute Personal...481276582024-04-11 14:03:3749 days ago1712844217IN
0x69015912...23F28d9f7
0 MATIC0.000331681.80000001
Execute Personal...481272162024-04-11 13:47:5049 days ago1712843270IN
0x69015912...23F28d9f7
0 MATIC0.0040307820.01900001
Execute Personal...481271772024-04-11 13:46:2649 days ago1712843186IN
0x69015912...23F28d9f7
0 MATIC0.0046982420.00000001
Execute Personal...481271082024-04-11 13:44:0049 days ago1712843040IN
0x69015912...23F28d9f7
0 MATIC0.007486820.00000001
Execute EIP712481204942024-04-11 9:48:2049 days ago1712828900IN
0x69015912...23F28d9f7
0 MATIC0.0112316225.00000001
Execute EIP712481203642024-04-11 9:43:4449 days ago1712828624IN
0x69015912...23F28d9f7
0 MATIC0.0123009627.38019001
Execute EIP712481201352024-04-11 9:35:3849 days ago1712828138IN
0x69015912...23F28d9f7
0 MATIC0.0076572924.76469421
Execute EIP712481177562024-04-11 8:10:5949 days ago1712823059IN
0x69015912...23F28d9f7
0 MATIC0.0047781915.45231789
Execute EIP712480983872024-04-10 20:27:5850 days ago1712780878IN
0x69015912...23F28d9f7
0 MATIC0.000654875.48732882
Execute EIP712480971142024-04-10 19:38:5250 days ago1712777932IN
0x69015912...23F28d9f7
0 MATIC0.001348533.75000001
Execute EIP712480969932024-04-10 19:34:0850 days ago1712777648IN
0x69015912...23F28d9f7
0 MATIC0.000343732.88000001
Execute EIP712480961022024-04-10 19:00:4850 days ago1712775648IN
0x69015912...23F28d9f7
0 MATIC0.00059755
Execute EIP712480956742024-04-10 18:45:3650 days ago1712774736IN
0x69015912...23F28d9f7
0 MATIC0.001145669.6
Execute EIP712480950082024-04-10 18:21:5050 days ago1712773310IN
0x69015912...23F28d9f7
0 MATIC0.000894637.5
View all transactions

Parent Transaction Hash Block From To Value
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

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)

File 1 of 5 : BiconomyForwarderV2.sol
// 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);
            }
        }
    }

}

File 2 of 5 : ECDSA.sol
// 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));
    }
}

File 2 of 5 : ForwardRequestTypesV2.sol
// 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; 
    }

}

File 2 of 5 : Ownable.sol
// 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);
    }
}

File 2 of 5 : Context.sol
// 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;
    }
}

Settings
{
  "evmVersion": "berlin",
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

[{"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"}]

608060405234801561001057600080fd5b5061001a33610023565b46600255610073565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611dbf806100826000396000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c80639563096811610097578063c3f28abd11610066578063c3f28abd146101fc578063c722f17714610211578063e630543314610244578063f2fde38b1461024c57600080fd5b806395630968146101c65780639c7b4592146101ce5780639e39b73e146101e1578063a41a03f2146101e957600080fd5b8063715018a6116100d3578063715018a61461014c5780638171e6321461015457806389535803146101675780638da5cb5b146101ab57600080fd5b806341706c4e146100fa5780634abec93d146101245780636e4cb07514610137575b600080fd5b61010d6101083660046117f0565b61025f565b60405161011b929190611928565b60405180910390f35b61010d610132366004611795565b61041a565b61014a610145366004611844565b6105fa565b005b61014a61063f565b61010d610162366004611844565b61067e565b61019d6101753660046116eb565b6001600160a01b03919091166000908152600360209081526040808320938352929052205490565b60405190815260200161011b565b6000546040516001600160a01b03909116815260200161011b565b61019d610837565b61014a6101dc36600461172c565b61085a565b61019d61097b565b61014a6101f73660046117f0565b61099e565b6102046109e5565b60405161011b919061194b565b61023461021f366004611714565b60016020526000908152604090205460ff1681565b604051901515815260200161011b565b61019d610a01565b61014a61025a3660046116ca565b610a25565b600060606102a4868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ac092505050565b6102ad86610c30565b6102bd60408701602088016116ca565b6001600160a01b031660608701356102d96101008901896119ff565b6102e660208b018b6116ca565b6040516020016102f8939291906118e6565b60408051601f19818403018152908290526103129161190c565b60006040518083038160008787f1925050503d8060008114610350576040519150601f19603f3d011682016040523d82523d6000602084013e610355565b606091505b50909250905061036a603f6060880135611a88565b5a1161038657634e487b7160e01b600052600160045260246000fd5b6103a982826040518060600160405280602d8152602001611c66602d9139610c7f565b6103b76101008701876119ff565b6040516103c59291906118d6565b604051908190039020336103dc60208901896116ca565b6001600160a01b03167f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b60405160405180910390a494509492505050565b6000606061045f868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610cae92505050565b61046886610de0565b6104756060870187611a5a565b6104869060408101906020016116ca565b6001600160a01b031661049c6060880188611a5a565b606001358780606001906104b09190611a5a565b6104bf906101008101906119ff565b6104cc60608b018b611a5a565b6104da9060208101906116ca565b6040516020016104ec939291906118e6565b60408051601f19818403018152908290526105069161190c565b60006040518083038160008787f1925050503d8060008114610544576040519150601f19603f3d011682016040523d82523d6000602084013e610549565b606091505b509092509050603f61055e6060880188611a5a565b6060013561056c9190611a88565b5a1161058857634e487b7160e01b600052600160045260246000fd5b6105ab82826040518060600160405280602d8152602001611c66602d9139610c7f565b6105b86060870187611a5a565b6105c7906101008101906119ff565b6040516105d59291906118d6565b604051908190039020336105ec6060890189611a5a565b6103dc9060208101906116ca565b61063a8383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e4b92505050565b505050565b6000546001600160a01b031633146106725760405162461bcd60e51b815260040161066990611987565b60405180910390fd5b61067c6000611010565b565b600060606106c28585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e4b92505050565b6106cb85610c30565b6106db60408601602087016116ca565b6001600160a01b031660608601356106f76101008801886119ff565b61070460208a018a6116ca565b604051602001610716939291906118e6565b60408051601f19818403018152908290526107309161190c565b60006040518083038160008787f1925050503d806000811461076e576040519150601f19603f3d011682016040523d82523d6000602084013e610773565b606091505b509092509050610788603f6060870135611a88565b5a116107a457634e487b7160e01b600052600160045260246000fd5b6107c782826040518060600160405280602d8152602001611c66602d9139610c7f565b6107d56101008601866119ff565b6040516107e39291906118d6565b604051908190039020336107fa60208801886116ca565b6001600160a01b03167f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b60405160405180910390a4935093915050565b6040518060c00160405280609d8152602001611bc9609d91398051906020012081565b6000546001600160a01b031633146108845760405162461bcd60e51b815260040161066990611987565b600046905060006040518060800160405280604f8152602001611b06604f91398051906020012086866040516108bb9291906118d6565b604051809103902085856040516108d39291906118d6565b604080519182900382206020830194909452810191909152606081019190915230608082015260a0810183905260c00160408051601f198184030181528282528051602080830191909120600081815260019283905293909320805460ff1916909117905592509081907f4bc68689cbe89a4a6333a3ab0a70093874da3e5bfb71e93102027f3f073687d89061096a90859061194b565b60405180910390a250505050505050565b6040518060a0016040528060748152602001611b55607491398051906020012081565b6109df848484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ac092505050565b50505050565b6040518060800160405280604f8152602001611b06604f913981565b60405180610120016040528060f78152602001611c9360f791398051906020012081565b6000546001600160a01b03163314610a4f5760405162461bcd60e51b815260040161066990611987565b6001600160a01b038116610ab45760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610669565b610abd81611010565b50565b4660e08401351580610ae0575060e0840135610add426014611a70565b11155b610afc5760405162461bcd60e51b81526004016106699061195e565b60008381526001602052604090205460ff16610b5a5760405162461bcd60e51b815260206004820152601d60248201527f756e7265676973746572656420646f6d61696e20736570617261746f720000006044820152606401610669565b8060025414610b7b5760405162461bcd60e51b8152600401610669906119bc565b600083610b8786611060565b60405161190160f01b60208201526022810192909252604282015260620160408051601f1981840301815291905280516020918201209150610bcb908601866116ca565b6001600160a01b0316610bde828561119a565b6001600160a01b031614610c295760405162461bcd60e51b81526020600482015260126024820152710e6d2cedcc2e8eae4ca40dad2e6dac2e8c6d60731b6044820152606401610669565b5050505050565b60036000610c4160208401846116ca565b6001600160a01b031681526020808201929092526040908101600090812060a085013582529092528120805491610c7783611ad4565b919050555050565b8261063a57815115610c945781518083602001fd5b8060405162461bcd60e51b8152600401610669919061194b565b46610cbc6060850185611a5a565b60e001351580610ce65750610cd46060850185611a5a565b60e00135610ce3426014611a70565b11155b610d025760405162461bcd60e51b81526004016106699061195e565b60008381526001602052604090205460ff16610d605760405162461bcd60e51b815260206004820152601d60248201527f756e7265676973746572656420646f6d61696e20736570617261746f720000006044820152606401610669565b8060025414610d815760405162461bcd60e51b8152600401610669906119bc565b600083610d8d866111be565b60405161190160f01b60208201526022810192909252604282015260620160408051601f1981840301815291905280516020909101209050610dd26060860186611a5a565b610bcb9060208101906116ca565b60036000610df16060840184611a5a565b610dff9060208101906116ca565b6001600160a01b031681526020810191909152604001600090812090610e286060840184611a5a565b60a0013581526020019081526020016000206000815480929190610c7790611ad4565b60e08201351580610e6a575060e0820135610e67426014611a70565b11155b610e865760405162461bcd60e51b81526004016106699061195e565b6000610fa3610e9860208501856116ca565b610ea860408601602087016116ca565b610eb860608701604088016116ca565b6060870135608088013560a089013560036000610ed860208d018d6116ca565b6001600160a01b031681526020808201929092526040908101600090812060a08e0135825290925290205460e08b0135610f166101008d018d6119ff565b604051610f249291906118d6565b6040519081900381206bffffffffffffffffffffffff1960609a8b1b81166020840152988a1b891660348301529690981b9096166048880152605c870193909352607c860191909152609c85015260bc84015260dc83019190915260fc82015261011c016040516020818303038152906040528051906020012061128e565b9050610fb260208401846116ca565b6001600160a01b0316610fc5828461119a565b6001600160a01b03161461063a5760405162461bcd60e51b81526020600482015260126024820152710e6d2cedcc2e8eae4ca40dad2e6dac2e8c6d60731b6044820152606401610669565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006040518060c00160405280609d8152602001611bc9609d9139805160209182012090611090908401846116ca565b6110a060408501602086016116ca565b6110b060608601604087016116ca565b6060860135608087013560a0880135600360006110d060208c018c6116ca565b6001600160a01b031681526020808201929092526040908101600090812060a08d0135825290925290205460e08a013561110e6101008c018c6119ff565b60405161111c9291906118d6565b60408051918290038220602083019b909b526001600160a01b03998a1690820152968816606088015296909416608086015260a085019290925260c084015260e0830152610100820152610120810191909152610140810191909152610160015b604051602081830303815290604052805190602001209050919050565b60008060006111a985856112c9565b915091506111b681611339565b509392505050565b600060405180610120016040528060f78152602001611c9360f7913980516020909101206111ec8380611a44565b6040516111fa9291906118d6565b6040519081900390206112106020850185611a44565b60405161121e9291906118d6565b60405180910390208480604001906112369190611a44565b6040516112449291906118d6565b60405190819003902061126261125d6060880188611a5a565b611060565b6040805160208101969096528501939093526060840191909152608083015260a082015260c00161117d565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c0161117d565b6000808251604114156113005760208301516040840151606085015160001a6112f48782858561153a565b94509450505050611332565b82516040141561132a576020830151604084015161131f868383611627565b935093505050611332565b506000905060025b9250929050565b600081600481111561135b57634e487b7160e01b600052602160045260246000fd5b14156113645750565b600181600481111561138657634e487b7160e01b600052602160045260246000fd5b14156113d45760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610669565b60028160048111156113f657634e487b7160e01b600052602160045260246000fd5b14156114445760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610669565b600381600481111561146657634e487b7160e01b600052602160045260246000fd5b14156114bf5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610669565b60048160048111156114e157634e487b7160e01b600052602160045260246000fd5b1415610abd5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610669565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611571575060009050600361161e565b8460ff16601b1415801561158957508460ff16601c14155b1561159a575060009050600461161e565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156115ee573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166116175760006001925092505061161e565b9150600090505b94509492505050565b6000806001600160ff1b03831660ff84901c601b016116488782888561153a565b935093505050935093915050565b80356001600160a01b038116811461166d57600080fd5b919050565b60008083601f840112611683578182fd5b50813567ffffffffffffffff81111561169a578182fd5b60208301915083602082850101111561133257600080fd5b600061012082840312156116c4578081fd5b50919050565b6000602082840312156116db578081fd5b6116e482611656565b9392505050565b600080604083850312156116fd578081fd5b61170683611656565b946020939093013593505050565b600060208284031215611725578081fd5b5035919050565b60008060008060408587031215611741578182fd5b843567ffffffffffffffff80821115611758578384fd5b61176488838901611672565b9096509450602087013591508082111561177c578384fd5b5061178987828801611672565b95989497509550505050565b600080600080606085870312156117aa578384fd5b843567ffffffffffffffff808211156117c1578586fd5b90860190608082890312156117d4578586fd5b909450602086013593506040860135908082111561177c578384fd5b60008060008060608587031215611805578384fd5b843567ffffffffffffffff8082111561181c578586fd5b611828888389016116b2565b955060208701359450604087013591508082111561177c578384fd5b600080600060408486031215611858578283fd5b833567ffffffffffffffff8082111561186f578485fd5b61187b878388016116b2565b94506020860135915080821115611890578384fd5b5061189d86828701611672565b9497909650939450505050565b600081518084526118c2816020860160208601611aa8565b601f01601f19169290920160200192915050565b8183823760009101908152919050565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b6000825161191e818460208701611aa8565b9190910192915050565b821515815260406020820152600061194360408301846118aa565b949350505050565b6020815260006116e460208301846118aa565b6020808252600f908201526e1c995c5d595cdd08195e1c1a5c9959608a1b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526023908201527f706f74656e7469616c207265706c61792061747461636b206f6e2074686520666040820152626f726b60e81b606082015260800190565b6000808335601e19843603018112611a15578283fd5b83018035915067ffffffffffffffff821115611a2f578283fd5b60200191503681900382131561133257600080fd5b6000808335601e19843603018112611a15578182fd5b6000823561011e1983360301811261191e578182fd5b60008219821115611a8357611a83611aef565b500190565b600082611aa357634e487b7160e01b81526012600452602481fd5b500490565b60005b83811015611ac3578181015183820152602001611aab565b838111156109df5750506000910152565b6000600019821415611ae857611ae8611aef565b5060010190565b634e487b7160e01b600052601160045260246000fdfe454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c6164647265737320766572696679696e67436f6e74726163742c627974657333322073616c7429466f72776172645265717565737428616464726573732066726f6d2c6164647265737320746f2c75696e743235362074784761732c75696e7432353620626174636849642c75696e743235362062617463684e6f6e63652c75696e7432353620646561646c696e652c62797465732064617461294552433230466f72776172645265717565737428616464726573732066726f6d2c6164647265737320746f2c6164647265737320746f6b656e2c75696e743235362074784761732c75696e7432353620746f6b656e47617350726963652c75696e7432353620626174636849642c75696e743235362062617463684e6f6e63652c75696e7432353620646561646c696e652c6279746573206461746129466f727761726465642063616c6c20746f2064657374696e6174696f6e20646964206e6f742073756363656564437573746f6d466f72776172645265717565737428737472696e67207761726e696e672c737472696e6720696e666f2c737472696e6720616374696f6e2c4552433230466f7277617264526571756573742072657175657374294552433230466f72776172645265717565737428616464726573732066726f6d2c6164647265737320746f2c6164647265737320746f6b656e2c75696e743235362074784761732c75696e7432353620746f6b656e47617350726963652c75696e7432353620626174636849642c75696e743235362062617463684e6f6e63652c75696e7432353620646561646c696e652c6279746573206461746129a26469706673582212205fbc05e07af55f4c17f97fd5da997389fe94192a5be1e03a1620cd754a89d82a64736f6c63430008040033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100f55760003560e01c80639563096811610097578063c3f28abd11610066578063c3f28abd146101fc578063c722f17714610211578063e630543314610244578063f2fde38b1461024c57600080fd5b806395630968146101c65780639c7b4592146101ce5780639e39b73e146101e1578063a41a03f2146101e957600080fd5b8063715018a6116100d3578063715018a61461014c5780638171e6321461015457806389535803146101675780638da5cb5b146101ab57600080fd5b806341706c4e146100fa5780634abec93d146101245780636e4cb07514610137575b600080fd5b61010d6101083660046117f0565b61025f565b60405161011b929190611928565b60405180910390f35b61010d610132366004611795565b61041a565b61014a610145366004611844565b6105fa565b005b61014a61063f565b61010d610162366004611844565b61067e565b61019d6101753660046116eb565b6001600160a01b03919091166000908152600360209081526040808320938352929052205490565b60405190815260200161011b565b6000546040516001600160a01b03909116815260200161011b565b61019d610837565b61014a6101dc36600461172c565b61085a565b61019d61097b565b61014a6101f73660046117f0565b61099e565b6102046109e5565b60405161011b919061194b565b61023461021f366004611714565b60016020526000908152604090205460ff1681565b604051901515815260200161011b565b61019d610a01565b61014a61025a3660046116ca565b610a25565b600060606102a4868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ac092505050565b6102ad86610c30565b6102bd60408701602088016116ca565b6001600160a01b031660608701356102d96101008901896119ff565b6102e660208b018b6116ca565b6040516020016102f8939291906118e6565b60408051601f19818403018152908290526103129161190c565b60006040518083038160008787f1925050503d8060008114610350576040519150601f19603f3d011682016040523d82523d6000602084013e610355565b606091505b50909250905061036a603f6060880135611a88565b5a1161038657634e487b7160e01b600052600160045260246000fd5b6103a982826040518060600160405280602d8152602001611c66602d9139610c7f565b6103b76101008701876119ff565b6040516103c59291906118d6565b604051908190039020336103dc60208901896116ca565b6001600160a01b03167f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b60405160405180910390a494509492505050565b6000606061045f868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610cae92505050565b61046886610de0565b6104756060870187611a5a565b6104869060408101906020016116ca565b6001600160a01b031661049c6060880188611a5a565b606001358780606001906104b09190611a5a565b6104bf906101008101906119ff565b6104cc60608b018b611a5a565b6104da9060208101906116ca565b6040516020016104ec939291906118e6565b60408051601f19818403018152908290526105069161190c565b60006040518083038160008787f1925050503d8060008114610544576040519150601f19603f3d011682016040523d82523d6000602084013e610549565b606091505b509092509050603f61055e6060880188611a5a565b6060013561056c9190611a88565b5a1161058857634e487b7160e01b600052600160045260246000fd5b6105ab82826040518060600160405280602d8152602001611c66602d9139610c7f565b6105b86060870187611a5a565b6105c7906101008101906119ff565b6040516105d59291906118d6565b604051908190039020336105ec6060890189611a5a565b6103dc9060208101906116ca565b61063a8383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e4b92505050565b505050565b6000546001600160a01b031633146106725760405162461bcd60e51b815260040161066990611987565b60405180910390fd5b61067c6000611010565b565b600060606106c28585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e4b92505050565b6106cb85610c30565b6106db60408601602087016116ca565b6001600160a01b031660608601356106f76101008801886119ff565b61070460208a018a6116ca565b604051602001610716939291906118e6565b60408051601f19818403018152908290526107309161190c565b60006040518083038160008787f1925050503d806000811461076e576040519150601f19603f3d011682016040523d82523d6000602084013e610773565b606091505b509092509050610788603f6060870135611a88565b5a116107a457634e487b7160e01b600052600160045260246000fd5b6107c782826040518060600160405280602d8152602001611c66602d9139610c7f565b6107d56101008601866119ff565b6040516107e39291906118d6565b604051908190039020336107fa60208801886116ca565b6001600160a01b03167f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b60405160405180910390a4935093915050565b6040518060c00160405280609d8152602001611bc9609d91398051906020012081565b6000546001600160a01b031633146108845760405162461bcd60e51b815260040161066990611987565b600046905060006040518060800160405280604f8152602001611b06604f91398051906020012086866040516108bb9291906118d6565b604051809103902085856040516108d39291906118d6565b604080519182900382206020830194909452810191909152606081019190915230608082015260a0810183905260c00160408051601f198184030181528282528051602080830191909120600081815260019283905293909320805460ff1916909117905592509081907f4bc68689cbe89a4a6333a3ab0a70093874da3e5bfb71e93102027f3f073687d89061096a90859061194b565b60405180910390a250505050505050565b6040518060a0016040528060748152602001611b55607491398051906020012081565b6109df848484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ac092505050565b50505050565b6040518060800160405280604f8152602001611b06604f913981565b60405180610120016040528060f78152602001611c9360f791398051906020012081565b6000546001600160a01b03163314610a4f5760405162461bcd60e51b815260040161066990611987565b6001600160a01b038116610ab45760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610669565b610abd81611010565b50565b4660e08401351580610ae0575060e0840135610add426014611a70565b11155b610afc5760405162461bcd60e51b81526004016106699061195e565b60008381526001602052604090205460ff16610b5a5760405162461bcd60e51b815260206004820152601d60248201527f756e7265676973746572656420646f6d61696e20736570617261746f720000006044820152606401610669565b8060025414610b7b5760405162461bcd60e51b8152600401610669906119bc565b600083610b8786611060565b60405161190160f01b60208201526022810192909252604282015260620160408051601f1981840301815291905280516020918201209150610bcb908601866116ca565b6001600160a01b0316610bde828561119a565b6001600160a01b031614610c295760405162461bcd60e51b81526020600482015260126024820152710e6d2cedcc2e8eae4ca40dad2e6dac2e8c6d60731b6044820152606401610669565b5050505050565b60036000610c4160208401846116ca565b6001600160a01b031681526020808201929092526040908101600090812060a085013582529092528120805491610c7783611ad4565b919050555050565b8261063a57815115610c945781518083602001fd5b8060405162461bcd60e51b8152600401610669919061194b565b46610cbc6060850185611a5a565b60e001351580610ce65750610cd46060850185611a5a565b60e00135610ce3426014611a70565b11155b610d025760405162461bcd60e51b81526004016106699061195e565b60008381526001602052604090205460ff16610d605760405162461bcd60e51b815260206004820152601d60248201527f756e7265676973746572656420646f6d61696e20736570617261746f720000006044820152606401610669565b8060025414610d815760405162461bcd60e51b8152600401610669906119bc565b600083610d8d866111be565b60405161190160f01b60208201526022810192909252604282015260620160408051601f1981840301815291905280516020909101209050610dd26060860186611a5a565b610bcb9060208101906116ca565b60036000610df16060840184611a5a565b610dff9060208101906116ca565b6001600160a01b031681526020810191909152604001600090812090610e286060840184611a5a565b60a0013581526020019081526020016000206000815480929190610c7790611ad4565b60e08201351580610e6a575060e0820135610e67426014611a70565b11155b610e865760405162461bcd60e51b81526004016106699061195e565b6000610fa3610e9860208501856116ca565b610ea860408601602087016116ca565b610eb860608701604088016116ca565b6060870135608088013560a089013560036000610ed860208d018d6116ca565b6001600160a01b031681526020808201929092526040908101600090812060a08e0135825290925290205460e08b0135610f166101008d018d6119ff565b604051610f249291906118d6565b6040519081900381206bffffffffffffffffffffffff1960609a8b1b81166020840152988a1b891660348301529690981b9096166048880152605c870193909352607c860191909152609c85015260bc84015260dc83019190915260fc82015261011c016040516020818303038152906040528051906020012061128e565b9050610fb260208401846116ca565b6001600160a01b0316610fc5828461119a565b6001600160a01b03161461063a5760405162461bcd60e51b81526020600482015260126024820152710e6d2cedcc2e8eae4ca40dad2e6dac2e8c6d60731b6044820152606401610669565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006040518060c00160405280609d8152602001611bc9609d9139805160209182012090611090908401846116ca565b6110a060408501602086016116ca565b6110b060608601604087016116ca565b6060860135608087013560a0880135600360006110d060208c018c6116ca565b6001600160a01b031681526020808201929092526040908101600090812060a08d0135825290925290205460e08a013561110e6101008c018c6119ff565b60405161111c9291906118d6565b60408051918290038220602083019b909b526001600160a01b03998a1690820152968816606088015296909416608086015260a085019290925260c084015260e0830152610100820152610120810191909152610140810191909152610160015b604051602081830303815290604052805190602001209050919050565b60008060006111a985856112c9565b915091506111b681611339565b509392505050565b600060405180610120016040528060f78152602001611c9360f7913980516020909101206111ec8380611a44565b6040516111fa9291906118d6565b6040519081900390206112106020850185611a44565b60405161121e9291906118d6565b60405180910390208480604001906112369190611a44565b6040516112449291906118d6565b60405190819003902061126261125d6060880188611a5a565b611060565b6040805160208101969096528501939093526060840191909152608083015260a082015260c00161117d565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c0161117d565b6000808251604114156113005760208301516040840151606085015160001a6112f48782858561153a565b94509450505050611332565b82516040141561132a576020830151604084015161131f868383611627565b935093505050611332565b506000905060025b9250929050565b600081600481111561135b57634e487b7160e01b600052602160045260246000fd5b14156113645750565b600181600481111561138657634e487b7160e01b600052602160045260246000fd5b14156113d45760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610669565b60028160048111156113f657634e487b7160e01b600052602160045260246000fd5b14156114445760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610669565b600381600481111561146657634e487b7160e01b600052602160045260246000fd5b14156114bf5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610669565b60048160048111156114e157634e487b7160e01b600052602160045260246000fd5b1415610abd5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610669565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611571575060009050600361161e565b8460ff16601b1415801561158957508460ff16601c14155b1561159a575060009050600461161e565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156115ee573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166116175760006001925092505061161e565b9150600090505b94509492505050565b6000806001600160ff1b03831660ff84901c601b016116488782888561153a565b935093505050935093915050565b80356001600160a01b038116811461166d57600080fd5b919050565b60008083601f840112611683578182fd5b50813567ffffffffffffffff81111561169a578182fd5b60208301915083602082850101111561133257600080fd5b600061012082840312156116c4578081fd5b50919050565b6000602082840312156116db578081fd5b6116e482611656565b9392505050565b600080604083850312156116fd578081fd5b61170683611656565b946020939093013593505050565b600060208284031215611725578081fd5b5035919050565b60008060008060408587031215611741578182fd5b843567ffffffffffffffff80821115611758578384fd5b61176488838901611672565b9096509450602087013591508082111561177c578384fd5b5061178987828801611672565b95989497509550505050565b600080600080606085870312156117aa578384fd5b843567ffffffffffffffff808211156117c1578586fd5b90860190608082890312156117d4578586fd5b909450602086013593506040860135908082111561177c578384fd5b60008060008060608587031215611805578384fd5b843567ffffffffffffffff8082111561181c578586fd5b611828888389016116b2565b955060208701359450604087013591508082111561177c578384fd5b600080600060408486031215611858578283fd5b833567ffffffffffffffff8082111561186f578485fd5b61187b878388016116b2565b94506020860135915080821115611890578384fd5b5061189d86828701611672565b9497909650939450505050565b600081518084526118c2816020860160208601611aa8565b601f01601f19169290920160200192915050565b8183823760009101908152919050565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b6000825161191e818460208701611aa8565b9190910192915050565b821515815260406020820152600061194360408301846118aa565b949350505050565b6020815260006116e460208301846118aa565b6020808252600f908201526e1c995c5d595cdd08195e1c1a5c9959608a1b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526023908201527f706f74656e7469616c207265706c61792061747461636b206f6e2074686520666040820152626f726b60e81b606082015260800190565b6000808335601e19843603018112611a15578283fd5b83018035915067ffffffffffffffff821115611a2f578283fd5b60200191503681900382131561133257600080fd5b6000808335601e19843603018112611a15578182fd5b6000823561011e1983360301811261191e578182fd5b60008219821115611a8357611a83611aef565b500190565b600082611aa357634e487b7160e01b81526012600452602481fd5b500490565b60005b83811015611ac3578181015183820152602001611aab565b838111156109df5750506000910152565b6000600019821415611ae857611ae8611aef565b5060010190565b634e487b7160e01b600052601160045260246000fdfe454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c6164647265737320766572696679696e67436f6e74726163742c627974657333322073616c7429466f72776172645265717565737428616464726573732066726f6d2c6164647265737320746f2c75696e743235362074784761732c75696e7432353620626174636849642c75696e743235362062617463684e6f6e63652c75696e7432353620646561646c696e652c62797465732064617461294552433230466f72776172645265717565737428616464726573732066726f6d2c6164647265737320746f2c6164647265737320746f6b656e2c75696e743235362074784761732c75696e7432353620746f6b656e47617350726963652c75696e7432353620626174636849642c75696e743235362062617463684e6f6e63652c75696e7432353620646561646c696e652c6279746573206461746129466f727761726465642063616c6c20746f2064657374696e6174696f6e20646964206e6f742073756363656564437573746f6d466f72776172645265717565737428737472696e67207761726e696e672c737472696e6720696e666f2c737472696e6720616374696f6e2c4552433230466f7277617264526571756573742072657175657374294552433230466f72776172645265717565737428616464726573732066726f6d2c6164647265737320746f2c6164647265737320746f6b656e2c75696e743235362074784761732c75696e7432353620746f6b656e47617350726963652c75696e7432353620626174636849642c75696e743235362062617463684e6f6e63652c75696e7432353620646561646c696e652c6279746573206461746129a26469706673582212205fbc05e07af55f4c17f97fd5da997389fe94192a5be1e03a1620cd754a89d82a64736f6c63430008040033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Txn Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.