Goerli Testnet

Contract

0x1A387Db642a76bEE516f1e16F542ed64ee81772c
Source Code

Overview

ETH Balance

0 ETH

Token Holdings

Multi Chain

Multichain Addresses

N/A
Transaction Hash
Method
Block
From
To
Value
Transfer79186252022-11-09 0:44:24322 days 15 hrs ago1667954664IN
0x1A387D...ee81772c
1 ETH0.000050011.10486607
Transfer79179592022-11-08 22:11:12322 days 18 hrs ago1667945472IN
0x1A387D...ee81772c
1 ETH0.0013305329.39241767
Whitelist Method79178452022-11-08 21:43:36322 days 18 hrs ago1667943816IN
0x1A387D...ee81772c
0 ETH0.000097642.06942332
Set Post Gas Usa...79177902022-11-08 21:31:00322 days 18 hrs ago1667943060IN
0x1A387D...ee81772c
0 ETH0.000188344.11233367
Set Target79176452022-11-08 20:58:24322 days 19 hrs ago1667941104IN
0x1A387D...ee81772c
0 ETH0.000188596.23645882
Transfer79175352022-11-08 20:31:36322 days 19 hrs ago1667939496IN
0x1A387D...ee81772c
1 ETH0.000049380.79179132
Set Target79173692022-11-08 19:52:48322 days 20 hrs ago1667937168IN
0x1A387D...ee81772c
0 ETH0.00011992.53286597
Set Trusted Forw...79173692022-11-08 19:52:48322 days 20 hrs ago1667937168IN
0x1A387D...ee81772c
0 ETH0.000135782.53286597
Set Relay Hub79173692022-11-08 19:52:48322 days 20 hrs ago1667937168IN
0x1A387D...ee81772c
0 ETH0.00013592.53286597
0x6080604079173652022-11-08 19:52:00322 days 20 hrs ago1667937120IN
 Create: Web3AnalyticsPaymaster
0 ETH0.004865872.91769462

Latest 25 internal transactions (View All)

Advanced mode:
Parent Txn Hash Block From To Value
89375012023-05-04 0:14:48146 days 16 hrs ago1683159288
0x1A387D...ee81772c
0 ETH
89375012023-05-04 0:14:48146 days 16 hrs ago1683159288
0x1A387D...ee81772c
0 ETH
89375012023-05-04 0:14:48146 days 16 hrs ago1683159288
0x1A387D...ee81772c
0 ETH
89375012023-05-04 0:14:48146 days 16 hrs ago1683159288
0x1A387D...ee81772c
0 ETH
89375012023-05-04 0:14:48146 days 16 hrs ago1683159288
0x1A387D...ee81772c
0 ETH
89375012023-05-04 0:14:48146 days 16 hrs ago1683159288
0x1A387D...ee81772c
0 ETH
89375012023-05-04 0:14:48146 days 16 hrs ago1683159288
0x1A387D...ee81772c
0 ETH
89375012023-05-04 0:14:48146 days 16 hrs ago1683159288
0x1A387D...ee81772c
0 ETH
89375012023-05-04 0:14:48146 days 16 hrs ago1683159288
0x1A387D...ee81772c
0 ETH
89370922023-05-03 22:32:00146 days 17 hrs ago1683153120
0x1A387D...ee81772c
0 ETH
89370922023-05-03 22:32:00146 days 17 hrs ago1683153120
0x1A387D...ee81772c
0 ETH
89370922023-05-03 22:32:00146 days 17 hrs ago1683153120
0x1A387D...ee81772c
0 ETH
89370922023-05-03 22:32:00146 days 17 hrs ago1683153120
0x1A387D...ee81772c
0 ETH
89370922023-05-03 22:32:00146 days 17 hrs ago1683153120
0x1A387D...ee81772c
0 ETH
89370922023-05-03 22:32:00146 days 17 hrs ago1683153120
0x1A387D...ee81772c
0 ETH
89370922023-05-03 22:32:00146 days 17 hrs ago1683153120
0x1A387D...ee81772c
0 ETH
89370922023-05-03 22:32:00146 days 17 hrs ago1683153120
0x1A387D...ee81772c
0 ETH
89370922023-05-03 22:32:00146 days 17 hrs ago1683153120
0x1A387D...ee81772c
0 ETH
89369252023-05-03 21:50:48146 days 18 hrs ago1683150648
0x1A387D...ee81772c
0 ETH
89369252023-05-03 21:50:48146 days 18 hrs ago1683150648
0x1A387D...ee81772c
0 ETH
89369252023-05-03 21:50:48146 days 18 hrs ago1683150648
0x1A387D...ee81772c
0 ETH
89369252023-05-03 21:50:48146 days 18 hrs ago1683150648
0x1A387D...ee81772c
0 ETH
89369252023-05-03 21:50:48146 days 18 hrs ago1683150648
0x1A387D...ee81772c
0 ETH
89369252023-05-03 21:50:48146 days 18 hrs ago1683150648
0x1A387D...ee81772c
0 ETH
89369252023-05-03 21:50:48146 days 18 hrs ago1683150648
0x1A387D...ee81772c
0 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Web3AnalyticsPaymaster

Compiler Version
v0.8.7+commit.e28d00a7

Optimization Enabled:
Yes with 10 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 22 : Web3AnalyticsPaymaster.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.7;
pragma experimental ABIEncoderV2;


import "@opengsn/contracts/src/BasePaymaster.sol";
import "./Web3Analytics.sol";


contract Web3AnalyticsPaymaster is BasePaymaster {
	address public ourTarget;
    uint256 public gasUsedByPost;
    mapping(address => mapping(bytes4 => bool)) public methodWhitelist;
    
    event FeeCharged(uint256 baseFee, uint256 networkFee, uint256 totalFee);

	// allow the owner to set target contract we are willing to pay for
	event TargetSet(address target);
	function setTarget(address target) external onlyOwner {
		ourTarget = target;
		emit TargetSet(target);
	}

	// allow the owner to set methods we are willing to pay for
    function whitelistMethod(address target, bytes4 method, bool isAllowed) public onlyOwner {
        methodWhitelist[target][method] = isAllowed;
    }

    /**
     * set gas used by postRelayedCall, for proper gas calculation.
     * You can use TokenGasCalculator to calculate these values 
     * (they depend on actual code of postRelayedCall,
     */
    function setPostGasUsage(uint256 _gasUsedByPost) external onlyOwner {
        gasUsedByPost = _gasUsedByPost;
    }


	function _preRelayedCall(
        GsnTypes.RelayRequest calldata relayRequest,
        bytes calldata signature,
        bytes calldata approvalData,
        uint256 maxPossibleGas
    )
    internal
    override
    virtual
    returns (bytes memory context, bool revertOnRecipientRevert) {
        (signature, maxPossibleGas);

        // only pay for transactions for our contract
        require(relayRequest.request.to == ourTarget);

        // check that the method being called is approved
        bytes4 method = GsnUtils.getMethodSig(relayRequest.request.data);
        require(methodWhitelist[ourTarget][method], "method not whitelisted");

        // get address of app user is registering for
        (, address app) = abi.decode(relayRequest.request.data[4:], (string, address) );

        // check account balance of app to see if has sufficient funds for user registration
        Web3Analytics w3 = Web3Analytics(ourTarget);
        uint256 balance = w3.getBalance(app);
        uint256 maxEstimatedCost = maxPossibleGas * tx.gasprice;
        uint256 fee = (maxEstimatedCost / 10000) * w3.getNetworkFee(); 
        uint256 price = maxEstimatedCost + fee;

        require(balance > price, "insufficient app balance");

        return (abi.encode(app), false);
    }


	function _postRelayedCall(
        bytes calldata context,
        bool success,
        uint256 gasUseWithoutPost,
        GsnTypes.RelayData calldata relayData
    )
    internal
    override
    virtual {
        (context, success, gasUseWithoutPost, relayData);

        // get app address for this transaction
        (address app) = abi.decode(context, (address) );

        // get actual cost of transaction
        uint256 ethActualCharge = relayHub.calculateCharge(
            gasUseWithoutPost + gasUsedByPost, relayData);

        // calculate price including network fee
        Web3Analytics w3 = Web3Analytics(ourTarget);
        uint256 fee = (ethActualCharge / 10000) * w3.getNetworkFee(); 
        uint256 price = ethActualCharge + fee;

        // deduct fee
        w3.chargeFee(app, price);

        emit FeeCharged(ethActualCharge, fee, price);

    }


  	function versionPaymaster() external virtual view 
		override returns (string memory) {
			return "3.0.0";
		}

}

File 2 of 22 : Web3Analytics.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.7;

import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "@opengsn/contracts/src/ERC2771Recipient.sol";



contract Web3Analytics is ERC2771Recipient, Ownable {
    using Address for address;
    using EnumerableSet for EnumerableSet.AddressSet;

    struct Registration {
        address userAddress;
        string userDid;
    }

    struct App {
        address appAddress;
        string appName;
        string appUrl;
    }

    address private allowedPaymaster;
    uint256 private feeInBasisPoints;
    uint256 private minimumAppRegBalance;
    EnumerableSet.AddressSet private registeredApps;
    mapping(address => App) private appData;
    mapping(address => uint256) private appBalances;
    mapping(address => Registration[]) private appRegistrations;
    mapping(address => EnumerableSet.AddressSet) private appUsers;


    /**
    * @dev the Web3Analytics contract constructor
    * @param forwarder the trusted forwarder contract address
    **/

    constructor(address forwarder) {
        _setTrustedForwarder(forwarder);
    }


    /**
    * @dev sets trusted paymaster
    * @param paymaster the address of our trusted paymaster
    **/

    function setTrustedPaymaster(address paymaster) public onlyOwner {
        allowedPaymaster = paymaster;
    }


    /**
    * @dev gets trusted paymaster
    **/

    function getTrustedPaymaster() public view returns(address) {
        return allowedPaymaster;
    }


    /**
    * @dev sets feeInBasisPoints
    * @param fee the fee in basis points
    **/

    function setNetworkFee(uint256 fee) public onlyOwner {
        feeInBasisPoints = fee;
    }


    /**
    * @dev gets feeInBasisPoints
    **/

    function getNetworkFee() public view returns(uint256) {
        return feeInBasisPoints;
    }


    /**
    * @dev sets minimum balance required to register an app
    * @param balance the minimum balance
    **/

    function setMinimumAppRegBalance(uint256 balance) public onlyOwner {
        minimumAppRegBalance = balance;
    }


    /**
    * @dev gets minimum balance required to register an app
    **/

    function getMinimumAppRegBalance() public view returns(uint256) {
        return minimumAppRegBalance;
    }


    /**
    * @dev provides a list of an app's users
    * @param app the application to retrieve users for
    **/

    function getUsers(address app) public view returns(address[] memory) {
        return appUsers[app].values();
    }


    /**
    * @dev provides a count of an app's users
    * @param app the application to retrieve users for
    **/

    function getUserCount(address app) public view returns(uint256) {
        return appUsers[app].length();
    }


    /**
    * @dev provides a list of an app's registrations
    * @param app the application to retrieve registrations for
    **/

    function getUserRegistrations(address app) public view returns(Registration[] memory) {
        return appRegistrations[app];
    }


    /**
    * @dev returns whether app is registered or not
    * @param app the application to check registration for
    **/

    function isAppRegistered(address app) public view returns(bool) {
        return registeredApps.contains(app);
    }


    /**
    * @dev returns whether user is registered for given app
    * @param app the application to check registration for
    **/

    function isUserRegistered(address app, address user) public view returns(bool) {
        return appUsers[app].contains(user);
    }


    /**
    * @dev provides a count of apps registered
    **/

    function getAppCount() public view returns(uint256) {
        return registeredApps.length();
    }


    /**
    * @dev provides a list of apps registered
    **/

    function getApps() public view returns(address[] memory) {
        return registeredApps.values();
    }


    /**
    * @dev adds a new user to an app
    * @param did the did key for the user to add
    * @param app the address of the app to register user for
    **/

    function addUser(string memory did, address app) public {
        // app must be registered and user must not exist for app
        require(registeredApps.contains(app), "App not registered");
        require(!appUsers[app].contains(_msgSender()), "User already exists");

        appUsers[app].add(_msgSender());
        appRegistrations[app].push(Registration(_msgSender(), did));                          
    }


    /**
    * @dev registers new app for web3analytics
    * @param name the name of the app
    * @param url the app's url (optional)
    **/

    function registerApp(string memory name, string memory url) public payable {
        require(!registeredApps.contains(_msgSender()), "App already registered");
        require(bytes(name).length != 0, "Name is required");
        require(msg.value >= minimumAppRegBalance, "Minimum balance to register not met");

        registeredApps.add(_msgSender());
        appData[_msgSender()] = App(_msgSender(), name, url);                          
    }


    /**
    * @dev provides app data for registered app
    * @param app the application to retrieve data for
    **/

    function getAppData(address app) public view returns(App memory) {
        return appData[app];
    }


    /**
    * @dev updates app data for registered app
    * @param name the name of the app
    * @param url the app's url (optional)
    **/

    function updateAppData(string memory name, string memory url) public {
        require(registeredApps.contains(_msgSender()), "App not registered");
        require(bytes(name).length != 0, "Name is required");

        appData[_msgSender()] = App(_msgSender(), name, url);                          
    }


    /**
    * @dev gets account balance of an app
    * @param app the application to retrieve balance for
    **/

    function getBalance(address app) public view returns(uint256) {
        return appBalances[app];
    }


    /**
    * @dev allows adding value to account balance of an app
    * @param app the application to add value to
    **/

    function topUpBalance(address app) public payable {
        require(msg.value > 0, 'Top up must be greater than 0');
        appBalances[app] = appBalances[app] + msg.value;
    }


    /**
    * @dev allows deducting value from account balance of an app
    * @param app the application to charge fee to
    * @param fee the amount of the fee
    **/

    function chargeFee(address app, uint256 fee) public payable {
        require(allowedPaymaster != address(0), 'Trusted paymaster must be set');
        require(allowedPaymaster == _msgSender(), 'Only trusted paymaster may charge fee');

        appBalances[app] = appBalances[app] - fee;
    }


    function _msgSender() internal view override(Context, ERC2771Recipient)
        returns (address sender) {
        sender = ERC2771Recipient._msgSender();
    }

    function _msgData() internal view override(Context, ERC2771Recipient)
        returns (bytes memory) {
        return ERC2771Recipient._msgData();
    }

}

File 3 of 22 : BasePaymaster.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.7.6;
pragma abicoder v2;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";

import "./utils/GsnTypes.sol";
import "./interfaces/IPaymaster.sol";
import "./interfaces/IRelayHub.sol";
import "./utils/GsnEip712Library.sol";
import "./forwarder/IForwarder.sol";

/**
 * @notice An abstract base class to be inherited by a concrete Paymaster.
 * A subclass must implement:
 *  - preRelayedCall
 *  - postRelayedCall
 */
abstract contract BasePaymaster is IPaymaster, Ownable, ERC165 {
    using ERC165Checker for address;

    IRelayHub internal relayHub;
    address private _trustedForwarder;

    /// @inheritdoc IPaymaster
    function getRelayHub() public override view returns (address) {
        return address(relayHub);
    }

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

    //These parameters are documented in IPaymaster.GasAndDataLimits
    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;
    uint256 constant public CALLDATA_SIZE_LIMIT = 10500;

    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
        return interfaceId == type(IPaymaster).interfaceId ||
            interfaceId == type(Ownable).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /// @inheritdoc IPaymaster
    function getGasAndDataLimits()
    public
    override
    virtual
    view
    returns (
        IPaymaster.GasAndDataLimits memory limits
    ) {
        return IPaymaster.GasAndDataLimits(
            PAYMASTER_ACCEPTANCE_BUDGET,
            PRE_RELAYED_CALL_GAS_LIMIT,
            POST_RELAYED_CALL_GAS_LIMIT,
            CALLDATA_SIZE_LIMIT
        );
    }

    /**
     * @notice 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)
    internal
    virtual
    view
    {
        require(getTrustedForwarder() == relayRequest.relayData.forwarder, "Forwarder is not trusted");
        GsnEip712Library.verifyForwarderTrusted(relayRequest);
    }

    function _verifyRelayHubOnly() internal virtual view {
        require(msg.sender == getRelayHub(), "can only be called by RelayHub");
    }

    function _verifyValue(GsnTypes.RelayRequest calldata relayRequest) internal virtual view{
        require(relayRequest.request.value == 0, "value transfer not supported");
    }

    function _verifyPaymasterData(GsnTypes.RelayRequest calldata relayRequest) internal virtual view {
        require(relayRequest.relayData.paymasterData.length == 0, "should have no paymasterData");
    }

    function _verifyApprovalData(bytes calldata approvalData) internal virtual view{
        require(approvalData.length == 0, "should have no approvalData");
    }

    /**
     * @notice The owner of the Paymaster can change the instance of the RelayHub this Paymaster works with.
     * :warning: **Warning** :warning: The deposit on the previous RelayHub must be withdrawn first.
     */
    function setRelayHub(IRelayHub hub) public onlyOwner {
        require(address(hub).supportsInterface(type(IRelayHub).interfaceId), "target is not a valid IRelayHub");
        relayHub = hub;
    }

    /**
     * @notice The owner of the Paymaster can change the instance of the Forwarder this Paymaster works with.
     * @notice the Recipients must trust this Forwarder as well in order for the configuration to remain functional.
     */
    function setTrustedForwarder(address forwarder) public virtual onlyOwner {
        require(forwarder.supportsInterface(type(IForwarder).interfaceId), "target is not a valid IForwarder");
        _trustedForwarder = forwarder;
    }

    function getTrustedForwarder() public virtual view override returns (address){
        return _trustedForwarder;
    }

    /**
     * @notice Any native Ether transferred into the paymaster is transferred as a deposit to the RelayHub.
     * 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));
    }

    /**
     * @notice Withdraw deposit from the RelayHub.
     * @param amount The amount to be subtracted from the sender.
     * @param target The target to which the amount will be transferred.
     */
    function withdrawRelayHubDepositTo(uint256 amount, address payable target) public onlyOwner {
        relayHub.withdraw(target, amount);
    }

    /// @inheritdoc IPaymaster
    function preRelayedCall(
        GsnTypes.RelayRequest calldata relayRequest,
        bytes calldata signature,
        bytes calldata approvalData,
        uint256 maxPossibleGas
    )
    external
    override
    returns (bytes memory, bool) {
        _verifyRelayHubOnly();
        _verifyForwarder(relayRequest);
        _verifyValue(relayRequest);
        _verifyPaymasterData(relayRequest);
        _verifyApprovalData(approvalData);
        return _preRelayedCall(relayRequest, signature, approvalData, maxPossibleGas);
    }


    /**
     * @notice internal logic the paymasters need to provide to select which transactions they are willing to pay for
     * @notice see the documentation for `IPaymaster::preRelayedCall` for details
     */
    function _preRelayedCall(
        GsnTypes.RelayRequest calldata,
        bytes calldata,
        bytes calldata,
        uint256
    )
    internal
    virtual
    returns (bytes memory, bool);

    /// @inheritdoc IPaymaster
    function postRelayedCall(
        bytes calldata context,
        bool success,
        uint256 gasUseWithoutPost,
        GsnTypes.RelayData calldata relayData
    )
    external
    override
    {
        _verifyRelayHubOnly();
        _postRelayedCall(context, success, gasUseWithoutPost, relayData);
    }

    /**
     * @notice internal logic the paymasters need to provide if they need to take some action after the transaction
     * @notice see the documentation for `IPaymaster::postRelayedCall` for details
     */
    function _postRelayedCall(
        bytes calldata,
        bool,
        uint256,
        GsnTypes.RelayData calldata
    )
    internal
    virtual;
}

File 4 of 22 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 5 of 22 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(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");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 6 of 22 : ERC2771Recipient.sol
// SPDX-License-Identifier: MIT
// solhint-disable no-inline-assembly
pragma solidity >=0.6.9;

import "./interfaces/IERC2771Recipient.sol";

/**
 * @title The ERC-2771 Recipient Base Abstract Class - Implementation
 *
 * @notice Note that this contract was called `BaseRelayRecipient` in the previous revision of the GSN.
 *
 * @notice A base contract to be inherited by any contract that want to receive relayed transactions.
 *
 * @notice A subclass must use `_msgSender()` instead of `msg.sender`.
 */
abstract contract ERC2771Recipient is IERC2771Recipient {

    /*
     * Forwarder singleton we accept calls from
     */
    address private _trustedForwarder;

    /**
     * :warning: **Warning** :warning: The Forwarder can have a full control over your Recipient. Only trust verified Forwarder.
     * @notice Method is not a required method to allow Recipients to trust multiple Forwarders. Not recommended yet.
     * @return forwarder The address of the Forwarder contract that is being used.
     */
    function getTrustedForwarder() public virtual view returns (address forwarder){
        return _trustedForwarder;
    }

    function _setTrustedForwarder(address _forwarder) internal {
        _trustedForwarder = _forwarder;
    }

    /// @inheritdoc IERC2771Recipient
    function isTrustedForwarder(address forwarder) public virtual override view returns(bool) {
        return forwarder == _trustedForwarder;
    }

    /// @inheritdoc IERC2771Recipient
    function _msgSender() internal override virtual view returns (address ret) {
        if (msg.data.length >= 20 && isTrustedForwarder(msg.sender)) {
            // At this point we know that the sender is a trusted forwarder,
            // so we trust that the last bytes of msg.data are the verified sender address.
            // extract sender address from the end of msg.data
            assembly {
                ret := shr(96,calldataload(sub(calldatasize(),20)))
            }
        } else {
            ret = msg.sender;
        }
    }

    /// @inheritdoc IERC2771Recipient
    function _msgData() internal override virtual view returns (bytes calldata ret) {
        if (msg.data.length >= 20 && isTrustedForwarder(msg.sender)) {
            return msg.data[0:msg.data.length-20];
        } else {
            return msg.data;
        }
    }
}

File 7 of 22 : EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (utils/structs/EnumerableSet.sol)

pragma solidity ^0.8.0;

/**
 * @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;

            if (lastIndex != toDeleteIndex) {
                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] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // 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) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // 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);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        return _values(set._inner);
    }

    // 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))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        assembly {
            result := store
        }

        return result;
    }

    // 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));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        assembly {
            result := store
        }

        return result;
    }
}

File 8 of 22 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

File 9 of 22 : IERC2771Recipient.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0;

/**
 * @title The ERC-2771 Recipient Base Abstract Class - Declarations
 *
 * @notice A contract must implement this interface in order to support relayed transaction.
 *
 * @notice It is recommended that your contract inherits from the ERC2771Recipient contract.
 */
abstract contract IERC2771Recipient {

    /**
     * :warning: **Warning** :warning: The Forwarder can have a full control over your Recipient. Only trust verified Forwarder.
     * @param forwarder The address of the Forwarder contract that is being used.
     * @return isTrustedForwarder `true` if the Forwarder is trusted to forward relayed transactions by this Recipient.
     */
    function isTrustedForwarder(address forwarder) public virtual view returns(bool);

    /**
     * @notice Use this method the contract anywhere instead of msg.sender to support relayed transactions.
     * @return sender The real sender of this call.
     * For a call that came through the Forwarder the real sender is extracted from the last 20 bytes of the `msg.data`.
     * Otherwise simply returns `msg.sender`.
     */
    function _msgSender() internal virtual view returns (address);

    /**
     * @notice Use this method in the contract instead of `msg.data` when difference matters (hashing, signature, etc.)
     * @return data The real `msg.data` of this call.
     * For a call that came through the Forwarder, the real sender address was appended as the last 20 bytes
     * of the `msg.data` - so this method will strip those 20 bytes off.
     * Otherwise (if the call was made directly and not through the forwarder) simply returns `msg.data`.
     */
    function _msgData() internal virtual view returns (bytes calldata);
}

File 10 of 22 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 11 of 22 : GsnEip712Library.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
pragma abicoder v2;

import "../utils/GsnTypes.sol";
import "../interfaces/IERC2771Recipient.sol";
import "../forwarder/IForwarder.sol";

import "./GsnUtils.sol";

/**
 * @title The ERC-712 Library for GSN
 * @notice Bridge Library to convert a GSN RelayRequest into a valid `ForwardRequest` for a `Forwarder`.
 */
library GsnEip712Library {
    // 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,uint256 validUntilTime";

    bytes public constant RELAYDATA_TYPE = "RelayData(uint256 maxFeePerGas,uint256 maxPriorityFeePerGas,uint256 transactionCalldataGasUsed,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);


    struct EIP712Domain {
        string name;
        string version;
        uint256 chainId;
        address verifyingContract;
    }

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

    function splitRequest(
        GsnTypes.RelayRequest calldata req
    )
    internal
    pure
    returns (
        bytes memory suffixData
    ) {
        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(
                IERC2771Recipient.isTrustedForwarder.selector, relayRequest.relayData.forwarder
            )
        );
        require(success, "isTrustedForwarder: reverted");
        require(ret.length == 32, "isTrustedForwarder: bad response");
        require(abi.decode(ret, (bool)), "invalid forwarder for recipient");
    }

    function verifySignature(GsnTypes.RelayRequest calldata relayRequest, bytes calldata signature) internal view {
        (bytes memory suffixData) = splitRequest(relayRequest);
        bytes32 _domainSeparator = domainSeparator(relayRequest.relayData.forwarder);
        IForwarder forwarder = IForwarder(payable(relayRequest.relayData.forwarder));
        forwarder.verify(relayRequest.request, _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) {
        (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,
            relayRequest.request, _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 : "3",
            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.maxFeePerGas,
                req.maxPriorityFeePerGas,
                req.transactionCalldataGasUsed,
                req.relayWorker,
                req.paymaster,
                req.forwarder,
                keccak256(req.paymasterData),
                req.clientId
            ));
    }
}

File 12 of 22 : ERC165Checker.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Checker.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Library used to query support of an interface declared via {IERC165}.
 *
 * Note that these functions return the actual result of the query: they do not
 * `revert` if an interface is not supported. It is up to the caller to decide
 * what to do in these cases.
 */
library ERC165Checker {
    // As per the EIP-165 spec, no interface should ever match 0xffffffff
    bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;

    /**
     * @dev Returns true if `account` supports the {IERC165} interface,
     */
    function supportsERC165(address account) internal view returns (bool) {
        // Any contract that implements ERC165 must explicitly indicate support of
        // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
        return
            _supportsERC165Interface(account, type(IERC165).interfaceId) &&
            !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);
    }

    /**
     * @dev Returns true if `account` supports the interface defined by
     * `interfaceId`. Support for {IERC165} itself is queried automatically.
     *
     * See {IERC165-supportsInterface}.
     */
    function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
        // query support of both ERC165 as per the spec and support of _interfaceId
        return supportsERC165(account) && _supportsERC165Interface(account, interfaceId);
    }

    /**
     * @dev Returns a boolean array where each value corresponds to the
     * interfaces passed in and whether they're supported or not. This allows
     * you to batch check interfaces for a contract where your expectation
     * is that some interfaces may not be supported.
     *
     * See {IERC165-supportsInterface}.
     *
     * _Available since v3.4._
     */
    function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)
        internal
        view
        returns (bool[] memory)
    {
        // an array of booleans corresponding to interfaceIds and whether they're supported or not
        bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);

        // query support of ERC165 itself
        if (supportsERC165(account)) {
            // query support of each interface in interfaceIds
            for (uint256 i = 0; i < interfaceIds.length; i++) {
                interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);
            }
        }

        return interfaceIdsSupported;
    }

    /**
     * @dev Returns true if `account` supports all the interfaces defined in
     * `interfaceIds`. Support for {IERC165} itself is queried automatically.
     *
     * Batch-querying can lead to gas savings by skipping repeated checks for
     * {IERC165} support.
     *
     * See {IERC165-supportsInterface}.
     */
    function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
        // query support of ERC165 itself
        if (!supportsERC165(account)) {
            return false;
        }

        // query support of each interface in _interfaceIds
        for (uint256 i = 0; i < interfaceIds.length; i++) {
            if (!_supportsERC165Interface(account, interfaceIds[i])) {
                return false;
            }
        }

        // all interfaces supported
        return true;
    }

    /**
     * @notice Query if a contract implements an interface, does not check ERC165 support
     * @param account The address of the contract to query for support of an interface
     * @param interfaceId The interface identifier, as specified in ERC-165
     * @return true if the contract at account indicates support of the interface with
     * identifier interfaceId, false otherwise
     * @dev Assumes that account contains a contract that supports ERC165, otherwise
     * the behavior of this method is undefined. This precondition can be checked
     * with {supportsERC165}.
     * Interface identification is specified in ERC-165.
     */
    function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {
        bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);
        (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams);
        if (result.length < 32) return false;
        return success && abi.decode(result, (bool));
    }
}

File 13 of 22 : GsnTypes.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;

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

interface GsnTypes {
    /// @notice maxFeePerGas, maxPriorityFeePerGas, pctRelayFee and baseRelayFee must be validated inside of the paymaster's preRelayedCall in order not to overpay
    struct RelayData {
        uint256 maxFeePerGas;
        uint256 maxPriorityFeePerGas;
        uint256 transactionCalldataGasUsed;
        address relayWorker;
        address paymaster;
        address forwarder;
        bytes paymasterData;
        uint256 clientId;
    }

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

File 14 of 22 : IPaymaster.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.7.6;
pragma abicoder v2;

import "@openzeppelin/contracts/interfaces/IERC165.sol";

import "../utils/GsnTypes.sol";

/**
 * @title The Paymaster Interface
 * @notice Contracts implementing this interface exist to make decision about paying the transaction fee to the relay.
 *
 * @notice There are two callbacks here that are executed by the RelayHub: `preRelayedCall` and `postRelayedCall`.
 *
 * @notice It is recommended that your implementation inherits from the abstract BasePaymaster contract.
*/
interface IPaymaster is IERC165 {
    /**
     * @notice The limits this Paymaster wants to be imposed by the RelayHub on user input. See `getGasAndDataLimits`.
     */
    struct GasAndDataLimits {
        uint256 acceptanceBudget;
        uint256 preRelayedCallGasLimit;
        uint256 postRelayedCallGasLimit;
        uint256 calldataSizeLimit;
    }

    /**
     * @notice Return the Gas Limits for Paymaster's functions and maximum msg.data length values for this Paymaster.
     * This function allows different paymasters to have different properties without changes to the RelayHub.
     * @return limits An instance of the `GasAndDataLimits` struct
     *
     * ##### `acceptanceBudget`
     * If the transactions consumes more than `acceptanceBudget` this Paymaster will be charged for gas no matter what.
     * Transaction that gets rejected after consuming more than `acceptanceBudget` gas is on this Paymaster's expense.
     *
     * Should be set to an amount gas this Paymaster expects to spend deciding whether to accept or reject a request.
     * This includes gas consumed by calculations in the `preRelayedCall`, `Forwarder` and the recipient contract.
     *
     * :warning: **Warning** :warning: 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 `preRelayedCallGasLimit`, it might might make Paymaster open to a "griefing" attack.
     *
     * The relayers should prefer lower `acceptanceBudget`, as it improves their chances of being compensated.
     * From a Relay's point of view, this is the highest gas value a bad Paymaster may cost the relay,
     * since the paymaster will pay anything above that value regardless of whether the transaction succeeds or reverts.
     * Specifying value too high might make the call rejected by relayers (see `maxAcceptanceBudget` in server config).
     *
     * ##### `preRelayedCallGasLimit`
     * The max gas usage of preRelayedCall. Any revert of the `preRelayedCall` is a request rejection by the paymaster.
     * As long as `acceptanceBudget` is above `preRelayedCallGasLimit`, any such revert is not payed by the paymaster.
     *
     * ##### `postRelayedCallGasLimit`
     * The max gas usage of postRelayedCall. The Paymaster is not charged for the maximum, only for actually used gas.
     * Note that an OOG will revert the inner transaction, but the paymaster will be charged for it anyway.
     */
    function getGasAndDataLimits()
    external
    view
    returns (
        GasAndDataLimits memory limits
    );

    /**
     * @notice :warning: **Warning** :warning: using incorrect Forwarder may cause the Paymaster to agreeing to pay for invalid transactions.
     * @return trustedForwarder The address of the `Forwarder` that is trusted by this Paymaster to execute the requests.
     */
    function getTrustedForwarder() external view returns (address trustedForwarder);

    /**
     * @return relayHub The address of the `RelayHub` that is trusted by this Paymaster to execute the requests.
     */
    function getRelayHub() external view returns (address relayHub);

    /**
     * @notice Called by the Relay in view mode and later by the `RelayHub` on-chain to validate that
     * the Paymaster agrees to pay for this call.
     *
     * The request is considered to be rejected by the Paymaster in one of the following conditions:
     *  - `preRelayedCall()` method reverts
     *  - the `Forwarder` reverts because of nonce or signature error
     *  - the `Paymaster` returned `rejectOnRecipientRevert: true` and the recipient contract reverted
     *    (and all that did not consume more than `acceptanceBudget` gas).
     *
     * In any of the above cases, all Paymaster calls and the recipient call are reverted.
     * In any other case the Paymaster will pay for the gas cost of the transaction.
     * Note that even if `postRelayedCall` is reverted the Paymaster will be charged.
     *

     * @param relayRequest - the full relay request structure
     * @param signature - user's EIP712-compatible signature of the `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 `getGasAndDataLimits`
     * 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 context
     * A byte array to be passed to postRelayedCall.
     * Can contain any data needed by this Paymaster in any form or be empty if no extra data is needed.
     * @return rejectOnRecipientRevert
     * The flag that allows a Paymaster to "delegate" the rejection to the recipient code.
     * It also means the Paymaster trust the recipient to reject fast: both preRelayedCall,
     * forwarder check and recipient checks must fit into the GasLimits.acceptanceBudget,
     * otherwise the TX is paid by the Paymaster.
     * `true` if the Paymaster wants to reject the TX if the recipient reverts.
     * `false` if the Paymaster wants rejects by the recipient to be completed on chain and paid by the Paymaster.
     */
    function preRelayedCall(
        GsnTypes.RelayRequest calldata relayRequest,
        bytes calldata signature,
        bytes calldata approvalData,
        uint256 maxPossibleGas
    )
    external
    returns (bytes memory context, bool rejectOnRecipientRevert);

    /**
     * @notice 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.
     *
     * 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.
     *
     * @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()
     *
     */
    function postRelayedCall(
        bytes calldata context,
        bool success,
        uint256 gasUseWithoutPost,
        GsnTypes.RelayData calldata relayData
    ) external;

    /**
     * @return version The SemVer string of this Paymaster's version.
     */
    function versionPaymaster() external view returns (string memory);
}

File 15 of 22 : IForwarder.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.7.6;
pragma abicoder v2;

import "@openzeppelin/contracts/interfaces/IERC165.sol";

/**
 * @title The Forwarder Interface
 * @notice The contracts implementing this interface take a role of authorization, authentication and replay protection
 * for contracts that choose to trust a `Forwarder`, instead of relying on a mechanism built into the Ethereum protocol.
 *
 * @notice if the `Forwarder` contract decides that an incoming `ForwardRequest` is valid, it must append 20 bytes that
 * represent the caller to the `data` field of the request and send this new data to the target address (the `to` field)
 *
 * :warning: **Warning** :warning: The Forwarder can have a full control over a `Recipient` contract.
 * Any vulnerability in a `Forwarder` implementation can make all of its `Recipient` contracts susceptible!
 * Recipient contracts should only trust forwarders that passed through security audit,
 * otherwise they are susceptible to identity theft.
 */
interface IForwarder is IERC165 {

    /**
     * @notice A representation of a request for a `Forwarder` to send `data` on behalf of a `from` to a target (`to`).
     */
    struct ForwardRequest {
        address from;
        address to;
        uint256 value;
        uint256 gas;
        uint256 nonce;
        bytes data;
        uint256 validUntilTime;
    }

    event DomainRegistered(bytes32 indexed domainSeparator, bytes domainValue);

    event RequestTypeRegistered(bytes32 indexed typeHash, string typeStr);

    /**
     * @param from The address of a sender.
     * @return The nonce for this address.
     */
    function getNonce(address from)
    external view
    returns(uint256);

    /**
     * @notice Verify the transaction is valid and can be executed.
     * Implementations must validate the signature and the nonce of the request are correct.
     * Does not revert and returns successfully if the input is valid.
     * Reverts if any validation has failed. For instance, if either signature or nonce are incorrect.
     * Reverts if `domainSeparator` or `requestTypeHash` are not registered as well.
     */
    function verify(
        ForwardRequest calldata forwardRequest,
        bytes32 domainSeparator,
        bytes32 requestTypeHash,
        bytes calldata suffixData,
        bytes calldata signature
    ) external view;

    /**
     * @notice Executes a transaction specified by the `ForwardRequest`.
     * The transaction is first verified and then executed.
     * The success flag and returned bytes array of the `CALL` are returned as-is.
     *
     * This method would revert only in case of a verification error.
     *
     * All the target errors are reported using the returned success flag and returned bytes array.
     *
     * @param forwardRequest All requested transaction parameters.
     * @param domainSeparator The domain used when signing this request.
     * @param requestTypeHash The request type used when signing this request.
     * @param suffixData The ABI-encoded extension data for the current `RequestType` used when signing this request.
     * @param signature The client signature to be validated.
     *
     * @return success The success flag of the underlying `CALL` to the target address.
     * @return ret The byte array returned by the underlying `CALL` to the target address.
     */
    function execute(
        ForwardRequest calldata forwardRequest,
        bytes32 domainSeparator,
        bytes32 requestTypeHash,
        bytes calldata suffixData,
        bytes calldata signature
    )
    external payable
    returns (bool success, bytes memory ret);

    /**
     * @notice Register a new Request typehash.
     *
     * @notice This is necessary for the Forwarder to be able to verify the signatures conforming to the ERC-712.
     *
     * @param typeName The name of the request type.
     * @param typeSuffix Any extra data after the generic params. Must contain add at least one param.
     * The generic ForwardRequest type is always registered by the constructor.
     */
    function registerRequestType(string calldata typeName, string calldata typeSuffix) external;

    /**
     * @notice Register a new domain separator.
     *
     * @notice This is necessary for the Forwarder to be able to verify the signatures conforming to the ERC-712.
     *
     * @notice 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's address.
     * This method accepts 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 16 of 22 : IRelayHub.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.7.6;
pragma abicoder v2;

import "@openzeppelin/contracts/interfaces/IERC165.sol";

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

/**
 * @title The RelayHub interface
 * @notice The implementation of this interface provides all the information the GSN client needs to
 * create a valid `RelayRequest` and also serves as an entry point for such requests.
 *
 * @notice The RelayHub also handles all the related financial records and hold the balances of participants.
 * The Paymasters keep their Ether deposited in the `RelayHub` in order to pay for the `RelayRequest`s that thay choose
 * to pay for, and Relay Servers keep their earned Ether in the `RelayHub` until they choose to `withdraw()`
 *
 * @notice The RelayHub on each supported network only needs a single instance and there is usually no need for dApp
 * developers or Relay Server operators to redeploy, reimplement, modify or override the `RelayHub`.
 */
interface IRelayHub is IERC165 {
    /**
     * @notice A struct that contains all the parameters of the `RelayHub` that can be modified after the deployment.
     */
    struct RelayHubConfig {
        // maximum number of worker accounts allowed per manager
        uint256 maxWorkerCount;
        // Gas set aside for all relayCall() instructions to prevent unexpected out-of-gas exceptions
        uint256 gasReserve;
        // Gas overhead to calculate gasUseWithoutPost
        uint256 postOverhead;
        // Gas cost of all relayCall() instructions after actual 'calculateCharge()'
        // Assume that relay has non-zero balance (costs 15'000 more otherwise).
        uint256 gasOverhead;
        // Minimum unstake delay seconds of a relay manager's stake on the StakeManager
        uint256 minimumUnstakeDelay;
        // Developers address
        address devAddress;
        // 0 < fee < 100, as percentage of total charge from paymaster to relayer
        uint8 devFee;
        // baseRelayFee The base fee the Relay Server charges for a single transaction in Ether, in wei.
        uint80 baseRelayFee;
        // pctRelayFee The percent of the total charge to add as a Relay Server fee to the total charge.
        uint16 pctRelayFee;
    }

    /// @notice Emitted when a configuration of the `RelayHub` is changed
    event RelayHubConfigured(RelayHubConfig config);

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

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

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

    /// @notice Emitted for each token configured for staking in setMinimumStakes
    event StakingTokenDataChanged(
        address token,
        uint256 minimumStake
    );

    /**
     * @notice Emitted when an attempt to relay a call fails and the `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,
        bytes32 indexed relayRequestID,
        address from,
        address to,
        address relayWorker,
        bytes4 selector,
        uint256 innerGasUsed,
        bytes reason
    );

    /**
     * @notice Emitted when a transaction is relayed. Note that the actual internal function call might be reverted.
     * The reason for a revert will be indicated in the `status` field of a corresponding `RelayCallStatus` value.
     * @notice `charge` is the Ether value deducted from the `Paymaster` balance.
     * The amount added to the `relayManager` balance will be lower if there is an activated `devFee` in the `config`.
     */
    event TransactionRelayed(
        address indexed relayManager,
        address indexed relayWorker,
        bytes32 indexed relayRequestID,
        address from,
        address to,
        address paymaster,
        bytes4 selector,
        RelayCallStatus status,
        uint256 charge
    );

    /// @notice This event is emitted in case the internal function returns a value or reverts with a revert string.
    event TransactionResult(
        RelayCallStatus status,
        bytes returnValue
    );

    /// @notice This event is emitted in case this `RelayHub` is deprecated and will stop serving transactions soon.
    event HubDeprecated(uint256 deprecationTime);

    /**
     * @notice This event is emitted in case a `relayManager` has been deemed "abandoned" for being
     * unresponsive for a prolonged period of time.
     * @notice This event means the entire balance of the relay has been transferred to the `devAddress`.
     */
    event AbandonedRelayManagerBalanceEscheated(
        address indexed relayManager,
        uint256 balance
    );

    /**
     * Error codes that describe all possible failure reasons reported in the `TransactionRelayed` event `status` field.
     *  @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
    }

    /**
     * @notice Add new worker addresses controlled by the 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;

    /**
     * @notice The `RelayRegistrar` callback to notify the `RelayHub` that this `relayManager` has updated registration.
     */
    function onRelayServerRegistered(address relayManager) external;

    // Balance management

    /**
     * @notice Deposits ether for a `Paymaster`, so that it can and pay for relayed transactions.
     * :warning: **Warning** :warning: Unused balance can only be withdrawn by the holder itself, by calling `withdraw`.
     * Emits a `Deposited` event.
     */
    function depositFor(address target) external payable;

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

    /**
     * @notice Withdraws from an account's balance, sending funds to multiple provided addresses.
     * Relay Managers call this to retrieve their revenue, and `Paymasters` can also use it to reduce their funding.
     * Emits a `Withdrawn` event for each destination.
     */
    function withdrawMultiple(address payable[] memory dest, uint256[] memory amount) external;

    // Relaying


    /**
     * @notice Relays a transaction. For this to succeed, multiple conditions must be met:
     *  - `Paymaster`'s `preRelayCall` method must succeed and not revert.
     *  - the `msg.sender` must be a registered Relay Worker that the user signed to use.
     *  - the transaction's gas fees must be equal or larger than the ones that were 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 if all gas is spent.
     *
     * @notice If all conditions are met, the call will be relayed and the `Paymaster` charged.
     *
     * @param maxAcceptanceBudget The maximum valid value for `paymaster.getGasLimits().acceptanceBudget` to return.
     * @param relayRequest All details of the requested relayed call.
     * @param signature The client's EIP-712 signature over the `relayRequest` struct.
     * @param approvalData The dapp-specific data forwarded to the `Paymaster`'s `preRelayedCall` method.
     * This value is **not** verified by the `RelayHub` in any way.
     * As an example, it can be used to pass some kind of a third-party signature to the `Paymaster` for verification.
     *
     * Emits a `TransactionRelayed` event regardless of whether the transaction succeeded or failed.
     */
    function relayCall(
        uint256 maxAcceptanceBudget,
        GsnTypes.RelayRequest calldata relayRequest,
        bytes calldata signature,
        bytes calldata approvalData
    )
    external
    returns (
        bool paymasterAccepted,
        uint256 charge,
        IRelayHub.RelayCallStatus status,
        bytes memory returnValue
    );

    /**
     * @notice In case the Relay Worker has been found to be in violation of some rules by the `Penalizer` contract,
     * the `Penalizer` will call this method to execute a penalization.
     * The `RelayHub` will look up the Relay Manager of the given Relay Worker and will forward the call to
     * the `StakeManager` contract. The `RelayHub` does not perform the actual penalization either.
     * @param relayWorker The address of the Relay Worker that committed a penalizable offense.
     * @param beneficiary The address that called the `Penalizer` and will receive a reward for it.
     */
    function penalize(address relayWorker, address payable beneficiary) external;

    /**
     * @notice Sets or changes the configuration of this `RelayHub`.
     * @param _config The new configuration.
     */
    function setConfiguration(RelayHubConfig memory _config) external;

    /**
     * @notice Sets or changes the minimum amount of a given `token` that needs to be staked so that the Relay Manager
     * is considered to be 'staked' by this `RelayHub`. Zero value means this token is not allowed for staking.
     * @param token An array of addresses of ERC-20 compatible tokens.
     * @param minimumStake An array of minimal amounts necessary for a corresponding token, in wei.
     */
    function setMinimumStakes(IERC20[] memory token, uint256[] memory minimumStake) external;

    /**
     * @notice Deprecate hub by reverting all incoming `relayCall()` calls starting from a given timestamp
     * @param _deprecationTime The timestamp in seconds after which the `RelayHub` stops serving transactions.
     */
    function deprecateHub(uint256 _deprecationTime) external;

    /**
     * @notice
     * @param relayManager
     */
    function escheatAbandonedRelayBalance(address relayManager) external;

    /**
     * @notice The fee is expressed as a base fee in wei plus percentage of the actual charge.
     * For example, a value '40' stands for a 40% fee, so the recipient will be charged for 1.4 times the spent amount.
     * @param gasUsed An amount of gas used by the transaction.
     * @param relayData The details of a transaction signed by the sender.
     * @return The calculated charge, in wei.
     */
    function calculateCharge(uint256 gasUsed, GsnTypes.RelayData calldata relayData) external view returns (uint256);

    /**
     * @notice The fee is expressed as a  percentage of the actual charge.
     * For example, a value '40' stands for a 40% fee, so the Relay Manager will only get 60% of the `charge`.
     * @param charge The amount of Ether in wei the Paymaster will be charged for this transaction.
     * @return The calculated devFee, in wei.
     */
    function calculateDevCharge(uint256 charge) external view returns (uint256);
    /* getters */

    /// @return config The configuration of the `RelayHub`.
    function getConfiguration() external view returns (RelayHubConfig memory config);

    /**
     * @param token An address of an ERC-20 compatible tokens.
     * @return The minimum amount of a given `token` that needs to be staked so that the Relay Manager
     * is considered to be 'staked' by this `RelayHub`. Zero value means this token is not allowed for staking.
     */
    function getMinimumStakePerToken(IERC20 token) external view returns (uint256);

    /**
     * @param worker An address of the Relay Worker.
     * @return The address of its Relay Manager.
     */
    function getWorkerManager(address worker) external view returns (address);

    /**
     * @param manager An address of the Relay Manager.
     * @return The count of Relay Workers associated with this Relay Manager.
     */
    function getWorkerCount(address manager) external view returns (uint256);

    /// @return An account's balance. It can be either a deposit of a `Paymaster`, or a revenue of a Relay Manager.
    function balanceOf(address target) external view returns (uint256);

    /// @return The `StakeManager` address for this `RelayHub`.
    function getStakeManager() external view returns (IStakeManager);

    /// @return The `Penalizer` address for this `RelayHub`.
    function getPenalizer() external view returns (address);

    /// @return The `RelayRegistrar` address for this `RelayHub`.
    function getRelayRegistrar() external view returns (address);

    /// @return The `BatchGateway` address for this `RelayHub`.
    function getBatchGateway() external view returns (address);

    /**
     * @notice Uses `StakeManager` to decide if the Relay Manager can be considered staked or not.
     * Returns if the stake's token, amount and delay satisfy all requirements, reverts otherwise.
     */
    function verifyRelayManagerStaked(address relayManager) external view;

    /**
     * @notice Uses `StakeManager` to check if the Relay Manager can be considered abandoned or not.
     * Returns true if the stake's abandonment time is in the past including the escheatment delay, false otherwise.
     */
    function isRelayEscheatable(address relayManager) external view returns (bool);

    /// @return `true` if the `RelayHub` is deprecated, `false` it it is not deprecated and can serve transactions.
    function isDeprecated() external view returns (bool);

    /// @return The timestamp from which the hub no longer allows relaying calls.
    function getDeprecationTime() external view returns (uint256);

    /// @return The block number in which the contract has been deployed.
    function getCreationBlock() external view returns (uint256);

    /// @return a SemVer-compliant version of the `RelayHub` contract.
    function versionHub() external view returns (string memory);

    /// @return A total measurable amount of gas left to current execution. Same as 'gasleft()' for pure EVMs.
    function aggregateGasleft() external view returns (uint256);
}

File 17 of 22 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 18 of 22 : GsnUtils.sol
/* solhint-disable no-inline-assembly */
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;

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

/**
 * @title The GSN Solidity Utils Library
 * @notice Some library functions used throughout the GSN Solidity codebase.
 */
library GsnUtils {

    bytes32 constant private RELAY_REQUEST_ID_MASK = 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

    /**
     * @notice Calculate an identifier for the meta-transaction in a format similar to a transaction hash.
     * Note that uniqueness relies on signature and may not be enforced if meta-transactions are verified
     * with a different algorithm, e.g. when batching.
     * @param relayRequest The `RelayRequest` for which an ID is being calculated.
     * @param signature The signature for the `RelayRequest`. It is not validated here and may even remain empty.
     */
    function getRelayRequestID(GsnTypes.RelayRequest calldata relayRequest, bytes calldata signature)
    internal
    pure
    returns (bytes32) {
        return keccak256(abi.encode(relayRequest.request.from, relayRequest.request.nonce, signature)) & RELAY_REQUEST_ID_MASK;
    }

    /**
     * @notice Extract the method identifier signature from the encoded function call.
     */
    function getMethodSig(bytes memory msgData) internal pure returns (bytes4) {
        return MinLibBytes.readBytes4(msgData, 0);
    }

    /**
     * @notice Extract a 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`).
     * @param msgData Byte array containing a uint256 value.
     * @param index Index in byte array of uint256 value.
     * @return result uint256 value from byte array.
     */
    function getParam(bytes memory msgData, uint256 index) internal pure returns (uint256 result) {
        return MinLibBytes.readUint256(msgData, 4 + index * 32);
    }

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

}

File 19 of 22 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol)

pragma solidity ^0.8.0;

import "../utils/introspection/IERC165.sol";

File 20 of 22 : 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.0;

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 21 of 22 : IStakeManager.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.7.6;
pragma abicoder v2;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";

/**
 * @title The StakeManager Interface
 * @notice In order to prevent an attacker from registering a large number of unresponsive relays, the GSN requires
 * the Relay Server to maintain a permanently locked stake in the system before being able to register.
 *
 * @notice Also, in some cases the behavior of a Relay Server may be found to be illegal by a `Penalizer` contract.
 * In such case, the stake will never be returned to the Relay Server operator and will be slashed.
 *
 * @notice An implementation of this interface is tasked with keeping Relay Servers' stakes, made in any ERC-20 token.
 * Note that the `RelayHub` chooses which ERC-20 tokens to support and how much stake is needed.
 */
interface IStakeManager is IERC165 {

    /// @notice Emitted when a `stake` or `unstakeDelay` are initialized or increased.
    event StakeAdded(
        address indexed relayManager,
        address indexed owner,
        IERC20 token,
        uint256 stake,
        uint256 unstakeDelay
    );

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

    /// @notice Emitted when owner withdraws `relayManager` funds.
    event StakeWithdrawn(
        address indexed relayManager,
        address indexed owner,
        IERC20 token,
        uint256 amount
    );

    /// @notice Emitted when an authorized `RelayHub` penalizes a `relayManager`.
    event StakePenalized(
        address indexed relayManager,
        address indexed beneficiary,
        IERC20 token,
        uint256 reward
    );

    /// @notice Emitted when a `relayManager` adds a new `RelayHub` to a list of authorized.
    event HubAuthorized(
        address indexed relayManager,
        address indexed relayHub
    );

    /// @notice Emitted when a `relayManager` removes a `RelayHub` from a list of authorized.
    event HubUnauthorized(
        address indexed relayManager,
        address indexed relayHub,
        uint256 removalTime
    );

    /// @notice Emitted when a `relayManager` sets its `owner`. This is necessary to prevent stake hijacking.
    event OwnerSet(
        address indexed relayManager,
        address indexed owner
    );

    /// @notice Emitted when a `burnAddress` is changed.
    event BurnAddressSet(
        address indexed burnAddress
    );

    /// @notice Emitted when a `devAddress` is changed.
    event DevAddressSet(
        address indexed devAddress
    );

    /// @notice Emitted if Relay Server is inactive for an `abandonmentDelay` and contract owner initiates its removal.
    event RelayServerAbandoned(
        address indexed relayManager,
        uint256 abandonedTime
    );

    /// @notice Emitted to indicate an action performed by a relay server to prevent it from being marked as abandoned.
    event RelayServerKeepalive(
        address indexed relayManager,
        uint256 keepaliveTime
    );

    /// @notice Emitted when the stake of an abandoned relayer has been confiscated and transferred to the `devAddress`.
    event AbandonedRelayManagerStakeEscheated(
        address indexed relayManager,
        address indexed owner,
        IERC20 token,
        uint256 amount
    );

    /**
     * @param stake - amount of ether staked for this relay
     * @param unstakeDelay - number of seconds to elapse before the owner can retrieve the stake after calling 'unlock'
     * @param withdrawTime - timestamp in seconds when '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 withdrawTime;
        uint256 abandonedTime;
        uint256 keepaliveTime;
        IERC20 token;
        address owner;
    }

    struct RelayHubInfo {
        uint256 removalTime;
    }

    /**
     * @param devAddress - the address that will receive the 'abandoned' stake
     * @param abandonmentDelay - the amount of time after which the relay can be marked as 'abandoned'
     * @param escheatmentDelay - the amount of time after which the abandoned relay's stake and balance may be withdrawn to the `devAddress`
     */
    struct AbandonedRelayServerConfig {
        address devAddress;
        uint256 abandonmentDelay;
        uint256 escheatmentDelay;
    }

    /**
     * @notice Set the owner of a Relay Manager. Called only by the RelayManager itself.
     * Note that owners cannot transfer ownership - if the entry already exists, reverts.
     * @param owner - owner of the relay (as configured off-chain)
     */
    function setRelayManagerOwner(address owner) external;

    /**
     * @notice Put a stake for a relayManager and set its unstake delay.
     * Only the owner can call this function. If the entry does not exist, reverts.
     * The owner must give allowance of the ERC-20 token to the StakeManager before calling this method.
     * It is the RelayHub who has a configurable list of minimum stakes per token. StakeManager accepts all tokens.
     * @param token The address of an ERC-20 token that is used by the relayManager as a stake
     * @param relayManager The address that represents a stake entry and controls relay registrations on relay hubs
     * @param unstakeDelay The number of seconds to elapse before an owner can retrieve the stake after calling `unlock`
     * @param amount The amount of tokens to be taken from the relayOwner and locked in the StakeManager as a stake
     */
    function stakeForRelayManager(IERC20 token, address relayManager, uint256 unstakeDelay, uint256 amount) external;

    /**
     * @notice Schedule the unlocking of the stake. The `unstakeDelay` must pass before owner can call `withdrawStake`.
     * @param relayManager The address of a Relay Manager whose stake is to be unlocked.
     */
    function unlockStake(address relayManager) external;
    /**
     * @notice Withdraw the unlocked stake.
     * @param relayManager The address of a Relay Manager whose stake is to be withdrawn.
     */
    function withdrawStake(address relayManager) external;

    /**
     * @notice Add the `RelayHub` to a list of authorized by this Relay Manager.
     * This allows the RelayHub to penalize this Relay Manager. The `RelayHub` cannot trust a Relay it cannot penalize.
     * @param relayManager The address of a Relay Manager whose stake is to be authorized for the new `RelayHub`.
     * @param relayHub The address of a `RelayHub` to be authorized.
     */
    function authorizeHubByOwner(address relayManager, address relayHub) external;

    /**
     * @notice Same as `authorizeHubByOwner` but can be called by the RelayManager itself.
     */
    function authorizeHubByManager(address relayHub) external;

    /**
     * @notice Remove the `RelayHub` from a list of authorized by this Relay Manager.
     * @param relayManager The address of a Relay Manager.
     * @param relayHub The address of a `RelayHub` to be unauthorized.
     */
    function unauthorizeHubByOwner(address relayManager, address relayHub) external;

    /**
     * @notice Same as `unauthorizeHubByOwner` but can be called by the RelayManager itself.
     */
    function unauthorizeHubByManager(address relayHub) external;

    /**
     * Slash the stake of the relay relayManager. In order to prevent stake kidnapping, burns part of stake on the way.
     * @param relayManager The address of a Relay Manager to be penalized.
     * @param beneficiary The address that receives part of the penalty amount.
     * @param amount A total amount of penalty to be withdrawn from stake.
     */
    function penalizeRelayManager(address relayManager, address beneficiary, uint256 amount) external;

    /**
     * @notice Allows the contract owner to set the given `relayManager` as abandoned after a configurable delay.
     * Its entire stake and balance will be taken from a relay if it does not respond to being marked as abandoned.
     */
    function markRelayAbandoned(address relayManager) external;

    /**
     * @notice If more than `abandonmentDelay` has passed since the last Keepalive transaction, and relay manager
     * has been marked as abandoned, and after that more that `escheatmentDelay` have passed, entire stake and
     * balance will be taken from this relay.
     */
    function escheatAbandonedRelayStake(address relayManager) external;

    /**
     * @notice Sets a new `keepaliveTime` for the given `relayManager`, preventing it from being marked as abandoned.
     * Can be called by an authorized `RelayHub` or by the `relayOwner` address.
     */
    function updateRelayKeepaliveTime(address relayManager) external;

    /**
     * @notice Check if the Relay Manager can be considered abandoned or not.
     * Returns true if the stake's abandonment time is in the past including the escheatment delay, false otherwise.
     */
    function isRelayEscheatable(address relayManager) external view returns(bool);

    /**
     * @notice Get the stake details information for the given Relay Manager.
     * @param relayManager The address of a Relay Manager.
     * @return stakeInfo The `StakeInfo` structure.
     * @return isSenderAuthorizedHub `true` if the `msg.sender` for this call was a `RelayHub` that is authorized now.
     * `false` if the `msg.sender` for this call is not authorized.
     */
    function getStakeInfo(address relayManager) external view returns (StakeInfo memory stakeInfo, bool isSenderAuthorizedHub);

    /**
     * @return The maximum unstake delay this `StakeManger` allows. This is to prevent locking money forever by mistake.
     */
    function getMaxUnstakeDelay() external view returns (uint256);

    /**
     * @notice Change the address that will receive the 'burned' part of the penalized stake.
     * This is done to prevent malicious Relay Server from penalizing itself and breaking even.
     */
    function setBurnAddress(address _burnAddress) external;

    /**
     * @return The address that will receive the 'burned' part of the penalized stake.
     */
    function getBurnAddress() external view returns (address);

    /**
     * @notice Change the address that will receive the 'abandoned' stake.
     * This is done to prevent Relay Servers that lost their keys from losing access to funds.
     */
    function setDevAddress(address _burnAddress) external;

    /**
     * @return The structure that contains all configuration values for the 'abandoned' stake.
     */
    function getAbandonedRelayServerConfig() external view returns (AbandonedRelayServerConfig memory);

    /**
     * @return the block number in which the contract has been deployed.
     */
    function getCreationBlock() external view returns (uint256);

    /**
     * @return a SemVer-compliant version of the `StakeManager` contract.
     */
    function versionSM() external view returns (string memory);
}

File 22 of 22 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

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

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"baseFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"networkFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalFee","type":"uint256"}],"name":"FeeCharged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"target","type":"address"}],"name":"TargetSet","type":"event"},{"inputs":[],"name":"CALLDATA_SIZE_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"gasUsedByPost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGasAndDataLimits","outputs":[{"components":[{"internalType":"uint256","name":"acceptanceBudget","type":"uint256"},{"internalType":"uint256","name":"preRelayedCallGasLimit","type":"uint256"},{"internalType":"uint256","name":"postRelayedCallGasLimit","type":"uint256"},{"internalType":"uint256","name":"calldataSizeLimit","type":"uint256"}],"internalType":"struct IPaymaster.GasAndDataLimits","name":"limits","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRelayHub","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTrustedForwarder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"methodWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ourTarget","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":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"uint256","name":"transactionCalldataGasUsed","type":"uint256"},{"internalType":"address","name":"relayWorker","type":"address"},{"internalType":"address","name":"paymaster","type":"address"},{"internalType":"address","name":"forwarder","type":"address"},{"internalType":"bytes","name":"paymasterData","type":"bytes"},{"internalType":"uint256","name":"clientId","type":"uint256"}],"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":"uint256","name":"validUntilTime","type":"uint256"}],"internalType":"struct IForwarder.ForwardRequest","name":"request","type":"tuple"},{"components":[{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"uint256","name":"transactionCalldataGasUsed","type":"uint256"},{"internalType":"address","name":"relayWorker","type":"address"},{"internalType":"address","name":"paymaster","type":"address"},{"internalType":"address","name":"forwarder","type":"address"},{"internalType":"bytes","name":"paymasterData","type":"bytes"},{"internalType":"uint256","name":"clientId","type":"uint256"}],"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":"","type":"bytes"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasUsedByPost","type":"uint256"}],"name":"setPostGasUsage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IRelayHub","name":"hub","type":"address"}],"name":"setRelayHub","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"setTarget","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"setTrustedForwarder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"versionPaymaster","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes4","name":"method","type":"bytes4"},{"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"whitelistMethod","outputs":[],"stateMutability":"nonpayable","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"}]

608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611cc08061007e6000396000f3fe60806040526004361061011e5760003560e01c8062be5dd4146101e757806301ffc9a71461021e5780632d14c4b71461024e5780633a0892e3146102705780635c5e3db1146102ab5780636d7c3e2b146102cf578063715018a6146102ef57806376fa01c314610304578063776d1a01146103245780637bb05264146103445780637bdf2ec71461036457806380d324f1146103865780638da5cb5b146103a6578063921276ea146103bb578063ad12e50e146103ef578063b039a88f14610405578063b90b41cf1461044d578063bbdaa3c914610463578063ce1b815f1461047a578063da7422281461048f578063df463a66146104af578063e1838f8d146104c4578063f2fde38b146104e4578063f9c002f71461050457600080fd5b366101e2576001546001600160a01b031661017c5760405162461bcd60e51b81526020600482015260196024820152781c995b185e481a1d58881859191c995cdcc81b9bdd081cd95d603a1b60448201526064015b60405180910390fd5b60015460405163aa67c91960e01b81526001600160a01b039091169063aa67c9199034906101ae903090600401611985565b6000604051808303818588803b1580156101c757600080fd5b505af11580156101db573d6000803e3d6000fd5b5050505050005b600080fd5b3480156101f357600080fd5b50610207610202366004611801565b61051b565b6040516102159291906119b2565b60405180910390f35b34801561022a57600080fd5b5061023e61023936600461169f565b610569565b6040519015158152602001610215565b34801561025a57600080fd5b5061026e6102693660046118d7565b6105bb565b005b34801561027c57600080fd5b5061023e61028b366004611604565b600560209081526000928352604080842090915290825290205460ff1681565b3480156102b757600080fd5b506102c161290481565b604051908152602001610215565b3480156102db57600080fd5b5061026e6102ea3660046118a5565b610652565b3480156102fb57600080fd5b5061026e610686565b34801561031057600080fd5b5061026e61031f3660046116ba565b6106c1565b34801561033057600080fd5b5061026e61033f3660046115e7565b6106dd565b34801561035057600080fd5b5061026e61035f3660046115e7565b610762565b34801561037057600080fd5b50610379610819565b6040516102159190611985565b34801561039257600080fd5b50600354610379906001600160a01b031681565b3480156103b257600080fd5b50610379610828565b3480156103c757600080fd5b5060408051808201825260058152640332e302e360dc1b6020820152905161021591906119d6565b3480156103fb57600080fd5b506102c160045481565b34801561041157600080fd5b5061041a610837565b60405161021591908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b34801561045957600080fd5b506102c161c35081565b34801561046f57600080fd5b506102c16201adb081565b34801561048657600080fd5b506103796108a0565b34801561049b57600080fd5b5061026e6104aa3660046115e7565b6108af565b3480156104bb57600080fd5b506102c1610966565b3480156104d057600080fd5b5061026e6104df366004611639565b610978565b3480156104f057600080fd5b5061026e6104ff3660046115e7565b6109e8565b34801561051057600080fd5b506102c1620186a081565b60606000610527610a88565b61053088610af0565b61053988610b79565b61054288610bd3565b61054c8585610c3c565b61055a888888888888610c8c565b91509150965096945050505050565b60006001600160e01b031982166370d596f560e11b148061059a57506001600160e01b03198216630704183b60e11b145b806105b557506301ffc9a760e01b6001600160e01b03198316145b92915050565b336105c4610828565b6001600160a01b0316146105ea5760405162461bcd60e51b8152600401610173906119e9565b60015460405163f3fef3a360e01b81526001600160a01b039091169063f3fef3a39061061c9084908690600401611999565b600060405180830381600087803b15801561063657600080fd5b505af115801561064a573d6000803e3d6000fd5b505050505050565b3361065b610828565b6001600160a01b0316146106815760405162461bcd60e51b8152600401610173906119e9565b600455565b3361068f610828565b6001600160a01b0316146106b55760405162461bcd60e51b8152600401610173906119e9565b6106bf6000610f84565b565b6106c9610a88565b6106d68585858585610fd4565b5050505050565b336106e6610828565b6001600160a01b03161461070c5760405162461bcd60e51b8152600401610173906119e9565b600380546001600160a01b0319166001600160a01b0383161790556040517f3bfb4bbf112628248058745a3c57e35b13369386e474b8e56c552f3063a4a19690610757908390611985565b60405180910390a150565b3361076b610828565b6001600160a01b0316146107915760405162461bcd60e51b8152600401610173906119e9565b6107ab6001600160a01b0382166334f57c6760e01b6111dc565b6107f75760405162461bcd60e51b815260206004820152601f60248201527f746172676574206973206e6f7420612076616c6964204952656c6179487562006044820152606401610173565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b031690565b6000546001600160a01b031690565b6108626040518060800160405280600081526020016000815260200160008152602001600081525090565b604051806080016040528061c350620186a061087e9190611bb2565b8152602001620186a081526020016201adb08152602001612904815250905090565b6002546001600160a01b031690565b336108b8610828565b6001600160a01b0316146108de5760405162461bcd60e51b8152600401610173906119e9565b6108f86001600160a01b0382166309788f9960e21b6111dc565b6109445760405162461bcd60e51b815260206004820181905260248201527f746172676574206973206e6f7420612076616c69642049466f727761726465726044820152606401610173565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b61097561c350620186a0611bb2565b81565b33610981610828565b6001600160a01b0316146109a75760405162461bcd60e51b8152600401610173906119e9565b6001600160a01b0390921660009081526005602090815260408083206001600160e01b0319909416835292905220805491151560ff19909216919091179055565b336109f1610828565b6001600160a01b031614610a175760405162461bcd60e51b8152600401610173906119e9565b6001600160a01b038116610a7c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610173565b610a8581610f84565b50565b610a90610819565b6001600160a01b0316336001600160a01b0316146106bf5760405162461bcd60e51b815260206004820152601e60248201527f63616e206f6e6c792062652063616c6c65642062792052656c617948756200006044820152606401610173565b610afd6020820182611b2d565b610b0e9060c081019060a0016115e7565b6001600160a01b0316610b1f6108a0565b6001600160a01b031614610b705760405162461bcd60e51b8152602060048201526018602482015277119bdc9dd85c99195c881a5cc81b9bdd081d1c9d5cdd195960421b6044820152606401610173565b610a85816111ff565b610b838180611b17565b6040013515610a855760405162461bcd60e51b815260206004820152601c60248201527b1d985b1d59481d1c985b9cd9995c881b9bdd081cdd5c1c1bdc9d195960221b6044820152606401610173565b610be06020820182611b2d565b610bee9060c0810190611ad1565b159050610a855760405162461bcd60e51b815260206004820152601c60248201527b73686f756c642068617665206e6f207061796d61737465724461746160201b6044820152606401610173565b8015610c885760405162461bcd60e51b815260206004820152601b60248201527a73686f756c642068617665206e6f20617070726f76616c4461746160281b6044820152606401610173565b5050565b6003546060906000906001600160a01b0316610ca88980611b17565b610cb99060408101906020016115e7565b6001600160a01b031614610ccc57600080fd5b6000610d23610cdb8a80611b17565b610ce99060a0810190611ad1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113e192505050565b6003546001600160a01b031660009081526005602090815260408083206001600160e01b03198516845290915290205490915060ff16610d9e5760405162461bcd60e51b81526020600482015260166024820152751b595d1a1bd9081b9bdd081dda1a5d195b1a5cdd195960521b6044820152606401610173565b6000610daa8a80611b17565b610db89060a0810190611ad1565b610dc6916004908290611b88565b810190610dd39190611749565b60035460405163f8b2cb4f60e01b81529193506001600160a01b03169150600090829063f8b2cb4f90610e0a908690600401611985565b60206040518083038186803b158015610e2257600080fd5b505afa158015610e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5a91906118be565b90506000610e683a89611bec565b90506000836001600160a01b031663fc0438306040518163ffffffff1660e01b815260040160206040518083038186803b158015610ea557600080fd5b505afa158015610eb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610edd91906118be565b610ee961271084611bca565b610ef39190611bec565b90506000610f018284611bb2565b9050808411610f4d5760405162461bcd60e51b8152602060048201526018602482015277696e73756666696369656e74206170702062616c616e636560401b6044820152606401610173565b85604051602001610f5e9190611985565b60408051601f198184030181529190529f60009f509d5050505050505050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000610fe2858701876115e7565b6001546004549192506000916001600160a01b0390911690638e53548b9061100a9087611bb2565b856040518363ffffffff1660e01b8152600401611028929190611a1e565b60206040518083038186803b15801561104057600080fd5b505afa158015611054573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107891906118be565b90506000600360009054906101000a90046001600160a01b031690506000816001600160a01b031663fc0438306040518163ffffffff1660e01b815260040160206040518083038186803b1580156110cf57600080fd5b505afa1580156110e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110791906118be565b61111361271085611bca565b61111d9190611bec565b9050600061112b8285611bb2565b604051631a77d65360e31b81529091506001600160a01b0384169063d3beb2989061115c9088908590600401611999565b600060405180830381600087803b15801561117657600080fd5b505af115801561118a573d6000803e3d6000fd5b505060408051878152602081018690529081018490527faad61a9664bc6be1128f98485df350d149d1d8f3dce21e21c1741501960b88099250606001905060405180910390a150505050505050505050565b60006111e7836113ee565b80156111f857506111f88383611421565b9392505050565b60008061120c8380611b17565b61121d9060408101906020016115e7565b6001600160a01b031663572b6c0560e01b61123b6020860186611b2d565b61124c9060c081019060a0016115e7565b60405160240161125c9190611985565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161129a9190611969565b600060405180830381855afa9150503d80600081146112d5576040519150601f19603f3d011682016040523d82523d6000602084013e6112da565b606091505b50915091508161132b5760405162461bcd60e51b815260206004820152601c60248201527b1a5cd51c9d5cdd1959119bdc9dd85c99195c8e881c995d995c9d195960221b6044820152606401610173565b805160201461137c5760405162461bcd60e51b815260206004820181905260248201527f697354727573746564466f727761726465723a2062616420726573706f6e73656044820152606401610173565b808060200190518101906113909190611682565b6113dc5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420666f7277617264657220666f7220726563697069656e74006044820152606401610173565b505050565b60006105b582600061150a565b6000611401826301ffc9a760e01b611421565b80156105b5575061141a826001600160e01b0319611421565b1592915050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b179052905160009190829081906001600160a01b0387169061753090611488908690611969565b6000604051808303818686fa925050503d80600081146114c4576040519150601f19603f3d011682016040523d82523d6000602084013e6114c9565b606091505b50915091506020815110156114e457600093505050506105b5565b8180156115005750808060200190518101906115009190611682565b9695505050505050565b6000611517826004611bb2565b835110156115645760405162461bcd60e51b815260206004820152601a6024820152791c995859109e5d195ccd0e8819185d18481d1bdbc81cda1bdc9d60321b6044820152606401610173565b5001602001516001600160e01b03191690565b803561158281611c67565b919050565b80356001600160e01b03198116811461158257600080fd5b60008083601f8401126115b157600080fd5b5081356001600160401b038111156115c857600080fd5b6020830191508360208285010111156115e057600080fd5b9250929050565b6000602082840312156115f957600080fd5b81356111f881611c67565b6000806040838503121561161757600080fd5b823561162281611c67565b915061163060208401611587565b90509250929050565b60008060006060848603121561164e57600080fd5b833561165981611c67565b925061166760208501611587565b9150604084013561167781611c7c565b809150509250925092565b60006020828403121561169457600080fd5b81516111f881611c7c565b6000602082840312156116b157600080fd5b6111f882611587565b6000806000806000608086880312156116d257600080fd5b85356001600160401b03808211156116e957600080fd5b6116f589838a0161159f565b90975095506020880135915061170a82611c7c565b909350604087013592506060870135908082111561172757600080fd5b508601610100818903121561173b57600080fd5b809150509295509295909350565b6000806040838503121561175c57600080fd5b82356001600160401b038082111561177357600080fd5b818501915085601f83011261178757600080fd5b81358181111561179957611799611c51565b604051601f8201601f19908116603f011681019083821181831017156117c1576117c1611c51565b816040528281528860208487010111156117da57600080fd5b82602086016020830137600060208483010152809650505050505061163060208401611577565b6000806000806000806080878903121561181a57600080fd5b86356001600160401b038082111561183157600080fd5b908801906040828b03121561184557600080fd5b9096506020880135908082111561185b57600080fd5b6118678a838b0161159f565b9097509550604089013591508082111561188057600080fd5b5061188d89828a0161159f565b979a9699509497949695606090950135949350505050565b6000602082840312156118b757600080fd5b5035919050565b6000602082840312156118d057600080fd5b5051919050565b600080604083850312156118ea57600080fd5b8235915060208301356118fc81611c67565b809150509250929050565b6001600160a01b03169052565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60008151808452611955816020860160208601611c0b565b601f01601f19169290920160200192915050565b6000825161197b818460208701611c0b565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6040815260006119c5604083018561193d565b905082151560208301529392505050565b6020815260006111f8602083018461193d565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b8281526040602082015281356040820152602082013560608201526040820135608082015260006060830135611a5381611c67565b6001600160a01b031660a0830152611a6d60808401611577565b611a7a60c0840182611907565b50611a8760a08401611577565b611a9460e0840182611907565b50611aa260c0840184611b43565b61010084810152611ab861014085018284611914565b91505060e0840135610120840152809150509392505050565b6000808335601e19843603018112611ae857600080fd5b8301803591506001600160401b03821115611b0257600080fd5b6020019150368190038213156115e057600080fd5b6000823560de1983360301811261197b57600080fd5b6000823560fe1983360301811261197b57600080fd5b6000808335601e19843603018112611b5a57600080fd5b83016020810192503590506001600160401b03811115611b7957600080fd5b8036038313156115e057600080fd5b60008085851115611b9857600080fd5b83861115611ba557600080fd5b5050820193919092039150565b60008219821115611bc557611bc5611c3b565b500190565b600082611be757634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615611c0657611c06611c3b565b500290565b60005b83811015611c26578181015183820152602001611c0e565b83811115611c35576000848401525b50505050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610a8557600080fd5b8015158114610a8557600080fdfea26469706673582212204477e91f97281fe0c3e7e6faa8f2e54e2e0ff29535215e81cbc56823c2bcfdfd64736f6c63430008070033

Deployed Bytecode

0x60806040526004361061011e5760003560e01c8062be5dd4146101e757806301ffc9a71461021e5780632d14c4b71461024e5780633a0892e3146102705780635c5e3db1146102ab5780636d7c3e2b146102cf578063715018a6146102ef57806376fa01c314610304578063776d1a01146103245780637bb05264146103445780637bdf2ec71461036457806380d324f1146103865780638da5cb5b146103a6578063921276ea146103bb578063ad12e50e146103ef578063b039a88f14610405578063b90b41cf1461044d578063bbdaa3c914610463578063ce1b815f1461047a578063da7422281461048f578063df463a66146104af578063e1838f8d146104c4578063f2fde38b146104e4578063f9c002f71461050457600080fd5b366101e2576001546001600160a01b031661017c5760405162461bcd60e51b81526020600482015260196024820152781c995b185e481a1d58881859191c995cdcc81b9bdd081cd95d603a1b60448201526064015b60405180910390fd5b60015460405163aa67c91960e01b81526001600160a01b039091169063aa67c9199034906101ae903090600401611985565b6000604051808303818588803b1580156101c757600080fd5b505af11580156101db573d6000803e3d6000fd5b5050505050005b600080fd5b3480156101f357600080fd5b50610207610202366004611801565b61051b565b6040516102159291906119b2565b60405180910390f35b34801561022a57600080fd5b5061023e61023936600461169f565b610569565b6040519015158152602001610215565b34801561025a57600080fd5b5061026e6102693660046118d7565b6105bb565b005b34801561027c57600080fd5b5061023e61028b366004611604565b600560209081526000928352604080842090915290825290205460ff1681565b3480156102b757600080fd5b506102c161290481565b604051908152602001610215565b3480156102db57600080fd5b5061026e6102ea3660046118a5565b610652565b3480156102fb57600080fd5b5061026e610686565b34801561031057600080fd5b5061026e61031f3660046116ba565b6106c1565b34801561033057600080fd5b5061026e61033f3660046115e7565b6106dd565b34801561035057600080fd5b5061026e61035f3660046115e7565b610762565b34801561037057600080fd5b50610379610819565b6040516102159190611985565b34801561039257600080fd5b50600354610379906001600160a01b031681565b3480156103b257600080fd5b50610379610828565b3480156103c757600080fd5b5060408051808201825260058152640332e302e360dc1b6020820152905161021591906119d6565b3480156103fb57600080fd5b506102c160045481565b34801561041157600080fd5b5061041a610837565b60405161021591908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b34801561045957600080fd5b506102c161c35081565b34801561046f57600080fd5b506102c16201adb081565b34801561048657600080fd5b506103796108a0565b34801561049b57600080fd5b5061026e6104aa3660046115e7565b6108af565b3480156104bb57600080fd5b506102c1610966565b3480156104d057600080fd5b5061026e6104df366004611639565b610978565b3480156104f057600080fd5b5061026e6104ff3660046115e7565b6109e8565b34801561051057600080fd5b506102c1620186a081565b60606000610527610a88565b61053088610af0565b61053988610b79565b61054288610bd3565b61054c8585610c3c565b61055a888888888888610c8c565b91509150965096945050505050565b60006001600160e01b031982166370d596f560e11b148061059a57506001600160e01b03198216630704183b60e11b145b806105b557506301ffc9a760e01b6001600160e01b03198316145b92915050565b336105c4610828565b6001600160a01b0316146105ea5760405162461bcd60e51b8152600401610173906119e9565b60015460405163f3fef3a360e01b81526001600160a01b039091169063f3fef3a39061061c9084908690600401611999565b600060405180830381600087803b15801561063657600080fd5b505af115801561064a573d6000803e3d6000fd5b505050505050565b3361065b610828565b6001600160a01b0316146106815760405162461bcd60e51b8152600401610173906119e9565b600455565b3361068f610828565b6001600160a01b0316146106b55760405162461bcd60e51b8152600401610173906119e9565b6106bf6000610f84565b565b6106c9610a88565b6106d68585858585610fd4565b5050505050565b336106e6610828565b6001600160a01b03161461070c5760405162461bcd60e51b8152600401610173906119e9565b600380546001600160a01b0319166001600160a01b0383161790556040517f3bfb4bbf112628248058745a3c57e35b13369386e474b8e56c552f3063a4a19690610757908390611985565b60405180910390a150565b3361076b610828565b6001600160a01b0316146107915760405162461bcd60e51b8152600401610173906119e9565b6107ab6001600160a01b0382166334f57c6760e01b6111dc565b6107f75760405162461bcd60e51b815260206004820152601f60248201527f746172676574206973206e6f7420612076616c6964204952656c6179487562006044820152606401610173565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b031690565b6000546001600160a01b031690565b6108626040518060800160405280600081526020016000815260200160008152602001600081525090565b604051806080016040528061c350620186a061087e9190611bb2565b8152602001620186a081526020016201adb08152602001612904815250905090565b6002546001600160a01b031690565b336108b8610828565b6001600160a01b0316146108de5760405162461bcd60e51b8152600401610173906119e9565b6108f86001600160a01b0382166309788f9960e21b6111dc565b6109445760405162461bcd60e51b815260206004820181905260248201527f746172676574206973206e6f7420612076616c69642049466f727761726465726044820152606401610173565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b61097561c350620186a0611bb2565b81565b33610981610828565b6001600160a01b0316146109a75760405162461bcd60e51b8152600401610173906119e9565b6001600160a01b0390921660009081526005602090815260408083206001600160e01b0319909416835292905220805491151560ff19909216919091179055565b336109f1610828565b6001600160a01b031614610a175760405162461bcd60e51b8152600401610173906119e9565b6001600160a01b038116610a7c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610173565b610a8581610f84565b50565b610a90610819565b6001600160a01b0316336001600160a01b0316146106bf5760405162461bcd60e51b815260206004820152601e60248201527f63616e206f6e6c792062652063616c6c65642062792052656c617948756200006044820152606401610173565b610afd6020820182611b2d565b610b0e9060c081019060a0016115e7565b6001600160a01b0316610b1f6108a0565b6001600160a01b031614610b705760405162461bcd60e51b8152602060048201526018602482015277119bdc9dd85c99195c881a5cc81b9bdd081d1c9d5cdd195960421b6044820152606401610173565b610a85816111ff565b610b838180611b17565b6040013515610a855760405162461bcd60e51b815260206004820152601c60248201527b1d985b1d59481d1c985b9cd9995c881b9bdd081cdd5c1c1bdc9d195960221b6044820152606401610173565b610be06020820182611b2d565b610bee9060c0810190611ad1565b159050610a855760405162461bcd60e51b815260206004820152601c60248201527b73686f756c642068617665206e6f207061796d61737465724461746160201b6044820152606401610173565b8015610c885760405162461bcd60e51b815260206004820152601b60248201527a73686f756c642068617665206e6f20617070726f76616c4461746160281b6044820152606401610173565b5050565b6003546060906000906001600160a01b0316610ca88980611b17565b610cb99060408101906020016115e7565b6001600160a01b031614610ccc57600080fd5b6000610d23610cdb8a80611b17565b610ce99060a0810190611ad1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113e192505050565b6003546001600160a01b031660009081526005602090815260408083206001600160e01b03198516845290915290205490915060ff16610d9e5760405162461bcd60e51b81526020600482015260166024820152751b595d1a1bd9081b9bdd081dda1a5d195b1a5cdd195960521b6044820152606401610173565b6000610daa8a80611b17565b610db89060a0810190611ad1565b610dc6916004908290611b88565b810190610dd39190611749565b60035460405163f8b2cb4f60e01b81529193506001600160a01b03169150600090829063f8b2cb4f90610e0a908690600401611985565b60206040518083038186803b158015610e2257600080fd5b505afa158015610e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5a91906118be565b90506000610e683a89611bec565b90506000836001600160a01b031663fc0438306040518163ffffffff1660e01b815260040160206040518083038186803b158015610ea557600080fd5b505afa158015610eb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610edd91906118be565b610ee961271084611bca565b610ef39190611bec565b90506000610f018284611bb2565b9050808411610f4d5760405162461bcd60e51b8152602060048201526018602482015277696e73756666696369656e74206170702062616c616e636560401b6044820152606401610173565b85604051602001610f5e9190611985565b60408051601f198184030181529190529f60009f509d5050505050505050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000610fe2858701876115e7565b6001546004549192506000916001600160a01b0390911690638e53548b9061100a9087611bb2565b856040518363ffffffff1660e01b8152600401611028929190611a1e565b60206040518083038186803b15801561104057600080fd5b505afa158015611054573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107891906118be565b90506000600360009054906101000a90046001600160a01b031690506000816001600160a01b031663fc0438306040518163ffffffff1660e01b815260040160206040518083038186803b1580156110cf57600080fd5b505afa1580156110e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110791906118be565b61111361271085611bca565b61111d9190611bec565b9050600061112b8285611bb2565b604051631a77d65360e31b81529091506001600160a01b0384169063d3beb2989061115c9088908590600401611999565b600060405180830381600087803b15801561117657600080fd5b505af115801561118a573d6000803e3d6000fd5b505060408051878152602081018690529081018490527faad61a9664bc6be1128f98485df350d149d1d8f3dce21e21c1741501960b88099250606001905060405180910390a150505050505050505050565b60006111e7836113ee565b80156111f857506111f88383611421565b9392505050565b60008061120c8380611b17565b61121d9060408101906020016115e7565b6001600160a01b031663572b6c0560e01b61123b6020860186611b2d565b61124c9060c081019060a0016115e7565b60405160240161125c9190611985565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161129a9190611969565b600060405180830381855afa9150503d80600081146112d5576040519150601f19603f3d011682016040523d82523d6000602084013e6112da565b606091505b50915091508161132b5760405162461bcd60e51b815260206004820152601c60248201527b1a5cd51c9d5cdd1959119bdc9dd85c99195c8e881c995d995c9d195960221b6044820152606401610173565b805160201461137c5760405162461bcd60e51b815260206004820181905260248201527f697354727573746564466f727761726465723a2062616420726573706f6e73656044820152606401610173565b808060200190518101906113909190611682565b6113dc5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420666f7277617264657220666f7220726563697069656e74006044820152606401610173565b505050565b60006105b582600061150a565b6000611401826301ffc9a760e01b611421565b80156105b5575061141a826001600160e01b0319611421565b1592915050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b179052905160009190829081906001600160a01b0387169061753090611488908690611969565b6000604051808303818686fa925050503d80600081146114c4576040519150601f19603f3d011682016040523d82523d6000602084013e6114c9565b606091505b50915091506020815110156114e457600093505050506105b5565b8180156115005750808060200190518101906115009190611682565b9695505050505050565b6000611517826004611bb2565b835110156115645760405162461bcd60e51b815260206004820152601a6024820152791c995859109e5d195ccd0e8819185d18481d1bdbc81cda1bdc9d60321b6044820152606401610173565b5001602001516001600160e01b03191690565b803561158281611c67565b919050565b80356001600160e01b03198116811461158257600080fd5b60008083601f8401126115b157600080fd5b5081356001600160401b038111156115c857600080fd5b6020830191508360208285010111156115e057600080fd5b9250929050565b6000602082840312156115f957600080fd5b81356111f881611c67565b6000806040838503121561161757600080fd5b823561162281611c67565b915061163060208401611587565b90509250929050565b60008060006060848603121561164e57600080fd5b833561165981611c67565b925061166760208501611587565b9150604084013561167781611c7c565b809150509250925092565b60006020828403121561169457600080fd5b81516111f881611c7c565b6000602082840312156116b157600080fd5b6111f882611587565b6000806000806000608086880312156116d257600080fd5b85356001600160401b03808211156116e957600080fd5b6116f589838a0161159f565b90975095506020880135915061170a82611c7c565b909350604087013592506060870135908082111561172757600080fd5b508601610100818903121561173b57600080fd5b809150509295509295909350565b6000806040838503121561175c57600080fd5b82356001600160401b038082111561177357600080fd5b818501915085601f83011261178757600080fd5b81358181111561179957611799611c51565b604051601f8201601f19908116603f011681019083821181831017156117c1576117c1611c51565b816040528281528860208487010111156117da57600080fd5b82602086016020830137600060208483010152809650505050505061163060208401611577565b6000806000806000806080878903121561181a57600080fd5b86356001600160401b038082111561183157600080fd5b908801906040828b03121561184557600080fd5b9096506020880135908082111561185b57600080fd5b6118678a838b0161159f565b9097509550604089013591508082111561188057600080fd5b5061188d89828a0161159f565b979a9699509497949695606090950135949350505050565b6000602082840312156118b757600080fd5b5035919050565b6000602082840312156118d057600080fd5b5051919050565b600080604083850312156118ea57600080fd5b8235915060208301356118fc81611c67565b809150509250929050565b6001600160a01b03169052565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60008151808452611955816020860160208601611c0b565b601f01601f19169290920160200192915050565b6000825161197b818460208701611c0b565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6040815260006119c5604083018561193d565b905082151560208301529392505050565b6020815260006111f8602083018461193d565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b8281526040602082015281356040820152602082013560608201526040820135608082015260006060830135611a5381611c67565b6001600160a01b031660a0830152611a6d60808401611577565b611a7a60c0840182611907565b50611a8760a08401611577565b611a9460e0840182611907565b50611aa260c0840184611b43565b61010084810152611ab861014085018284611914565b91505060e0840135610120840152809150509392505050565b6000808335601e19843603018112611ae857600080fd5b8301803591506001600160401b03821115611b0257600080fd5b6020019150368190038213156115e057600080fd5b6000823560de1983360301811261197b57600080fd5b6000823560fe1983360301811261197b57600080fd5b6000808335601e19843603018112611b5a57600080fd5b83016020810192503590506001600160401b03811115611b7957600080fd5b8036038313156115e057600080fd5b60008085851115611b9857600080fd5b83861115611ba557600080fd5b5050820193919092039150565b60008219821115611bc557611bc5611c3b565b500190565b600082611be757634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615611c0657611c06611c3b565b500290565b60005b83811015611c26578181015183820152602001611c0e565b83811115611c35576000848401525b50505050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610a8557600080fd5b8015158114610a8557600080fdfea26469706673582212204477e91f97281fe0c3e7e6faa8f2e54e2e0ff29535215e81cbc56823c2bcfdfd64736f6c63430008070033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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