Contract 0x85ac853595993be6d687da892594aa5d63695b92

Contract Overview

Balance:
0 BNB
Txn Hash
Block
From
To
Value [Txn Fee]
0x9a4a365711fc83951ce4c9ce308163e1bc95350a1a4a271a119c8bf5db02984a70197012021-03-12 10:16:0392 days 18 hrs ago0x9c7b915eec1e9860aedc9373bdf45998a190df7e IN  0x85ac853595993be6d687da892594aa5d63695b922 BNB0.0011019
0x00d39fe201de7e93ab71680e06c69424e5d77475a471e737cc8336d89f5ed65770197002021-03-12 10:16:0092 days 18 hrs ago0x9c7b915eec1e9860aedc9373bdf45998a190df7e IN  0x85ac853595993be6d687da892594aa5d63695b920 BNB0.00147608
0x766d9a39f093d10b995c13dd7a5aeb5d7ff39b3d30dcfe5066753fb830b1ce5a70196942021-03-12 10:15:4292 days 18 hrs ago0x9c7b915eec1e9860aedc9373bdf45998a190df7e IN  0x85ac853595993be6d687da892594aa5d63695b920 BNB0.00087062
0x74cb42f2a61217d0814d14c234fd349df97c552baca88467ac50402a6ab74dcc70196932021-03-12 10:15:3992 days 18 hrs ago0x9c7b915eec1e9860aedc9373bdf45998a190df7e IN  0x85ac853595993be6d687da892594aa5d63695b920 BNB0.00087132
0x7081079db0e1b7a1165835b51b7fae8f3019c4cc858ed99f457a4ca44431e12d70196932021-03-12 10:15:3992 days 18 hrs ago0x9c7b915eec1e9860aedc9373bdf45998a190df7e IN  0x85ac853595993be6d687da892594aa5d63695b920 BNB0.00177584
0xe8101107479b1219a82d1939acda70369ef05df285f731dfece4377eebf7c6e470196902021-03-12 10:15:3092 days 18 hrs ago0x9c7b915eec1e9860aedc9373bdf45998a190df7e IN  Contract Creation0 BNB0.04349982
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xa09ad969a57517cadc9f268f21bb608f40b994be8ae985b17a7794f4c3ec7b1170205382021-03-12 10:57:5492 days 17 hrs ago 0x515b28e7638ac923f0db63298658167a4e4db770 0x85ac853595993be6d687da892594aa5d63695b920 BNB
0xa09ad969a57517cadc9f268f21bb608f40b994be8ae985b17a7794f4c3ec7b1170205382021-03-12 10:57:5492 days 17 hrs ago 0x85ac853595993be6d687da892594aa5d63695b92 0x58f24a413f6fb98f217600703c7086ea22b49c470 BNB
0xa09ad969a57517cadc9f268f21bb608f40b994be8ae985b17a7794f4c3ec7b1170205382021-03-12 10:57:5492 days 17 hrs ago 0x85ac853595993be6d687da892594aa5d63695b92 0xdd482fc88cca00f668dc80ca6304c5fb4978dcdb0 BNB
0xa09ad969a57517cadc9f268f21bb608f40b994be8ae985b17a7794f4c3ec7b1170205382021-03-12 10:57:5492 days 17 hrs ago 0x515b28e7638ac923f0db63298658167a4e4db770 0x85ac853595993be6d687da892594aa5d63695b920 BNB
0xa09ad969a57517cadc9f268f21bb608f40b994be8ae985b17a7794f4c3ec7b1170205382021-03-12 10:57:5492 days 17 hrs ago 0x515b28e7638ac923f0db63298658167a4e4db770 0x85ac853595993be6d687da892594aa5d63695b920 BNB
0xb6d5a6f08112d6bf48b3db263d2b994a1f06df7051da49011784e22eec9a252170205082021-03-12 10:56:2492 days 17 hrs ago 0x515b28e7638ac923f0db63298658167a4e4db770 0x85ac853595993be6d687da892594aa5d63695b920 BNB
0xb6d5a6f08112d6bf48b3db263d2b994a1f06df7051da49011784e22eec9a252170205082021-03-12 10:56:2492 days 17 hrs ago 0x85ac853595993be6d687da892594aa5d63695b92 0x58f24a413f6fb98f217600703c7086ea22b49c470 BNB
0xb6d5a6f08112d6bf48b3db263d2b994a1f06df7051da49011784e22eec9a252170205082021-03-12 10:56:2492 days 17 hrs ago 0x85ac853595993be6d687da892594aa5d63695b92 0xdd482fc88cca00f668dc80ca6304c5fb4978dcdb0 BNB
0xb6d5a6f08112d6bf48b3db263d2b994a1f06df7051da49011784e22eec9a252170205082021-03-12 10:56:2492 days 17 hrs ago 0x515b28e7638ac923f0db63298658167a4e4db770 0x85ac853595993be6d687da892594aa5d63695b920 BNB
0xb6d5a6f08112d6bf48b3db263d2b994a1f06df7051da49011784e22eec9a252170205082021-03-12 10:56:2492 days 17 hrs ago 0x515b28e7638ac923f0db63298658167a4e4db770 0x85ac853595993be6d687da892594aa5d63695b920 BNB
0x54421af841fb4fc0cf2647a48581b3a201e22c2247f2b1a92afc3909004088ac70204852021-03-12 10:55:1592 days 17 hrs ago 0x515b28e7638ac923f0db63298658167a4e4db770 0x85ac853595993be6d687da892594aa5d63695b920 BNB
0x54421af841fb4fc0cf2647a48581b3a201e22c2247f2b1a92afc3909004088ac70204852021-03-12 10:55:1592 days 17 hrs ago 0x85ac853595993be6d687da892594aa5d63695b92 0x58f24a413f6fb98f217600703c7086ea22b49c470 BNB
0x54421af841fb4fc0cf2647a48581b3a201e22c2247f2b1a92afc3909004088ac70204852021-03-12 10:55:1592 days 17 hrs ago 0x85ac853595993be6d687da892594aa5d63695b92 0xdd482fc88cca00f668dc80ca6304c5fb4978dcdb0 BNB
0x54421af841fb4fc0cf2647a48581b3a201e22c2247f2b1a92afc3909004088ac70204852021-03-12 10:55:1592 days 17 hrs ago 0x515b28e7638ac923f0db63298658167a4e4db770 0x85ac853595993be6d687da892594aa5d63695b920 BNB
0x54421af841fb4fc0cf2647a48581b3a201e22c2247f2b1a92afc3909004088ac70204852021-03-12 10:55:1592 days 17 hrs ago 0x515b28e7638ac923f0db63298658167a4e4db770 0x85ac853595993be6d687da892594aa5d63695b920 BNB
0xf3a026e5d913b32cea1e01882fd17c782392902c745ab12b051520a7101e0aee70202552021-03-12 10:43:4592 days 17 hrs ago 0x515b28e7638ac923f0db63298658167a4e4db770 0x85ac853595993be6d687da892594aa5d63695b920 BNB
0xf3a026e5d913b32cea1e01882fd17c782392902c745ab12b051520a7101e0aee70202552021-03-12 10:43:4592 days 17 hrs ago 0x85ac853595993be6d687da892594aa5d63695b92 0x58f24a413f6fb98f217600703c7086ea22b49c470 BNB
0xf3a026e5d913b32cea1e01882fd17c782392902c745ab12b051520a7101e0aee70202552021-03-12 10:43:4592 days 17 hrs ago 0x85ac853595993be6d687da892594aa5d63695b92 0xdd482fc88cca00f668dc80ca6304c5fb4978dcdb0 BNB
0xf3a026e5d913b32cea1e01882fd17c782392902c745ab12b051520a7101e0aee70202552021-03-12 10:43:4592 days 17 hrs ago 0x515b28e7638ac923f0db63298658167a4e4db770 0x85ac853595993be6d687da892594aa5d63695b920 BNB
0xf3a026e5d913b32cea1e01882fd17c782392902c745ab12b051520a7101e0aee70202552021-03-12 10:43:4592 days 17 hrs ago 0x515b28e7638ac923f0db63298658167a4e4db770 0x85ac853595993be6d687da892594aa5d63695b920 BNB
0xff9e671e64037615d84b02d0408229c86e48f640be3443858d9ae328c153feeb70202532021-03-12 10:43:3992 days 17 hrs ago 0x515b28e7638ac923f0db63298658167a4e4db770 0x85ac853595993be6d687da892594aa5d63695b920 BNB
0xff9e671e64037615d84b02d0408229c86e48f640be3443858d9ae328c153feeb70202532021-03-12 10:43:3992 days 17 hrs ago 0xdd482fc88cca00f668dc80ca6304c5fb4978dcdb 0x85ac853595993be6d687da892594aa5d63695b920 BNB
0xff9e671e64037615d84b02d0408229c86e48f640be3443858d9ae328c153feeb70202532021-03-12 10:43:3992 days 17 hrs ago 0xdd482fc88cca00f668dc80ca6304c5fb4978dcdb 0x85ac853595993be6d687da892594aa5d63695b920 BNB
0xff9e671e64037615d84b02d0408229c86e48f640be3443858d9ae328c153feeb70202532021-03-12 10:43:3992 days 17 hrs ago 0x85ac853595993be6d687da892594aa5d63695b92 0x58f24a413f6fb98f217600703c7086ea22b49c470 BNB
0xff9e671e64037615d84b02d0408229c86e48f640be3443858d9ae328c153feeb70202532021-03-12 10:43:3992 days 17 hrs ago 0x85ac853595993be6d687da892594aa5d63695b92 0xdd482fc88cca00f668dc80ca6304c5fb4978dcdb0 BNB
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Whitelist

Compiler Version
v0.8.1+commit.df193b15

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 18 : Whitelist.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.1;

import "./interfaces/IWhitelist.sol";
import "./libraries/AccessControl.sol";
import "./GSN/BasePaymaster.sol";

/// @title GNS whitelist contract
contract Whitelist is IWhitelist, AccessControl, BasePaymaster {

    bytes32 public constant WHITELIST_ROLE = keccak256("WHITELIST_ROLE");
        
    constructor() {
        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
    }

    function preRelayedCall(
        GsnTypes.RelayRequest calldata relayRequest,
        bytes calldata signature,
        bytes calldata approvalData,
        uint256 maxPossibleGas
    )
        external
        view
        override
        relayHubOnly
        returns (
            bytes memory context,
            bool rejectOnRecipientRevert
        )
    {
        require(
            inWhitelist(relayRequest.request.from) ||
            isAdmin(relayRequest.request.from),
            "Address is not in whitelist"
        );

        _verifyForwarder(relayRequest);
        _verifySignature(relayRequest, signature);
        return ("PreRelayedCall success", false);
    }
    
    function postRelayedCall(
        bytes calldata context,
        bool success,
        uint256 gasUseWithoutPost,
        GsnTypes.RelayData calldata relayData
    )
        external
        override
        relayHubOnly
    {
    }
    
    function versionPaymaster()
        external
        pure
        override
        returns (string memory)
    {
        return "2.1.0";
    }

    /// @notice Quries whether an address has admin role
    /// @param _account The address to be queried
    /// @return `True` if `_account` has admin role
    function isAdmin(address _account) 
        public
        view
        override
        returns (bool)
    {
        return hasRole(DEFAULT_ADMIN_ROLE, _account);
    }

    /// @notice Queries whether an address has whitelist role
    /// @param _account The address to be queried
    /// @return `True` if `_account` has whitelist role
    function inWhitelist(address _account)
        public
        view
        override
        returns (bool)
    {
        return hasRole(WHITELIST_ROLE, _account);
    }
    
    /// @notice Remove an address from admin role
    /// @dev It throws if `msg.sender` does no have admin role.
    ///  It does not throw if address is not in admin role.
    /// @param _account The address to be removed
    function removeAdmin(address _account)
        external
        override
    {
        revokeRole(DEFAULT_ADMIN_ROLE, _account);
    }

    /// @notice Insert an address into whitelist role
    /// @dev It does not throw if address already has whitelist role
    /// @param _account The address to be inserted
    function addWhitelist(address _account)
        external
        override
    {
        grantRole(WHITELIST_ROLE, _account);
    }

    /// @notice Remove an address from whitelist role
    /// @dev It throws if `msg.sender` does no have admin role.
    ///  It does not throw if address is not in whitelist role.
    /// @param _account The address to be removed
    function removeWhitelist(address _account)
        external
        override
    {
        revokeRole(WHITELIST_ROLE, _account);
    }
    
    /// @notice Insert an address into role admin
    /// @dev It does not throw if address already has role admin
    /// @param _account The address to be inserted
    function addAdmin(address _account)
        external
        override
    {
        grantRole(DEFAULT_ADMIN_ROLE, _account);
    }
}

File 2 of 18 : IWhitelist.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IWhitelist {
    function addWhitelist(address _account) external;
    function removeWhitelist(address _account) external;
    function addAdmin(address _account) external;
    function removeAdmin(address _account) external;
    function inWhitelist(address _account) external view returns (bool);
    function isAdmin(address _account) external view returns (bool);
}

File 3 of 18 : AccessControl.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.1;

import "./utils/EnumerableSet.sol";
import "./GSN/Context.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context {
    using EnumerableSet for EnumerableSet.AddressSet;

    struct RoleData {
        EnumerableSet.AddressSet members;
        bytes32 adminRole;
    }

    mapping (bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view returns (bool) {
        return _roles[role].members.contains(account);
    }

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) public view returns (uint256) {
        return _roles[role].members.length();
    }

    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) public view returns (address) {
        return _roles[role].members.at(index);
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) public virtual {
        require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant");

        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) public virtual {
        require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke");

        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) public virtual {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        emit RoleAdminChanged(role, _roles[role].adminRole, adminRole);
        _roles[role].adminRole = adminRole;
    }

    function _grantRole(bytes32 role, address account) private {
        if (_roles[role].members.add(account)) {
            emit RoleGranted(role, account, _msgSender());
        }
    }

    function _revokeRole(bytes32 role, address account) private {
        if (_roles[role].members.remove(account)) {
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

File 4 of 18 : BasePaymaster.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.1;
pragma experimental ABIEncoderV2;

import "../libraries/Ownable.sol";
import "./interfaces/GsnTypes.sol";
import "./interfaces/IPaymaster.sol";
import "./interfaces/IRelayHub.sol";
import "./utils/GsnEip712Library.sol";
import "./forwarder/Forwarder.sol";

/**
 * Abstract base class to be inherited by a concrete Paymaster
 * A subclass must implement:
 *  - preRelayedCall
 *  - postRelayedCall
 */
abstract contract BasePaymaster is IPaymaster, Ownable {

    IRelayHub internal relayHub;
    IForwarder public override trustedForwarder;

    //overhead of forwarder verify+signature, plus hub overhead.
    uint256 constant public FORWARDER_HUB_OVERHEAD = 50000;

    //These parameters are documented in IPaymaster.GasLimits
    uint256 constant public PRE_RELAYED_CALL_GAS_LIMIT = 100000;
    uint256 constant public POST_RELAYED_CALL_GAS_LIMIT = 110000;
    uint256 constant public PAYMASTER_ACCEPTANCE_BUDGET = PRE_RELAYED_CALL_GAS_LIMIT + FORWARDER_HUB_OVERHEAD;


    function getHubAddr() public override view returns (address) {
        return address(relayHub);
    }
    
    function getGasLimits()
        public
        override
        virtual
        view
        returns (IPaymaster.GasLimits memory limits)
    {
        return IPaymaster.GasLimits(
            PAYMASTER_ACCEPTANCE_BUDGET,
            PRE_RELAYED_CALL_GAS_LIMIT,
            POST_RELAYED_CALL_GAS_LIMIT
        );
    }

    // this method must be called from preRelayedCall to validate that the forwarder
    // is approved by the paymaster as well as by the recipient contract.
    function _verifyForwarder(GsnTypes.RelayRequest calldata relayRequest)
        public
        view
    {
        require(address(trustedForwarder) == relayRequest.relayData.forwarder, "Forwarder is not trusted");
        GsnEip712Library.verifyForwarderTrusted(relayRequest);
    }
    
    function _verifySignature(GsnTypes.RelayRequest calldata relayRequest, bytes calldata signature)
        public
        view
    {
        GsnEip712Library.verifySignature(relayRequest, signature);
    }

    /*
     * modifier to be used by recipients as access control protection for preRelayedCall & postRelayedCall
     */
    modifier relayHubOnly() {
        require(msg.sender == getHubAddr(), "Function can only be called by RelayHub");
        _;
    }

    function setRelayHub(IRelayHub hub) public onlyOwner {
        relayHub = hub;
    }

    function setTrustedForwarder(IForwarder forwarder) public onlyOwner {
        trustedForwarder = forwarder;
    }

    /// check current deposit on relay hub.
    function getRelayHubDeposit()
        public
        override
        view
        returns (uint)
    {
        return relayHub.balanceOf(address(this));
    }

    // any money moved into the paymaster is transferred as a deposit.
    // This way, we don't need to understand the RelayHub API in order to replenish
    // the paymaster.
    receive() external virtual payable {
        require(address(relayHub) != address(0), "relay hub address not set");
        relayHub.depositFor{value:msg.value}(address(this));
    }

    /// withdraw deposit from relayHub
    function withdrawRelayHubDepositTo(uint amount, address payable target) public onlyOwner {
        relayHub.withdraw(amount, target);
    }
}

File 5 of 18 : EnumerableSet.sol
// SPDX-License-Identifier: MIT

/* solhint-disable ordering */
pragma solidity 0.8.1;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;

        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping (bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) { // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            bytes32 lastvalue = set._values[lastIndex];

            // Move the last value to the index where the value to delete is
            set._values[toDeleteIndex] = lastvalue;
            // Update the index for the moved value
            set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        require(set._values.length > index, "EnumerableSet: index out of bounds");
        return set._values[index];
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }


    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }
}

File 6 of 18 : 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 GSN 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 payable) {
        return payable(msg.sender);
    }

    function _msgData() internal view virtual returns (bytes memory) {
        return msg.data;
    }
}

File 7 of 18 : Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.1;

import "./GSN/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;
    address public newOwner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view 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 {
        emit OwnershipTransferred(_owner, address(0));
        _owner = 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");
        newOwner = _newOwner;
    }

    function acceptOwnership() public {
      require(_msgSender() == newOwner, "Owable: Not new owner");

      emit OwnershipTransferred(_owner, newOwner);
      
      _owner = newOwner;
      newOwner = address(0x0);
    }
}

File 8 of 18 : GsnTypes.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../forwarder/IForwarder.sol";

interface GsnTypes {
    struct RelayData {
        uint256 gasPrice;
        uint256 pctRelayFee;
        uint256 baseRelayFee;
        address relayWorker;
        address paymaster;
        bytes paymasterData;
        uint256 clientId;
        address forwarder;
    }

    //note: must start with the ForwardRequest to be an extension of the generic forwarder
    struct RelayRequest {
        IForwarder.ForwardRequest request;
        RelayData relayData;
    }
}

File 9 of 18 : IPaymaster.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;

import "./GsnTypes.sol";

interface IPaymaster {

    /**
     * @param acceptanceBudget -
     *      Paymaster expected gas budget to accept (or reject) a request
     *      This a gas required by any calculations that might need to reject the
     *      transaction, by preRelayedCall, forwarder and recipient.
     *      See value in BasePaymaster.PAYMASTER_ACCEPTANCE_BUDGET
     *      Transaction that gets rejected above that gas usage is on the paymaster's expense.
     *      As long this value is above preRelayedCallGasLimit (see defaults in BasePaymaster), the
     *      Paymaster is guaranteed it will never pay for rejected transactions.
     *      If this value is below preRelayedCallGasLimt, it might might make Paymaster open to a "griefing" attack.
     *
     *      Specifying value too high might make the call rejected by some relayers.
     *
     *      From a Relay's point of view, this is the highest gas value a paymaster might "grief" the relay,
     *      since the paymaster will pay anything above that (regardless if the tx reverts)
     *
     * @param preRelayedCallGasLimit - the max gas usage of preRelayedCall. any revert (including OOG)
     *      of preRelayedCall is a reject by the paymaster.
     *      as long as acceptanceBudget is above preRelayedCallGasLimit, any such revert (including OOG)
     *      is not payed by the paymaster.
     * @param postRelayedCallGasLimit - the max gas usage of postRelayedCall.
     *      note that an OOG will revert the transaction, but the paymaster already committed to pay,
     *      so the relay will get compensated, at the expense of the paymaster
     */
    struct GasLimits {
        uint256 acceptanceBudget;
        uint256 preRelayedCallGasLimit;
        uint256 postRelayedCallGasLimit;
    }

    /**
     * Return the GasLimits constants used by the Paymaster.
     */
    function getGasLimits()
    external
    view
    returns (
        GasLimits memory limits
    );

    function trustedForwarder() external view returns (IForwarder);

    /**
     * return the relayHub of this contract.
     */
    function getHubAddr() external view returns (address);

    /**
     * Can be used to determine if the contract can pay for incoming calls before making any.
     * @return the paymaster's deposit in the RelayHub.
     */
    function getRelayHubDeposit() external view returns (uint256);

    /**
     * Called by Relay (and RelayHub), to validate if the paymaster agrees to pay for this call.
     *
     * MUST be protected with relayHubOnly() in case it modifies state.
     *
     * The Paymaster rejects by the following "revert" operations
     *  - preRelayedCall() method reverts
     *  - the forwarder reverts because of nonce or signature error
     *  - the paymaster returned "rejectOnRecipientRevert", and the recipient contract reverted.
     * In any of the above cases, all paymaster calls (and recipient call) are reverted.
     * In any other case, the paymaster agrees to pay for the gas cost of the transaction (note
     *  that this includes also postRelayedCall revert)
     *
     * The rejectOnRecipientRevert flag means the Paymaster "delegate" the rejection to the recipient
     *  code.  It also means the Paymaster trust the recipient to reject fast: both preRelayedCall,
     *  forwarder check and receipient checks must fit into the GasLimits.acceptanceBudget,
     *  otherwise the TX is paid by the Paymaster.
     *
     *  @param relayRequest - the full relay request structure
     *  @param signature - user's EIP712-compatible signature of the {@link relayRequest}.
     *              Note that in most cases the paymaster shouldn't try use it at all. It is always checked
     *              by the forwarder immediately after preRelayedCall returns.
     *  @param approvalData - extra dapp-specific data (e.g. signature from trusted party)
     *  @param maxPossibleGas - based on values returned from {@link getGasLimits},
     *         the RelayHub will calculate the maximum possible amount of gas the user may be charged for.
     *         In order to convert this value to wei, the Paymaster has to call "relayHub.calculateCharge()"
     *  return:
     *      a context to be passed to postRelayedCall
     *      rejectOnRecipientRevert - TRUE if paymaster want to reject the TX if the recipient reverts.
     *          FALSE means that rejects by the recipient will be completed on chain, and paid by the paymaster.
     *          (note that in the latter case, the preRelayedCall and postRelayedCall are not reverted).
     */
    function preRelayedCall(
        GsnTypes.RelayRequest calldata relayRequest,
        bytes calldata signature,
        bytes calldata approvalData,
        uint256 maxPossibleGas
    )
    external
    returns (bytes memory context, bool rejectOnRecipientRevert);

    /**
     * This method is called after the actual relayed function call.
     * It may be used to record the transaction (e.g. charge the caller by some contract logic) for this call.
     *
     * MUST be protected with relayHubOnly() in case it modifies state.
     *
     * @param context - the call context, as returned by the preRelayedCall
     * @param success - true if the relayed call succeeded, false if it reverted
     * @param gasUseWithoutPost - the actual amount of gas used by the entire transaction, EXCEPT
     *        the gas used by the postRelayedCall itself.
     * @param relayData - the relay params of the request. can be used by relayHub.calculateCharge()
     *
     * Revert in this functions causes a revert of the client's relayed call (and preRelayedCall(), but the Paymaster
     * is still committed to pay the relay for the entire transaction.
     */
    function postRelayedCall(
        bytes calldata context,
        bool success,
        uint256 gasUseWithoutPost,
        GsnTypes.RelayData calldata relayData
    ) external;

    function versionPaymaster() external view returns (string memory);
}

File 10 of 18 : IRelayHub.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;

import "./GsnTypes.sol";
import "./IStakeManager.sol";

interface IRelayHub {

    /// Emitted when a relay server registers or updates its details
    /// Looking at these events lets a client discover relay servers
    event RelayServerRegistered(
        address indexed relayManager,
        uint256 baseRelayFee,
        uint256 pctRelayFee,
        string relayUrl);

    /// Emitted when relays are added by a relayManager
    event RelayWorkersAdded(
        address indexed relayManager,
        address[] newRelayWorkers,
        uint256 workersCount
    );

    // Emitted when an account withdraws funds from RelayHub.
    event Withdrawn(
        address indexed account,
        address indexed dest,
        uint256 amount
    );

    // Emitted when depositFor is called, including the amount and account that was funded.
    event Deposited(
        address indexed paymaster,
        address indexed from,
        uint256 amount
    );

    /// Emitted when an attempt to relay a call fails and Paymaster does not accept the transaction.
    /// The actual relayed call was not executed, and the recipient not charged.
    /// @param reason contains a revert reason returned from preRelayedCall or forwarder.
    event TransactionRejectedByPaymaster(
        address indexed relayManager,
        address indexed paymaster,
        address indexed from,
        address to,
        address relayWorker,
        bytes4 selector,
        uint256 innerGasUsed,
        bytes reason);

    // Emitted when a transaction is relayed. Note that the actual encoded function might be reverted: this will be
    // indicated in the status field.
    // Useful when monitoring a relay's operation and relayed calls to a contract.
    // Charge is the ether value deducted from the recipient's balance, paid to the relay's manager.
    event TransactionRelayed(
        address indexed relayManager,
        address indexed relayWorker,
        address indexed from,
        address to,
        address paymaster,
        bytes4 selector,
        RelayCallStatus status,
        uint256 charge);

    event TransactionResult(
        RelayCallStatus status,
        bytes returnValue
    );

    /// Reason error codes for the TransactionRelayed event
    /// @param OK - the transaction was successfully relayed and execution successful - never included in the event
    /// @param RelayedCallFailed - the transaction was relayed, but the relayed call failed
    /// @param RejectedByPreRelayed - the transaction was not relayed due to preRelatedCall reverting
    /// @param RejectedByForwarder - the transaction was not relayed due to forwarder check (signature,nonce)
    /// @param PostRelayedFailed - the transaction was relayed and reverted due to postRelatedCall reverting
    /// @param PaymasterBalanceChanged - the transaction was relayed and reverted due to the paymaster balance change
    enum RelayCallStatus {
        OK,
        RelayedCallFailed,
        RejectedByPreRelayed,
        RejectedByForwarder,
        RejectedByRecipientRevert,
        PostRelayedFailed,
        PaymasterBalanceChanged
    }

    /// Add new worker addresses controlled by sender who must be a staked Relay Manager address.
    /// Emits a RelayWorkersAdded event.
    /// This function can be called multiple times, emitting new events
    function addRelayWorkers(address[] calldata newRelayWorkers) external;

    function registerRelayServer(uint256 baseRelayFee, uint256 pctRelayFee, string calldata url) external;

    // Balance management

    // Deposits ether for a contract, so that it can receive (and pay for) relayed transactions. Unused balance can only
    // be withdrawn by the contract itself, by calling withdraw.
    // Emits a Deposited event.
    function depositFor(address target) external payable;

    // Withdraws from an account's balance, sending it back to it. Relay managers call this to retrieve their revenue, and
    // contracts can also use it to reduce their funding.
    // Emits a Withdrawn event.
    function withdraw(uint256 amount, address payable dest) external;

    // Relaying


    /// Relays a transaction. For this to succeed, multiple conditions must be met:
    ///  - Paymaster's "acceptRelayCall" method must succeed and not revert
    ///  - the sender must be a registered Relay Worker that the user signed
    ///  - the transaction's gas price must be equal or larger than the one that was signed by the sender
    ///  - the transaction must have enough gas to run all internal transactions if they use all gas available to them
    ///  - the Paymaster must have enough balance to pay the Relay Worker for the scenario when all gas is spent
    ///
    /// If all conditions are met, the call will be relayed and the recipient charged.
    ///
    /// Arguments:
    /// @param relayRequest - all details of the requested relayed call
    /// @param signature - client's EIP-712 signature over the relayRequest struct
    /// @param approvalData: dapp-specific data forwarded to preRelayedCall.
    ///        This value is *not* verified by the Hub. For example, it can be used to pass a signature to the Paymaster
    /// @param externalGasLimit - the value passed as gasLimit to the transaction.
    ///
    /// Emits a TransactionRelayed event.
    function relayCall(
        uint paymasterMaxAcceptanceBudget,
        GsnTypes.RelayRequest calldata relayRequest,
        bytes calldata signature,
        bytes calldata approvalData,
        uint externalGasLimit
    )
    external
    returns (bool paymasterAccepted, bytes memory returnValue);

    function penalize(address relayWorker, address payable beneficiary) external;

    /// The fee is expressed as a base fee in wei plus percentage on actual charge.
    /// E.g. a value of 40 stands for a 40% fee, so the recipient will be
    /// charged for 1.4 times the spent amount.
    function calculateCharge(uint256 gasUsed, GsnTypes.RelayData calldata relayData) external view returns (uint256);

    /* getters */

    /// Returns the stake manager of this RelayHub.
    function stakeManager() external view returns(IStakeManager);
    function penalizer() external view returns(address);

    /// Returns an account's deposits. It can be either a deposit of a paymaster, or a revenue of a relay manager.
    function balanceOf(address target) external view returns (uint256);

    // Minimum stake a relay can have. An attack to the network will never cost less than half this value.
    function minimumStake() external view returns (uint256);

    // Minimum unstake delay blocks of a relay manager's stake on the StakeManager
    function minimumUnstakeDelay() external view returns (uint256);

    // Maximum funds that can be deposited at once. Prevents user error by disallowing large deposits.
    function maximumRecipientDeposit() external view returns (uint256);

    //gas overhead to calculate gasUseWithoutPost
    function postOverhead() external view returns (uint256);

    // Gas set aside for all relayCall() instructions to prevent unexpected out-of-gas exceptions
    function gasReserve() external view returns (uint256);

    // maximum number of worker account allowed per manager
    function maxWorkerCount() external view returns (uint256);

    function workerToManager(address worker) external view returns(address);

    function workerCount(address manager) external view returns(uint256);

    function isRelayManagerStaked(address relayManager) external view returns(bool);

    /**
    * @dev the total gas overhead of relayCall(), before the first gasleft() and after the last gasleft().
    * Assume that relay has non-zero balance (costs 15'000 more otherwise).
    */

    // Gas cost of all relayCall() instructions after actual 'calculateCharge()'
    function gasOverhead() external view returns (uint256);

    function versionHub() external view returns (string memory);
}

File 11 of 18 : GsnEip712Library.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.1;
pragma experimental ABIEncoderV2;

import "../interfaces/GsnTypes.sol";
import "../interfaces/IRelayRecipient.sol";
import "../forwarder/IForwarder.sol";

import "./GsnUtils.sol";

/**
 * Bridge Library to map GSN RelayRequest into a call of a Forwarder
 */
library GsnEip712Library {
    struct EIP712Domain {
        string name;
        string version;
        uint256 chainId;
        address verifyingContract;
    }
    
    // maximum length of return value/revert reason for 'execute' method. Will truncate result if exceeded.
    uint256 private constant MAX_RETURN_SIZE = 1024;

    //copied from Forwarder (can't reference string constants even from another library)
    string public constant GENERIC_PARAMS = "address from,address to,uint256 value,uint256 gas,uint256 nonce,bytes data";

    bytes public constant RELAYDATA_TYPE = "RelayData(uint256 gasPrice,uint256 pctRelayFee,uint256 baseRelayFee,address relayWorker,address paymaster,address forwarder,bytes paymasterData,uint256 clientId)";

    string public constant RELAY_REQUEST_NAME = "RelayRequest";
    string public constant RELAY_REQUEST_SUFFIX = string(abi.encodePacked("RelayData relayData)", RELAYDATA_TYPE));

    bytes public constant RELAY_REQUEST_TYPE = abi.encodePacked(
        RELAY_REQUEST_NAME,"(",GENERIC_PARAMS,",", RELAY_REQUEST_SUFFIX);

    bytes32 public constant RELAYDATA_TYPEHASH = keccak256(RELAYDATA_TYPE);
    bytes32 public constant RELAY_REQUEST_TYPEHASH = keccak256(RELAY_REQUEST_TYPE);

    bytes32 public constant EIP712DOMAIN_TYPEHASH = keccak256(
        "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
    );

    function splitRequest(
        GsnTypes.RelayRequest calldata req
    )
        internal
        pure
        returns (
            IForwarder.ForwardRequest memory forwardRequest,
            bytes memory suffixData
        )
    {
        forwardRequest = IForwarder.ForwardRequest(
            req.request.from,
            req.request.to,
            req.request.value,
            req.request.gas,
            req.request.nonce,
            req.request.data
        );
        suffixData = abi.encode(
            hashRelayData(req.relayData));
    }

    //verify that the recipient trusts the given forwarder
    // MUST be called by paymaster
    function verifyForwarderTrusted(GsnTypes.RelayRequest calldata relayRequest)
        internal
        view
    {
        (bool success, bytes memory ret) = relayRequest.request.to.staticcall(
            abi.encodeWithSelector(
                IRelayRecipient.isTrustedForwarder.selector, relayRequest.relayData.forwarder
            )
        );
        require(success, "isTrustedForwarder reverted");
        require(ret.length == 32, "isTrustedForwarder returned invalid response");
        require(abi.decode(ret, (bool)), "invalid forwarder for recipient");
    }

    function verifySignature(GsnTypes.RelayRequest calldata relayRequest, bytes calldata signature)
        internal
        view
    {
        (IForwarder.ForwardRequest memory forwardRequest, bytes memory suffixData) = splitRequest(relayRequest);
        bytes32 _domainSeparator = domainSeparator(relayRequest.relayData.forwarder);
        IForwarder forwarder = IForwarder(payable(relayRequest.relayData.forwarder));
        forwarder.verify(forwardRequest, _domainSeparator, RELAY_REQUEST_TYPEHASH, suffixData, signature);
    }

    function verify(GsnTypes.RelayRequest calldata relayRequest, bytes calldata signature)
        internal
        view
    {
        verifyForwarderTrusted(relayRequest);
        verifySignature(relayRequest, signature);
    }

    function execute(GsnTypes.RelayRequest calldata relayRequest, bytes calldata signature) 
        internal
        returns (
            bool forwarderSuccess,
            bool callSuccess,
            bytes memory ret
        )
    {
        (IForwarder.ForwardRequest memory forwardRequest, bytes memory suffixData) = splitRequest(relayRequest);
        bytes32 _domainSeparator = domainSeparator(relayRequest.relayData.forwarder);
        /* solhint-disable-next-line avoid-low-level-calls */
        (forwarderSuccess, ret) = relayRequest.relayData.forwarder.call(
            abi.encodeWithSelector(IForwarder.execute.selector,
            forwardRequest, _domainSeparator, RELAY_REQUEST_TYPEHASH, suffixData, signature
        ));
        if ( forwarderSuccess ) {

          //decode return value of execute:
          (callSuccess, ret) = abi.decode(ret, (bool, bytes));
        }
        truncateInPlace(ret);
    }

    //truncate the given parameter (in-place) if its length is above the given maximum length
    // do nothing otherwise.
    //NOTE: solidity warns unless the method is marked "pure", but it DOES modify its parameter.
    function truncateInPlace(bytes memory data) internal pure {
        MinLibBytes.truncateInPlace(data, MAX_RETURN_SIZE);
    }

    function domainSeparator(address forwarder)
        internal
        view
        returns (bytes32)
    {
        return hashDomain(EIP712Domain({
            name : "GSN Relayed Transaction",
            version : "2",
            chainId : getChainID(),
            verifyingContract : forwarder
            }));
    }

    function getChainID() 
        internal
        view
        returns (uint256 id)
    {
        /* solhint-disable no-inline-assembly */
        assembly {
            id := chainid()
        }
    }

    function hashDomain(EIP712Domain memory req) 
        internal
        pure
        returns (bytes32)
    {
        return keccak256(abi.encode(
                EIP712DOMAIN_TYPEHASH,
                keccak256(bytes(req.name)),
                keccak256(bytes(req.version)),
                req.chainId,
                req.verifyingContract));
    }

    function hashRelayData(GsnTypes.RelayData calldata req)
        internal
        pure
        returns (bytes32)
    {
        return keccak256(abi.encode(
                RELAYDATA_TYPEHASH,
                req.gasPrice,
                req.pctRelayFee,
                req.baseRelayFee,
                req.relayWorker,
                req.paymaster,
                req.forwarder,
                keccak256(req.paymasterData),
                req.clientId
            ));
    }


}

File 12 of 18 : Forwarder.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.1;
pragma experimental ABIEncoderV2;

import "../../libraries/utils/ECDSA.sol";
import "./IForwarder.sol";

contract Forwarder is IForwarder {
    using ECDSA for bytes32;

    string public constant GENERIC_PARAMS = "address from,address to,uint256 value,uint256 gas,uint256 nonce,bytes data";

    string public constant EIP712_DOMAIN_TYPE = "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)";

    mapping(bytes32 => bool) public typeHashes;
    mapping(bytes32 => bool) public domains;

    // Nonces of senders, used to prevent replay attacks
    mapping(address => uint256) private nonces;

    // solhint-disable-next-line no-empty-blocks
    receive() external payable {}

    function getNonce(address from) public view override returns (uint256) {
        return nonces[from];
    }

    constructor() {

        string memory requestType = string(abi.encodePacked("ForwardRequest(", GENERIC_PARAMS, ")"));
        registerRequestTypeInternal(requestType);
    }

    function verify(
        ForwardRequest memory req,
        bytes32 domainSeparator,
        bytes32 requestTypeHash,
        bytes calldata suffixData,
        bytes calldata sig
    )
        external
        override
        view
    {

        _verifyNonce(req);
        _verifySig(req, domainSeparator, requestTypeHash, suffixData, sig);
    }

    function execute(
        ForwardRequest memory req,
        bytes32 domainSeparator,
        bytes32 requestTypeHash,
        bytes calldata suffixData,
        bytes calldata sig
    )
        external payable
        override
        returns (bool success, bytes memory ret)
    {
        _verifyNonce(req);
        _verifySig(req, domainSeparator, requestTypeHash, suffixData, sig);
        _updateNonce(req);

        // solhint-disable-next-line avoid-low-level-calls
        (success,ret) = req.to.call{gas : req.gas, value : req.value}(abi.encodePacked(req.data, req.from));
        if ( address(this).balance>0 ) {
            //can't fail: req.from signed (off-chain) the request, so it must be an EOA...
            payable(req.from).transfer(address(this).balance);
        }
        return (success,ret);
    }


    function _verifyNonce(ForwardRequest memory req) internal view {
        require(nonces[req.from] == req.nonce, "nonce mismatch");
    }

    function _updateNonce(ForwardRequest memory req) internal {
        nonces[req.from]++;
    }

    function registerRequestType(string calldata typeName, string calldata typeSuffix)
        external
        override
    {

        for (uint i = 0; i < bytes(typeName).length; i++) {
            bytes1 c = bytes(typeName)[i];
            require(c != "(" && c != ")", "invalid typename");
        }

        string memory requestType = string(abi.encodePacked(typeName, "(", GENERIC_PARAMS, ",", typeSuffix));
        registerRequestTypeInternal(requestType);
    }

    function registerDomainSeparator(string calldata name, string calldata version)
        external
        override
    {
        uint256 chainId;
        /* solhint-disable-next-line no-inline-assembly */
        assembly { chainId := chainid() }

        bytes memory domainValue = abi.encode(
            keccak256(bytes(EIP712_DOMAIN_TYPE)),
            keccak256(bytes(name)),
            keccak256(bytes(version)),
            chainId,
            address(this));

        bytes32 domainHash = keccak256(domainValue);

        domains[domainHash] = true;
        emit DomainRegistered(domainHash, domainValue);
    }

    function registerRequestTypeInternal(string memory requestType)
        internal
    {

        bytes32 requestTypehash = keccak256(bytes(requestType));
        typeHashes[requestTypehash] = true;
        emit RequestTypeRegistered(requestTypehash, requestType);
    }

    event DomainRegistered(bytes32 indexed domainSeparator, bytes domainValue);

    event RequestTypeRegistered(bytes32 indexed typeHash, string typeStr);


    function _verifySig(
        ForwardRequest memory req,
        bytes32 domainSeparator,
        bytes32 requestTypeHash,
        bytes memory suffixData,
        bytes memory sig
    )
        internal
        view
    {
        require(domains[domainSeparator], "unregistered domain separator");
        require(typeHashes[requestTypeHash], "unregistered request typehash");
        bytes32 digest = keccak256(abi.encodePacked(
                "\x19\x01", domainSeparator,
                keccak256(_getEncoded(req, requestTypeHash, suffixData))
            ));
        require(digest.recover(sig) == req.from, "signature mismatch");
    }

    function _getEncoded(
        ForwardRequest memory req,
        bytes32 requestTypeHash,
        bytes memory suffixData
    )
        public
        pure
        returns (bytes memory)
    {
        return abi.encodePacked(
            requestTypeHash,
            abi.encode(
                req.from,
                req.to,
                req.value,
                req.gas,
                req.nonce,
                keccak256(req.data)
            ),
            suffixData
        );
    }
}

File 13 of 18 : IForwarder.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;

interface IForwarder {

    struct ForwardRequest {
        address from;
        address to;
        uint256 value;
        uint256 gas;
        uint256 nonce;
        bytes data;
    }

    function getNonce(address from)
    external view
    returns(uint256);

    /**
     * verify the transaction would execute.
     * validate the signature and the nonce of the request.
     * revert if either signature or nonce are incorrect.
     */
    function verify(
        ForwardRequest calldata forwardRequest,
        bytes32 domainSeparator,
        bytes32 requestTypeHash,
        bytes calldata suffixData,
        bytes calldata signature
    ) external view;

    /**
     * execute a transaction
     * @param forwardRequest - all transaction parameters
     * @param domainSeparator - domain used when signing this request
     * @param requestTypeHash - request type used when signing this request.
     * @param suffixData - the extension data used when signing this request.
     * @param signature - signature to validate.
     *
     * the transaction is verified, and then executed.
     * the success and ret of "call" are returned.
     * This method would revert only verification errors. target errors
     * are reported using the returned "success" and ret string
     */
    function execute(
        ForwardRequest calldata forwardRequest,
        bytes32 domainSeparator,
        bytes32 requestTypeHash,
        bytes calldata suffixData,
        bytes calldata signature
    )
    external payable
    returns (bool success, bytes memory ret);

    /**
     * Register a new Request typehash.
     * @param typeName - the name of the request type.
     * @param typeSuffix - anything after the generic params can be empty string (if no extra fields are needed)
     *        if it does contain a value, then a comma is added first.
     */
    function registerRequestType(string calldata typeName, string calldata typeSuffix) external;

    /**
     * Register a new domain separator.
     * The domain separator must have the following fields: name,version,chainId, verifyingContract.
     * the chainId is the current network's chainId, and the verifyingContract is this forwarder.
     * This method is given the domain name and version to create and register the domain separator value.
     * @param name the domain's display name
     * @param version the domain/protocol version
     */
    function registerDomainSeparator(string calldata name, string calldata version) external;
}

File 14 of 18 : IStakeManager.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;

/*
  import openzepplin safemath
*/

interface IStakeManager {

    /// Emitted when a stake or unstakeDelay are initialized or increased
    event StakeAdded(
        address indexed relayManager,
        address indexed owner,
        uint256 stake,
        uint256 unstakeDelay
    );

    /// Emitted once a stake is scheduled for withdrawal
    event StakeUnlocked(
        address indexed relayManager,
        address indexed owner,
        uint256 withdrawBlock
    );

    /// Emitted when owner withdraws relayManager funds
    event StakeWithdrawn(
        address indexed relayManager,
        address indexed owner,
        uint256 amount
    );

    /// Emitted when an authorized Relay Hub penalizes a relayManager
    event StakePenalized(
        address indexed relayManager,
        address indexed beneficiary,
        uint256 reward
    );

    event HubAuthorized(
        address indexed relayManager,
        address indexed relayHub
    );

    event HubUnauthorized(
        address indexed relayManager,
        address indexed relayHub,
        uint256 removalBlock
    );

    /// @param stake - amount of ether staked for this relay
    /// @param unstakeDelay - number of blocks to elapse before the owner can retrieve the stake after calling 'unlock'
    /// @param withdrawBlock - first block number 'withdraw' will be callable, or zero if the unlock has not been called
    /// @param owner - address that receives revenue and manages relayManager's stake
    struct StakeInfo {
        uint256 stake;
        uint256 unstakeDelay;
        uint256 withdrawBlock;
        address payable owner;
    }

    struct RelayHubInfo {
        uint256 removalBlock;
    }

    /// Put a stake for a relayManager and set its unstake delay.
    /// If the entry does not exist, it is created, and the caller of this function becomes its owner.
    /// If the entry already exists, only the owner can call this function.
    /// @param relayManager - address that represents a stake entry and controls relay registrations on relay hubs
    /// @param unstakeDelay - number of blocks to elapse before the owner can retrieve the stake after calling 'unlock'
    function stakeForAddress(address relayManager, uint256 unstakeDelay) external payable;

    function unlockStake(address relayManager) external;

    function withdrawStake(address relayManager) external;

    function authorizeHubByOwner(address relayManager, address relayHub) external;

    function authorizeHubByManager(address relayHub) external;

    function unauthorizeHubByOwner(address relayManager, address relayHub) external;

    function unauthorizeHubByManager(address relayHub) external;

    function isRelayManagerStaked(address relayManager, address relayHub, uint256 minAmount, uint256 minUnstakeDelay)
        external
        view
        returns (bool);

    /// Slash the stake of the relay relayManager. In order to prevent stake kidnapping, burns half of stake on the way.
    /// @param relayManager - entry to penalize
    /// @param beneficiary - address that receives half of the penalty amount
    /// @param amount - amount to withdraw from stake
    function penalizeRelayManager(address relayManager, address payable beneficiary, uint256 amount) external;

    function getStakeInfo(address relayManager) external view returns (StakeInfo memory stakeInfo);

    function versionSM() external view returns (string memory);
}

File 15 of 18 : IRelayRecipient.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * a contract must implement this interface in order to support relayed transaction.
 * It is better to inherit the BaseRelayRecipient as its implementation.
 */
abstract contract IRelayRecipient {

    /**
     * return if the forwarder is trusted to forward relayed transactions to us.
     * the forwarder is required to verify the sender's signature, and verify
     * the call is not a replay.
     */
    function isTrustedForwarder(address forwarder) public virtual view returns(bool);

    /**
     * return the sender of this call.
     * if the call came through our trusted forwarder, then the real sender is appended as the last 20 bytes
     * of the msg.data.
     * otherwise, return `msg.sender`
     * should be used in the contract anywhere instead of msg.sender
     */
    function _msgSender() internal virtual view returns (address payable);

    /**
     * return the msg.data of this call.
     * if the call came through our trusted forwarder, then the real sender was appended as the last 20 bytes
     * of the msg.data - so this method will strip those 20 bytes off.
     * otherwise, return `msg.data`
     * should be used in the contract instead of msg.data, where the difference matters (e.g. when explicitly
     * signing or hashing the
     */
    function _msgData() internal virtual view returns (bytes memory);

    function versionRecipient() external virtual view returns (string memory);
}

File 16 of 18 : GsnUtils.sol
// SPDX-License-Identifier: MIT

/* solhint-disable no-inline-assembly */
// SPDX-License-Identifier:MIT
pragma solidity 0.8.1;

import "../utils/MinLibBytes.sol";

library GsnUtils {

    /**
     * extract method sig from encoded function call
     */
    function getMethodSig(bytes memory msgData) internal pure returns (bytes4) {
        return MinLibBytes.readBytes4(msgData, 0);
    }

    /**
     * extract parameter from encoded-function block.
     * see: https://solidity.readthedocs.io/en/develop/abi-spec.html#formal-specification-of-the-encoding
     * the return value should be casted to the right type (uintXXX/bytesXXX/address/bool/enum)
     */
    function getParam(bytes memory msgData, uint index) internal pure returns (uint) {
        return MinLibBytes.readUint256(msgData, 4 + index * 32);
    }

    //re-throw revert with the same revert data.
    function revertWithData(bytes memory data) 
        internal 
        pure
    {
        assembly {
            revert(add(data,32), mload(data))
        }
    }

}

File 17 of 18 : MinLibBytes.sol
// SPDX-License-Identifier: MIT

// minimal bytes manipulation required by GSN
// a minimal subset from 0x/LibBytes
/* solhint-disable no-inline-assembly */
pragma solidity 0.8.1;

library MinLibBytes {

    //truncate the given parameter (in-place) if its length is above the given maximum length
    // do nothing otherwise.
    //NOTE: solidity warns unless the method is marked "pure", but it DOES modify its parameter.
    function truncateInPlace(bytes memory data, uint256 maxlen) 
        internal 
        pure
    {
        if (data.length > maxlen) {
            assembly { mstore(data, maxlen) }
        }
    }

    /// @dev Reads an address from a position in a byte array.
    /// @param b Byte array containing an address.
    /// @param index Index in byte array of address.
    /// @return result address from byte array.
    function readAddress(
        bytes memory b,
        uint256 index
    )
        internal
        pure
        returns (address result)
    {
        require (b.length >= index + 20, "readAddress: data too short");

        // Add offset to index:
        // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
        // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index)
        index += 20;

        // Read address from array memory
        assembly {
            // 1. Add index to address of bytes array
            // 2. Load 32-byte word from memory
            // 3. Apply 20-byte mask to obtain address
            result := and(mload(add(b, index)), 0xffffffffffffffffffffffffffffffffffffffff)
        }
        return result;
    }

    function readBytes32(
        bytes memory b,
        uint256 index
    )
        internal
        pure
        returns (bytes32 result)
    {
        require(b.length >= index + 32, "readBytes32: data too short" );

        // Read the bytes32 from array memory
        assembly {
            result := mload(add(b, add(index,32)))
        }
        return result;
    }

    /// @dev Reads a uint256 value from a position in a byte array.
    /// @param b Byte array containing a uint256 value.
    /// @param index Index in byte array of uint256 value.
    /// @return result uint256 value from byte array.
    function readUint256(
        bytes memory b,
        uint256 index
    )
        internal
        pure
        returns (uint256 result)
    {
        result = uint256(readBytes32(b, index));
        return result;
    }

    function readBytes4(
        bytes memory b,
        uint256 index
    )
        internal
        pure
        returns (bytes4 result)
    {
        require(b.length >= index + 4, "readBytes4: data too short");

        // Read the bytes4 from array memory
        assembly {
            result := mload(add(b, add(index,32)))
            // Solidity does not require us to clean the trailing bytes.
            // We do it anyway
            result := and(result, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)
        }
        return result;
    }
}

File 18 of 18 : ECDSA.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.1;

/**
 * @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 {
    /**
     * @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) {
        // Check the signature length
        if (signature.length != 65) {
            revert("ECDSA: invalid signature length");
        }

        // Divide the signature in r, s and v variables
        bytes32 r;
        bytes32 s;
        uint8 v;

        // ecrecover takes the signature parameters, and the only way to get them
        // currently is to use assembly.
        // solhint-disable-next-line no-inline-assembly
        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := byte(0, mload(add(signature, 0x60)))
        }

        return recover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover-bytes32-bytes-} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        // 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 (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): 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.
        require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "ECDSA: invalid signature 's' value");
        require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value");

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        require(signer != address(0), "ECDSA: invalid signature");

        return signer;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * replicates the behavior of the
     * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`]
     * JSON-RPC method.
     *
     * 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));
    }
}

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

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FORWARDER_HUB_OVERHEAD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAYMASTER_ACCEPTANCE_BUDGET","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POST_RELAYED_CALL_GAS_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRE_RELAYED_CALL_GAS_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WHITELIST_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IForwarder.ForwardRequest","name":"request","type":"tuple"},{"components":[{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"pctRelayFee","type":"uint256"},{"internalType":"uint256","name":"baseRelayFee","type":"uint256"},{"internalType":"address","name":"relayWorker","type":"address"},{"internalType":"address","name":"paymaster","type":"address"},{"internalType":"bytes","name":"paymasterData","type":"bytes"},{"internalType":"uint256","name":"clientId","type":"uint256"},{"internalType":"address","name":"forwarder","type":"address"}],"internalType":"struct GsnTypes.RelayData","name":"relayData","type":"tuple"}],"internalType":"struct GsnTypes.RelayRequest","name":"relayRequest","type":"tuple"}],"name":"_verifyForwarder","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IForwarder.ForwardRequest","name":"request","type":"tuple"},{"components":[{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"pctRelayFee","type":"uint256"},{"internalType":"uint256","name":"baseRelayFee","type":"uint256"},{"internalType":"address","name":"relayWorker","type":"address"},{"internalType":"address","name":"paymaster","type":"address"},{"internalType":"bytes","name":"paymasterData","type":"bytes"},{"internalType":"uint256","name":"clientId","type":"uint256"},{"internalType":"address","name":"forwarder","type":"address"}],"internalType":"struct GsnTypes.RelayData","name":"relayData","type":"tuple"}],"internalType":"struct GsnTypes.RelayRequest","name":"relayRequest","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"_verifySignature","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"addAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"addWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getGasLimits","outputs":[{"components":[{"internalType":"uint256","name":"acceptanceBudget","type":"uint256"},{"internalType":"uint256","name":"preRelayedCallGasLimit","type":"uint256"},{"internalType":"uint256","name":"postRelayedCallGasLimit","type":"uint256"}],"internalType":"struct IPaymaster.GasLimits","name":"limits","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getHubAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRelayHubDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"inWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"newOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"context","type":"bytes"},{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"gasUseWithoutPost","type":"uint256"},{"components":[{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"pctRelayFee","type":"uint256"},{"internalType":"uint256","name":"baseRelayFee","type":"uint256"},{"internalType":"address","name":"relayWorker","type":"address"},{"internalType":"address","name":"paymaster","type":"address"},{"internalType":"bytes","name":"paymasterData","type":"bytes"},{"internalType":"uint256","name":"clientId","type":"uint256"},{"internalType":"address","name":"forwarder","type":"address"}],"internalType":"struct GsnTypes.RelayData","name":"relayData","type":"tuple"}],"name":"postRelayedCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IForwarder.ForwardRequest","name":"request","type":"tuple"},{"components":[{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"pctRelayFee","type":"uint256"},{"internalType":"uint256","name":"baseRelayFee","type":"uint256"},{"internalType":"address","name":"relayWorker","type":"address"},{"internalType":"address","name":"paymaster","type":"address"},{"internalType":"bytes","name":"paymasterData","type":"bytes"},{"internalType":"uint256","name":"clientId","type":"uint256"},{"internalType":"address","name":"forwarder","type":"address"}],"internalType":"struct GsnTypes.RelayData","name":"relayData","type":"tuple"}],"internalType":"struct GsnTypes.RelayRequest","name":"relayRequest","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"approvalData","type":"bytes"},{"internalType":"uint256","name":"maxPossibleGas","type":"uint256"}],"name":"preRelayedCall","outputs":[{"internalType":"bytes","name":"context","type":"bytes"},{"internalType":"bool","name":"rejectOnRecipientRevert","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"removeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"removeWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IRelayHub","name":"hub","type":"address"}],"name":"setRelayHub","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IForwarder","name":"forwarder","type":"address"}],"name":"setTrustedForwarder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trustedForwarder","outputs":[{"internalType":"contract IForwarder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"versionPaymaster","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"target","type":"address"}],"name":"withdrawRelayHubDepositTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040523480156200001157600080fd5b5060006200001e62000088565b600180546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506200008260006200007c62000088565b6200008c565b6200019c565b3390565b6200009882826200009c565b5050565b600082815260208181526040909120620000c191839062000f4262000115821b17901c565b156200009857620000d162000088565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60006200012c836001600160a01b03841662000135565b90505b92915050565b600062000143838362000184565b6200017b575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200012f565b5060006200012f565b60009081526001919091016020526040902054151590565b6124cb80620001ac6000396000f3fe6080604052600436106102535760003560e01c80639010d07c11610138578063d547741f116100b0578063e5c124461161007f578063f2fde38b11610064578063f2fde38b146106ed578063f80f5dd51461070d578063f9c002f71461072d57610308565b8063e5c124461461069f578063e61370b7146106cd57610308565b8063d547741f1461062a578063da7422281461064a578063df463a661461066a578063e2aafa211461067f57610308565b8063a217fddf11610107578063bbdaa3c9116100ec578063bbdaa3c9146105e0578063ca15c873146105f5578063d4ee1d901461061557610308565b8063a217fddf146105b6578063b90b41cf146105cb57610308565b80639010d07c1461053457806391d1485414610554578063921276ea146105745780639ea092111461059657610308565b8063715018a6116101cb5780637a997ab71161019a5780637da0a8771161017f5780637da0a877146104ea5780638da5cb5b146104ff5780638e9483b01461051457610308565b80637a997ab7146104b55780637bb05264146104ca57610308565b8063715018a61461044957806374e861d61461045e57806378c8cda71461048057806379ba5097146104a057610308565b80632d14c4b71161022257806336568abe1161020757806336568abe146103e75780635ea54eee14610407578063704802751461042957610308565b80632d14c4b7146103a75780632f2ff15d146103c757610308565b80631785f53c1461030d578063248a9ca31461032f57806324d7806c146103655780632afe31c11461039257610308565b36610308576003546001600160a01b03166102895760405162461bcd60e51b815260040161028090611f45565b60405180910390fd5b6003546040517faa67c9190000000000000000000000000000000000000000000000000000000081526001600160a01b039091169063aa67c9199034906102d4903090600401611ceb565b6000604051808303818588803b1580156102ed57600080fd5b505af1158015610301573d6000803e3d6000fd5b5050505050005b600080fd5b34801561031957600080fd5b5061032d6103283660046118fd565b610742565b005b34801561033b57600080fd5b5061034f61034a366004611935565b610750565b60405161035c9190611d0a565b60405180910390f35b34801561037157600080fd5b506103856103803660046118fd565b610765565b60405161035c9190611cff565b34801561039e57600080fd5b5061034f610777565b3480156103b357600080fd5b5061032d6103c2366004611b7b565b610816565b3480156103d357600080fd5b5061032d6103e236600461194d565b6108ca565b3480156103f357600080fd5b5061032d61040236600461194d565b610912565b34801561041357600080fd5b5061041c610954565b60405161035c919061226b565b34801561043557600080fd5b5061032d6104443660046118fd565b610992565b34801561045557600080fd5b5061032d61099d565b34801561046a57600080fd5b50610473610a1c565b60405161035c9190611ceb565b34801561048c57600080fd5b5061032d61049b3660046118fd565b610a2b565b3480156104ac57600080fd5b5061032d610a55565b3480156104c157600080fd5b5061034f610af5565b3480156104d657600080fd5b5061032d6104e53660046118fd565b610b19565b3480156104f657600080fd5b50610473610b70565b34801561050b57600080fd5b50610473610b7f565b34801561052057600080fd5b5061032d61052f36600461199d565b610b8e565b34801561054057600080fd5b5061047361054f36600461197c565b610bcd565b34801561056057600080fd5b5061038561056f36600461194d565b610bec565b34801561058057600080fd5b50610589610c04565b60405161035c9190611dad565b3480156105a257600080fd5b5061032d6105b1366004611a29565b610c3b565b3480156105c257600080fd5b5061034f610c90565b3480156105d757600080fd5b5061034f610c95565b3480156105ec57600080fd5b5061034f610c9b565b34801561060157600080fd5b5061034f610610366004611935565b610ca2565b34801561062157600080fd5b50610473610cb9565b34801561063657600080fd5b5061032d61064536600461194d565b610cc8565b34801561065657600080fd5b5061032d6106653660046118fd565b610d02565b34801561067657600080fd5b5061034f610d59565b34801561068b57600080fd5b5061038561069a3660046118fd565b610d6b565b3480156106ab57600080fd5b506106bf6106ba366004611aca565b610d97565b60405161035c929190611d89565b3480156106d957600080fd5b5061032d6106e8366004611a64565b610e82565b3480156106f957600080fd5b5061032d6107083660046118fd565b610e92565b34801561071957600080fd5b5061032d6107283660046118fd565b610f11565b34801561073957600080fd5b5061034f610f3b565b61074d600082610cc8565b50565b60009081526020819052604090206002015490565b60006107718183610bec565b92915050565b6003546040517f70a082310000000000000000000000000000000000000000000000000000000081526000916001600160a01b0316906370a08231906107c1903090600401611ceb565b60206040518083038186803b1580156107d957600080fd5b505afa1580156107ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108119190611b63565b905090565b61081e610f57565b6001546001600160a01b0390811691161461084b5760405162461bcd60e51b815260040161028090612101565b6003546040517ef714ce0000000000000000000000000000000000000000000000000000000081526001600160a01b039091169062f714ce90610894908590859060040161228c565b600060405180830381600087803b1580156108ae57600080fd5b505af11580156108c2573d6000803e3d6000fd5b505050505050565b6000828152602081905260409020600201546108e89061056f610f57565b6109045760405162461bcd60e51b815260040161028090611e1d565b61090e8282610f5b565b5050565b61091a610f57565b6001600160a01b0316816001600160a01b03161461094a5760405162461bcd60e51b81526004016102809061216d565b61090e8282610fc4565b61095c611836565b604051806060016040528061c350620186a06109789190612312565b8152602001620186a081526020016201adb0815250905090565b61074d6000826108ca565b6109a5610f57565b6001546001600160a01b039081169116146109d25760405162461bcd60e51b815260040161028090612101565b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b6003546001600160a01b031690565b61074d7fdc72ed553f2544c34465af23b847953efeb813428162d767f9ba5f4013be676082610cc8565b6002546001600160a01b0316610a69610f57565b6001600160a01b031614610a8f5760405162461bcd60e51b815260040161028090612136565b6002546001546040516001600160a01b0392831692909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a360028054600180546001600160a01b03199081166001600160a01b03841617909155169055565b7fdc72ed553f2544c34465af23b847953efeb813428162d767f9ba5f4013be676081565b610b21610f57565b6001546001600160a01b03908116911614610b4e5760405162461bcd60e51b815260040161028090612101565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6004546001600160a01b031681565b6001546001600160a01b031690565b610b96610a1c565b6001600160a01b0316336001600160a01b031614610bc65760405162461bcd60e51b8152600401610280906120a4565b5050505050565b6000828152602081905260408120610be5908361102d565b9392505050565b6000828152602081905260408120610be59083611039565b60408051808201909152600581527f322e312e30000000000000000000000000000000000000000000000000000000602082015290565b610c4860208201826122fd565b610c5a9061010081019060e0016118fd565b6004546001600160a01b03908116911614610c875760405162461bcd60e51b815260040161028090611f7c565b61074d8161104e565b600081565b61c35081565b6201adb081565b6000818152602081905260408120610771906111e3565b6002546001600160a01b031681565b600082815260208190526040902060020154610ce69061056f610f57565b61094a5760405162461bcd60e51b815260040161028090611fb3565b610d0a610f57565b6001546001600160a01b03908116911614610d375760405162461bcd60e51b815260040161028090612101565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b610d6861c350620186a0612312565b81565b60006107717fdc72ed553f2544c34465af23b847953efeb813428162d767f9ba5f4013be676083610bec565b60606000610da3610a1c565b6001600160a01b0316336001600160a01b031614610dd35760405162461bcd60e51b8152600401610280906120a4565b610dee610de089806122e8565b61069a9060208101906118fd565b80610e0f5750610e0f610e0189806122e8565b6103809060208101906118fd565b610e2b5760405162461bcd60e51b815260040161028090611e7a565b610e3488610c3b565b610e3f888888610e82565b505060408051808201909152601681527f50726552656c6179656443616c6c20737563636573730000000000000000000060208201526000965096945050505050565b610e8d8383836111ee565b505050565b610e9a610f57565b6001546001600160a01b03908116911614610ec75760405162461bcd60e51b815260040161028090612101565b6002546001600160a01b0316610eef5760405162461bcd60e51b815260040161028090611ee8565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b61074d7fdc72ed553f2544c34465af23b847953efeb813428162d767f9ba5f4013be6760826108ca565b620186a081565b6000610be5836001600160a01b038416611368565b3390565b6000828152602081905260409020610f739082610f42565b1561090e57610f80610f57565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000828152602081905260409020610fdc90826113b2565b1561090e57610fe9610f57565b6001600160a01b0316816001600160a01b0316837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45050565b6000610be583836113c7565b6000610be5836001600160a01b038416611420565b60008061105b83806122e8565b61106c9060408101906020016118fd565b6001600160a01b03167f572b6c05000000000000000000000000000000000000000000000000000000006110a360208601866122fd565b6110b59061010081019060e0016118fd565b6040516024016110c59190611ceb565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516111309190611bf3565b600060405180830381855afa9150503d806000811461116b576040519150601f19603f3d011682016040523d82523d6000602084013e611170565b606091505b5091509150816111925760405162461bcd60e51b81526004016102809061206d565b80516020146111b35760405162461bcd60e51b815260040161028090612010565b808060200190518101906111c79190611919565b610e8d5760405162461bcd60e51b815260040161028090611eb1565b600061077182611438565b6000806111fa8561143c565b9092509050600061122861121160208801886122fd565b6112239061010081019060e0016118fd565b611566565b9050600061123960208801886122fd565b61124b9061010081019060e0016118fd565b9050806001600160a01b031663992d82c385846040518060400160405280600c81526020017f52656c61795265717565737400000000000000000000000000000000000000008152506040518060800160405280604a815260200161244c604a91396040518060e0016040528060a181526020016123ab60a191396040516020016112d69190611ca6565b60408051601f19818403018152908290526112f5939291602001611c0f565b60405160208183030381529060405280519060200120878b8b6040518763ffffffff1660e01b815260040161132f969594939291906121ca565b60006040518083038186803b15801561134757600080fd5b505afa15801561135b573d6000803e3d6000fd5b5050505050505050505050565b60006113748383611420565b6113aa57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610771565b506000610771565b6000610be5836001600160a01b038416611602565b815460009082106113ea5760405162461bcd60e51b815260040161028090611dc0565b82600001828154811061140d57634e487b7160e01b600052603260045260246000fd5b9060005260206000200154905092915050565b60009081526001919091016020526040902054151590565b5490565b611444611857565b6040805160c081019091526060908061145d85806122e8565b61146b9060208101906118fd565b6001600160a01b0316815260200161148385806122e8565b6114949060408101906020016118fd565b6001600160a01b031681526020016114ac85806122e8565b6040013581526020016114bf85806122e8565b6060013581526020016114d285806122e8565b6080013581526020016114e585806122e8565b6114f39060a08101906122a3565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050915250915061154061153b60208501856122fd565b61171f565b6040516020016115509190611d0a565b6040516020818303038152906040529050915091565b6040805160c0810182526017608082019081527f47534e2052656c61796564205472616e73616374696f6e00000000000000000060a0830152815281518083018352600181527f3200000000000000000000000000000000000000000000000000000000000000602082810191909152820152600091610771919081016115eb6117d9565b8152602001846001600160a01b03168152506117dd565b6000818152600183016020526040812054801561171557600061162660018361232a565b855490915060009061163a9060019061232a565b9050600086600001828154811061166157634e487b7160e01b600052603260045260246000fd5b906000526020600020015490508087600001848154811061169257634e487b7160e01b600052603260045260246000fd5b6000918252602090912001556116a9836001612312565b600082815260018901602052604090205586548790806116d957634e487b7160e01b600052603160045260246000fd5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050610771565b6000915050610771565b60006040518060e0016040528060a181526020016123ab60a19139805160209182012090833590840135604085013561175e60808701606088016118fd565b61176e60a08801608089016118fd565b61177f610100890160e08a016118fd565b61178c60a08a018a6122a3565b60405161179a929190611be3565b6040519081900381206117bc989796959493929160c08c013590602001611d3f565b604051602081830303815290604052805190602001209050919050565b4690565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f826000015180519060200120836020015180519060200120846040015185606001516040516020016117bc959493929190611d13565b60405180606001604052806000815260200160008152602001600081525090565b6040518060c0016040528060006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001606081525090565b60008083601f8401126118b0578182fd5b50813567ffffffffffffffff8111156118c7578182fd5b6020830191508360208285010111156118df57600080fd5b9250929050565b6000604082840312156118f7578081fd5b50919050565b60006020828403121561190e578081fd5b8135610be581612387565b60006020828403121561192a578081fd5b8151610be58161239c565b600060208284031215611946578081fd5b5035919050565b6000806040838503121561195f578081fd5b82359150602083013561197181612387565b809150509250929050565b6000806040838503121561198e578182fd5b50508035926020909101359150565b6000806000806000608086880312156119b4578081fd5b853567ffffffffffffffff808211156119cb578283fd5b6119d789838a0161189f565b9097509550602088013591506119ec8261239c565b9093506040870135925060608701359080821115611a08578283fd5b5086016101008189031215611a1b578182fd5b809150509295509295909350565b600060208284031215611a3a578081fd5b813567ffffffffffffffff811115611a50578182fd5b611a5c848285016118e6565b949350505050565b600080600060408486031215611a78578283fd5b833567ffffffffffffffff80821115611a8f578485fd5b611a9b878388016118e6565b94506020860135915080821115611ab0578384fd5b50611abd8682870161189f565b9497909650939450505050565b60008060008060008060808789031215611ae2578081fd5b863567ffffffffffffffff80821115611af9578283fd5b611b058a838b016118e6565b97506020890135915080821115611b1a578283fd5b611b268a838b0161189f565b90975095506040890135915080821115611b3e578283fd5b50611b4b89828a0161189f565b979a9699509497949695606090950135949350505050565b600060208284031215611b74578081fd5b5051919050565b6000806040838503121561195f578182fd5b60008284528282602086013780602084860101526020601f19601f85011685010190509392505050565b60008151808452611bcf816020860160208601612341565b601f01601f19169290920160200192915050565b6000828483379101908152919050565b60008251611c05818460208701612341565b9190910192915050565b60008451611c21818460208901612341565b7f28000000000000000000000000000000000000000000000000000000000000009083019081528451611c5b816001840160208901612341565b7f2c00000000000000000000000000000000000000000000000000000000000000600192909101918201528351611c99816002840160208801612341565b0160020195945050505050565b60007f52656c6179446174612072656c6179446174612900000000000000000000000082528251611cde816014850160208701612341565b9190910160140192915050565b6001600160a01b0391909116815260200190565b901515815260200190565b90815260200190565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b9889526020890197909752604088019590955260608701939093526001600160a01b039182166080870152811660a08601521660c084015260e08301526101008201526101200190565b600060408252611d9c6040830185611bb7565b905082151560208301529392505050565b600060208252610be56020830184611bb7565b60208082526022908201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e60408201527f6473000000000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252602f908201527f416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e60408201527f2061646d696e20746f206772616e740000000000000000000000000000000000606082015260800190565b6020808252601b908201527f41646472657373206973206e6f7420696e2077686974656c6973740000000000604082015260600190565b6020808252601f908201527f696e76616c696420666f7277617264657220666f7220726563697069656e7400604082015260600190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201527f6464726573730000000000000000000000000000000000000000000000000000606082015260800190565b60208082526019908201527f72656c6179206875622061646472657373206e6f742073657400000000000000604082015260600190565b60208082526018908201527f466f72776172646572206973206e6f7420747275737465640000000000000000604082015260600190565b60208082526030908201527f416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e60408201527f2061646d696e20746f207265766f6b6500000000000000000000000000000000606082015260800190565b6020808252602c908201527f697354727573746564466f727761726465722072657475726e656420696e766160408201527f6c696420726573706f6e73650000000000000000000000000000000000000000606082015260800190565b6020808252601b908201527f697354727573746564466f727761726465722072657665727465640000000000604082015260600190565b60208082526027908201527f46756e6374696f6e2063616e206f6e6c792062652063616c6c6564206279205260408201527f656c617948756200000000000000000000000000000000000000000000000000606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526015908201527f4f7761626c653a204e6f74206e6577206f776e65720000000000000000000000604082015260600190565b6020808252602f908201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560408201527f20726f6c657320666f722073656c660000000000000000000000000000000000606082015260800190565b600060a082526001600160a01b038089511660a08401528060208a01511660c084015250604088015160e08301526060880151610100830152608088015161012083015260a088015160c0610140840152612229610160840182611bb7565b905087602084015286604084015282810360608401526122498187611bb7565b9050828103608084015261225e818587611b8d565b9998505050505050505050565b81518152602080830151908201526040918201519181019190915260600190565b9182526001600160a01b0316602082015260400190565b6000808335601e198436030181126122b9578283fd5b83018035915067ffffffffffffffff8211156122d3578283fd5b6020019150368190038213156118df57600080fd5b6000823560be19833603018112611c05578182fd5b6000823560fe19833603018112611c05578182fd5b6000821982111561232557612325612371565b500190565b60008282101561233c5761233c612371565b500390565b60005b8381101561235c578181015183820152602001612344565b8381111561236b576000848401525b50505050565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b038116811461074d57600080fd5b801515811461074d57600080fdfe52656c6179446174612875696e743235362067617350726963652c75696e743235362070637452656c61794665652c75696e74323536206261736552656c61794665652c616464726573732072656c6179576f726b65722c61646472657373207061796d61737465722c6164647265737320666f727761726465722c6279746573207061796d6173746572446174612c75696e7432353620636c69656e74496429616464726573732066726f6d2c6164647265737320746f2c75696e743235362076616c75652c75696e74323536206761732c75696e74323536206e6f6e63652c62797465732064617461a26469706673582212204587ff3cc3bc5659a66d10b9ae86af24e04491961db87fc3f9608e8177e3b26e64736f6c63430008010033

Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading