MATIC Price: $0.574633 (-0.86%)
Gas: 30 GWei
 

Overview

MATIC Balance

Polygon PoS Chain LogoPolygon PoS Chain LogoPolygon PoS Chain Logo0 MATIC

MATIC Value

$0.00

Token Holdings

Sponsored

Transaction Hash
Method
Block
From
To
Value
Register Token397843922023-02-27 23:02:00479 days ago1677538920IN
0x98E69a69...112eBe4BD
0 MATIC0.0058184484.22646846
Set Wrapped Chai...397841282023-02-27 22:51:36479 days ago1677538296IN
0x98E69a69...112eBe4BD
0 MATIC0.0060433879.67963908
Set Relay Hub397840492023-02-27 22:48:16479 days ago1677538096IN
0x98E69a69...112eBe4BD
0 MATIC0.0036124978.23989651
0x61010060397840052023-02-27 22:46:42479 days ago1677538002IN
 Create: ERC20MetaHandler
0 MATIC0.289429473.23453593

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To Value
543594932024-03-07 4:34:44106 days ago1709786084
0x98E69a69...112eBe4BD
0.14939163 MATIC
543594932024-03-07 4:34:44106 days ago1709786084
0x98E69a69...112eBe4BD
0.14939163 MATIC
543583242024-03-07 3:51:12106 days ago1709783472
0x98E69a69...112eBe4BD
0.12066962 MATIC
543583242024-03-07 3:51:12106 days ago1709783472
0x98E69a69...112eBe4BD
0.12066962 MATIC
543470472024-03-06 20:57:21106 days ago1709758641
0x98E69a69...112eBe4BD
0.07450964 MATIC
543470472024-03-06 20:57:21106 days ago1709758641
0x98E69a69...112eBe4BD
0.07450964 MATIC
543416262024-03-06 17:39:35107 days ago1709746775
0x98E69a69...112eBe4BD
0.09254899 MATIC
543416262024-03-06 17:39:35107 days ago1709746775
0x98E69a69...112eBe4BD
0.09254899 MATIC
543292122024-03-06 10:06:28107 days ago1709719588
0x98E69a69...112eBe4BD
0.28364298 MATIC
543292122024-03-06 10:06:28107 days ago1709719588
0x98E69a69...112eBe4BD
0.28364298 MATIC
543276262024-03-06 9:06:00107 days ago1709715960
0x98E69a69...112eBe4BD
0.18244542 MATIC
543276262024-03-06 9:06:00107 days ago1709715960
0x98E69a69...112eBe4BD
0.18244542 MATIC
543272652024-03-06 8:52:10107 days ago1709715130
0x98E69a69...112eBe4BD
0.15758742 MATIC
543272652024-03-06 8:52:10107 days ago1709715130
0x98E69a69...112eBe4BD
0.15758742 MATIC
543192552024-03-06 3:58:28107 days ago1709697508
0x98E69a69...112eBe4BD
0.08605675 MATIC
543192552024-03-06 3:58:28107 days ago1709697508
0x98E69a69...112eBe4BD
0.08605675 MATIC
543153962024-03-06 1:38:54107 days ago1709689134
0x98E69a69...112eBe4BD
0.08360928 MATIC
543153962024-03-06 1:38:54107 days ago1709689134
0x98E69a69...112eBe4BD
0.08360928 MATIC
543151412024-03-06 1:29:50107 days ago1709688590
0x98E69a69...112eBe4BD
0.08456491 MATIC
543151412024-03-06 1:29:50107 days ago1709688590
0x98E69a69...112eBe4BD
0.08456491 MATIC
543100612024-03-05 22:21:41107 days ago1709677301
0x98E69a69...112eBe4BD
0.09221799 MATIC
543100612024-03-05 22:21:41107 days ago1709677301
0x98E69a69...112eBe4BD
0.09221799 MATIC
543095752024-03-05 22:04:29107 days ago1709676269
0x98E69a69...112eBe4BD
0.08903847 MATIC
543095752024-03-05 22:04:29107 days ago1709676269
0x98E69a69...112eBe4BD
0.08903847 MATIC
543036352024-03-05 18:24:07108 days ago1709663047
0x98E69a69...112eBe4BD
0.17890247 MATIC
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ERC20MetaHandler

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 31 : ERC20MetaHandler.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.0;

import "@uniswap/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol";
import "./BaseERC20MetaHandler.sol";

/**
 * @title An OpenGSN-powered meta transaction handler for ERC20 tokens
 * @notice This contract allows sending ERC20 tokens without having to acquire the chains native token first.
 * The network fee is paid using the ERC20 token, which is converted automatically using UniSwap.
 */
contract ERC20MetaHandler is BaseERC20MetaHandler {

    function transferPrivate(address userAddress, TransferRequestData memory requestData) private {
        require(requestData.token.transferFrom(userAddress, requestData.target, requestData.amount), "Meta: Value transfer failed");
    }

    function checkTransferPrivate(address userAddress, TransferRequestData memory requestData, FeeInformation memory feeInformation) private view onlyWithWrappedChainToken onlyRegisteredToken(requestData.token) {
        require(requestData.token.balanceOf(userAddress) >= requestData.amount + feeInformation.fee, "Meta: balance too low");
    }

    function checkTransferWithApproval(address userAddress, TransferRequestData memory requestData, FeeInformation memory feeInformation, ApprovalRequestData memory approvalRequestData) internal view {
        checkTransferPrivate(userAddress, requestData, feeInformation);
        if (requestData.token.allowance(userAddress, address(this)) < requestData.amount + feeInformation.fee) {
            require(approvalRequestData.approval >= requestData.amount + feeInformation.fee, "Meta: approval too low");
        }
    }

    function approvePrivate(address userAddress, TransferRequestData memory requestData, FeeInformation memory feeInformation, ApprovalRequestData memory approvalRequestData) private {
        approveIfRequiredInternal(userAddress, approvalRequestData, requestData.amount + feeInformation.fee);
    }

    /**
     * @notice Transfers `amount` of `token` to `target`. Includes an approval for `approval` `token`.
     */
    function transferWithApproval(IERC20Meta token, uint256 amount, address target, uint256 fee, uint256 approval, bytes32 sigR, bytes32 sigS, uint8 sigV) public {
        TransferRequestData memory requestData = TransferRequestData(token, amount, target);
        FeeInformation memory feeInformation = FeeInformation(token, msg.sender, fee, 0);
        ApprovalRequestData memory approvalRequestData = ApprovalRequestData(token, approval, sigR, sigS, sigV);

        checkTransferWithApproval(msg.sender, requestData, feeInformation, approvalRequestData);
        approvePrivate(msg.sender, requestData, feeInformation, approvalRequestData);
        processFeeInternal(feeInformation);
        transferPrivate(msg.sender, requestData);
        finishFeeInternal(feeInformation);
    }

    function checkTransfer(address userAddress, TransferRequestData memory requestData, FeeInformation memory feeInformation) internal view {
        checkTransferPrivate(userAddress, requestData, feeInformation);
        require(requestData.token.allowance(userAddress, address(this)) >= requestData.amount + feeInformation.fee, "Meta: allowance too low");
    }

    /**
     * @notice Transfers `amount` of `token` to `target`.
     */
    function transfer(IERC20Meta token, uint256 amount, address target, uint256 fee) public {
        TransferRequestData memory requestData = TransferRequestData(token, amount, target);
        FeeInformation memory feeInformation = FeeInformation(token, msg.sender, fee, 0);

        checkTransfer(msg.sender, requestData, feeInformation);
        processFeeInternal(feeInformation);
        transferPrivate(msg.sender, requestData);
        finishFeeInternal(feeInformation);
    }

    struct TransferRequestData {
        IERC20Meta token;
        uint256 amount;
        address target;
    }

    function decodeTransferRequestDataPrivate(bytes memory data, uint tokenIndex, uint amountIndex, uint targetIndex) private pure returns (TransferRequestData memory requestData) {
        requestData = TransferRequestData({
            token : IERC20Meta(address(uint160(GsnUtils.getParam(data, tokenIndex)))),
            amount : uint256(GsnUtils.getParam(data, amountIndex)),
            target : address(uint160(GsnUtils.getParam(data, targetIndex)))
        });
    }

    function decodeRequestDataPrivate(bytes4 methodId, address payer, bytes memory data, uint256 chainTokenFee) private pure returns (TransferRequestData memory requestData, FeeInformation memory feeInformation) {
        if (methodId == this.transfer.selector || methodId == this.transferWithApproval.selector) {
            requestData = decodeTransferRequestDataPrivate(data, 0, 1, 2);
            feeInformation = decodeFeeInformationInternal(data, requestData.token, payer, 3, chainTokenFee);
        } else {
            require(false, "Meta: unsupported method");
        }
    }

    function verifyCallPrivate(IForwarder.ForwardRequest memory request, GsnTypes.RelayData calldata relayData, bytes memory signature, bytes memory approvalData) private view returns (TransferRequestData memory requestData, FeeInformation memory feeInformation, ApprovalRequestData memory approvalRequestData) {
        (approvalData);
        bytes memory suffixData = abi.encode(GsnEip712Library.hashRelayData(relayData));
        bytes32 _domainSeparator = GsnEip712Library.domainSeparator(relayData.forwarder);
        verifyInternal(request, _domainSeparator, GsnEip712Library.RELAY_REQUEST_TYPEHASH, suffixData, signature);

        bytes4 methodId = GsnUtils.getMethodSig(request.data);
        (requestData, feeInformation) = decodeRequestDataPrivate(methodId, request.from, request.data, getRequiredRelayFee(relayData, methodId));

        if (methodId == this.transfer.selector) {
            checkTransfer(request.from, requestData, feeInformation);
        } else if (methodId == this.transferWithApproval.selector) {
            approvalRequestData = decodeApprovalRequestDataWithKnownTokenInternal(request.data, requestData.token, 4, 5);
            checkTransferWithApproval(request.from, requestData, feeInformation, approvalRequestData);
        }
    }

    function preRelayedCall(GsnTypes.RelayRequest calldata relayRequest, bytes calldata signature, bytes calldata approvalData, uint256 maxPossibleGas) external override virtual onlyRelayHub onlyToSelf(relayRequest) returns (bytes memory context, bool revertOnRecipientRevert) {
        (relayRequest, signature, approvalData, maxPossibleGas);
        require(relayRequest.request.to == address(this), "Meta: illegal request.to");
        require(relayRequest.request.nonce == getNonce(relayRequest.request.from), "Meta: Invalid nonce");

        (TransferRequestData memory requestData, FeeInformation memory feeInformation, ApprovalRequestData memory approvalRequestData) = verifyCallPrivate(relayRequest.request, relayRequest.relayData, signature, approvalData);
        if (approvalRequestData.approval != 0) {
            approvePrivate(relayRequest.request.from, requestData, feeInformation, approvalRequestData);
        }
        processFeeInternal(feeInformation);

        context = abi.encode(feeInformation);
        revertOnRecipientRevert = true;
    }

    function execute(ForwardRequest calldata request, bytes32 domainSeparator, bytes32 requestTypeHash, bytes calldata suffixData, bytes calldata signature) public override payable onlyRelayHub returns (bool success, bytes memory ret) {
        (request, domainSeparator, requestTypeHash, suffixData, signature);

        bytes4 methodId = GsnUtils.getMethodSig(request.data);
        // chainTokenFee is not needed here, so we just set it to 0
        (TransferRequestData memory requestData, FeeInformation memory feeInformation) = decodeRequestDataPrivate(methodId, request.from, request.data, 0);
        (feeInformation);
        nonces[request.from] = nonces[request.from] + 1;
        transferPrivate(request.from, requestData);

        success = true;
        ret = "";
    }

    function postRelayedCall(bytes calldata context, bool success, uint256 gasUseWithoutPost, GsnTypes.RelayData calldata relayData) external override virtual onlyRelayHub {
        (context, success, gasUseWithoutPost, relayData);
        (FeeInformation memory feeInformation) = abi.decode(context, (FeeInformation));
        finishFeeInternal(feeInformation);
    }

    function versionRecipient() external override virtual view returns (string memory) {
        return "2.2.6+opengsn.recipient.erc20meta.handler";
    }

    function versionPaymaster() external override virtual view returns (string memory) {
        return "2.2.6+opengsn.paymaster.erc20meta.handler";
    }

    constructor() {
        registerRequestTypeInternal(string(abi.encodePacked("ForwardRequest(", GsnEip712Library.GENERIC_PARAMS, ")")));
        registerRequestTypeInternal(GsnEip712Library.RELAY_REQUEST_NAME, GsnEip712Library.RELAY_REQUEST_SUFFIX);
        registerDomainSeparatorInternal("GSN Relayed Transaction", "2");
    }
}

File 2 of 31 : IWrappedChainToken.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.0;

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

interface IWrappedChainToken is IERC20 {
    receive() external payable;

    function deposit() external payable;

    function withdraw(uint256 wad) external;
}

File 3 of 31 : IERC20Meta.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.0;

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

interface IERC20Meta is IERC20 {
    function getChainId() external view returns (uint256);

    function getDomainSeperator() external view returns (bytes32);

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

    function executeMetaTransaction(address userAddress, bytes memory functionSignature, bytes32 sigR, bytes32 sigS, uint8 sigV) external payable returns (bytes memory);
}

File 4 of 31 : BaseERC20MetaHandler.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.0;

import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import "@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "./interfaces/IERC20Meta.sol";
import "./interfaces/IWrappedChainToken.sol";
import "./BaseCombinedGsnHandler.sol";

using SafeCast for uint256;

abstract contract BaseERC20MetaHandler is BaseCombinedGsnHandler, IUniswapV3SwapCallback {

    /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
    uint160 internal constant MIN_SQRT_RATIO = 4295128739;
    /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
    uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;

    IWrappedChainToken public wrappedChainToken;

    mapping(IERC20Meta => IUniswapV3Pool) public registeredTokenPool;
    mapping(IERC20Meta => uint256) public deposits;
    uint256 private registeredTokenCount = 0;

    mapping(address => uint256) internal nonces;

    struct FeeInformation {
        IERC20Meta token;
        address payer;
        uint256 fee;
        uint256 chainTokenFee;
    }

    struct ApprovalRequestData {
        IERC20Meta token;
        uint256 approval;
        bytes32 sigR;
        bytes32 sigS;
        uint8 sigV;
    }

    modifier onlyRegisteredToken(IERC20Meta token) {
        require(address(registeredTokenPool[token]) != address(0), "Base: token not registered");
        _;
    }

    modifier onlyWithWrappedChainToken() {
        require(address(wrappedChainToken) != address(0), "Base: no wrapped chain token");
        _;
    }

    function setWrappedChainToken(IWrappedChainToken _wrappedChainToken) public onlyOwner {
        require(registeredTokenCount == 0, "Base: tokens registered");
        wrappedChainToken = _wrappedChainToken;
        require(wrappedChainToken.approve(owner(), type(uint256).max), "Base: owner approval failed");
    }

    function registerToken(IERC20Meta token, IUniswapV3Pool pool) public onlyOwner {
        require(address(pool) != address(0), "Base: No pool defined");
        require(address(registeredTokenPool[token]) == address(0), "Base: token already registered");
        registeredTokenPool[token] = pool;
        registeredTokenCount = registeredTokenCount + 1;
    }

    // @dev deprecated
    function registeredTokenPoolFee(IERC20Meta token) public view returns (uint24 fee) {
        if (address(registeredTokenPool[token]) != address(0)) {
            return registeredTokenPool[token].fee();
        }
        return 0;
    }

    function unregisterToken(IERC20Meta token) public onlyOwner onlyRegisteredToken(token) {
        delete registeredTokenPool[token];
        registeredTokenCount = registeredTokenCount - 1;
    }

    function processFeeInternal(FeeInformation memory feeInformation) internal {
        if (feeInformation.fee > 0) {
            if (feeInformation.chainTokenFee > 0) {
                bool zeroForOne = address(feeInformation.token) < address(wrappedChainToken);
                (int256 amount0Delta, int256 amount1Delta) = registeredTokenPool[feeInformation.token].swap(
                    address(this),
                    zeroForOne,
                    -(feeInformation.chainTokenFee).toInt256(),
                    (zeroForOne ? MIN_SQRT_RATIO + 1 : MAX_SQRT_RATIO - 1),
                    abi.encode(feeInformation)
                );
                (amount0Delta, amount1Delta);
            } else {
                require(feeInformation.token.transferFrom(feeInformation.payer, address(this), feeInformation.fee), "Base: Fee transfer failed");
            }
        } else {
            require(feeInformation.chainTokenFee == 0, "Base: Fee too low");
        }
    }

    function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata _data) external override {
        require(amount0Delta > 0 || amount1Delta > 0);
        (FeeInformation memory feeInformation) = abi.decode(_data, (FeeInformation));
        require(msg.sender == address(registeredTokenPool[feeInformation.token]));
        bool zeroForOne = address(feeInformation.token) < address(wrappedChainToken);
        (uint256 amountIn, uint256 amountOutReceived) = zeroForOne ? (uint256(amount0Delta), uint256(-amount1Delta)) : (uint256(amount1Delta), uint256(-amount0Delta));
        require(amountIn <= feeInformation.fee, "Base: fee too low");
        require(amountOutReceived == feeInformation.chainTokenFee, "Base: pool failed");
        if (feeInformation.payer == address(this)) {
            require(feeInformation.token.transfer(msg.sender, amountIn), "Base: Fee transfer failed");
        } else {
            require(feeInformation.token.transferFrom(feeInformation.payer, msg.sender, amountIn), "Base: Fee transfer failed");
        }
    }

    function finishFeeInternal(FeeInformation memory feeInformation) internal {
        if (feeInformation.chainTokenFee > 0) {
            wrappedChainToken.withdraw(feeInformation.chainTokenFee);
            relayHub.depositFor{value : feeInformation.chainTokenFee}(address(this));
        }
    }

    function finishFeeWithCustomTargetInternal(FeeInformation memory feeInformation, address payable target) internal {
        if (feeInformation.chainTokenFee > 0) {
            wrappedChainToken.withdraw(feeInformation.chainTokenFee);
            target.transfer(feeInformation.chainTokenFee);
        }
    }

    function executeApproveInternal(address userAddress, ApprovalRequestData memory approvalRequestData) internal {
        bytes memory functionSignature = abi.encodeCall(IERC20.approve, (address(this), approvalRequestData.approval));
        approvalRequestData.token.executeMetaTransaction(userAddress, functionSignature, approvalRequestData.sigR, approvalRequestData.sigS, approvalRequestData.sigV);
    }

    function approveIfRequiredInternal(address userAddress, ApprovalRequestData memory approvalRequestData, uint256 required) internal {
        if (approvalRequestData.token.allowance(userAddress, address(this)) < required) {
            executeApproveInternal(userAddress, approvalRequestData);
        }
    }

    function decodeFeeInformationInternal(bytes memory data, IERC20Meta token, address payer, uint feeIndex, uint256 chainTokenFee) internal pure returns(FeeInformation memory feeInformation) {
        feeInformation = FeeInformation({
            token : token,
            payer : payer,
            fee : uint256(GsnUtils.getParam(data, feeIndex)),
            chainTokenFee : chainTokenFee
        });
    }

    function decodeApprovalRequestDataInternal(bytes memory data, uint tokenIndex, uint approvalIndex, uint sigIndex) internal pure returns(ApprovalRequestData memory approvalRequestData) {
        approvalRequestData = ApprovalRequestData({
            token : IERC20Meta(address(uint160(GsnUtils.getParam(data, tokenIndex)))),
            approval : uint256(GsnUtils.getParam(data, approvalIndex)),
            sigR : bytes32(GsnUtils.getParam(data, sigIndex)),
            sigS : bytes32(GsnUtils.getParam(data, sigIndex + 1)),
            sigV : uint8(GsnUtils.getParam(data, sigIndex + 2))
        });
    }

    function decodeApprovalRequestDataWithKnownTokenInternal(bytes memory data, IERC20Meta token, uint approvalIndex, uint sigIndex) internal pure returns(ApprovalRequestData memory approvalRequestData) {
        approvalRequestData = ApprovalRequestData({
            token : token,
            approval : uint256(GsnUtils.getParam(data, approvalIndex)),
            sigR : bytes32(GsnUtils.getParam(data, sigIndex)),
            sigS : bytes32(GsnUtils.getParam(data, sigIndex + 1)),
            sigV : uint8(GsnUtils.getParam(data, sigIndex + 2))
        });
    }

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

    function withdraw(uint amount, address payable target) public onlyOwner {
        target.transfer(amount);
    }

    function withdrawToken(IERC20Meta token, uint amount, address target) public onlyOwner {
        uint balance = token.balanceOf(address(this));
        require(balance >= deposits[token]);
        require(amount <= balance - deposits[token]);
        token.transfer(target, amount);
    }

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

File 5 of 31 : BaseCombinedGsnHandler.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.0;

import "@opengsn/contracts/src/interfaces/IPaymaster.sol";
import "@opengsn/contracts/src/interfaces/IRelayHub.sol";
import "@opengsn/contracts/src/interfaces/IRelayRecipient.sol";
import "@opengsn/contracts/src/forwarder/IForwarder.sol";
import "@opengsn/contracts/src/utils/GsnEip712Library.sol";
import "@opengsn/contracts/src/utils/GsnUtils.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

abstract contract BaseCombinedGsnHandler is IRelayRecipient, IPaymaster, IForwarder, Ownable {
    IRelayHub internal relayHub;

    using ECDSA for bytes32;

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

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

    IPaymaster.GasAndDataLimits private gasAndDataLimits = IPaymaster.GasAndDataLimits({
        acceptanceBudget: 250000,
        preRelayedCallGasLimit: 250000,
        postRelayedCallGasLimit: 100000,
        calldataSizeLimit: 2048
    });

    mapping(bytes4 => uint256) private methodRequiredRelayGas;
    uint256 private maxRequiredRelayGas = 500000;

    modifier onlyToSelf(GsnTypes.RelayRequest calldata relayRequest) {
        require(relayRequest.request.to == address(this), "Base: illegal request.to");
        _;
    }

    modifier onlyRelayHub() {
        require(msg.sender == getHubAddr(), "Base: illegal msg.sender");
        _;
    }

    function verify(ForwardRequest calldata forwardRequest, bytes32 domainSeparator, bytes32 requestTypeHash, bytes calldata suffixData, bytes calldata signature) public override view {
        verifyInternal(forwardRequest, domainSeparator, requestTypeHash, suffixData, signature);
    }

    function verifyInternal(ForwardRequest memory forwardRequest, bytes32 domainSeparator, bytes32 requestTypeHash, bytes memory suffixData, bytes memory signature) internal view {
        require(domains[domainSeparator], "Base: unregistered domain sep.");
        require(typeHashes[requestTypeHash], "Base: unregistered typehash");
        bytes memory encoded = abi.encodePacked(
            requestTypeHash,
            uint256(uint160(forwardRequest.from)),
            uint256(uint160(forwardRequest.to)),
            forwardRequest.value,
            forwardRequest.gas,
            forwardRequest.nonce,
            keccak256(forwardRequest.data),
            forwardRequest.validUntil,
            suffixData
        );
        bytes32 digest = keccak256(abi.encodePacked(
                "\x19\x01", domainSeparator,
                keccak256(encoded)
            ));
        require(digest.recover(signature) == forwardRequest.from, "Base: signature mismatch");
    }

    function isTrustedForwarder(address forwarder) public override view returns (bool) {
        return forwarder == address(this);
    }

    function trustedForwarder() override(IPaymaster) public view returns (address forwarder){
        forwarder = address(this);
    }

    function getHubAddr() public override view returns (address) {
        return address(relayHub);
    }

    function getRelayHubDeposit() public override view returns (uint) {
        return relayHub.balanceOf(address(this));
    }

    function getGasAndDataLimits() public override virtual view returns (IPaymaster.GasAndDataLimits memory limits) {
        return gasAndDataLimits;
    }

    function setGasAndDataLimits(IPaymaster.GasAndDataLimits calldata limits) public onlyOwner {
        gasAndDataLimits = limits;
    }

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

    // @dev deprecated
    function requiredRelayGas() public view returns (uint256) {
        return maxRequiredRelayGas;
    }

    // @dev deprecated
    function setMaxRequiredRelayGas(uint256 gas) public onlyOwner {
        maxRequiredRelayGas = gas;
    }

    // @dev deprecated
    function getMinimumRelayFee(GsnTypes.RelayData calldata relayData) public view returns (uint256 amount) {
        amount = relayHub.calculateCharge(requiredRelayGas(), relayData);
    }

    function getRequiredRelayGas(bytes4 methodId) public view returns (uint256 gas) {
        gas = methodRequiredRelayGas[methodId];
        if (gas == 0) gas = maxRequiredRelayGas;
    }

    function getRequiredRelayFee(GsnTypes.RelayData calldata relayData, bytes4 methodId) public view returns (uint256 amount) {
        amount = relayHub.calculateCharge(getRequiredRelayGas(methodId), relayData);
    }

    function setRequiredRelayGas(bytes4 methodId, uint256 gas) public onlyOwner {
        methodRequiredRelayGas[methodId] = gas;
        if (gas > maxRequiredRelayGas) maxRequiredRelayGas = gas;
    }

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

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

    function withdrawRelayHubDeposit(uint amount, address payable target) public onlyOwner {
        relayHub.withdraw(amount, target);
    }

    function registerDomainSeparator(string calldata name, string calldata version) public override {
        registerDomainSeparatorInternal(name, version);
    }

    function registerDomainSeparatorInternal(string memory name, string memory version) internal {
        uint256 chainId;
        /* solhint-disable-next-line no-inline-assembly */
        assembly {chainId := chainid()}

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

        bytes32 domainHash = keccak256(domainValue);

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

    function registerRequestType(string calldata typeName, string calldata typeSuffix) public override {
        registerRequestTypeInternal(typeName, typeSuffix);
    }

    function registerRequestTypeInternal(string memory typeName, string memory typeSuffix) internal {
        for (uint i = 0; i < bytes(typeName).length; i++) {
            bytes1 c = bytes(typeName)[i];
            require(c != "(" && c != ")", "Base: invalid typename");
        }

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

    function registerRequestTypeInternal(string memory requestType) internal {
        bytes32 requestTypehash = keccak256(bytes(requestType));
        typeHashes[requestTypehash] = true;
        emit RequestTypeRegistered(requestTypehash, requestType);
    }
}

File 6 of 31 : IUniswapV3PoolState.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Pool state that can change
/// @notice These methods compose the pool's state, and can change with any frequency including multiple times
/// per transaction
interface IUniswapV3PoolState {
    /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas
    /// when accessed externally.
    /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value
    /// tick The current tick of the pool, i.e. according to the last tick transition that was run.
    /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick
    /// boundary.
    /// observationIndex The index of the last oracle observation that was written,
    /// observationCardinality The current maximum number of observations stored in the pool,
    /// observationCardinalityNext The next maximum number of observations, to be updated when the observation.
    /// feeProtocol The protocol fee for both tokens of the pool.
    /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0
    /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.
    /// unlocked Whether the pool is currently locked to reentrancy
    function slot0()
        external
        view
        returns (
            uint160 sqrtPriceX96,
            int24 tick,
            uint16 observationIndex,
            uint16 observationCardinality,
            uint16 observationCardinalityNext,
            uint8 feeProtocol,
            bool unlocked
        );

    /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool
    /// @dev This value can overflow the uint256
    function feeGrowthGlobal0X128() external view returns (uint256);

    /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool
    /// @dev This value can overflow the uint256
    function feeGrowthGlobal1X128() external view returns (uint256);

    /// @notice The amounts of token0 and token1 that are owed to the protocol
    /// @dev Protocol fees will never exceed uint128 max in either token
    function protocolFees() external view returns (uint128 token0, uint128 token1);

    /// @notice The currently in range liquidity available to the pool
    /// @dev This value has no relationship to the total liquidity across all ticks
    function liquidity() external view returns (uint128);

    /// @notice Look up information about a specific tick in the pool
    /// @param tick The tick to look up
    /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or
    /// tick upper,
    /// liquidityNet how much liquidity changes when the pool price crosses the tick,
    /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,
    /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,
    /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick
    /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick,
    /// secondsOutside the seconds spent on the other side of the tick from the current tick,
    /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false.
    /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.
    /// In addition, these values are only relative and must be used only in comparison to previous snapshots for
    /// a specific position.
    function ticks(int24 tick)
        external
        view
        returns (
            uint128 liquidityGross,
            int128 liquidityNet,
            uint256 feeGrowthOutside0X128,
            uint256 feeGrowthOutside1X128,
            int56 tickCumulativeOutside,
            uint160 secondsPerLiquidityOutsideX128,
            uint32 secondsOutside,
            bool initialized
        );

    /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information
    function tickBitmap(int16 wordPosition) external view returns (uint256);

    /// @notice Returns the information about a position by the position's key
    /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper
    /// @return _liquidity The amount of liquidity in the position,
    /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke,
    /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke,
    /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke,
    /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke
    function positions(bytes32 key)
        external
        view
        returns (
            uint128 _liquidity,
            uint256 feeGrowthInside0LastX128,
            uint256 feeGrowthInside1LastX128,
            uint128 tokensOwed0,
            uint128 tokensOwed1
        );

    /// @notice Returns data about a specific observation index
    /// @param index The element of the observations array to fetch
    /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time
    /// ago, rather than at a specific index in the array.
    /// @return blockTimestamp The timestamp of the observation,
    /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp,
    /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp,
    /// Returns initialized whether the observation has been initialized and the values are safe to use
    function observations(uint256 index)
        external
        view
        returns (
            uint32 blockTimestamp,
            int56 tickCumulative,
            uint160 secondsPerLiquidityCumulativeX128,
            bool initialized
        );
}

File 7 of 31 : IUniswapV3PoolOwnerActions.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Permissioned pool actions
/// @notice Contains pool methods that may only be called by the factory owner
interface IUniswapV3PoolOwnerActions {
    /// @notice Set the denominator of the protocol's % share of the fees
    /// @param feeProtocol0 new protocol fee for token0 of the pool
    /// @param feeProtocol1 new protocol fee for token1 of the pool
    function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external;

    /// @notice Collect the protocol fee accrued to the pool
    /// @param recipient The address to which collected protocol fees should be sent
    /// @param amount0Requested The maximum amount of token0 to send, can be 0 to collect fees in only token1
    /// @param amount1Requested The maximum amount of token1 to send, can be 0 to collect fees in only token0
    /// @return amount0 The protocol fee collected in token0
    /// @return amount1 The protocol fee collected in token1
    function collectProtocol(
        address recipient,
        uint128 amount0Requested,
        uint128 amount1Requested
    ) external returns (uint128 amount0, uint128 amount1);
}

File 8 of 31 : IUniswapV3PoolImmutables.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Pool state that never changes
/// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values
interface IUniswapV3PoolImmutables {
    /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface
    /// @return The contract address
    function factory() external view returns (address);

    /// @notice The first of the two tokens of the pool, sorted by address
    /// @return The token contract address
    function token0() external view returns (address);

    /// @notice The second of the two tokens of the pool, sorted by address
    /// @return The token contract address
    function token1() external view returns (address);

    /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6
    /// @return The fee
    function fee() external view returns (uint24);

    /// @notice The pool tick spacing
    /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive
    /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...
    /// This value is an int24 to avoid casting even though it is always positive.
    /// @return The tick spacing
    function tickSpacing() external view returns (int24);

    /// @notice The maximum amount of position liquidity that can use any tick in the range
    /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and
    /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool
    /// @return The max amount of liquidity per tick
    function maxLiquidityPerTick() external view returns (uint128);
}

File 9 of 31 : IUniswapV3PoolEvents.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Events emitted by a pool
/// @notice Contains all events emitted by the pool
interface IUniswapV3PoolEvents {
    /// @notice Emitted exactly once by a pool when #initialize is first called on the pool
    /// @dev Mint/Burn/Swap cannot be emitted by the pool before Initialize
    /// @param sqrtPriceX96 The initial sqrt price of the pool, as a Q64.96
    /// @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool
    event Initialize(uint160 sqrtPriceX96, int24 tick);

    /// @notice Emitted when liquidity is minted for a given position
    /// @param sender The address that minted the liquidity
    /// @param owner The owner of the position and recipient of any minted liquidity
    /// @param tickLower The lower tick of the position
    /// @param tickUpper The upper tick of the position
    /// @param amount The amount of liquidity minted to the position range
    /// @param amount0 How much token0 was required for the minted liquidity
    /// @param amount1 How much token1 was required for the minted liquidity
    event Mint(
        address sender,
        address indexed owner,
        int24 indexed tickLower,
        int24 indexed tickUpper,
        uint128 amount,
        uint256 amount0,
        uint256 amount1
    );

    /// @notice Emitted when fees are collected by the owner of a position
    /// @dev Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees
    /// @param owner The owner of the position for which fees are collected
    /// @param tickLower The lower tick of the position
    /// @param tickUpper The upper tick of the position
    /// @param amount0 The amount of token0 fees collected
    /// @param amount1 The amount of token1 fees collected
    event Collect(
        address indexed owner,
        address recipient,
        int24 indexed tickLower,
        int24 indexed tickUpper,
        uint128 amount0,
        uint128 amount1
    );

    /// @notice Emitted when a position's liquidity is removed
    /// @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect
    /// @param owner The owner of the position for which liquidity is removed
    /// @param tickLower The lower tick of the position
    /// @param tickUpper The upper tick of the position
    /// @param amount The amount of liquidity to remove
    /// @param amount0 The amount of token0 withdrawn
    /// @param amount1 The amount of token1 withdrawn
    event Burn(
        address indexed owner,
        int24 indexed tickLower,
        int24 indexed tickUpper,
        uint128 amount,
        uint256 amount0,
        uint256 amount1
    );

    /// @notice Emitted by the pool for any swaps between token0 and token1
    /// @param sender The address that initiated the swap call, and that received the callback
    /// @param recipient The address that received the output of the swap
    /// @param amount0 The delta of the token0 balance of the pool
    /// @param amount1 The delta of the token1 balance of the pool
    /// @param sqrtPriceX96 The sqrt(price) of the pool after the swap, as a Q64.96
    /// @param liquidity The liquidity of the pool after the swap
    /// @param tick The log base 1.0001 of price of the pool after the swap
    event Swap(
        address indexed sender,
        address indexed recipient,
        int256 amount0,
        int256 amount1,
        uint160 sqrtPriceX96,
        uint128 liquidity,
        int24 tick
    );

    /// @notice Emitted by the pool for any flashes of token0/token1
    /// @param sender The address that initiated the swap call, and that received the callback
    /// @param recipient The address that received the tokens from flash
    /// @param amount0 The amount of token0 that was flashed
    /// @param amount1 The amount of token1 that was flashed
    /// @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee
    /// @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee
    event Flash(
        address indexed sender,
        address indexed recipient,
        uint256 amount0,
        uint256 amount1,
        uint256 paid0,
        uint256 paid1
    );

    /// @notice Emitted by the pool for increases to the number of observations that can be stored
    /// @dev observationCardinalityNext is not the observation cardinality until an observation is written at the index
    /// just before a mint/swap/burn.
    /// @param observationCardinalityNextOld The previous value of the next observation cardinality
    /// @param observationCardinalityNextNew The updated value of the next observation cardinality
    event IncreaseObservationCardinalityNext(
        uint16 observationCardinalityNextOld,
        uint16 observationCardinalityNextNew
    );

    /// @notice Emitted when the protocol fee is changed by the pool
    /// @param feeProtocol0Old The previous value of the token0 protocol fee
    /// @param feeProtocol1Old The previous value of the token1 protocol fee
    /// @param feeProtocol0New The updated value of the token0 protocol fee
    /// @param feeProtocol1New The updated value of the token1 protocol fee
    event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New);

    /// @notice Emitted when the collected protocol fees are withdrawn by the factory owner
    /// @param sender The address that collects the protocol fees
    /// @param recipient The address that receives the collected protocol fees
    /// @param amount0 The amount of token0 protocol fees that is withdrawn
    /// @param amount0 The amount of token1 protocol fees that is withdrawn
    event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1);
}

File 10 of 31 : IUniswapV3PoolDerivedState.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Pool state that is not stored
/// @notice Contains view functions to provide information about the pool that is computed rather than stored on the
/// blockchain. The functions here may have variable gas costs.
interface IUniswapV3PoolDerivedState {
    /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp
    /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing
    /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,
    /// you must call it with secondsAgos = [3600, 0].
    /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in
    /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.
    /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned
    /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp
    /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block
    /// timestamp
    function observe(uint32[] calldata secondsAgos)
        external
        view
        returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);

    /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range
    /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed.
    /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first
    /// snapshot is taken and the second snapshot is taken.
    /// @param tickLower The lower tick of the range
    /// @param tickUpper The upper tick of the range
    /// @return tickCumulativeInside The snapshot of the tick accumulator for the range
    /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range
    /// @return secondsInside The snapshot of seconds per liquidity for the range
    function snapshotCumulativesInside(int24 tickLower, int24 tickUpper)
        external
        view
        returns (
            int56 tickCumulativeInside,
            uint160 secondsPerLiquidityInsideX128,
            uint32 secondsInside
        );
}

File 11 of 31 : IUniswapV3PoolActions.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Permissionless pool actions
/// @notice Contains pool methods that can be called by anyone
interface IUniswapV3PoolActions {
    /// @notice Sets the initial price for the pool
    /// @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value
    /// @param sqrtPriceX96 the initial sqrt price of the pool as a Q64.96
    function initialize(uint160 sqrtPriceX96) external;

    /// @notice Adds liquidity for the given recipient/tickLower/tickUpper position
    /// @dev The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback
    /// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends
    /// on tickLower, tickUpper, the amount of liquidity, and the current price.
    /// @param recipient The address for which the liquidity will be created
    /// @param tickLower The lower tick of the position in which to add liquidity
    /// @param tickUpper The upper tick of the position in which to add liquidity
    /// @param amount The amount of liquidity to mint
    /// @param data Any data that should be passed through to the callback
    /// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback
    /// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback
    function mint(
        address recipient,
        int24 tickLower,
        int24 tickUpper,
        uint128 amount,
        bytes calldata data
    ) external returns (uint256 amount0, uint256 amount1);

    /// @notice Collects tokens owed to a position
    /// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity.
    /// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or
    /// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the
    /// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.
    /// @param recipient The address which should receive the fees collected
    /// @param tickLower The lower tick of the position for which to collect fees
    /// @param tickUpper The upper tick of the position for which to collect fees
    /// @param amount0Requested How much token0 should be withdrawn from the fees owed
    /// @param amount1Requested How much token1 should be withdrawn from the fees owed
    /// @return amount0 The amount of fees collected in token0
    /// @return amount1 The amount of fees collected in token1
    function collect(
        address recipient,
        int24 tickLower,
        int24 tickUpper,
        uint128 amount0Requested,
        uint128 amount1Requested
    ) external returns (uint128 amount0, uint128 amount1);

    /// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position
    /// @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0
    /// @dev Fees must be collected separately via a call to #collect
    /// @param tickLower The lower tick of the position for which to burn liquidity
    /// @param tickUpper The upper tick of the position for which to burn liquidity
    /// @param amount How much liquidity to burn
    /// @return amount0 The amount of token0 sent to the recipient
    /// @return amount1 The amount of token1 sent to the recipient
    function burn(
        int24 tickLower,
        int24 tickUpper,
        uint128 amount
    ) external returns (uint256 amount0, uint256 amount1);

    /// @notice Swap token0 for token1, or token1 for token0
    /// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback
    /// @param recipient The address to receive the output of the swap
    /// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0
    /// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
    /// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
    /// value after the swap. If one for zero, the price cannot be greater than this value after the swap
    /// @param data Any data to be passed through to the callback
    /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
    /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
    function swap(
        address recipient,
        bool zeroForOne,
        int256 amountSpecified,
        uint160 sqrtPriceLimitX96,
        bytes calldata data
    ) external returns (int256 amount0, int256 amount1);

    /// @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback
    /// @dev The caller of this method receives a callback in the form of IUniswapV3FlashCallback#uniswapV3FlashCallback
    /// @dev Can be used to donate underlying tokens pro-rata to currently in-range liquidity providers by calling
    /// with 0 amount{0,1} and sending the donation amount(s) from the callback
    /// @param recipient The address which will receive the token0 and token1 amounts
    /// @param amount0 The amount of token0 to send
    /// @param amount1 The amount of token1 to send
    /// @param data Any data to be passed through to the callback
    function flash(
        address recipient,
        uint256 amount0,
        uint256 amount1,
        bytes calldata data
    ) external;

    /// @notice Increase the maximum number of price and liquidity observations that this pool will store
    /// @dev This method is no-op if the pool already has an observationCardinalityNext greater than or equal to
    /// the input observationCardinalityNext.
    /// @param observationCardinalityNext The desired minimum number of observations for the pool to store
    function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;
}

File 12 of 31 : IUniswapV3SwapCallback.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Callback for IUniswapV3PoolActions#swap
/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface
interface IUniswapV3SwapCallback {
    /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
    /// @dev In the implementation you must pay the pool tokens owed for the swap.
    /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
    /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
    /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
    /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
    /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
    /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
    /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
    function uniswapV3SwapCallback(
        int256 amount0Delta,
        int256 amount1Delta,
        bytes calldata data
    ) external;
}

File 13 of 31 : IUniswapV3Pool.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

import './pool/IUniswapV3PoolImmutables.sol';
import './pool/IUniswapV3PoolState.sol';
import './pool/IUniswapV3PoolDerivedState.sol';
import './pool/IUniswapV3PoolActions.sol';
import './pool/IUniswapV3PoolOwnerActions.sol';
import './pool/IUniswapV3PoolEvents.sol';

/// @title The interface for a Uniswap V3 Pool
/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform
/// to the ERC20 specification
/// @dev The pool interface is broken up into many smaller pieces
interface IUniswapV3Pool is
    IUniswapV3PoolImmutables,
    IUniswapV3PoolState,
    IUniswapV3PoolDerivedState,
    IUniswapV3PoolActions,
    IUniswapV3PoolOwnerActions,
    IUniswapV3PoolEvents
{

}

File 14 of 31 : IV3SwapRouter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;

import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol';

/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface IV3SwapRouter is IUniswapV3SwapCallback {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 amountIn;
        uint256 amountOutMinimum;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another token
    /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance,
    /// and swap the entire amount, enabling contracts to send tokens before calling this function.
    /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);

    struct ExactInputParams {
        bytes path;
        address recipient;
        uint256 amountIn;
        uint256 amountOutMinimum;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
    /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance,
    /// and swap the entire amount, enabling contracts to send tokens before calling this function.
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);

    struct ExactOutputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 amountOut;
        uint256 amountInMaximum;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Swaps as little as possible of one token for `amountOut` of another token
    /// that may remain in the router after the swap.
    /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);

    struct ExactOutputParams {
        bytes path;
        address recipient;
        uint256 amountOut;
        uint256 amountInMaximum;
    }

    /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
    /// that may remain in the router after the swap.
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}

File 15 of 31 : SafeMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

File 16 of 31 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.0;

/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {
    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     *
     * _Available since v4.7._
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     *
     * _Available since v4.7._
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     *
     * _Available since v4.7._
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     *
     * _Available since v4.2._
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     *
     * _Available since v4.7._
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     *
     * _Available since v4.7._
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     *
     * _Available since v4.7._
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     *
     * _Available since v4.7._
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     *
     * _Available since v4.7._
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     *
     * _Available since v4.7._
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     *
     * _Available since v4.7._
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     *
     * _Available since v4.7._
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     *
     * _Available since v4.7._
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     *
     * _Available since v4.7._
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     *
     * _Available since v4.7._
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v2.5._
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     *
     * _Available since v4.7._
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     *
     * _Available since v4.7._
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     *
     * _Available since v4.7._
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     *
     * _Available since v4.2._
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     *
     * _Available since v4.7._
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     *
     * _Available since v4.7._
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     *
     * _Available since v4.7._
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v2.5._
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     *
     * _Available since v4.7._
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     *
     * _Available since v4.7._
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     *
     * _Available since v4.7._
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v2.5._
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     *
     * _Available since v4.7._
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v2.5._
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     *
     * _Available since v2.5._
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     *
     * _Available since v3.0._
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     *
     * _Available since v4.7._
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     *
     * _Available since v4.7._
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     *
     * _Available since v4.7._
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     *
     * _Available since v4.7._
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     *
     * _Available since v4.7._
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     *
     * _Available since v4.7._
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     *
     * _Available since v4.7._
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     *
     * _Available since v4.7._
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     *
     * _Available since v4.7._
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     *
     * _Available since v4.7._
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     *
     * _Available since v4.7._
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     *
     * _Available since v4.7._
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     *
     * _Available since v4.7._
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     *
     * _Available since v4.7._
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     *
     * _Available since v4.7._
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     *
     * _Available since v4.7._
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     *
     * _Available since v4.7._
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     *
     * _Available since v4.7._
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     *
     * _Available since v4.7._
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     *
     * _Available since v4.7._
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     *
     * _Available since v4.7._
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     *
     * _Available since v4.7._
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     *
     * _Available since v4.7._
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     *
     * _Available since v4.7._
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     *
     * _Available since v4.7._
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     *
     * _Available since v4.7._
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     *
     * _Available since v3.0._
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}

File 17 of 31 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator,
        Rounding rounding
    ) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10**64) {
                value /= 10**64;
                result += 64;
            }
            if (value >= 10**32) {
                value /= 10**32;
                result += 32;
            }
            if (value >= 10**16) {
                value /= 10**16;
                result += 16;
            }
            if (value >= 10**8) {
                value /= 10**8;
                result += 8;
            }
            if (value >= 10**4) {
                value /= 10**4;
                result += 4;
            }
            if (value >= 10**2) {
                value /= 10**2;
                result += 2;
            }
            if (value >= 10**1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
        }
    }
}

File 18 of 31 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV // Deprecated in v4.8
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}

File 19 of 31 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

File 20 of 31 : 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 21 of 31 : 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);
}

File 22 of 31 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (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 Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        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 23 of 31 : 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 24 of 31 : GsnUtils.sol
/* solhint-disable no-inline-assembly */
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;

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

library GsnUtils {

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

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

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

}

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

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

interface GsnTypes {
    /// @notice gasPrice, pctRelayFee and baseRelayFee must be validated inside of the paymaster's preRelayedCall in order not to overpay
    struct RelayData {
        uint256 gasPrice;
        uint256 pctRelayFee;
        uint256 baseRelayFee;
        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 26 of 31 : GsnEip712Library.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
pragma abicoder v2;

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

import "./GsnUtils.sol";

/**
 * Bridge Library to map GSN RelayRequest into a call of a Forwarder
 */
library GsnEip712Library {
    // 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 validUntil";

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

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

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

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


    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(
                IRelayRecipient.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 : "2",
            chainId : getChainID(),
            verifyingContract : forwarder
            }));
    }

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

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

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

File 27 of 31 : IStakeManager.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.7.6;
pragma abicoder v2;

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

interface IStakeManager {

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

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

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

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

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

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

    event OwnerSet(
        address indexed relayManager,
        address indexed owner
    );

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

    struct RelayHubInfo {
        uint256 removalBlock;
    }

    /// 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 payable owner) external;

    /// Only the owner can call this function. If the entry does not exist, reverts.
    /// @param relayManager - address that represents a stake entry and controls relay registrations on relay hubs
    /// @param unstakeDelay - number of blocks to elapse before the owner can retrieve the stake after calling 'unlock'
    function stakeForRelayManager(address relayManager, uint256 unstakeDelay) external payable;

    function unlockStake(address relayManager) external;

    function withdrawStake(address relayManager) external;

    function authorizeHubByOwner(address relayManager, address relayHub) external;

    function authorizeHubByManager(address relayHub) external;

    function unauthorizeHubByOwner(address relayManager, address relayHub) external;

    function unauthorizeHubByManager(address relayHub) external;

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

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

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

    function maxUnstakeDelay() external view returns (uint256);

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

File 28 of 31 : IRelayRecipient.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0;

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

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

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

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

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

File 29 of 31 : IRelayHub.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.7.6;
pragma abicoder v2;

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

interface IRelayHub {
    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;
        // Maximum funds that can be deposited at once. Prevents user error by disallowing large deposits.
        uint256 maximumRecipientDeposit;
        // Minimum unstake delay blocks of a relay manager's stake on the StakeManager
        uint256 minimumUnstakeDelay;
        // Minimum stake a relay can have. An attack on the network will never cost less than half this value.
        uint256 minimumStake;
        // relayCall()'s msg.data upper bound gas cost per byte
        uint256 dataGasCostPerByte;
        // relayCalls() minimal gas overhead when calculating cost of putting tx on chain.
        uint256 externalCallDataCostOverhead;
    }

    event RelayHubConfigured(RelayHubConfig config);

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

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

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

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

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

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

    event TransactionResult(
        RelayCallStatus status,
        bytes returnValue
    );

    event HubDeprecated(uint256 fromBlock);

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

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

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

    // Balance management

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

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

    // Relaying


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

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

    function setConfiguration(RelayHubConfig memory _config) external;

    // Deprecate hub (reverting relayCall()) from block number 'fromBlock'
    // Can only be called by owner
    function deprecateHub(uint256 fromBlock) external;

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

    /* getters */

    /// Returns the whole hub configuration
    function getConfiguration() external view returns (RelayHubConfig memory config);

    function calldataGasCost(uint256 length) external view returns (uint256);

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

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

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

    function stakeManager() external view returns (IStakeManager);

    function penalizer() external view returns (address);

    /// Uses StakeManager info to decide if the Relay Manager can be considered staked
    /// @return true if stake size and delay satisfy all requirements
    function isRelayManagerStaked(address relayManager) external view returns(bool);

    // Checks hubs' deprecation status
    function isDeprecated() external view returns (bool);

    // Returns the block number from which the hub no longer allows relaying calls.
    function deprecationBlock() external view returns (uint256);

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

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

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

interface IPaymaster {

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

    /**
     * Return the Gas Limits and msg.data max size constants used by the Paymaster.
     */
    function getGasAndDataLimits()
    external
    view
    returns (
        GasAndDataLimits memory limits
    );

    function trustedForwarder() external view returns (address);

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

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

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

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

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

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

interface IForwarder {

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

    event DomainRegistered(bytes32 indexed domainSeparator, bytes domainValue);

    event RequestTypeRegistered(bytes32 indexed typeHash, string typeStr);

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

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

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

    /**
     * Register a new Request typehash.
     * @param typeName - the name of the request type.
     * @param typeSuffix - any extra data after the generic params.
     *  (must add at least one param. The generic ForwardRequest type is always registered by the constructor)
     */
    function registerRequestType(string calldata typeName, string calldata typeSuffix) external;

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

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

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"domainValue","type":"bytes"}],"name":"DomainRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"typeHash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"typeStr","type":"string"}],"name":"RequestTypeRegistered","type":"event"},{"inputs":[],"name":"EIP712_DOMAIN_TYPE","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Meta","name":"","type":"address"}],"name":"deposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"domains","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"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":"validUntil","type":"uint256"}],"internalType":"struct IForwarder.ForwardRequest","name":"request","type":"tuple"},{"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"internalType":"bytes32","name":"requestTypeHash","type":"bytes32"},{"internalType":"bytes","name":"suffixData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"ret","type":"bytes"}],"stateMutability":"payable","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":"getHubAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"pctRelayFee","type":"uint256"},{"internalType":"uint256","name":"baseRelayFee","type":"uint256"},{"internalType":"address","name":"relayWorker","type":"address"},{"internalType":"address","name":"paymaster","type":"address"},{"internalType":"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":"getMinimumRelayFee","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRelayHubDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"pctRelayFee","type":"uint256"},{"internalType":"uint256","name":"baseRelayFee","type":"uint256"},{"internalType":"address","name":"relayWorker","type":"address"},{"internalType":"address","name":"paymaster","type":"address"},{"internalType":"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":"bytes4","name":"methodId","type":"bytes4"}],"name":"getRequiredRelayFee","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"methodId","type":"bytes4"}],"name":"getRequiredRelayGas","outputs":[{"internalType":"uint256","name":"gas","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"context","type":"bytes"},{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"gasUseWithoutPost","type":"uint256"},{"components":[{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"pctRelayFee","type":"uint256"},{"internalType":"uint256","name":"baseRelayFee","type":"uint256"},{"internalType":"address","name":"relayWorker","type":"address"},{"internalType":"address","name":"paymaster","type":"address"},{"internalType":"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":"validUntil","type":"uint256"}],"internalType":"struct IForwarder.ForwardRequest","name":"request","type":"tuple"},{"components":[{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"pctRelayFee","type":"uint256"},{"internalType":"uint256","name":"baseRelayFee","type":"uint256"},{"internalType":"address","name":"relayWorker","type":"address"},{"internalType":"address","name":"paymaster","type":"address"},{"internalType":"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":"context","type":"bytes"},{"internalType":"bool","name":"revertOnRecipientRevert","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"}],"name":"registerDomainSeparator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"typeName","type":"string"},{"internalType":"string","name":"typeSuffix","type":"string"}],"name":"registerRequestType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Meta","name":"token","type":"address"},{"internalType":"contract IUniswapV3Pool","name":"pool","type":"address"}],"name":"registerToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Meta","name":"","type":"address"}],"name":"registeredTokenPool","outputs":[{"internalType":"contract IUniswapV3Pool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Meta","name":"token","type":"address"}],"name":"registeredTokenPoolFee","outputs":[{"internalType":"uint24","name":"fee","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requiredRelayGas","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"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"}],"name":"setGasAndDataLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"gas","type":"uint256"}],"name":"setMaxRequiredRelayGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IRelayHub","name":"hub","type":"address"}],"name":"setRelayHub","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"methodId","type":"bytes4"},{"internalType":"uint256","name":"gas","type":"uint256"}],"name":"setRequiredRelayGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IWrappedChainToken","name":"_wrappedChainToken","type":"address"}],"name":"setWrappedChainToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Meta","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Meta","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"approval","type":"uint256"},{"internalType":"bytes32","name":"sigR","type":"bytes32"},{"internalType":"bytes32","name":"sigS","type":"bytes32"},{"internalType":"uint8","name":"sigV","type":"uint8"}],"name":"transferWithApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trustedForwarder","outputs":[{"internalType":"address","name":"forwarder","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"typeHashes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Meta","name":"token","type":"address"}],"name":"unregisterToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"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":"validUntil","type":"uint256"}],"internalType":"struct IForwarder.ForwardRequest","name":"forwardRequest","type":"tuple"},{"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"internalType":"bytes32","name":"requestTypeHash","type":"bytes32"},{"internalType":"bytes","name":"suffixData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"verify","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"versionPaymaster","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"versionRecipient","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"target","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"target","type":"address"}],"name":"withdrawRelayHubDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Meta","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"target","type":"address"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrappedChainToken","outputs":[{"internalType":"contract IWrappedChainToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

6101006040526203d090608081905260a0819052620186a060c081905261080060e081905260048390556005929092556006556007556207a1206009556000600d553480156200004e57600080fd5b50620000636200005d6200017a565b62000196565b620000a96040518060800160405280605d8152602001620047eb605d913960405160200162000093919062000458565b60408051601f19818403018152919052620001e6565b620001146040518060400160405280600c81526020016b14995b185e54995c5d595cdd60a21b8152506040518060e0016040528060a181526020016200484860a19139604051602001620000fe91906200049c565b60408051601f198184030181529190526200024b565b620001746040518060400160405280601781526020017f47534e2052656c61796564205472616e73616374696f6e000000000000000000815250604051806040016040528060018152602001601960f91b8152506200035f60201b60201c565b620005d0565b6000620001916200042e60201b62001ade1760201c565b905090565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b805160208083019190912060008181526002909252604091829020805460ff19166001179055905181907f64d6bce64323458c44643c51fe45113efc882082f7b7fd5f09f0d69d2eedb202906200023f90859062000511565b60405180910390a25050565b60005b82518110156200030a5760008382815181106200026f576200026f6200052d565b01602001516001600160f81b0319169050600560fb1b8114801590620002a35750602960f81b6001600160f81b0319821614155b620002f45760405162461bcd60e51b815260206004820152601660248201527f426173653a20696e76616c696420747970656e616d6500000000000000000000604482015260640160405180910390fd5b5080620003018162000543565b9150506200024e565b506000826040518060800160405280605d8152602001620047eb605d9139836040516020016200033d939291906200056b565b60408051601f1981840301815291905290506200035a81620001e6565b505050565b60004690506000604051806080016040528060528152602001620048e96052913980516020918201208551868301208551868401206040805194850193909352918301526060820152608081018390523060a082015260c00160408051601f19818403018152828252805160208083019190912060008181526003909252929020805460ff1916600117905592509081907f4bc68689cbe89a4a6333a3ab0a70093874da3e5bfb71e93102027f3f073687d8906200041f90859062000511565b60405180910390a25050505050565b3390565b60005b838110156200044f57818101518382015260200162000435565b50506000910152565b6e08cdee4eec2e4c8a4cae2eacae6e85608b1b8152600082516200048481600f85016020870162000432565b602960f81b600f939091019283015250601001919050565b7f52656c6179446174612072656c61794461746129000000000000000000000000815260008251620004d681601485016020870162000432565b9190910160140192915050565b60008151808452620004fd81602086016020860162000432565b601f01601f19169290920160200192915050565b602081526000620005266020830184620004e3565b9392505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016200056457634e487b7160e01b600052601160045260246000fd5b5060010190565b600084516200057f81846020890162000432565b600560fb1b90830190815284516200059f81600184016020890162000432565b600b60fa1b600192909101918201528351620005c381600284016020880162000432565b0160020195945050505050565b61420b80620005e06000396000f3fe6080604052600436106102485760003560e01c806389903b5e11610139578063bc5fd07f116100b6578063dcefecb91161007a578063dcefecb914610734578063dd12bb5b14610754578063e024dc7f1461078a578063f2fde38b146107ab578063fa461e33146107cb578063fc7e286d146107eb57600080fd5b8063bc5fd07f1461067b578063c3f28abd146106af578063c722f177146106c4578063cdc602db146106f4578063d9210be51461071457600080fd5b80639336bc31116100fd5780639336bc31146105b35780639c7b4592146105d3578063ad9f99c7146105f3578063b039a88f14610613578063b41b23cd1461065b57600080fd5b806389903b5e146105205780638d89149b146105405780638da5cb5b146105605780639031b76f1461057e578063921276ea1461059e57600080fd5b80634739f7e5116101c757806375bf9f9f1161018b57806375bf9f9f1461049857806376fa01c3146104ad57806377860cdd146104cd5780637bb05264146104ed5780637da0a8771461050d57600080fd5b80634739f7e5146103e6578063486ff0cd14610406578063572b6c0514610428578063715018a61461045157806374e861d61461046657600080fd5b80632afe31c11161020e5780632afe31c11461033b5780632d0335ab1461035057806330e3db9514610386578063335a9406146103a65780633ccdbb28146103c657600080fd5b8062be5dd414610254578062f714ce1461028b5780630fffb977146102ad5780631c8216c5146102db57806321fe98df146102fb57600080fd5b3661024f57005b600080fd5b34801561026057600080fd5b5061027461026f366004613276565b610818565b60405161028292919061336a565b60405180910390f35b34801561029757600080fd5b506102ab6102a63660046133a3565b610ad2565b005b3480156102b957600080fd5b506102cd6102c83660046133eb565b610b15565b604051908152602001610282565b3480156102e757600080fd5b506102cd6102f636600461341f565b610b41565b34801561030757600080fd5b5061032b61031636600461346c565b60026020526000908152604090205460ff1681565b6040519015158152602001610282565b34801561034757600080fd5b506102cd610bc4565b34801561035c57600080fd5b506102cd61036b366004613490565b6001600160a01b03166000908152600e602052604090205490565b34801561039257600080fd5b506102ab6103a1366004613490565b610c36565b3480156103b257600080fd5b506102ab6103c13660046134ad565b610d85565b3480156103d257600080fd5b506102ab6103e13660046134f5565b610e1d565b3480156103f257600080fd5b506102ab610401366004613537565b610f61565b34801561041257600080fd5b5061041b611062565b6040516102829190613565565b34801561043457600080fd5b5061032b610443366004613490565b6001600160a01b0316301490565b34801561045d57600080fd5b506102ab611082565b34801561047257600080fd5b506001546001600160a01b03165b6040516001600160a01b039091168152602001610282565b3480156104a457600080fd5b506009546102cd565b3480156104b957600080fd5b506102ab6104c8366004613586565b611096565b3480156104d957600080fd5b506102ab6104e8366004613490565b6110d9565b3480156104f957600080fd5b506102ab610508366004613490565b61117f565b34801561051957600080fd5b5030610480565b34801561052c57600080fd5b506102ab61053b36600461360d565b6111a9565b34801561054c57600080fd5b506102ab61055b36600461361f565b6111cf565b34801561056c57600080fd5b506000546001600160a01b0316610480565b34801561058a57600080fd5b506102cd6105993660046136a1565b611283565b3480156105aa57600080fd5b5061041b611305565b3480156105bf57600080fd5b50600a54610480906001600160a01b031681565b3480156105df57600080fd5b506102ab6105ee3660046136dd565b611325565b3480156105ff57600080fd5b506102ab61060e366004613748565b61139e565b34801561061f57600080fd5b50610628611425565b60405161028291908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b34801561066757600080fd5b506102ab61067636600461346c565b61147d565b34801561068757600080fd5b5061069b610696366004613490565b61148a565b60405162ffffff9091168152602001610282565b3480156106bb57600080fd5b5061041b61152e565b3480156106d057600080fd5b5061032b6106df36600461346c565b60036020526000908152604090205460ff1681565b34801561070057600080fd5b506102ab61070f3660046133a3565b61154a565b34801561072057600080fd5b506102ab61072f3660046136dd565b6115b2565b34801561074057600080fd5b506102ab61074f3660046137f7565b611625565b34801561076057600080fd5b5061048061076f366004613490565b600b602052600090815260409020546001600160a01b031681565b61079d610798366004613748565b61165d565b604051610282929190613821565b3480156107b757600080fd5b506102ab6107c6366004613490565b6117f8565b3480156107d757600080fd5b506102ab6107e636600461383c565b61186e565b3480156107f757600080fd5b506102cd610806366004613490565b600c6020526000908152604090205481565b6060600061082e6001546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146108675760405162461bcd60e51b815260040161085e90613882565b60405180910390fd5b873061087382806138b9565b610884906040810190602001613490565b6001600160a01b0316146108da5760405162461bcd60e51b815260206004820152601860248201527f426173653a20696c6c6567616c20726571756573742e746f0000000000000000604482015260640161085e565b306108e58a806138b9565b6108f6906040810190602001613490565b6001600160a01b03161461094c5760405162461bcd60e51b815260206004820152601860248201527f4d6574613a20696c6c6567616c20726571756573742e746f0000000000000000604482015260640161085e565b6109676109598a806138b9565b61036b906020810190613490565b6109718a806138b9565b60800135146109b85760405162461bcd60e51b81526020600482015260136024820152724d6574613a20496e76616c6964206e6f6e636560681b604482015260640161085e565b60008080610a606109c98d806138b9565b6109d2906139c4565b6109df60208f018f613a54565b8d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611ae292505050565b9250925092508060200151600014610a9557610a95610a7f8d806138b9565b610a8d906020810190613490565b848484611ccd565b610a9e82611ceb565b81604051602001610aaf9190613a6a565b60408051601f198184030181529190529c60019c509a5050505050505050505050565b610ada611efa565b6040516001600160a01b0382169083156108fc029084906000818181858888f19350505050158015610b10573d6000803e3d6000fd5b505050565b6001600160e01b0319811660009081526008602052604081205490819003610b3c57506009545b919050565b6001546000906001600160a01b0316638e53548b610b5e84610b15565b856040518363ffffffff1660e01b8152600401610b7c929190613b11565b602060405180830381865afa158015610b99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bbd9190613bc4565b9392505050565b6001546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015610c0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c319190613bc4565b905090565b610c3e611efa565b600d5415610c8e5760405162461bcd60e51b815260206004820152601760248201527f426173653a20746f6b656e732072656769737465726564000000000000000000604482015260640161085e565b600a80546001600160a01b0383166001600160a01b0319909116811790915563095ea7b3610cc46000546001600160a01b031690565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260001960248201526044016020604051808303816000875af1158015610d12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d369190613bdd565b610d825760405162461bcd60e51b815260206004820152601b60248201527f426173653a206f776e657220617070726f76616c206661696c65640000000000604482015260640161085e565b50565b60006040518060600160405280866001600160a01b03168152602001858152602001846001600160a01b0316815250905060006040518060800160405280876001600160a01b03168152602001336001600160a01b0316815260200184815260200160008152509050610df9338383611f54565b610e0281611ceb565b610e0c3383612034565b610e1581612109565b505050505050565b610e25611efa565b6040516370a0823160e01b81523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa158015610e6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e909190613bc4565b6001600160a01b0385166000908152600c6020526040902054909150811015610eb857600080fd5b6001600160a01b0384166000908152600c6020526040902054610edb9082613c10565b831115610ee757600080fd5b60405163a9059cbb60e01b81526001600160a01b0383811660048301526024820185905285169063a9059cbb906044016020604051808303816000875af1158015610f36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5a9190613bdd565b5050505050565b610f69611efa565b6001600160a01b038116610fb75760405162461bcd60e51b815260206004820152601560248201527410985cd94e88139bc81c1bdbdb081919599a5b9959605a1b604482015260640161085e565b6001600160a01b038281166000908152600b6020526040902054161561101f5760405162461bcd60e51b815260206004820152601e60248201527f426173653a20746f6b656e20616c726561647920726567697374657265640000604482015260640161085e565b6001600160a01b038281166000908152600b6020526040902080546001600160a01b031916918316919091179055600d5461105b906001613c23565b600d555050565b60606040518060600160405280602981526020016141ad60299139905090565b61108a611efa565b61109460006121c6565b565b6001546001600160a01b031633146110c05760405162461bcd60e51b815260040161085e90613882565b60006110ce85870187613c36565b9050610e1581612109565b6110e1611efa565b6001600160a01b038082166000908152600b602052604090205482911661114a5760405162461bcd60e51b815260206004820152601a60248201527f426173653a20746f6b656e206e6f742072656769737465726564000000000000604482015260640161085e565b6001600160a01b0382166000908152600b6020526040902080546001600160a01b0319169055600d5461105b90600190613c10565b611187611efa565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6111b1611efa565b80356004556020810135600555604081013560065560600135600755565b60408051606080820183526001600160a01b03808c1680845260208085018d9052918b1684860152845160808082018752828252338285018190528288018d9052600083870152875160a0810189529384529383018b905295820189905292810187905260ff8616948101949094529192909161124e90848484612216565b61125a33848484611ccd565b61126382611ceb565b61126d3384612034565b61127682612109565b5050505050505050505050565b6001546000906001600160a01b0316638e53548b6112a060095490565b846040518363ffffffff1660e01b81526004016112be929190613b11565b602060405180830381865afa1580156112db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ff9190613bc4565b92915050565b606060405180606001604052806029815260200161413260299139905090565b61139884848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8801819004810282018101909252868152925086915085908190840183828082843760009201919091525061230e92505050565b50505050565b61141c6113aa886139c4565b878787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b0181900481028201810190925289815292508991508890819084018382808284376000920191909152506123da92505050565b50505050505050565b6114506040518060800160405280600081526020016000815260200160008152602001600081525090565b50604080516080810182526004548152600554602082015260065491810191909152600754606082015290565b611485611efa565b600955565b6001600160a01b038181166000908152600b602052604081205490911615611526576001600160a01b038083166000908152600b602090815260409182902054825163ddca3f4360e01b8152925193169263ddca3f439260048082019392918290030181865afa158015611502573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ff9190613caa565b506000919050565b60405180608001604052806052815260200161415b6052913981565b611552611efa565b600154604051627b8a6760e11b8152600481018490526001600160a01b0383811660248301529091169062f714ce90604401600060405180830381600087803b15801561159e57600080fd5b505af1158015610e15573d6000803e3d6000fd5b61139884848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f880181900481028201810190925286815292508691508590819084018382808284376000920191909152506125b792505050565b61162d611efa565b6001600160e01b0319821660009081526008602052604090208190556009548111156116595760098190555b5050565b600060606116736001546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146116a35760405162461bcd60e51b815260040161085e90613882565b60006116ef6116b560a08c018c613ccf565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506126ac92505050565b905060008061174f8361170560208f018f613490565b8e8060a001906117159190613ccf565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525092506126b9915050565b9092509050600e600061176560208f018f613490565b6001600160a01b0316815260208101919091526040016000205461178a906001613c23565b600e60008e60000160208101906117a19190613490565b6001600160a01b03168152602080820192909252604001600020919091556117d5906117cf908e018e613490565b83612034565b505060408051602081019091526000815260019b909a5098505050505050505050565b611800611efa565b6001600160a01b0381166118655760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161085e565b610d82816121c6565b600084138061187d5750600083135b61188657600080fd5b600061189482840184613c36565b80516001600160a01b039081166000908152600b60205260409020549192501633146118bf57600080fd5b600a5481516001600160a01b03918216911610600080826118e957866118e489613d15565b6118f3565b876118f388613d15565b91509150836040015182111561193f5760405162461bcd60e51b8152602060048201526011602482015270426173653a2066656520746f6f206c6f7760781b604482015260640161085e565b836060015181146119865760405162461bcd60e51b815260206004820152601160248201527010985cd94e881c1bdbdb0819985a5b1959607a1b604482015260640161085e565b306001600160a01b031684602001516001600160a01b031603611a3857835160405163a9059cbb60e01b8152336004820152602481018490526001600160a01b039091169063a9059cbb906044016020604051808303816000875af11580156119f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a179190613bdd565b611a335760405162461bcd60e51b815260040161085e90613d31565b611ad4565b835160208501516040516323b872dd60e01b81526001600160a01b039182166004820152336024820152604481018590529116906323b872dd906064016020604051808303816000875af1158015611a94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab89190613bdd565b611ad45760405162461bcd60e51b815260040161085e90613d31565b5050505050505050565b3390565b6040805160608101825260008082526020820181905291810191909152611b076131fb565b6040805160a081018252600080825260208201819052918101829052606081018290526080810182905290611b3b8761278d565b604051602001611b4d91815260200190565b60408051601f1981840301815291905290506000611b79611b7460c08a0160a08b01613490565b61288b565b9050611c2389826040518060400160405280600c81526020016b14995b185e54995c5d595cdd60a21b8152506040518060800160405280605d8152602001614034605d91396040518060e0016040528060a1815260200161409160a19139604051602001611be79190613d68565b60408051601f1981840301815290829052611c06939291602001613da4565b60405160208183030381529060405280519060200120858b6123da565b6000611c328a60a001516126ac565b9050611c51818b600001518c60a00151611c4c8d86610b41565b6126b9565b9096509450636652b5fd60e11b6001600160e01b0319821601611c80578951611c7b908787611f54565b611cc0565b637276eb6560e01b6001600160e01b0319821601611cc057611cae8a60a00151876000015160046005612904565b9350611cc08a60000151878787612216565b5050509450945094915050565b611398848284604001518660200151611ce69190613c23565b61299d565b604081015115611eb457606081015115611e1257600a5481516001600160a01b039081166000818152600b602052604081205460608601519484169092109390928392169063128acb089030908690611d4390612a20565b611d4c90613d15565b87611d7557611d70600173fffd8963efd1fc6a506488495d951d5263988d26613e03565b611d85565b611d856401000276a36001613e2a565b89604051602001611d969190613a6a565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401611dc5959493929190613e4a565b60408051808303816000875af1158015611de3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e079190613e90565b50610d829350505050565b8051602082015160408084015190516323b872dd60e01b81526001600160a01b03928316600482015230602482015260448101919091529116906323b872dd906064016020604051808303816000875af1158015611e74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e989190613bdd565b610d825760405162461bcd60e51b815260040161085e90613d31565b606081015115610d825760405162461bcd60e51b8152602060048201526011602482015270426173653a2046656520746f6f206c6f7760781b604482015260640161085e565b6000546001600160a01b031633146110945760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161085e565b611f5f838383612a8e565b80604001518260200151611f739190613c23565b8251604051636eb1769f60e11b81526001600160a01b0386811660048301523060248301529091169063dd62ed3e90604401602060405180830381865afa158015611fc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fe69190613bc4565b1015610b105760405162461bcd60e51b815260206004820152601760248201527f4d6574613a20616c6c6f77616e636520746f6f206c6f77000000000000000000604482015260640161085e565b8051604080830151602084015191516323b872dd60e01b81526001600160a01b03868116600483015291821660248201526044810192909252909116906323b872dd906064016020604051808303816000875af1158015612099573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bd9190613bdd565b6116595760405162461bcd60e51b815260206004820152601b60248201527f4d6574613a2056616c7565207472616e73666572206661696c65640000000000604482015260640161085e565b606081015115610d8257600a546060820151604051632e1a7d4d60e01b81526001600160a01b0390921691632e1a7d4d9161214a9160040190815260200190565b600060405180830381600087803b15801561216457600080fd5b505af1158015612178573d6000803e3d6000fd5b5050600154606084015160405163aa67c91960e01b81523060048201526001600160a01b03909216935063aa67c9199250906024016000604051808303818588803b15801561159e57600080fd5b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b612221848484612a8e565b816040015183602001516122359190613c23565b8351604051636eb1769f60e11b81526001600160a01b0387811660048301523060248301529091169063dd62ed3e90604401602060405180830381865afa158015612284573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122a89190613bc4565b101561139857816040015183602001516122c29190613c23565b816020015110156113985760405162461bcd60e51b81526020600482015260166024820152754d6574613a20617070726f76616c20746f6f206c6f7760501b604482015260640161085e565b6000469050600060405180608001604052806052815260200161415b6052913980516020918201208551868301208551868401206040805194850193909352918301526060820152608081018390523060a082015260c00160408051601f19818403018152828252805160208083019190912060008181526003909252929020805460ff1916600117905592509081907f4bc68689cbe89a4a6333a3ab0a70093874da3e5bfb71e93102027f3f073687d8906123cb908590613565565b60405180910390a25050505050565b60008481526003602052604090205460ff166124385760405162461bcd60e51b815260206004820152601e60248201527f426173653a20756e7265676973746572656420646f6d61696e207365702e0000604482015260640161085e565b60008381526002602052604090205460ff166124965760405162461bcd60e51b815260206004820152601b60248201527f426173653a20756e726567697374657265642074797065686173680000000000604482015260640161085e565b60008386600001516001600160a01b031687602001516001600160a01b0316886040015189606001518a608001518b60a00151805190602001208c60c001518a6040516020016124ee99989796959493929190613eb4565b6040516020818303038152906040529050600085828051906020012060405160200161253192919061190160f01b81526002810192909252602282015260420190565b60408051601f19818403018152919052805160209091012087519091506001600160a01b03166125618285612c16565b6001600160a01b03161461141c5760405162461bcd60e51b815260206004820152601860248201527f426173653a207369676e6174757265206d69736d617463680000000000000000604482015260640161085e565b60005b82518110156126625760008382815181106125d7576125d7613f0d565b01602001516001600160f81b0319169050600560fb1b811480159061260a5750602960f81b6001600160f81b0319821614155b61264f5760405162461bcd60e51b8152602060048201526016602482015275426173653a20696e76616c696420747970656e616d6560501b604482015260640161085e565b508061265a81613f23565b9150506125ba565b506000826040518060800160405280605d8152602001614034605d91398360405160200161269293929190613da4565b6040516020818303038152906040529050610b1081612c3a565b60006112ff826000612c9d565b60408051606081018252600080825260208201819052918101919091526126de6131fb565b6001600160e01b031986166319ad4a0360e11b148061270d57506001600160e01b03198616638d89149b60e01b145b1561273c5761272184600060016002612d0d565b915061273584836000015187600387612d7a565b9050612784565b60405162461bcd60e51b815260206004820152601860248201527f4d6574613a20756e737570706f72746564206d6574686f640000000000000000604482015260640161085e565b94509492505050565b60006040518060e0016040528060a1815260200161409160a1913980516020918201209083359084013560408501356127cc6080870160608801613490565b6127dc60a0880160808901613490565b6127ec60c0890160a08a01613490565b6127f960c08a018a613ccf565b604051612807929190613f3c565b60405190819003812061286e989796959493929160e08c0135906020019889526020890197909752604088019590955260608701939093526001600160a01b039182166080870152811660a08601521660c084015260e08301526101008201526101200190565b604051602081830303815290604052805190602001209050919050565b6040805160c0810182526017608082019081527f47534e2052656c61796564205472616e73616374696f6e00000000000000000060a083015281528151808301835260018152601960f91b6020808301919091528201526000916112ff91908101468152602001846001600160a01b0316815250612dc7565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040518060a00160405280856001600160a01b031681526020016129538786612e47565b81526020016129628785612e47565b815260200161297b87612976866001613c23565b612e47565b815260200161298f87612976866002613c23565b60ff16905295945050505050565b8151604051636eb1769f60e11b81526001600160a01b0385811660048301523060248301528392169063dd62ed3e90604401602060405180830381865afa1580156129ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a109190613bc4565b1015610b1057610b108383612e68565b60006001600160ff1b03821115612a8a5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b606482015260840161085e565b5090565b600a546001600160a01b0316612ae65760405162461bcd60e51b815260206004820152601c60248201527f426173653a206e6f207772617070656420636861696e20746f6b656e00000000604482015260640161085e565b81516001600160a01b038082166000908152600b602052604090205416612b4f5760405162461bcd60e51b815260206004820152601a60248201527f426173653a20746f6b656e206e6f742072656769737465726564000000000000604482015260640161085e565b81604001518360200151612b639190613c23565b83516040516370a0823160e01b81526001600160a01b038781166004830152909116906370a0823190602401602060405180830381865afa158015612bac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd09190613bc4565b10156113985760405162461bcd60e51b81526020600482015260156024820152744d6574613a2062616c616e636520746f6f206c6f7760581b604482015260640161085e565b6000806000612c258585612f39565b91509150612c3281612f7e565b509392505050565b805160208083019190912060008181526002909252604091829020805460ff19166001179055905181907f64d6bce64323458c44643c51fe45113efc882082f7b7fd5f09f0d69d2eedb20290612c91908590613565565b60405180910390a25050565b6000612caa826004613c23565b83511015612cfa5760405162461bcd60e51b815260206004820152601a60248201527f726561644279746573343a206461746120746f6f2073686f7274000000000000604482015260640161085e565b5001602001516001600160e01b03191690565b60408051606081018252600080825260208201819052918101919091526040518060600160405280612d3f8787612e47565b6001600160a01b03168152602001612d578786612e47565b8152602001612d668785612e47565b6001600160a01b0316905295945050505050565b612d826131fb565b6040518060800160405280866001600160a01b03168152602001856001600160a01b03168152602001612db58886612e47565b81526020019290925250949350505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8260000151805190602001208360200151805190602001208460400151856060015160405160200161286e9594939291909485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b6000610bbd83612e58846020613f4c565b612e63906004613c23565b6130c8565b6020810151604051306024820152604481019190915260009060640160408051601f198184030181529181526020820180516001600160e01b031663095ea7b360e01b179052835184820151606086015160808701519351630314f14760e21b81529495506001600160a01b0390921693630c53c51c93612ef29389938893909290600401613f63565b6000604051808303816000875af1158015612f11573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113989190810190613fa7565b6000808251604103612f6f5760208301516040840151606085015160001a612f63878285856130d4565b94509450505050612f77565b506000905060025b9250929050565b6000816004811115612f9257612f9261401d565b03612f9a5750565b6001816004811115612fae57612fae61401d565b03612ffb5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161085e565b600281600481111561300f5761300f61401d565b0361305c5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161085e565b60038160048111156130705761307061401d565b03610d825760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161085e565b6000610bbd8383613195565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561310b5750600090506003612784565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561315f573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661318857600060019250925050612784565b9660009650945050505050565b60006131a2826020613c23565b835110156131f25760405162461bcd60e51b815260206004820152601b60248201527f72656164427974657333323a206461746120746f6f2073686f72740000000000604482015260640161085e565b50016020015190565b604051806080016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081525090565b60008083601f84011261324757600080fd5b5081356001600160401b0381111561325e57600080fd5b602083019150836020828501011115612f7757600080fd5b6000806000806000806080878903121561328f57600080fd5b86356001600160401b03808211156132a657600080fd5b908801906040828b0312156132ba57600080fd5b909650602088013590808211156132d057600080fd5b6132dc8a838b01613235565b909750955060408901359150808211156132f557600080fd5b5061330289828a01613235565b979a9699509497949695606090950135949350505050565b60005b8381101561333557818101518382015260200161331d565b50506000910152565b6000815180845261335681602086016020860161331a565b601f01601f19169290920160200192915050565b60408152600061337d604083018561333e565b905082151560208301529392505050565b6001600160a01b0381168114610d8257600080fd5b600080604083850312156133b657600080fd5b8235915060208301356133c88161338e565b809150509250929050565b80356001600160e01b031981168114610b3c57600080fd5b6000602082840312156133fd57600080fd5b610bbd826133d3565b6000610100828403121561341957600080fd5b50919050565b6000806040838503121561343257600080fd5b82356001600160401b0381111561344857600080fd5b61345485828601613406565b925050613463602084016133d3565b90509250929050565b60006020828403121561347e57600080fd5b5035919050565b8035610b3c8161338e565b6000602082840312156134a257600080fd5b8135610bbd8161338e565b600080600080608085870312156134c357600080fd5b84356134ce8161338e565b93506020850135925060408501356134e58161338e565b9396929550929360600135925050565b60008060006060848603121561350a57600080fd5b83356135158161338e565b925060208401359150604084013561352c8161338e565b809150509250925092565b6000806040838503121561354a57600080fd5b82356135558161338e565b915060208301356133c88161338e565b602081526000610bbd602083018461333e565b8015158114610d8257600080fd5b60008060008060006080868803121561359e57600080fd5b85356001600160401b03808211156135b557600080fd5b6135c189838a01613235565b9097509550602088013591506135d682613578565b90935060408701359250606087013590808211156135f357600080fd5b5061360088828901613406565b9150509295509295909350565b60006080828403121561341957600080fd5b600080600080600080600080610100898b03121561363c57600080fd5b88356136478161338e565b975060208901359650604089013561365e8161338e565b9550606089013594506080890135935060a0890135925060c0890135915060e089013560ff8116811461369057600080fd5b809150509295985092959890939650565b6000602082840312156136b357600080fd5b81356001600160401b038111156136c957600080fd5b6136d584828501613406565b949350505050565b600080600080604085870312156136f357600080fd5b84356001600160401b038082111561370a57600080fd5b61371688838901613235565b9096509450602087013591508082111561372f57600080fd5b5061373c87828801613235565b95989497509550505050565b600080600080600080600060a0888a03121561376357600080fd5b87356001600160401b038082111561377a57600080fd5b9089019060e0828c03121561378e57600080fd5b9097506020890135965060408901359550606089013590808211156137b257600080fd5b6137be8b838c01613235565b909650945060808a01359150808211156137d757600080fd5b506137e48a828b01613235565b989b979a50959850939692959293505050565b6000806040838503121561380a57600080fd5b613813836133d3565b946020939093013593505050565b82151581526040602082015260006136d5604083018461333e565b6000806000806060858703121561385257600080fd5b843593506020850135925060408501356001600160401b0381111561387657600080fd5b61373c87828801613235565b60208082526018908201527f426173653a20696c6c6567616c206d73672e73656e6465720000000000000000604082015260600190565b6000823560de198336030181126138cf57600080fd5b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b0381118282101715613911576139116138d9565b60405290565b604051601f8201601f191681016001600160401b038111828210171561393f5761393f6138d9565b604052919050565b60006001600160401b03821115613960576139606138d9565b50601f01601f191660200190565b600082601f83011261397f57600080fd5b813561399261398d82613947565b613917565b8181528460208386010111156139a757600080fd5b816020850160208301376000918101602001919091529392505050565b600060e082360312156139d657600080fd5b6139de6138ef565b6139e783613485565b81526139f560208401613485565b602082015260408301356040820152606083013560608201526080830135608082015260a08301356001600160401b03811115613a3157600080fd5b613a3d3682860161396e565b60a08301525060c092830135928101929092525090565b6000823560fe198336030181126138cf57600080fd5b81516001600160a01b03908116825260208084015190911690820152604080830151908201526060918201519181019190915260800190565b6000808335601e19843603018112613aba57600080fd5b83016020810192503590506001600160401b03811115613ad957600080fd5b803603821315612f7757600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8281526040602082015281356040820152602082013560608201526040820135608082015260006060830135613b468161338e565b6001600160a01b031660a0830152613b6060808401613485565b6001600160a01b031660c0830152613b7a60a08401613485565b6001600160a01b031660e0830152613b9560c0840184613aa3565b61010084810152613bab61014085018284613ae8565b91505060e0840135610120840152809150509392505050565b600060208284031215613bd657600080fd5b5051919050565b600060208284031215613bef57600080fd5b8151610bbd81613578565b634e487b7160e01b600052601160045260246000fd5b818103818111156112ff576112ff613bfa565b808201808211156112ff576112ff613bfa565b600060808284031215613c4857600080fd5b604051608081018181106001600160401b0382111715613c6a57613c6a6138d9565b6040528235613c788161338e565b81526020830135613c888161338e565b6020820152604083810135908201526060928301359281019290925250919050565b600060208284031215613cbc57600080fd5b815162ffffff81168114610bbd57600080fd5b6000808335601e19843603018112613ce657600080fd5b8301803591506001600160401b03821115613d0057600080fd5b602001915036819003821315612f7757600080fd5b6000600160ff1b8201613d2a57613d2a613bfa565b5060000390565b60208082526019908201527f426173653a20466565207472616e73666572206661696c656400000000000000604082015260600190565b7352656c6179446174612072656c6179446174612960601b815260008251613d9781601485016020870161331a565b9190910160140192915050565b60008451613db681846020890161331a565b600560fb1b9083019081528451613dd481600184016020890161331a565b600b60fa1b600192909101918201528351613df681600284016020880161331a565b0160020195945050505050565b6001600160a01b03828116828216039080821115613e2357613e23613bfa565b5092915050565b6001600160a01b03818116838216019080821115613e2357613e23613bfa565b6001600160a01b0386811682528515156020830152604082018590528316606082015260a060808201819052600090613e859083018461333e565b979650505050505050565b60008060408385031215613ea357600080fd5b505080516020909101519092909150565b8981528860208201528760408201528660608201528560808201528460a08201528360c08201528260e082015260006101008351613ef8818386016020880161331a565b929092019091019a9950505050505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201613f3557613f35613bfa565b5060010190565b8183823760009101908152919050565b80820281158282048414176112ff576112ff613bfa565b6001600160a01b038616815260a060208201819052600090613f879083018761333e565b604083019590955250606081019290925260ff1660809091015292915050565b600060208284031215613fb957600080fd5b81516001600160401b03811115613fcf57600080fd5b8201601f81018413613fe057600080fd5b8051613fee61398d82613947565b81815285602083850101111561400357600080fd5b61401482602083016020860161331a565b95945050505050565b634e487b7160e01b600052602160045260246000fdfe616464726573732066726f6d2c6164647265737320746f2c75696e743235362076616c75652c75696e74323536206761732c75696e74323536206e6f6e63652c627974657320646174612c75696e743235362076616c6964556e74696c52656c6179446174612875696e743235362067617350726963652c75696e743235362070637452656c61794665652c75696e74323536206261736552656c61794665652c616464726573732072656c6179576f726b65722c61646472657373207061796d61737465722c6164647265737320666f727761726465722c6279746573207061796d6173746572446174612c75696e7432353620636c69656e74496429322e322e362b6f70656e67736e2e7061796d61737465722e65726332306d6574612e68616e646c6572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429322e322e362b6f70656e67736e2e726563697069656e742e65726332306d6574612e68616e646c6572a264697066735822122074be3b18ed1576ab6989000cf3c0a1548412c7851b4bdbc27c2dcc720938938064736f6c63430008110033616464726573732066726f6d2c6164647265737320746f2c75696e743235362076616c75652c75696e74323536206761732c75696e74323536206e6f6e63652c627974657320646174612c75696e743235362076616c6964556e74696c52656c6179446174612875696e743235362067617350726963652c75696e743235362070637452656c61794665652c75696e74323536206261736552656c61794665652c616464726573732072656c6179576f726b65722c61646472657373207061796d61737465722c6164647265737320666f727761726465722c6279746573207061796d6173746572446174612c75696e7432353620636c69656e74496429454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429

Deployed Bytecode

0x6080604052600436106102485760003560e01c806389903b5e11610139578063bc5fd07f116100b6578063dcefecb91161007a578063dcefecb914610734578063dd12bb5b14610754578063e024dc7f1461078a578063f2fde38b146107ab578063fa461e33146107cb578063fc7e286d146107eb57600080fd5b8063bc5fd07f1461067b578063c3f28abd146106af578063c722f177146106c4578063cdc602db146106f4578063d9210be51461071457600080fd5b80639336bc31116100fd5780639336bc31146105b35780639c7b4592146105d3578063ad9f99c7146105f3578063b039a88f14610613578063b41b23cd1461065b57600080fd5b806389903b5e146105205780638d89149b146105405780638da5cb5b146105605780639031b76f1461057e578063921276ea1461059e57600080fd5b80634739f7e5116101c757806375bf9f9f1161018b57806375bf9f9f1461049857806376fa01c3146104ad57806377860cdd146104cd5780637bb05264146104ed5780637da0a8771461050d57600080fd5b80634739f7e5146103e6578063486ff0cd14610406578063572b6c0514610428578063715018a61461045157806374e861d61461046657600080fd5b80632afe31c11161020e5780632afe31c11461033b5780632d0335ab1461035057806330e3db9514610386578063335a9406146103a65780633ccdbb28146103c657600080fd5b8062be5dd414610254578062f714ce1461028b5780630fffb977146102ad5780631c8216c5146102db57806321fe98df146102fb57600080fd5b3661024f57005b600080fd5b34801561026057600080fd5b5061027461026f366004613276565b610818565b60405161028292919061336a565b60405180910390f35b34801561029757600080fd5b506102ab6102a63660046133a3565b610ad2565b005b3480156102b957600080fd5b506102cd6102c83660046133eb565b610b15565b604051908152602001610282565b3480156102e757600080fd5b506102cd6102f636600461341f565b610b41565b34801561030757600080fd5b5061032b61031636600461346c565b60026020526000908152604090205460ff1681565b6040519015158152602001610282565b34801561034757600080fd5b506102cd610bc4565b34801561035c57600080fd5b506102cd61036b366004613490565b6001600160a01b03166000908152600e602052604090205490565b34801561039257600080fd5b506102ab6103a1366004613490565b610c36565b3480156103b257600080fd5b506102ab6103c13660046134ad565b610d85565b3480156103d257600080fd5b506102ab6103e13660046134f5565b610e1d565b3480156103f257600080fd5b506102ab610401366004613537565b610f61565b34801561041257600080fd5b5061041b611062565b6040516102829190613565565b34801561043457600080fd5b5061032b610443366004613490565b6001600160a01b0316301490565b34801561045d57600080fd5b506102ab611082565b34801561047257600080fd5b506001546001600160a01b03165b6040516001600160a01b039091168152602001610282565b3480156104a457600080fd5b506009546102cd565b3480156104b957600080fd5b506102ab6104c8366004613586565b611096565b3480156104d957600080fd5b506102ab6104e8366004613490565b6110d9565b3480156104f957600080fd5b506102ab610508366004613490565b61117f565b34801561051957600080fd5b5030610480565b34801561052c57600080fd5b506102ab61053b36600461360d565b6111a9565b34801561054c57600080fd5b506102ab61055b36600461361f565b6111cf565b34801561056c57600080fd5b506000546001600160a01b0316610480565b34801561058a57600080fd5b506102cd6105993660046136a1565b611283565b3480156105aa57600080fd5b5061041b611305565b3480156105bf57600080fd5b50600a54610480906001600160a01b031681565b3480156105df57600080fd5b506102ab6105ee3660046136dd565b611325565b3480156105ff57600080fd5b506102ab61060e366004613748565b61139e565b34801561061f57600080fd5b50610628611425565b60405161028291908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b34801561066757600080fd5b506102ab61067636600461346c565b61147d565b34801561068757600080fd5b5061069b610696366004613490565b61148a565b60405162ffffff9091168152602001610282565b3480156106bb57600080fd5b5061041b61152e565b3480156106d057600080fd5b5061032b6106df36600461346c565b60036020526000908152604090205460ff1681565b34801561070057600080fd5b506102ab61070f3660046133a3565b61154a565b34801561072057600080fd5b506102ab61072f3660046136dd565b6115b2565b34801561074057600080fd5b506102ab61074f3660046137f7565b611625565b34801561076057600080fd5b5061048061076f366004613490565b600b602052600090815260409020546001600160a01b031681565b61079d610798366004613748565b61165d565b604051610282929190613821565b3480156107b757600080fd5b506102ab6107c6366004613490565b6117f8565b3480156107d757600080fd5b506102ab6107e636600461383c565b61186e565b3480156107f757600080fd5b506102cd610806366004613490565b600c6020526000908152604090205481565b6060600061082e6001546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146108675760405162461bcd60e51b815260040161085e90613882565b60405180910390fd5b873061087382806138b9565b610884906040810190602001613490565b6001600160a01b0316146108da5760405162461bcd60e51b815260206004820152601860248201527f426173653a20696c6c6567616c20726571756573742e746f0000000000000000604482015260640161085e565b306108e58a806138b9565b6108f6906040810190602001613490565b6001600160a01b03161461094c5760405162461bcd60e51b815260206004820152601860248201527f4d6574613a20696c6c6567616c20726571756573742e746f0000000000000000604482015260640161085e565b6109676109598a806138b9565b61036b906020810190613490565b6109718a806138b9565b60800135146109b85760405162461bcd60e51b81526020600482015260136024820152724d6574613a20496e76616c6964206e6f6e636560681b604482015260640161085e565b60008080610a606109c98d806138b9565b6109d2906139c4565b6109df60208f018f613a54565b8d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611ae292505050565b9250925092508060200151600014610a9557610a95610a7f8d806138b9565b610a8d906020810190613490565b848484611ccd565b610a9e82611ceb565b81604051602001610aaf9190613a6a565b60408051601f198184030181529190529c60019c509a5050505050505050505050565b610ada611efa565b6040516001600160a01b0382169083156108fc029084906000818181858888f19350505050158015610b10573d6000803e3d6000fd5b505050565b6001600160e01b0319811660009081526008602052604081205490819003610b3c57506009545b919050565b6001546000906001600160a01b0316638e53548b610b5e84610b15565b856040518363ffffffff1660e01b8152600401610b7c929190613b11565b602060405180830381865afa158015610b99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bbd9190613bc4565b9392505050565b6001546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015610c0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c319190613bc4565b905090565b610c3e611efa565b600d5415610c8e5760405162461bcd60e51b815260206004820152601760248201527f426173653a20746f6b656e732072656769737465726564000000000000000000604482015260640161085e565b600a80546001600160a01b0383166001600160a01b0319909116811790915563095ea7b3610cc46000546001600160a01b031690565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260001960248201526044016020604051808303816000875af1158015610d12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d369190613bdd565b610d825760405162461bcd60e51b815260206004820152601b60248201527f426173653a206f776e657220617070726f76616c206661696c65640000000000604482015260640161085e565b50565b60006040518060600160405280866001600160a01b03168152602001858152602001846001600160a01b0316815250905060006040518060800160405280876001600160a01b03168152602001336001600160a01b0316815260200184815260200160008152509050610df9338383611f54565b610e0281611ceb565b610e0c3383612034565b610e1581612109565b505050505050565b610e25611efa565b6040516370a0823160e01b81523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa158015610e6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e909190613bc4565b6001600160a01b0385166000908152600c6020526040902054909150811015610eb857600080fd5b6001600160a01b0384166000908152600c6020526040902054610edb9082613c10565b831115610ee757600080fd5b60405163a9059cbb60e01b81526001600160a01b0383811660048301526024820185905285169063a9059cbb906044016020604051808303816000875af1158015610f36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5a9190613bdd565b5050505050565b610f69611efa565b6001600160a01b038116610fb75760405162461bcd60e51b815260206004820152601560248201527410985cd94e88139bc81c1bdbdb081919599a5b9959605a1b604482015260640161085e565b6001600160a01b038281166000908152600b6020526040902054161561101f5760405162461bcd60e51b815260206004820152601e60248201527f426173653a20746f6b656e20616c726561647920726567697374657265640000604482015260640161085e565b6001600160a01b038281166000908152600b6020526040902080546001600160a01b031916918316919091179055600d5461105b906001613c23565b600d555050565b60606040518060600160405280602981526020016141ad60299139905090565b61108a611efa565b61109460006121c6565b565b6001546001600160a01b031633146110c05760405162461bcd60e51b815260040161085e90613882565b60006110ce85870187613c36565b9050610e1581612109565b6110e1611efa565b6001600160a01b038082166000908152600b602052604090205482911661114a5760405162461bcd60e51b815260206004820152601a60248201527f426173653a20746f6b656e206e6f742072656769737465726564000000000000604482015260640161085e565b6001600160a01b0382166000908152600b6020526040902080546001600160a01b0319169055600d5461105b90600190613c10565b611187611efa565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6111b1611efa565b80356004556020810135600555604081013560065560600135600755565b60408051606080820183526001600160a01b03808c1680845260208085018d9052918b1684860152845160808082018752828252338285018190528288018d9052600083870152875160a0810189529384529383018b905295820189905292810187905260ff8616948101949094529192909161124e90848484612216565b61125a33848484611ccd565b61126382611ceb565b61126d3384612034565b61127682612109565b5050505050505050505050565b6001546000906001600160a01b0316638e53548b6112a060095490565b846040518363ffffffff1660e01b81526004016112be929190613b11565b602060405180830381865afa1580156112db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ff9190613bc4565b92915050565b606060405180606001604052806029815260200161413260299139905090565b61139884848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8801819004810282018101909252868152925086915085908190840183828082843760009201919091525061230e92505050565b50505050565b61141c6113aa886139c4565b878787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b0181900481028201810190925289815292508991508890819084018382808284376000920191909152506123da92505050565b50505050505050565b6114506040518060800160405280600081526020016000815260200160008152602001600081525090565b50604080516080810182526004548152600554602082015260065491810191909152600754606082015290565b611485611efa565b600955565b6001600160a01b038181166000908152600b602052604081205490911615611526576001600160a01b038083166000908152600b602090815260409182902054825163ddca3f4360e01b8152925193169263ddca3f439260048082019392918290030181865afa158015611502573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ff9190613caa565b506000919050565b60405180608001604052806052815260200161415b6052913981565b611552611efa565b600154604051627b8a6760e11b8152600481018490526001600160a01b0383811660248301529091169062f714ce90604401600060405180830381600087803b15801561159e57600080fd5b505af1158015610e15573d6000803e3d6000fd5b61139884848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f880181900481028201810190925286815292508691508590819084018382808284376000920191909152506125b792505050565b61162d611efa565b6001600160e01b0319821660009081526008602052604090208190556009548111156116595760098190555b5050565b600060606116736001546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146116a35760405162461bcd60e51b815260040161085e90613882565b60006116ef6116b560a08c018c613ccf565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506126ac92505050565b905060008061174f8361170560208f018f613490565b8e8060a001906117159190613ccf565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525092506126b9915050565b9092509050600e600061176560208f018f613490565b6001600160a01b0316815260208101919091526040016000205461178a906001613c23565b600e60008e60000160208101906117a19190613490565b6001600160a01b03168152602080820192909252604001600020919091556117d5906117cf908e018e613490565b83612034565b505060408051602081019091526000815260019b909a5098505050505050505050565b611800611efa565b6001600160a01b0381166118655760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161085e565b610d82816121c6565b600084138061187d5750600083135b61188657600080fd5b600061189482840184613c36565b80516001600160a01b039081166000908152600b60205260409020549192501633146118bf57600080fd5b600a5481516001600160a01b03918216911610600080826118e957866118e489613d15565b6118f3565b876118f388613d15565b91509150836040015182111561193f5760405162461bcd60e51b8152602060048201526011602482015270426173653a2066656520746f6f206c6f7760781b604482015260640161085e565b836060015181146119865760405162461bcd60e51b815260206004820152601160248201527010985cd94e881c1bdbdb0819985a5b1959607a1b604482015260640161085e565b306001600160a01b031684602001516001600160a01b031603611a3857835160405163a9059cbb60e01b8152336004820152602481018490526001600160a01b039091169063a9059cbb906044016020604051808303816000875af11580156119f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a179190613bdd565b611a335760405162461bcd60e51b815260040161085e90613d31565b611ad4565b835160208501516040516323b872dd60e01b81526001600160a01b039182166004820152336024820152604481018590529116906323b872dd906064016020604051808303816000875af1158015611a94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab89190613bdd565b611ad45760405162461bcd60e51b815260040161085e90613d31565b5050505050505050565b3390565b6040805160608101825260008082526020820181905291810191909152611b076131fb565b6040805160a081018252600080825260208201819052918101829052606081018290526080810182905290611b3b8761278d565b604051602001611b4d91815260200190565b60408051601f1981840301815291905290506000611b79611b7460c08a0160a08b01613490565b61288b565b9050611c2389826040518060400160405280600c81526020016b14995b185e54995c5d595cdd60a21b8152506040518060800160405280605d8152602001614034605d91396040518060e0016040528060a1815260200161409160a19139604051602001611be79190613d68565b60408051601f1981840301815290829052611c06939291602001613da4565b60405160208183030381529060405280519060200120858b6123da565b6000611c328a60a001516126ac565b9050611c51818b600001518c60a00151611c4c8d86610b41565b6126b9565b9096509450636652b5fd60e11b6001600160e01b0319821601611c80578951611c7b908787611f54565b611cc0565b637276eb6560e01b6001600160e01b0319821601611cc057611cae8a60a00151876000015160046005612904565b9350611cc08a60000151878787612216565b5050509450945094915050565b611398848284604001518660200151611ce69190613c23565b61299d565b604081015115611eb457606081015115611e1257600a5481516001600160a01b039081166000818152600b602052604081205460608601519484169092109390928392169063128acb089030908690611d4390612a20565b611d4c90613d15565b87611d7557611d70600173fffd8963efd1fc6a506488495d951d5263988d26613e03565b611d85565b611d856401000276a36001613e2a565b89604051602001611d969190613a6a565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401611dc5959493929190613e4a565b60408051808303816000875af1158015611de3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e079190613e90565b50610d829350505050565b8051602082015160408084015190516323b872dd60e01b81526001600160a01b03928316600482015230602482015260448101919091529116906323b872dd906064016020604051808303816000875af1158015611e74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e989190613bdd565b610d825760405162461bcd60e51b815260040161085e90613d31565b606081015115610d825760405162461bcd60e51b8152602060048201526011602482015270426173653a2046656520746f6f206c6f7760781b604482015260640161085e565b6000546001600160a01b031633146110945760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161085e565b611f5f838383612a8e565b80604001518260200151611f739190613c23565b8251604051636eb1769f60e11b81526001600160a01b0386811660048301523060248301529091169063dd62ed3e90604401602060405180830381865afa158015611fc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fe69190613bc4565b1015610b105760405162461bcd60e51b815260206004820152601760248201527f4d6574613a20616c6c6f77616e636520746f6f206c6f77000000000000000000604482015260640161085e565b8051604080830151602084015191516323b872dd60e01b81526001600160a01b03868116600483015291821660248201526044810192909252909116906323b872dd906064016020604051808303816000875af1158015612099573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bd9190613bdd565b6116595760405162461bcd60e51b815260206004820152601b60248201527f4d6574613a2056616c7565207472616e73666572206661696c65640000000000604482015260640161085e565b606081015115610d8257600a546060820151604051632e1a7d4d60e01b81526001600160a01b0390921691632e1a7d4d9161214a9160040190815260200190565b600060405180830381600087803b15801561216457600080fd5b505af1158015612178573d6000803e3d6000fd5b5050600154606084015160405163aa67c91960e01b81523060048201526001600160a01b03909216935063aa67c9199250906024016000604051808303818588803b15801561159e57600080fd5b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b612221848484612a8e565b816040015183602001516122359190613c23565b8351604051636eb1769f60e11b81526001600160a01b0387811660048301523060248301529091169063dd62ed3e90604401602060405180830381865afa158015612284573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122a89190613bc4565b101561139857816040015183602001516122c29190613c23565b816020015110156113985760405162461bcd60e51b81526020600482015260166024820152754d6574613a20617070726f76616c20746f6f206c6f7760501b604482015260640161085e565b6000469050600060405180608001604052806052815260200161415b6052913980516020918201208551868301208551868401206040805194850193909352918301526060820152608081018390523060a082015260c00160408051601f19818403018152828252805160208083019190912060008181526003909252929020805460ff1916600117905592509081907f4bc68689cbe89a4a6333a3ab0a70093874da3e5bfb71e93102027f3f073687d8906123cb908590613565565b60405180910390a25050505050565b60008481526003602052604090205460ff166124385760405162461bcd60e51b815260206004820152601e60248201527f426173653a20756e7265676973746572656420646f6d61696e207365702e0000604482015260640161085e565b60008381526002602052604090205460ff166124965760405162461bcd60e51b815260206004820152601b60248201527f426173653a20756e726567697374657265642074797065686173680000000000604482015260640161085e565b60008386600001516001600160a01b031687602001516001600160a01b0316886040015189606001518a608001518b60a00151805190602001208c60c001518a6040516020016124ee99989796959493929190613eb4565b6040516020818303038152906040529050600085828051906020012060405160200161253192919061190160f01b81526002810192909252602282015260420190565b60408051601f19818403018152919052805160209091012087519091506001600160a01b03166125618285612c16565b6001600160a01b03161461141c5760405162461bcd60e51b815260206004820152601860248201527f426173653a207369676e6174757265206d69736d617463680000000000000000604482015260640161085e565b60005b82518110156126625760008382815181106125d7576125d7613f0d565b01602001516001600160f81b0319169050600560fb1b811480159061260a5750602960f81b6001600160f81b0319821614155b61264f5760405162461bcd60e51b8152602060048201526016602482015275426173653a20696e76616c696420747970656e616d6560501b604482015260640161085e565b508061265a81613f23565b9150506125ba565b506000826040518060800160405280605d8152602001614034605d91398360405160200161269293929190613da4565b6040516020818303038152906040529050610b1081612c3a565b60006112ff826000612c9d565b60408051606081018252600080825260208201819052918101919091526126de6131fb565b6001600160e01b031986166319ad4a0360e11b148061270d57506001600160e01b03198616638d89149b60e01b145b1561273c5761272184600060016002612d0d565b915061273584836000015187600387612d7a565b9050612784565b60405162461bcd60e51b815260206004820152601860248201527f4d6574613a20756e737570706f72746564206d6574686f640000000000000000604482015260640161085e565b94509492505050565b60006040518060e0016040528060a1815260200161409160a1913980516020918201209083359084013560408501356127cc6080870160608801613490565b6127dc60a0880160808901613490565b6127ec60c0890160a08a01613490565b6127f960c08a018a613ccf565b604051612807929190613f3c565b60405190819003812061286e989796959493929160e08c0135906020019889526020890197909752604088019590955260608701939093526001600160a01b039182166080870152811660a08601521660c084015260e08301526101008201526101200190565b604051602081830303815290604052805190602001209050919050565b6040805160c0810182526017608082019081527f47534e2052656c61796564205472616e73616374696f6e00000000000000000060a083015281528151808301835260018152601960f91b6020808301919091528201526000916112ff91908101468152602001846001600160a01b0316815250612dc7565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040518060a00160405280856001600160a01b031681526020016129538786612e47565b81526020016129628785612e47565b815260200161297b87612976866001613c23565b612e47565b815260200161298f87612976866002613c23565b60ff16905295945050505050565b8151604051636eb1769f60e11b81526001600160a01b0385811660048301523060248301528392169063dd62ed3e90604401602060405180830381865afa1580156129ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a109190613bc4565b1015610b1057610b108383612e68565b60006001600160ff1b03821115612a8a5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b606482015260840161085e565b5090565b600a546001600160a01b0316612ae65760405162461bcd60e51b815260206004820152601c60248201527f426173653a206e6f207772617070656420636861696e20746f6b656e00000000604482015260640161085e565b81516001600160a01b038082166000908152600b602052604090205416612b4f5760405162461bcd60e51b815260206004820152601a60248201527f426173653a20746f6b656e206e6f742072656769737465726564000000000000604482015260640161085e565b81604001518360200151612b639190613c23565b83516040516370a0823160e01b81526001600160a01b038781166004830152909116906370a0823190602401602060405180830381865afa158015612bac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd09190613bc4565b10156113985760405162461bcd60e51b81526020600482015260156024820152744d6574613a2062616c616e636520746f6f206c6f7760581b604482015260640161085e565b6000806000612c258585612f39565b91509150612c3281612f7e565b509392505050565b805160208083019190912060008181526002909252604091829020805460ff19166001179055905181907f64d6bce64323458c44643c51fe45113efc882082f7b7fd5f09f0d69d2eedb20290612c91908590613565565b60405180910390a25050565b6000612caa826004613c23565b83511015612cfa5760405162461bcd60e51b815260206004820152601a60248201527f726561644279746573343a206461746120746f6f2073686f7274000000000000604482015260640161085e565b5001602001516001600160e01b03191690565b60408051606081018252600080825260208201819052918101919091526040518060600160405280612d3f8787612e47565b6001600160a01b03168152602001612d578786612e47565b8152602001612d668785612e47565b6001600160a01b0316905295945050505050565b612d826131fb565b6040518060800160405280866001600160a01b03168152602001856001600160a01b03168152602001612db58886612e47565b81526020019290925250949350505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8260000151805190602001208360200151805190602001208460400151856060015160405160200161286e9594939291909485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b6000610bbd83612e58846020613f4c565b612e63906004613c23565b6130c8565b6020810151604051306024820152604481019190915260009060640160408051601f198184030181529181526020820180516001600160e01b031663095ea7b360e01b179052835184820151606086015160808701519351630314f14760e21b81529495506001600160a01b0390921693630c53c51c93612ef29389938893909290600401613f63565b6000604051808303816000875af1158015612f11573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113989190810190613fa7565b6000808251604103612f6f5760208301516040840151606085015160001a612f63878285856130d4565b94509450505050612f77565b506000905060025b9250929050565b6000816004811115612f9257612f9261401d565b03612f9a5750565b6001816004811115612fae57612fae61401d565b03612ffb5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161085e565b600281600481111561300f5761300f61401d565b0361305c5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161085e565b60038160048111156130705761307061401d565b03610d825760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161085e565b6000610bbd8383613195565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561310b5750600090506003612784565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561315f573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661318857600060019250925050612784565b9660009650945050505050565b60006131a2826020613c23565b835110156131f25760405162461bcd60e51b815260206004820152601b60248201527f72656164427974657333323a206461746120746f6f2073686f72740000000000604482015260640161085e565b50016020015190565b604051806080016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081525090565b60008083601f84011261324757600080fd5b5081356001600160401b0381111561325e57600080fd5b602083019150836020828501011115612f7757600080fd5b6000806000806000806080878903121561328f57600080fd5b86356001600160401b03808211156132a657600080fd5b908801906040828b0312156132ba57600080fd5b909650602088013590808211156132d057600080fd5b6132dc8a838b01613235565b909750955060408901359150808211156132f557600080fd5b5061330289828a01613235565b979a9699509497949695606090950135949350505050565b60005b8381101561333557818101518382015260200161331d565b50506000910152565b6000815180845261335681602086016020860161331a565b601f01601f19169290920160200192915050565b60408152600061337d604083018561333e565b905082151560208301529392505050565b6001600160a01b0381168114610d8257600080fd5b600080604083850312156133b657600080fd5b8235915060208301356133c88161338e565b809150509250929050565b80356001600160e01b031981168114610b3c57600080fd5b6000602082840312156133fd57600080fd5b610bbd826133d3565b6000610100828403121561341957600080fd5b50919050565b6000806040838503121561343257600080fd5b82356001600160401b0381111561344857600080fd5b61345485828601613406565b925050613463602084016133d3565b90509250929050565b60006020828403121561347e57600080fd5b5035919050565b8035610b3c8161338e565b6000602082840312156134a257600080fd5b8135610bbd8161338e565b600080600080608085870312156134c357600080fd5b84356134ce8161338e565b93506020850135925060408501356134e58161338e565b9396929550929360600135925050565b60008060006060848603121561350a57600080fd5b83356135158161338e565b925060208401359150604084013561352c8161338e565b809150509250925092565b6000806040838503121561354a57600080fd5b82356135558161338e565b915060208301356133c88161338e565b602081526000610bbd602083018461333e565b8015158114610d8257600080fd5b60008060008060006080868803121561359e57600080fd5b85356001600160401b03808211156135b557600080fd5b6135c189838a01613235565b9097509550602088013591506135d682613578565b90935060408701359250606087013590808211156135f357600080fd5b5061360088828901613406565b9150509295509295909350565b60006080828403121561341957600080fd5b600080600080600080600080610100898b03121561363c57600080fd5b88356136478161338e565b975060208901359650604089013561365e8161338e565b9550606089013594506080890135935060a0890135925060c0890135915060e089013560ff8116811461369057600080fd5b809150509295985092959890939650565b6000602082840312156136b357600080fd5b81356001600160401b038111156136c957600080fd5b6136d584828501613406565b949350505050565b600080600080604085870312156136f357600080fd5b84356001600160401b038082111561370a57600080fd5b61371688838901613235565b9096509450602087013591508082111561372f57600080fd5b5061373c87828801613235565b95989497509550505050565b600080600080600080600060a0888a03121561376357600080fd5b87356001600160401b038082111561377a57600080fd5b9089019060e0828c03121561378e57600080fd5b9097506020890135965060408901359550606089013590808211156137b257600080fd5b6137be8b838c01613235565b909650945060808a01359150808211156137d757600080fd5b506137e48a828b01613235565b989b979a50959850939692959293505050565b6000806040838503121561380a57600080fd5b613813836133d3565b946020939093013593505050565b82151581526040602082015260006136d5604083018461333e565b6000806000806060858703121561385257600080fd5b843593506020850135925060408501356001600160401b0381111561387657600080fd5b61373c87828801613235565b60208082526018908201527f426173653a20696c6c6567616c206d73672e73656e6465720000000000000000604082015260600190565b6000823560de198336030181126138cf57600080fd5b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b0381118282101715613911576139116138d9565b60405290565b604051601f8201601f191681016001600160401b038111828210171561393f5761393f6138d9565b604052919050565b60006001600160401b03821115613960576139606138d9565b50601f01601f191660200190565b600082601f83011261397f57600080fd5b813561399261398d82613947565b613917565b8181528460208386010111156139a757600080fd5b816020850160208301376000918101602001919091529392505050565b600060e082360312156139d657600080fd5b6139de6138ef565b6139e783613485565b81526139f560208401613485565b602082015260408301356040820152606083013560608201526080830135608082015260a08301356001600160401b03811115613a3157600080fd5b613a3d3682860161396e565b60a08301525060c092830135928101929092525090565b6000823560fe198336030181126138cf57600080fd5b81516001600160a01b03908116825260208084015190911690820152604080830151908201526060918201519181019190915260800190565b6000808335601e19843603018112613aba57600080fd5b83016020810192503590506001600160401b03811115613ad957600080fd5b803603821315612f7757600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8281526040602082015281356040820152602082013560608201526040820135608082015260006060830135613b468161338e565b6001600160a01b031660a0830152613b6060808401613485565b6001600160a01b031660c0830152613b7a60a08401613485565b6001600160a01b031660e0830152613b9560c0840184613aa3565b61010084810152613bab61014085018284613ae8565b91505060e0840135610120840152809150509392505050565b600060208284031215613bd657600080fd5b5051919050565b600060208284031215613bef57600080fd5b8151610bbd81613578565b634e487b7160e01b600052601160045260246000fd5b818103818111156112ff576112ff613bfa565b808201808211156112ff576112ff613bfa565b600060808284031215613c4857600080fd5b604051608081018181106001600160401b0382111715613c6a57613c6a6138d9565b6040528235613c788161338e565b81526020830135613c888161338e565b6020820152604083810135908201526060928301359281019290925250919050565b600060208284031215613cbc57600080fd5b815162ffffff81168114610bbd57600080fd5b6000808335601e19843603018112613ce657600080fd5b8301803591506001600160401b03821115613d0057600080fd5b602001915036819003821315612f7757600080fd5b6000600160ff1b8201613d2a57613d2a613bfa565b5060000390565b60208082526019908201527f426173653a20466565207472616e73666572206661696c656400000000000000604082015260600190565b7352656c6179446174612072656c6179446174612960601b815260008251613d9781601485016020870161331a565b9190910160140192915050565b60008451613db681846020890161331a565b600560fb1b9083019081528451613dd481600184016020890161331a565b600b60fa1b600192909101918201528351613df681600284016020880161331a565b0160020195945050505050565b6001600160a01b03828116828216039080821115613e2357613e23613bfa565b5092915050565b6001600160a01b03818116838216019080821115613e2357613e23613bfa565b6001600160a01b0386811682528515156020830152604082018590528316606082015260a060808201819052600090613e859083018461333e565b979650505050505050565b60008060408385031215613ea357600080fd5b505080516020909101519092909150565b8981528860208201528760408201528660608201528560808201528460a08201528360c08201528260e082015260006101008351613ef8818386016020880161331a565b929092019091019a9950505050505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201613f3557613f35613bfa565b5060010190565b8183823760009101908152919050565b80820281158282048414176112ff576112ff613bfa565b6001600160a01b038616815260a060208201819052600090613f879083018761333e565b604083019590955250606081019290925260ff1660809091015292915050565b600060208284031215613fb957600080fd5b81516001600160401b03811115613fcf57600080fd5b8201601f81018413613fe057600080fd5b8051613fee61398d82613947565b81815285602083850101111561400357600080fd5b61401482602083016020860161331a565b95945050505050565b634e487b7160e01b600052602160045260246000fdfe616464726573732066726f6d2c6164647265737320746f2c75696e743235362076616c75652c75696e74323536206761732c75696e74323536206e6f6e63652c627974657320646174612c75696e743235362076616c6964556e74696c52656c6179446174612875696e743235362067617350726963652c75696e743235362070637452656c61794665652c75696e74323536206261736552656c61794665652c616464726573732072656c6179576f726b65722c61646472657373207061796d61737465722c6164647265737320666f727761726465722c6279746573207061796d6173746572446174612c75696e7432353620636c69656e74496429322e322e362b6f70656e67736e2e7061796d61737465722e65726332306d6574612e68616e646c6572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429322e322e362b6f70656e67736e2e726563697069656e742e65726332306d6574612e68616e646c6572a264697066735822122074be3b18ed1576ab6989000cf3c0a1548412c7851b4bdbc27c2dcc720938938064736f6c63430008110033

Block Transaction Gas Used Reward
view all blocks produced

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

Validator Index Block Amount
View All Withdrawals

Transaction 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.