Sepolia Testnet

Contract

0x62BEbF3FB38DF89c13be114d3761528df7f75c2F
Source Code Source Code

Overview

ETH Balance

0 ETH

More Info

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Amount

There are no matching entries

Please try again later

Advanced mode:
Parent Transaction Hash Method Block
From
To
Amount
View All Internal Transactions
Loading...
Loading

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
EnterpriseModule

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.18;

import "./common/Utils.sol";
import "./common/BaseModule.sol";
import "./RelayerManager.sol";
import "./SecurityManager.sol";
import "./EnterpriseTransactionManager.sol";
import "./SignatureModule.sol";
import "hardhat/console.sol";

//TODO: add notice
/**
 * @title EnterpriseModule
 * @notice .
 */

contract EnterpriseModule is SignatureModule, BaseModule, RelayerManager, SecurityManager, EnterpriseTransactionManager {

    bytes32 constant public NAME = "EnterpriseModule";

    constructor (
        IModuleRegistry _registry,
        IGuardianStorage _guardianStorage,
        ITransferStorage _userWhitelist,
        IAuthoriser _authoriser,
        uint256 _securityPeriod,
        uint256 _securityWindow,
        uint256 _recoveryPeriod,
        uint256 _lockPeriod
    )
        BaseModule(_registry, _guardianStorage, _userWhitelist, _authoriser, NAME)
        SecurityManager(_recoveryPeriod, _securityPeriod, _securityWindow, _lockPeriod)
        EnterpriseTransactionManager(_securityPeriod)
        RelayerManager("RelayerKnobs")
    {
    }

    /**
     * @inheritdoc IModule
     */
    function init(address _wallet) external override onlyWallet(_wallet) {
        enableDefaultStaticCalls(_wallet); 
    }

    /**
    * @inheritdoc IModule
    */
    function addModule(address _wallet, address _module) external override onlyWalletOwnerOrSelf(_wallet) onlyWhenUnlocked(_wallet) {
        require(registry.isRegisteredModule(_module), "AM: module is not registered");
        IWallet(_wallet).authoriseModule(_module, true);
    }
    
    /**
     * @inheritdoc RelayerManager
     */
    function getRequiredSignatures(address _wallet, bytes calldata _data) public view override returns (uint256, OwnerSignature) {
        bytes4 methodId = Utils.functionPrefix(_data);

        if (methodId ==EnterpriseTransactionManager.multiCall.selector ||
            methodId ==EnterpriseTransactionManager.addToWhitelist.selector ||
            methodId ==EnterpriseTransactionManager.removeFromWhitelist.selector ||
            // methodId ==EnterpriseTransactionManager.enableERC1155TokenReceiver.selector ||
            methodId ==EnterpriseTransactionManager.clearSession.selector )
        {
            if(msg.sender == _wallet) {
                return (0, OwnerSignature.Anyone);
            }
            // owner
            return (1, OwnerSignature.Required);
        }
        if (methodId ==EnterpriseTransactionManager.multiCallWithSession.selector) {
            if(msg.sender == _wallet) {
                return (0, OwnerSignature.Session);
            }
            return (1, OwnerSignature.Session);
        }
        if (methodId == SecurityManager.executeRecovery.selector) {
            // majority of guardians
            uint numberOfSignaturesRequired = _majorityOfGuardians(_wallet);
            require(numberOfSignaturesRequired > 0, "AM: no guardians set on wallet");
            return (numberOfSignaturesRequired, OwnerSignature.Disallowed);
        }
        if (methodId == SecurityManager.cancelRecovery.selector) {
            // majority of (owner + guardians)
            uint numberOfSignaturesRequired = Utils.ceil(recoveryConfigs[_wallet].guardianCount + 1, 2);
            if(msg.sender == _wallet) {
                return (numberOfSignaturesRequired - 1, OwnerSignature.Disallowed);      
            } 
            return (numberOfSignaturesRequired, OwnerSignature.Optional);
        }
        if (
            methodId == SecurityManager.addGuardian.selector ||
            methodId == SecurityManager.revokeGuardian.selector ||
            methodId == SecurityManager.cancelGuardianAddition.selector ||
            methodId == SecurityManager.cancelGuardianRevokation.selector ||
            methodId == SecurityManager.transferOwnership.selector ||
            methodId == EnterpriseModule.addModule.selector ||
            methodId == SecurityManager.upgradeWallet.selector ||
            methodId ==EnterpriseTransactionManager.multiCallWithGuardians.selector ||
            methodId ==EnterpriseTransactionManager.multiCallWithGuardiansAndStartSession.selector)
        {
            // owner + majority of guardians
            uint majorityGuardians = _majorityOfGuardians(_wallet);
            // uint numberOfSignaturesRequired = majorityGuardians + 1;
            return (majorityGuardians, OwnerSignature.Disallowed);
        }
        if (methodId == SecurityManager.finalizeRecovery.selector ||
            methodId == SecurityManager.confirmGuardianAddition.selector ||
            methodId == SecurityManager.confirmGuardianRevokation.selector)
        {
            // anyone
            return (0, OwnerSignature.Anyone);
        }
        if (methodId == SecurityManager.lock.selector || methodId == SecurityManager.unlock.selector) {
            // any guardian
            return (1, OwnerSignature.Disallowed);
        }
        revert("SM: unknown method");
    }

    function _majorityOfGuardians(address _wallet) internal view returns (uint) {
        return Utils.ceil(guardianStorage.guardianCount(_wallet), 2);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)

pragma solidity ^0.8.0;

/**
 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
 * proxy whose upgrades are fully controlled by the current implementation.
 */
interface IERC1822Proxiable {
    /**
     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
     * address.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy.
     */
    function proxiableUUID() external view returns (bytes32);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC1271 standard signature validation method for
 * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
 *
 * _Available since v4.1._
 */
interface IERC1271 {
    /**
     * @dev Should return whether the signature provided is valid for the provided data
     * @param hash      Hash of the data to be signed
     * @param signature Signature byte array associated with _data
     */
    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}

File 4 of 36 : IERC1967.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)

pragma solidity ^0.8.0;

/**
 * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
 *
 * _Available since v4.8.3._
 */
interface IERC1967 {
    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Emitted when the beacon is changed.
     */
    event BeaconUpgraded(address indexed beacon);
}

File 5 of 36 : IERC5267.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol)

pragma solidity ^0.8.0;

interface IERC5267 {
    /**
     * @dev MAY be emitted to signal that the domain could have changed.
     */
    event EIP712DomainChanged();

    /**
     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
     * signature.
     */
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.0;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeacon {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {BeaconProxy} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)

pragma solidity ^0.8.2;

import "../beacon/IBeacon.sol";
import "../../interfaces/IERC1967.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 *
 * _Available since v4.1._
 */
abstract contract ERC1967Upgrade is IERC1967 {
    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev Returns the current implementation address.
     */
    function _getImplementation() internal view returns (address) {
        return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
        StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Perform implementation upgrade
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeTo(address newImplementation) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
    }

    /**
     * @dev Perform implementation upgrade with additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
        _upgradeTo(newImplementation);
        if (data.length > 0 || forceCall) {
            Address.functionDelegateCall(newImplementation, data);
        }
    }

    /**
     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
        // Upgrades from old implementations will perform a rollback test. This test requires the new
        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
        // this special case will break upgrade paths from old UUPS implementation to new ones.
        if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
            _setImplementation(newImplementation);
        } else {
            try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
            } catch {
                revert("ERC1967Upgrade: new implementation is not UUPS");
            }
            _upgradeToAndCall(newImplementation, data, forceCall);
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Returns the current admin.
     */
    function _getAdmin() internal view returns (address) {
        return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
        StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {AdminChanged} event.
     */
    function _changeAdmin(address newAdmin) internal {
        emit AdminChanged(_getAdmin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /**
     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
     */
    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Returns the current beacon.
     */
    function _getBeacon() internal view returns (address) {
        return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the EIP1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
        require(
            Address.isContract(IBeacon(newBeacon).implementation()),
            "ERC1967: beacon implementation is not a contract"
        );
        StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
    }

    /**
     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
     *
     * Emits a {BeaconUpgraded} event.
     */
    function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);
        if (data.length > 0 || forceCall) {
            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol)

pragma solidity ^0.8.0;

import "../../interfaces/draft-IERC1822.sol";
import "../ERC1967/ERC1967Upgrade.sol";

/**
 * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
 * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
 *
 * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
 * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
 * `UUPSUpgradeable` with a custom implementation of upgrades.
 *
 * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
 *
 * _Available since v4.1._
 */
abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade {
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
    address private immutable __self = address(this);

    /**
     * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
     * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
     * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
     * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
     * fail.
     */
    modifier onlyProxy() {
        require(address(this) != __self, "Function must be called through delegatecall");
        require(_getImplementation() == __self, "Function must be called through active proxy");
        _;
    }

    /**
     * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
     * callable on the implementing contract but not through proxies.
     */
    modifier notDelegated() {
        require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
        _;
    }

    /**
     * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
     * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
     */
    function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
        return _IMPLEMENTATION_SLOT;
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     *
     * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
     */
    function upgradeTo(address newImplementation) public virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
     * encoded in `data`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     *
     * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, data, true);
    }

    /**
     * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
     * {upgradeTo} and {upgradeToAndCall}.
     *
     * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
     *
     * ```solidity
     * function _authorizeUpgrade(address) internal override onlyOwner {}
     * ```
     */
    function _authorizeUpgrade(address newImplementation) internal virtual;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)

pragma solidity ^0.8.0;

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 */
library Counters {
    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        unchecked {
            counter._value = value - 1;
        }
    }

    function reset(Counter storage counter) internal {
        counter._value = 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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 message) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32")
            mstore(0x1c, hash)
            message := keccak256(0x00, 0x3c)
        }
    }

    /**
     * @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 data) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, "\x19\x01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            data := keccak256(ptr, 0x42)
        }
    }

    /**
     * @dev Returns an Ethereum Signed Data with intended validator, created from a
     * `validator` and `data` according to the version 0 of EIP-191.
     *
     * See {recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x00", validator, data));
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol)

pragma solidity ^0.8.8;

import "./ECDSA.sol";
import "../ShortStrings.sol";
import "../../interfaces/IERC5267.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
 * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
 * they need in their contracts using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
 * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the
 * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
 *
 * _Available since v3.4._
 *
 * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
 */
abstract contract EIP712 is IERC5267 {
    using ShortStrings for *;

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

    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    bytes32 private immutable _cachedDomainSeparator;
    uint256 private immutable _cachedChainId;
    address private immutable _cachedThis;

    bytes32 private immutable _hashedName;
    bytes32 private immutable _hashedVersion;

    ShortString private immutable _name;
    ShortString private immutable _version;
    string private _nameFallback;
    string private _versionFallback;

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    constructor(string memory name, string memory version) {
        _name = name.toShortStringWithFallback(_nameFallback);
        _version = version.toShortStringWithFallback(_versionFallback);
        _hashedName = keccak256(bytes(name));
        _hashedVersion = keccak256(bytes(version));

        _cachedChainId = block.chainid;
        _cachedDomainSeparator = _buildDomainSeparator();
        _cachedThis = address(this);
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
            return _cachedDomainSeparator;
        } else {
            return _buildDomainSeparator();
        }
    }

    function _buildDomainSeparator() private view returns (bytes32) {
        return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
    }

    /**
     * @dev See {EIP-5267}.
     *
     * _Available since v4.9._
     */
    function eip712Domain()
        public
        view
        virtual
        override
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        )
    {
        return (
            hex"0f", // 01111
            _name.toStringWithFallback(_nameFallback),
            _version.toStringWithFallback(_versionFallback),
            block.chainid,
            address(this),
            bytes32(0),
            new uint256[](0)
        );
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/SignatureChecker.sol)

pragma solidity ^0.8.0;

import "./ECDSA.sol";
import "../../interfaces/IERC1271.sol";

/**
 * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
 * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
 * Argent and Gnosis Safe.
 *
 * _Available since v4.1._
 */
library SignatureChecker {
    /**
     * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
     * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
     *
     * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
     * change through time. It could return true at block N and false at block N+1 (or the opposite).
     */
    function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
        (address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature);
        return
            (error == ECDSA.RecoverError.NoError && recovered == signer) ||
            isValidERC1271SignatureNow(signer, hash, signature);
    }

    /**
     * @dev Checks if a signature is valid for a given signer and data hash. The signature is validated
     * against the signer smart contract using ERC1271.
     *
     * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
     * change through time. It could return true at block N and false at block N+1 (or the opposite).
     */
    function isValidERC1271SignatureNow(
        address signer,
        bytes32 hash,
        bytes memory signature
    ) internal view returns (bool) {
        (bool success, bytes memory result) = signer.staticcall(
            abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)
        );
        return (success &&
            result.length >= 32 &&
            abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

            ///////////////////////////////////////////////
            // 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 256, 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 << 3) < value ? 1 : 0);
        }
    }
}

File 16 of 36 : 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);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

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

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol)

pragma solidity ^0.8.8;

import "./StorageSlot.sol";

// | string  | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA   |
// | length  | 0x                                                              BB |
type ShortString is bytes32;

/**
 * @dev This library provides functions to convert short memory strings
 * into a `ShortString` type that can be used as an immutable variable.
 *
 * Strings of arbitrary length can be optimized using this library if
 * they are short enough (up to 31 bytes) by packing them with their
 * length (1 byte) in a single EVM word (32 bytes). Additionally, a
 * fallback mechanism can be used for every other case.
 *
 * Usage example:
 *
 * ```solidity
 * contract Named {
 *     using ShortStrings for *;
 *
 *     ShortString private immutable _name;
 *     string private _nameFallback;
 *
 *     constructor(string memory contractName) {
 *         _name = contractName.toShortStringWithFallback(_nameFallback);
 *     }
 *
 *     function name() external view returns (string memory) {
 *         return _name.toStringWithFallback(_nameFallback);
 *     }
 * }
 * ```
 */
library ShortStrings {
    // Used as an identifier for strings longer than 31 bytes.
    bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;

    error StringTooLong(string str);
    error InvalidShortString();

    /**
     * @dev Encode a string of at most 31 chars into a `ShortString`.
     *
     * This will trigger a `StringTooLong` error is the input string is too long.
     */
    function toShortString(string memory str) internal pure returns (ShortString) {
        bytes memory bstr = bytes(str);
        if (bstr.length > 31) {
            revert StringTooLong(str);
        }
        return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
    }

    /**
     * @dev Decode a `ShortString` back to a "normal" string.
     */
    function toString(ShortString sstr) internal pure returns (string memory) {
        uint256 len = byteLength(sstr);
        // using `new string(len)` would work locally but is not memory safe.
        string memory str = new string(32);
        /// @solidity memory-safe-assembly
        assembly {
            mstore(str, len)
            mstore(add(str, 0x20), sstr)
        }
        return str;
    }

    /**
     * @dev Return the length of a `ShortString`.
     */
    function byteLength(ShortString sstr) internal pure returns (uint256) {
        uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
        if (result > 31) {
            revert InvalidShortString();
        }
        return result;
    }

    /**
     * @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
     */
    function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
        if (bytes(value).length < 32) {
            return toShortString(value);
        } else {
            StorageSlot.getStringSlot(store).value = value;
            return ShortString.wrap(_FALLBACK_SENTINEL);
        }
    }

    /**
     * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
     */
    function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
        if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
            return toString(value);
        } else {
            return store;
        }
    }

    /**
     * @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
     *
     * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
     * actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
     */
    function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
        if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
            return byteLength(value);
        } else {
            return bytes(store).length;
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.0;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
 * _Available since v4.9 for `string`, `bytes`._
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";
import "./math/SignedMath.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 `int256` to its ASCII `string` decimal representation.
     */
    function toString(int256 value) internal pure returns (string memory) {
        return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
    }

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

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

/* solhint-disable no-inline-assembly */

/**
 * returned data from validateUserOp.
 * validateUserOp returns a uint256, with is created by `_packedValidationData` and parsed by `_parseValidationData`
 * @param aggregator - address(0) - the account validated the signature by itself.
 *              address(1) - the account failed to validate the signature.
 *              otherwise - this is an address of a signature aggregator that must be used to validate the signature.
 * @param validAfter - this UserOp is valid only after this timestamp.
 * @param validaUntil - this UserOp is valid only up to this timestamp.
 */
    struct ValidationData {
        address aggregator;
        uint48 validAfter;
        uint48 validUntil;
    }

//extract sigFailed, validAfter, validUntil.
// also convert zero validUntil to type(uint48).max
    function _parseValidationData(uint validationData) pure returns (ValidationData memory data) {
        address aggregator = address(uint160(validationData));
        uint48 validUntil = uint48(validationData >> 160);
        if (validUntil == 0) {
            validUntil = type(uint48).max;
        }
        uint48 validAfter = uint48(validationData >> (48 + 160));
        return ValidationData(aggregator, validAfter, validUntil);
    }

// intersect account and paymaster ranges.
    function _intersectTimeRange(uint256 validationData, uint256 paymasterValidationData) pure returns (ValidationData memory) {
        ValidationData memory accountValidationData = _parseValidationData(validationData);
        ValidationData memory pmValidationData = _parseValidationData(paymasterValidationData);
        address aggregator = accountValidationData.aggregator;
        if (aggregator == address(0)) {
            aggregator = pmValidationData.aggregator;
        }
        uint48 validAfter = accountValidationData.validAfter;
        uint48 validUntil = accountValidationData.validUntil;
        uint48 pmValidAfter = pmValidationData.validAfter;
        uint48 pmValidUntil = pmValidationData.validUntil;

        if (validAfter < pmValidAfter) validAfter = pmValidAfter;
        if (validUntil > pmValidUntil) validUntil = pmValidUntil;
        return ValidationData(aggregator, validAfter, validUntil);
    }

/**
 * helper to pack the return value for validateUserOp
 * @param data - the ValidationData to pack
 */
    function _packValidationData(ValidationData memory data) pure returns (uint256) {
        return uint160(data.aggregator) | (uint256(data.validUntil) << 160) | (uint256(data.validAfter) << (160 + 48));
    }

/**
 * helper to pack the return value for validateUserOp, when not using an aggregator
 * @param sigFailed - true for signature failure, false for success
 * @param validUntil last timestamp this UserOperation is valid (or zero for infinite)
 * @param validAfter first timestamp this UserOperation is valid
 */
    function _packValidationData(bool sigFailed, uint48 validUntil, uint48 validAfter) pure returns (uint256) {
        return (sigFailed ? 1 : 0) | (uint256(validUntil) << 160) | (uint256(validAfter) << (160 + 48));
    }

/**
 * keccak function over calldata.
 * @dev copy calldata into memory, do keccak and drop allocated memory. Strangely, this is more efficient than letting solidity do it.
 */
    function calldataKeccak(bytes calldata data) pure returns (bytes32 ret) {
        assembly {
            let mem := mload(0x40)
            let len := data.length
            calldatacopy(mem, data.offset, len)
            ret := keccak256(mem, len)
        }
    }

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

/* solhint-disable no-inline-assembly */

import {calldataKeccak} from "../core/Helpers.sol";

/**
 * User Operation struct
 * @param sender the sender account of this request.
     * @param nonce unique value the sender uses to verify it is not a replay.
     * @param initCode if set, the account contract will be created by this constructor/
     * @param callData the method call to execute on this account.
     * @param callGasLimit the gas limit passed to the callData method call.
     * @param verificationGasLimit gas used for validateUserOp and validatePaymasterUserOp.
     * @param preVerificationGas gas not calculated by the handleOps method, but added to the gas paid. Covers batch overhead.
     * @param maxFeePerGas same as EIP-1559 gas parameter.
     * @param maxPriorityFeePerGas same as EIP-1559 gas parameter.
     * @param paymasterAndData if set, this field holds the paymaster address and paymaster-specific data. the paymaster will pay for the transaction instead of the sender.
     * @param signature sender-verified signature over the entire request, the EntryPoint address and the chain ID.
     */
    struct UserOperation {

        address sender;
        uint256 nonce;
        bytes initCode;
        bytes callData;
        uint256 callGasLimit;
        uint256 verificationGasLimit;
        uint256 preVerificationGas;
        uint256 maxFeePerGas;
        uint256 maxPriorityFeePerGas;
        bytes paymasterAndData;
        bytes signature;
    }

/**
 * Utility functions helpful when working with UserOperation structs.
 */
library UserOperationLib {

    function getSender(UserOperation calldata userOp) internal pure returns (address) {
        address data;
        //read sender from userOp, which is first userOp member (saves 800 gas...)
        assembly {data := calldataload(userOp)}
        return address(uint160(data));
    }

    //relayer/block builder might submit the TX with higher priorityFee, but the user should not
    // pay above what he signed for.
    function gasPrice(UserOperation calldata userOp) internal view returns (uint256) {
    unchecked {
        uint256 maxFeePerGas = userOp.maxFeePerGas;
        uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
        if (maxFeePerGas == maxPriorityFeePerGas) {
            //legacy mode (for networks that don't support basefee opcode)
            return maxFeePerGas;
        }
        return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);
    }
    }

    function pack(UserOperation calldata userOp) internal pure returns (bytes memory ret) {
        address sender = getSender(userOp);
        uint256 nonce = userOp.nonce;
        bytes32 hashInitCode = calldataKeccak(userOp.initCode);
        bytes32 hashCallData = calldataKeccak(userOp.callData);
        uint256 callGasLimit = userOp.callGasLimit;
        uint256 verificationGasLimit = userOp.verificationGasLimit;
        uint256 preVerificationGas = userOp.preVerificationGas;
        uint256 maxFeePerGas = userOp.maxFeePerGas;
        uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
        bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData);

        return abi.encode(
            sender, nonce,
            hashInitCode, hashCallData,
            callGasLimit, verificationGasLimit, preVerificationGas,
            maxFeePerGas, maxPriorityFeePerGas,
            hashPaymasterAndData
        );
    }

    function hash(UserOperation calldata userOp) internal pure returns (bytes32) {
        return keccak256(pack(userOp));
    }

    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }
}

// Copyright (C) 2021  Argent Labs Ltd. <https://argent.xyz>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.3;

interface IAuthoriser {
    function isAuthorised(address _wallet, address _spender, address _to, bytes calldata _data) external view returns (bool);
    function areAuthorised(
        address _wallet,
        address[] calldata _spenders,
        address[] calldata _to,
        bytes[] calldata _data
    )
        external
        view
        returns (bool);
}

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.3;

import "../argent-trustlists/contracts/interfaces/IAuthoriser.sol"; //TODO: should we keep the authoriser for the first version?
import "../../wallet/IWallet.sol";
import "../infrastructure/IModuleRegistry.sol";
import "../infrastructure/storage/IGuardianStorage.sol";
import "../infrastructure/storage/ITransferStorage.sol";
import "./IModule.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "hardhat/console.sol";

/**
 * @title BaseModule
 * @notice Base Module contract that contains methods common to all Modules.
 */
abstract contract BaseModule is IModule {

    // Empty calldata
    bytes constant internal EMPTY_BYTES = "";
    // Mock token address for ETH
    address constant internal ETH_TOKEN = address(0);

    // The module registry
    IModuleRegistry internal immutable registry;
    // The guardians storage
    IGuardianStorage internal immutable guardianStorage;
    // The trusted contacts storage
    ITransferStorage internal immutable userWhitelist;
    // The authoriser
    IAuthoriser internal immutable authoriser;

    event ModuleCreated(bytes32 name);

    enum OwnerSignature {
        Anyone,             // Anyone
        Required,           // Owner required
        Optional,           // Owner and/or guardians
        Disallowed,         // Guardians only
        Session             // Session only
    }

    struct Session {
        address key;
        uint64 expires;
    }

    // Maps wallet to session
    mapping (address => Session) internal sessions;

    struct Lock {
        // the lock's release timestamp
        uint64 release;
        // the signature of the method that set the last lock
        bytes4 locker;
    }
    
    // Wallet specific lock storage
    mapping (address => Lock) internal locks;

    /**
     * @notice Throws if the wallet is not locked.
     */
    modifier onlyWhenLocked(address _wallet) {
        require(_isLocked(_wallet), "BM: wallet must be locked");
        _;
    }

    /**
     * @notice Throws if the wallet is locked.
     */
    modifier onlyWhenUnlocked(address _wallet) {
        require(!_isLocked(_wallet), "BM: wallet locked");
        _;
    }

    /**
     * @notice Throws if the sender is not the module itself.
     */
    modifier onlySelf() {
        require(_isSelf(msg.sender), "BM: must be module");
        _;
    }

    /**
     * @notice Throws if the sender is not the module itself or the owner of the target wallet.
     */
    modifier onlyWalletOwnerOrSelf(address _wallet) {
        require(_isSelf(msg.sender) || _isOwner(_wallet, msg.sender), "BM: must be wallet owner/self");
        _;
    }

    modifier onlyWalletOrSelf(address _wallet) {
        require(_isSelf(msg.sender) || msg.sender == _wallet, "BM: must be wallet/self");
        _;
    }

    /**
     * @dev Throws if the sender is not the target wallet of the call.
     */
    modifier onlyWallet(address _wallet) {
        require(msg.sender == _wallet, "BM: caller must be wallet");
        _;
    }

    constructor(
        IModuleRegistry _registry,
        IGuardianStorage _guardianStorage,
        ITransferStorage _userWhitelist,
        IAuthoriser _authoriser,
        bytes32 _name
    ) {
        registry = _registry;
        guardianStorage = _guardianStorage;
        userWhitelist = _userWhitelist;
        authoriser = _authoriser;
        emit ModuleCreated(_name);
    }

    /**
     * @notice Moves tokens that have been sent to the module by mistake.
     * @param _token The target token.
     */
    function recoverToken(address _token) external {
        uint total = IERC20(_token).balanceOf(address(this));
        IERC20(_token).transfer(address(registry), total);
    }

    function _clearSession(address _wallet) internal {
        delete sessions[_wallet];
    }
    
    /**
     * @notice Helper method to check if an address is the owner of a target wallet.
     * @param _wallet The target wallet.
     * @param _addr The address.
     */
    function _isOwner(address _wallet, address _addr) internal view returns (bool) {
        return IWallet(_wallet).owner() == _addr;
    }

    /**
     * @notice Helper method to check if a wallet is locked.
     * @param _wallet The target wallet.
     */
    function _isLocked(address _wallet) internal view returns (bool) {
        return locks[_wallet].release > uint64(block.timestamp);
    }

    /**
     * @notice Helper method to check if an address is the module itself.
     * @param _addr The target address.
     */
    function _isSelf(address _addr) internal view returns (bool) {
        return _addr == address(this);
    }

    /**
     * @notice Helper method to invoke a wallet.
     * @param _wallet The target wallet.
     * @param _to The target address for the transaction.
     * @param _value The value of the transaction.
     * @param _data The data of the transaction.
     */
    function invokeWallet(address _wallet, address _to, uint256 _value, bytes memory _data) internal returns (bytes memory _res) {
        bool success;
        //TODO: change to execute? or whatever name there is in the wallet contract
        console.log("invokeWallet");
        (success, _res) = _wallet.call(abi.encodeWithSignature("invoke(address,uint256,bytes)", _to, _value, _data));
        if (success && _res.length > 0) { //_res is empty if _wallet is an "old" BaseWallet that can't return output values
            (_res) = abi.decode(_res, (bytes));
        } else if (_res.length > 0) {
            // solhint-disable-next-line no-inline-assembly
            assembly {
                returndatacopy(0, 0, returndatasize())
                revert(0, returndatasize())
            }
        } else if (!success) {
            revert("BM: wallet invoke reverted");
        }
    }
}

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.3;

/**
 * @title IModule
 * @notice Interface for a Module.
 */
interface IModule {

    /**	
     * @notice Adds a module to a wallet. Cannot execute when wallet is locked (or under recovery)	
     * @param _wallet The target wallet.	
     * @param _module The modules to authorise.	
     */	
    function addModule(address _wallet, address _module) external;

    /**
     * @notice Inits a Module for a wallet by e.g. setting some wallet specific parameters in storage.
     * @param _wallet The wallet.
     */
    function init(address _wallet) external;


    /**
     * @notice Returns whether the module implements a callback for a given static call method.
     * @param _methodId The method id.
     */
    function supportsStaticCall(bytes4 _methodId) external view returns (bool _isSupported);


}

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.3;

/**
 * @title Utils
 * @notice Common utility methods used by modules.
 */
library Utils {

    // ERC20, ERC721 & ERC1155 transfers & approvals
    bytes4 private constant ERC20_TRANSFER = bytes4(keccak256("transfer(address,uint256)"));
    bytes4 private constant ERC20_APPROVE = bytes4(keccak256("approve(address,uint256)"));
    bytes4 private constant ERC721_SET_APPROVAL_FOR_ALL = bytes4(keccak256("setApprovalForAll(address,bool)"));
    bytes4 private constant ERC721_TRANSFER_FROM = bytes4(keccak256("transferFrom(address,address,uint256)"));
    bytes4 private constant ERC721_SAFE_TRANSFER_FROM = bytes4(keccak256("safeTransferFrom(address,address,uint256)"));
    bytes4 private constant ERC721_SAFE_TRANSFER_FROM_BYTES = bytes4(keccak256("safeTransferFrom(address,address,uint256,bytes)"));
    bytes4 private constant ERC1155_SAFE_TRANSFER_FROM = bytes4(keccak256("safeTransferFrom(address,address,uint256,uint256,bytes)"));

    bytes4 private constant OWNER_SIG = 0x8da5cb5b;
    /**
    * @notice Helper method to recover the signer at a given position from a list of concatenated signatures.
    * @param _signedHash The signed hash
    * @param _signatures The concatenated signatures.
    * @param _index The index of the signature to recover.
    */
    function recoverSigner(bytes32 _signedHash, bytes memory _signatures, uint _index) internal pure returns (address) {
        uint8 v;
        bytes32 r;
        bytes32 s;
        // we jump 32 (0x20) as the first slot of bytes contains the length
        // we jump 65 (0x41) per signature
        // for v we load 32 bytes ending with v (the first 31 come from s) then apply a mask
        // solhint-disable-next-line no-inline-assembly
        assembly {
            r := mload(add(_signatures, add(0x20,mul(0x41,_index))))
            s := mload(add(_signatures, add(0x40,mul(0x41,_index))))
            v := and(mload(add(_signatures, add(0x41,mul(0x41,_index)))), 0xff)
        }
        require(v == 27 || v == 28, "Utils: bad v value in signature");

        address recoveredAddress = ecrecover(_signedHash, v, r, s);
        require(recoveredAddress != address(0), "Utils: ecrecover returned 0");
        return recoveredAddress;
    }

    /**
    * @notice Helper method to recover the spender from a contract call. 
    * The method returns the contract unless the call is to a standard method of a ERC20/ERC721/ERC1155 token
    * in which case the spender is recovered from the data.
    * @param _to The target contract.
    * @param _data The data payload.
    */
    function recoverSpender(address _to, bytes memory _data) internal pure returns (address spender) {
        if(_data.length >= 68) {
            bytes4 methodId;
            // solhint-disable-next-line no-inline-assembly
            assembly {
                methodId := mload(add(_data, 0x20))
            }
            if(
                methodId == ERC20_TRANSFER ||
                methodId == ERC20_APPROVE ||
                methodId == ERC721_SET_APPROVAL_FOR_ALL) 
            {
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    spender := mload(add(_data, 0x24))
                }
                return spender;
            }
            if(
                methodId == ERC721_TRANSFER_FROM ||
                methodId == ERC721_SAFE_TRANSFER_FROM ||
                methodId == ERC721_SAFE_TRANSFER_FROM_BYTES ||
                methodId == ERC1155_SAFE_TRANSFER_FROM)
            {
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    spender := mload(add(_data, 0x44))
                }
                return spender;
            }
        }

        spender = _to;
    }

    /**
    * @notice Helper method to parse data and extract the method signature.
    */
    function functionPrefix(bytes memory _data) internal pure returns (bytes4 prefix) {
        require(_data.length >= 4, "Utils: Invalid functionPrefix");
        // solhint-disable-next-line no-inline-assembly
        assembly {
            prefix := mload(add(_data, 0x20))
        }
    }

    /**
    * @notice Checks if an address is a contract.
    * @param _addr The address.
    */
    function isContract(address _addr) internal view returns (bool) {
        uint32 size;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            size := extcodesize(_addr)
        }
        return (size > 0);
    }

    /**
    * @notice Checks if an address is a guardian or an account authorised to sign on behalf of a smart-contract guardian
    * given a list of guardians.
    * @param _guardians the list of guardians
    * @param _guardian the address to test
    * @return true and the list of guardians minus the found guardian upon success, false and the original list of guardians if not found.
    */
    function isGuardianOrGuardianSigner(address[] memory _guardians, address _guardian) internal view returns (bool, address[] memory) {
        if (_guardians.length == 0 || _guardian == address(0)) {
            return (false, _guardians);
        }
        bool isFound = false;
        address[] memory updatedGuardians = new address[](_guardians.length - 1);
        uint256 index = 0;
        for (uint256 i = 0; i < _guardians.length; i++) {
            if (!isFound) {
                // check if _guardian is an account guardian
                if (_guardian == _guardians[i]) {
                    isFound = true;
                    continue;
                }
                // check if _guardian is the owner of a smart contract guardian
                if (isContract(_guardians[i]) && isGuardianOwner(_guardians[i], _guardian)) {
                    isFound = true;
                    continue;
                }
            }
            if (index < updatedGuardians.length) {
                updatedGuardians[index] = _guardians[i];
                index++;
            }
        }
        return isFound ? (true, updatedGuardians) : (false, _guardians);
    }

    /**
    * @notice Checks if an address is the owner of a guardian contract.
    * The method does not revert if the call to the owner() method consumes more then 25000 gas.
    * @param _guardian The guardian contract
    * @param _owner The owner to verify.
    */
    function isGuardianOwner(address _guardian, address _owner) internal view returns (bool) {
        address owner = address(0);

        // solhint-disable-next-line no-inline-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr,OWNER_SIG)
            let result := staticcall(25000, _guardian, ptr, 0x20, ptr, 0x20)
            if eq(result, 1) {
                owner := mload(ptr)
            }
        }
        return owner == _owner;
    }

    /**
    * @notice Returns ceil(a / b).
    */
    function ceil(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a / b;
        if (a % b == 0) {
            return c;
        } else {
            return c + 1;
        }
    }
}

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.3;

import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "./common/Utils.sol";
import "./common/BaseModule.sol";
import "hardhat/console.sol";


/**
 * @title EnterpriseTransactionManager
 * @notice Module to execute transactions in sequence to e.g. transfer tokens (ETH, ERC20, ERC721, ERC1155) or call third-party contracts.
 */

abstract contract EnterpriseTransactionManager is BaseModule {

    // Static calls
    bytes4 private constant ERC1271_IS_VALID_SIGNATURE = bytes4(keccak256("isValidSignature(bytes32,bytes)"));
    bytes4 private constant ERC721_RECEIVED = bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
    bytes4 private constant ERC1155_RECEIVED = bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"));
    bytes4 private constant ERC1155_BATCH_RECEIVED = bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"));
    bytes4 private constant ERC165_INTERFACE = bytes4(keccak256("supportsInterface(bytes4)"));

    struct Call {
        address to;
        uint256 value;
        bytes data;
    }

    // The time delay for adding a trusted contact
    uint256 internal immutable whitelistPeriod;

    // *************** Events *************************** //

    event AddedToWhitelist(address indexed wallet, address indexed target, uint64 whitelistAfter);
    event RemovedFromWhitelist(address indexed wallet, address indexed target);
    event SessionCreated(address indexed wallet, address sessionKey, uint64 expires);
    event SessionCleared(address indexed wallet, address sessionKey);
    // *************** Constructor ************************ //

    constructor(uint256 _whitelistPeriod) {
        whitelistPeriod = _whitelistPeriod;
    }

    // *************** External functions ************************ //

    /**
     * @notice Makes the target wallet execute a sequence of transactions authorised by the wallet owner.
     * The method reverts if any of the inner transactions reverts.
     * The method reverts if any of the inner transaction is not to a trusted contact or an authorised dapp.
     * @param _wallet The target wallet.
     * @param _transactions The sequence of transactions.
     */
    function multiCall(
        address _wallet,
        Call[] calldata _transactions
    )
        external
        onlySelf()
        onlyWhenUnlocked(_wallet)
        returns (bytes[] memory)
    {
        bytes[] memory results = new bytes[](_transactions.length);
        for(uint i = 0; i < _transactions.length; i++) {
            //FIX: check authoriser
            // address spender = Utils.recoverSpender(_transactions[i].to, _transactions[i].data);
            require(
                _transactions[i].to != address(this),
                "TM: call not authorised");
            results[i] = invokeWallet(_wallet, _transactions[i].to, _transactions[i].value, _transactions[i].data);
        }
        return results;
    }

    /**
     * @notice Makes the target wallet execute a sequence of transactions authorised by a session key.
     * The method reverts if any of the inner transactions reverts.
     * @param _wallet The target wallet.
     * @param _transactions The sequence of transactions.
     */
    function multiCallWithSession(
        address _wallet,
        Call[] calldata _transactions
    )
        external
        onlySelf()
        onlyWhenUnlocked(_wallet)
        returns (bytes[] memory)
    {
        return multiCallWithApproval(_wallet, _transactions);
    }

    /**
     * @notice Makes the target wallet execute a sequence of transactions approved by a majority of guardians.
     * The method reverts if any of the inner transactions reverts.
     * @param _wallet The target wallet.
     * @param _transactions The sequence of transactions.
     */
    function multiCallWithGuardians(
        address _wallet,
        Call[] calldata _transactions
    )
        external 
        onlySelf()
        onlyWhenUnlocked(_wallet)
        returns (bytes[] memory)
    {
        console.log("multiCall");
        console.log(_transactions.length);
        return multiCallWithApproval(_wallet, _transactions);
    }

    /**
     * @notice Makes the target wallet execute a sequence of transactions approved by a majority of guardians.
     * The method reverts if any of the inner transactions reverts.
     * Upon success a new session is started.
     * @param _wallet The target wallet.
     * @param _transactions The sequence of transactions.
     */
    function multiCallWithGuardiansAndStartSession(
        address _wallet,
        Call[] calldata _transactions,
        address _sessionUser,
        uint64 _duration
    )
        external 
        onlySelf()
        onlyWhenUnlocked(_wallet)
        returns (bytes[] memory)
    {
        startSession(_wallet, _sessionUser, _duration);
        return multiCallWithApproval(_wallet, _transactions);
    }

    /**
    * @notice Clears the active session of a wallet if any.
    * @param _wallet The target wallet.
    */
    function clearSession(address _wallet) external onlyWalletOwnerOrSelf(_wallet) onlyWhenUnlocked(_wallet) {
        emit SessionCleared(_wallet, sessions[_wallet].key);
        _clearSession(_wallet);
    }

    /**
     * @notice Adds an address to the list of trusted contacts.
     * @param _wallet The target wallet.
     * @param _target The address to add.
     */
    function addToWhitelist(address _wallet, address _target) external onlyWalletOwnerOrSelf(_wallet) onlyWhenUnlocked(_wallet) {
        require(_target != _wallet, "TM: Cannot whitelist wallet");
        require(!registry.isRegisteredModule(_target), "TM: Cannot whitelist module");
        require(!isWhitelisted(_wallet, _target), "TM: target already whitelisted");

        uint256 whitelistAfter = block.timestamp + whitelistPeriod;
        setWhitelist(_wallet, _target, whitelistAfter);
        emit AddedToWhitelist(_wallet, _target, uint64(whitelistAfter));
    }

    /**
     * @notice Removes an address from the list of trusted contacts.
     * @param _wallet The target wallet.
     * @param _target The address to remove.
     */
    function removeFromWhitelist(address _wallet, address _target) external onlyWalletOwnerOrSelf(_wallet) onlyWhenUnlocked(_wallet) {
        setWhitelist(_wallet, _target, 0);
        emit RemovedFromWhitelist(_wallet, _target);
    }

    /**
    * @notice Checks if an address is a trusted contact for a wallet.
    * @param _wallet The target wallet.
    * @param _target The address.
    * @return _isWhitelisted true if the address is a trusted contact.
    */
    function isWhitelisted(address _wallet, address _target) public view returns (bool _isWhitelisted) {
        uint whitelistAfter = userWhitelist.getWhitelist(_wallet, _target);
        return whitelistAfter > 0 && whitelistAfter < block.timestamp;
    }
    
    /**
     * @inheritdoc IModule
     */
    function supportsStaticCall(bytes4 _methodId) external pure override returns (bool _isSupported) {
        return _methodId == ERC1271_IS_VALID_SIGNATURE ||
               _methodId == ERC721_RECEIVED ||
               _methodId == ERC165_INTERFACE ||
               _methodId == ERC1155_RECEIVED ||
               _methodId == ERC1155_BATCH_RECEIVED;
    }

    /** ******************* Callbacks ************************** */

    /**
     * @notice Returns true if this contract implements the interface defined by
     * `interfaceId` (see https://eips.ethereum.org/EIPS/eip-165).
     */
    // function supportsInterface(bytes4 _interfaceID) external pure returns (bool) {
    //     return  _interfaceID == ERC165_INTERFACE || _interfaceID == (ERC1155_RECEIVED ^ ERC1155_BATCH_RECEIVED);          
    // }

    /**
    * @notice Implementation of EIP 1271.
    * Should return whether the signature provided is valid for the provided data.
    * @param _msgHash Hash of a message signed on the behalf of address(this)
    * @param _signature Signature byte array associated with _msgHash
    */

    function isValidSignature(bytes32 _msgHash, bytes memory _signature) external view returns (bytes4) {
        require(_signature.length == 65, "TM: invalid signature length");

        address signer = Utils.recoverSigner(_msgHash, _signature, 0);
        require(_isOwner(msg.sender, signer), "TM: Invalid signer");
        return ERC1271_IS_VALID_SIGNATURE;
    }


    fallback() external {
        bytes4 methodId = Utils.functionPrefix(msg.data);
        if(methodId == ERC721_RECEIVED || methodId == ERC1155_RECEIVED || methodId == ERC1155_BATCH_RECEIVED) {
            // solhint-disable-next-line no-inline-assembly
            assembly {                
                calldatacopy(0, 0, 0x04)
                return (0, 0x20)
            }
        }
    }

    // *************** Internal Functions ********************* //

    function enableDefaultStaticCalls(address _wallet) internal {
        // setup this module as static call executor
        IWallet(_wallet).enableStaticCall(address(this), ERC1271_IS_VALID_SIGNATURE);
    }

    function multiCallWithApproval(address _wallet, Call[] calldata _transactions) internal returns (bytes[] memory) {
        bytes[] memory results = new bytes[](_transactions.length);
        console.log(_transactions.length);
        for(uint i = 0; i < _transactions.length; i++) {
            console.log(_transactions[i].to);
            console.logBytes(_transactions[i].data);
            console.log(_transactions[i].value);
            results[i] = invokeWallet(_wallet, _transactions[i].to, _transactions[i].value, _transactions[i].data);
        }
        return results;
    }

    function startSession(address _wallet, address _sessionUser, uint64 _duration) internal {
        require(_sessionUser != address(0), "TM: Invalid session user");
        require(_duration > 0, "TM: Invalid session duration");

        uint64 expiry = SafeCast.toUint64(block.timestamp + _duration);
        sessions[_wallet] = Session(_sessionUser, expiry);
        emit SessionCreated(_wallet, _sessionUser, expiry);
    }

    function setWhitelist(address _wallet, address _target, uint256 _whitelistAfter) internal {
        userWhitelist.setWhitelist(_wallet, _target, _whitelistAfter);
    }
}

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.9.0;

/**
 * @title IModuleRegistry
 * @notice Interface for the registry of authorised modules.
 */
interface IModuleRegistry {
    function registerModule(address _module, bytes32 _name) external;

    function deregisterModule(address _module) external;

    function registerUpgrader(address _upgrader, bytes32 _name) external;

    function deregisterUpgrader(address _upgrader) external;

    function recoverToken(address _token) external;

    function moduleInfo(address _module) external view returns (bytes32);

    function upgraderInfo(address _upgrader) external view returns (bytes32);

    function isRegisteredModule(address _module) external view returns (bool);

    function isRegisteredModule(address[] calldata _modules) external view returns (bool);

    function isRegisteredUpgrader(address _upgrader) external view returns (bool);
}

// Copyright (C) 2018  Argent Labs Ltd. <https://argent.xyz>

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.9.0;

interface IGuardianStorage {

    /**
     * @notice Lets an authorised module add a guardian to a wallet.
     * @param _wallet The target wallet.
     * @param _guardian The guardian to add.
     */
    function addGuardian(address _wallet, address _guardian) external;

    /**
     * @notice Lets an authorised module revoke a guardian from a wallet.
     * @param _wallet The target wallet.
     * @param _guardian The guardian to revoke.
     */
    function revokeGuardian(address _wallet, address _guardian) external;

    /**
     * @notice Checks if an account is a guardian for a wallet.
     * @param _wallet The target wallet.
     * @param _guardian The account.
     * @return true if the account is a guardian for a wallet.
     */
    function isGuardian(address _wallet, address _guardian) external view returns (bool);

    function isLocked(address _wallet) external view returns (bool);

    function getLock(address _wallet) external view returns (uint256);

    function getLocker(address _wallet) external view returns (address);

    function setLock(address _wallet, uint256 _releaseAfter) external;

    function getGuardians(address _wallet) external view returns (address[] memory);

    function guardianCount(address _wallet) external view returns (uint256);
}

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.9.0;

/**
 * @title ITransferStorage
 * @notice TransferStorage interface
 */
interface ITransferStorage {
    function setWhitelist(address _wallet, address _target, uint256 _value) external;

    function getWhitelist(address _wallet, address _target) external view returns (uint256);
}

// SPDX-License-Identifier: GPL-3.0-or-later

import "../interfaces/UserOperation.sol";

pragma solidity ^0.8.18;

interface ISignatureModule {
     function isValidSignature(
        UserOperation calldata _userOp,
        bytes32 _userOpHash
    ) external view returns (uint256);

    function isSignatureModule() external pure returns (bool);
}

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.3;

import "@openzeppelin/contracts/utils/math/Math.sol";
import "./common/Utils.sol";
import "./common/BaseModule.sol";
import "./infrastructure/storage/IGuardianStorage.sol";

import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import "hardhat/console.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

import "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";

/**
 * @title RelayerManager
 * @notice Abstract Module to execute transactions signed by ETH-less accounts and sent by a relayer.
 */

abstract contract RelayerManager is BaseModule, EIP712 {
    // solhint-disable-next-line var-name-mixedcase
    bytes32 private constant _TRANSACTION_TYPEHASH =
        keccak256(
            "Transaction(address wallet,bytes data,uint256 nonce,uint256 deadline)"
        );

    mapping(address => mapping(bytes32 => bool)) private _usedSignHashes;


    event TransactionExecuted(
        address indexed wallet,
        bool indexed success,
        bytes returnData,
        bytes32 signedHash
    );
    event Refund(
        address indexed wallet,
        address indexed refundAddress,
        address refundToken,
        uint256 refundAmount
    );

    // *************** Constructor ************************ //

    /**
     * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
     *
     *
     */
    constructor(string memory name) EIP712(name, "1") {}

    /* ***************** External methods ************************* */

    /**
     * @notice Gets the number of valid signatures that must be provided to execute a
     * specific relayed transaction.
     * @param _wallet The target wallet.
     * @param _data The data of the relayed transaction.
     * @return The number of required signatures and the wallet owner signature requirement.
     */
    function getRequiredSignatures(
        address _wallet,
        bytes calldata _data
    ) public view virtual returns (uint256, OwnerSignature);

    /**
     * @notice Executes a relayed transaction.
     * @param _wallet The target wallet.
     * @param _data The data for the relayed transaction
     * @param _nonce The nonce used to prevent replay attacks.
     * @param _signatures The signatures as a concatenated byte array.
     */
    function execute(
        address _wallet,
        bytes calldata _data,
        uint256 _nonce,
        uint256 _deadline,
        bytes calldata _signatures
    ) external returns (bool) {
        require(verifyData(_wallet, _data), "RM: Target of _data != _wallet");
        require(!_isLocked(_wallet), "RM: Locked wallet refund");

        uint256 requiredSignatures;
        OwnerSignature ownerSignatureRequirement;
        bool success;
        bytes memory returnData;

        (requiredSignatures, ownerSignatureRequirement) = getRequiredSignatures(
            _wallet,
            _data
        );

        require(
            requiredSignatures > 0 ||
                ownerSignatureRequirement == OwnerSignature.Anyone,
            "RM: Wrong signature requirement"
        );
        require(
            requiredSignatures * 65 == _signatures.length,
            "RM: Wrong number of signatures"
        );

        bytes32 structHash = keccak256(
            abi.encode(
                _TRANSACTION_TYPEHASH,
                _wallet,
                keccak256(_data),
                _nonce,
                _deadline
            )
        );
        bytes32 hash = _hashTypedDataV4(structHash);

        if (ownerSignatureRequirement == OwnerSignature.Session) {
            require(validateSession(_wallet), "RM: Invalid session");
        } else {
            require(
                validateSignatures(
                    _wallet,
                    hash,
                    _signatures,
                    ownerSignatureRequirement
                ),
                "RM: Invalid signatures"
            );
        }
        (success, returnData) = address(this).call(_data);

        emit TransactionExecuted(
            _wallet,
            success,
            returnData,
            hash
        );
        return success;
    }

    /**
     * @notice Checks if a transaction identified by its sign hash has already been executed.
     * @param _wallet The target wallet.
     * @param _signHash The sign hash of the transaction.
     */
    function isExecutedTx(
        address _wallet,
        bytes32 _signHash
    ) public view returns (bool executed) {
        return _usedSignHashes[_wallet][_signHash];
    }

    /**
     * @notice Gets the last stored session for a wallet.
     * @param _wallet The target wallet.
     */
    function getSession(
        address _wallet
    ) external view returns (address key, uint64 expires) {
        return (sessions[_wallet].key, sessions[_wallet].expires);
    }

    /**
     * @notice Validates the signatures provided with a relayed transaction.
     * @param _wallet The target wallet.
     * @param _signHash The sign hash of the transaction.
     * @param _signatures The signatures as a concatenated bytes array.
     * @param _option An OwnerSignature enum indicating whether the owner is required, optional or disallowed.
     * @return A boolean indicating whether the signatures are valid.
     */
    function validateSignatures(
        address _wallet,
        bytes32 _signHash,
        bytes calldata _signatures,
        OwnerSignature _option
    ) internal view returns (bool) {
        if (_signatures.length == 0) {
            return true;
        }
        address lastSigner = address(0);
        address[] memory guardians;
        if (_option != OwnerSignature.Required || _signatures.length > 65) {
            guardians = guardianStorage.getGuardians(_wallet); // guardians are only read if they may be needed
        }

        require(
            !isExecutedTx(_wallet, _signHash),
            "RM: validateSignatures: tx already executed"
        );
        for (uint256 i = 0; i < _signatures.length / 65; i++) {
            bytes memory signature = new bytes(65);

            assembly {
                // Calculate the offset for the signature based on the index
                let offset := add(mul(i, 65), _signatures.offset)

                // Copy 65 bytes from the calculated offset in calldata to the memory location of the signature array
                calldatacopy(add(signature, 32), offset, 65)
            }
            if (i == 0) {
                bool ownerFound;
                ownerFound = SignatureChecker.isValidSignatureNow(
                    IWallet(_wallet).owner(),
                    _signHash,
                    signature
                );
                if (_option == OwnerSignature.Required) {
                    // First signer must be owner
                    if (ownerFound) {
                        continue;
                    }
                    return false;
                } else if (_option == OwnerSignature.Optional) {
                    // First signer can be owner
                    if (ownerFound) {
                        continue;
                    }
                }
            }

            bool guardianFound;
            for (uint256 j = 0; j < guardians.length; j++) {
                if (
                    SignatureChecker.isValidSignatureNow(
                        guardians[j],
                        _signHash,
                        signature
                    )
                ) {
                    if (guardians[j] <= lastSigner) {
                        return false; // Signers must be different
                    }
                    lastSigner = guardians[j];
                    guardianFound = true;
                    break;
                }
            }

            if (!guardianFound) {
                return false;
            }
        }
        return true;
    }

    /**
     * @notice Validates the signature provided when a session key was used.
     * @param _wallet The target wallet.
     * @return A boolean indicating whether the signature is valid.
     */
    function validateSession(address _wallet) internal view returns (bool) {
        Session memory session = sessions[_wallet];
        return (msg.sender == _wallet && session.expires >= block.timestamp);
    }

    /**
     * @notice Checks that the wallet address provided as the first parameter of _data matches _wallet
     * @return false if the addresses are different.
     */
    function verifyData(
        address _wallet,
        bytes calldata _data
    ) internal pure returns (bool) {
        require(_data.length >= 36, "RM: Invalid dataWallet");
        address dataWallet = abi.decode(_data[4:], (address));
        return dataWallet == _wallet;
    }
}

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.3;

import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "./common/Utils.sol";
import "./common/BaseModule.sol";
import "../wallet/IWallet.sol";
import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";

/**
 * @title SecurityManager
 * @notice Abstract module implementing the key security features of the wallet: guardians, lock and recovery.
 */
abstract contract SecurityManager is BaseModule {

    struct RecoveryConfig {
        address recovery;
        uint64 executeAfter;
        uint32 guardianCount;
    }

    struct GuardianManagerConfig {
        // The time at which a guardian addition or revokation will be confirmable by the owner
        mapping (bytes32 => uint256) pending;
    }

    // Wallet specific storage for recovery
    mapping (address => RecoveryConfig) internal recoveryConfigs;
    // Wallet specific storage for pending guardian addition/revokation
    mapping (address => GuardianManagerConfig) internal guardianConfigs;


    // Recovery period
    uint256 internal immutable recoveryPeriod;
    // Lock period
    uint256 internal immutable lockPeriod;
    // The security period to add/remove guardians
    uint256 internal immutable securityPeriod;
    // The security window
    uint256 internal immutable securityWindow;

    // *************** Events *************************** //

    event RecoveryExecuted(address indexed wallet, address indexed _recovery, uint64 executeAfter);
    event RecoveryFinalized(address indexed wallet, address indexed _recovery);
    event RecoveryCanceled(address indexed wallet, address indexed _recovery);
    event OwnershipTransfered(address indexed wallet, address indexed _newOwner);
    event WalletUpgraded(address indexed wallet, address indexed _newImplementation);
    event Locked(address indexed wallet, uint64 releaseAfter);
    event Unlocked(address indexed wallet);
    event GuardianAdditionRequested(address indexed wallet, address indexed guardian, uint256 executeAfter);
    event GuardianRevokationRequested(address indexed wallet, address indexed guardian, uint256 executeAfter);
    event GuardianAdditionCancelled(address indexed wallet, address indexed guardian);
    event GuardianRevokationCancelled(address indexed wallet, address indexed guardian);
    event GuardianAdded(address indexed wallet, address indexed guardian);
    event GuardianRevoked(address indexed wallet, address indexed guardian);
    // *************** Modifiers ************************ //

    /**
     * @notice Throws if there is no ongoing recovery procedure.
     */
    modifier onlyWhenRecovery(address _wallet) {
        require(recoveryConfigs[_wallet].executeAfter > 0, "SM: no ongoing recovery");
        _;
    }

    /**
     * @notice Throws if there is an ongoing recovery procedure.
     */
    modifier notWhenRecovery(address _wallet) {
        require(recoveryConfigs[_wallet].executeAfter == 0, "SM: ongoing recovery");
        _;
    }

    /**
     * @notice Throws if the caller is not a guardian for the wallet or the module itself.
     */
    modifier onlyGuardianOrSelf(address _wallet) {
        require(_isSelf(msg.sender) || isGuardian(_wallet, msg.sender), "SM: must be guardian/self");
        _;
    }

    // *************** Constructor ************************ //

    constructor(
        uint256 _recoveryPeriod,
        uint256 _securityPeriod,
        uint256 _securityWindow,
        uint256 _lockPeriod
    ) {
        // For the wallet to be secure we must have recoveryPeriod >= securityPeriod + securityWindow
        // where securityPeriod and securityWindow are the security parameters of adding/removing guardians.
        require(_lockPeriod >= _recoveryPeriod, "SM: insecure lock period");
        require(_recoveryPeriod >= _securityPeriod + _securityWindow, "SM: insecure security periods");
        recoveryPeriod = _recoveryPeriod;
        lockPeriod = _lockPeriod;
        securityWindow = _securityWindow;
        securityPeriod = _securityPeriod;
    }

    // *************** External functions ************************ //

    // *************** Recovery functions ************************ //

    /**
     * @notice Lets the guardians start the execution of the recovery procedure.
     * Once triggered the recovery is pending for the security period before it can be finalized.
     * Must be confirmed by N guardians, where N = ceil(Nb Guardians / 2).
     * @param _wallet The target wallet.
     * @param _recovery The address to which ownership should be transferred.
     */
    function executeRecovery(address _wallet, address _recovery) external onlySelf() notWhenRecovery(_wallet) {
        validateNewOwner(_wallet, _recovery);
        uint64 executeAfter = uint64(block.timestamp + recoveryPeriod);
        recoveryConfigs[_wallet] = RecoveryConfig(_recovery, executeAfter, uint32(guardianStorage.guardianCount(_wallet)));
        _setLock(_wallet, block.timestamp + lockPeriod, SecurityManager.executeRecovery.selector);
        emit RecoveryExecuted(_wallet, _recovery, executeAfter);
    }

    /**
     * @notice Finalizes an ongoing recovery procedure if the security period is over.
     * The method is public and callable by anyone to enable orchestration.
     * @param _wallet The target wallet.
     */
    function finalizeRecovery(address _wallet) external onlyWhenRecovery(_wallet) {
        RecoveryConfig storage config = recoveryConfigs[_wallet];
        require(uint64(block.timestamp) > config.executeAfter, "SM: ongoing recovery period");
        address recoveryOwner = config.recovery;
        delete recoveryConfigs[_wallet];

        _clearSession(_wallet);

        IWallet(_wallet).setOwner(recoveryOwner);
        _setLock(_wallet, 0, bytes4(0));

        emit RecoveryFinalized(_wallet, recoveryOwner);
    }

    /**
     * @notice Lets the owner cancel an ongoing recovery procedure.
     * Must be confirmed by N guardians, where N = ceil(Nb Guardian at executeRecovery + 1) / 2) - 1.
     * @param _wallet The target wallet.
     */
    function cancelRecovery(address _wallet) external onlySelf() onlyWhenRecovery(_wallet) {
        address recoveryOwner = recoveryConfigs[_wallet].recovery;
        delete recoveryConfigs[_wallet];
        _setLock(_wallet, 0, bytes4(0));

        emit RecoveryCanceled(_wallet, recoveryOwner);
    }

    /**
     * @notice Lets the owner transfer the wallet ownership. This is executed immediately.
     * @param _wallet The target wallet.
     * @param _newOwner The address to which ownership should be transferred.
     */
    function transferOwnership(address _wallet, address _newOwner) external onlySelf() onlyWhenUnlocked(_wallet) {
        validateNewOwner(_wallet, _newOwner);
        IWallet(_wallet).setOwner(_newOwner);

        emit OwnershipTransfered(_wallet, _newOwner);
    }

    /**
     * @notice Lets the owner upgrade the wallet. This is executed immediately.
     * @param _wallet The target wallet.
     * @param _newImplementation The address of the new implementation.
     */
    function upgradeWallet(address _wallet, address _newImplementation) external onlySelf() onlyWhenUnlocked(_wallet) {
        //TODO: validate new implementation
        UUPSUpgradeable(_wallet).upgradeTo(_newImplementation);

        emit WalletUpgraded(_wallet, _newImplementation);
    }

    /**
    * @notice Gets the details of the ongoing recovery procedure if any.
    * @param _wallet The target wallet.
    */
    function getRecovery(address _wallet) external view returns(address _address, uint64 _executeAfter, uint32 _guardianCount) {
        RecoveryConfig storage config = recoveryConfigs[_wallet];
        return (config.recovery, config.executeAfter, config.guardianCount);
    }

    // *************** Lock functions ************************ //

    /**
     * @notice Lets a guardian lock a wallet.
     * @param _wallet The target wallet.
     */
    function lock(address _wallet) external onlyGuardianOrSelf(_wallet) onlyWhenUnlocked(_wallet) {
        _setLock(_wallet, block.timestamp + lockPeriod, SecurityManager.lock.selector);
        emit Locked(_wallet, uint64(block.timestamp + lockPeriod));
    }

    /**
     * @notice Lets a guardian unlock a locked wallet.
     * @param _wallet The target wallet.
     */
    function unlock(address _wallet) external onlyGuardianOrSelf(_wallet) onlyWhenLocked(_wallet) {
        require(locks[_wallet].locker == SecurityManager.lock.selector, "SM: cannot unlock");
        _setLock(_wallet, 0, bytes4(0));
        emit Unlocked(_wallet);
    }

    /**
     * @notice Returns the release time of a wallet lock or 0 if the wallet is unlocked.
     * @param _wallet The target wallet.
     * @return _releaseAfter The epoch time at which the lock will release (in seconds).
     */
    function getLock(address _wallet) external view returns(uint64 _releaseAfter) {
        return _isLocked(_wallet) ? locks[_wallet].release : 0;
    }

    /**
     * @notice Checks if a wallet is locked.
     * @param _wallet The target wallet.
     * @return _isLocked `true` if the wallet is locked otherwise `false`.
     */
    function isLocked(address _wallet) external view returns (bool) {
        return _isLocked(_wallet);
    }

    // *************** Guardian functions ************************ //

    /**
     * @notice Lets the owner add a guardian to its wallet.
     * The first guardian is added immediately. All following additions must be confirmed
     * by calling the confirmGuardianAddition() method.
     * @param _wallet The target wallet.
     * @param _guardian The guardian to add.
     */
    function addGuardian(address _wallet, address _guardian) external onlyWalletOrSelf(_wallet) onlyWhenUnlocked(_wallet) {
        console.log("addGuardian");
        require(!_isOwner(_wallet, _guardian), "SM: guardian cannot be owner");
        require(!isGuardian(_wallet, _guardian), "SM: duplicate guardian");
        // Guardians must either be an EOA or a contract with an owner()
        // method that returns an address with a 25000 gas stipend.
        // Note that this test is not meant to be strict and can be bypassed by custom malicious contracts.
        (bool success,) = _guardian.call{gas: 25000}(abi.encodeWithSignature("owner()"));
        require(success, "SM: must be EOA/Argent wallet");

        bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "addition"));
        GuardianManagerConfig storage config = guardianConfigs[_wallet];
        require(
            config.pending[id] == 0 || block.timestamp > config.pending[id] + securityWindow,
            "SM: duplicate pending addition");
        config.pending[id] = block.timestamp + securityPeriod;
        emit GuardianAdditionRequested(_wallet, _guardian, block.timestamp + securityPeriod);
    }

    /**
     * @notice Confirms the pending addition of a guardian to a wallet.
     * The method must be called during the confirmation window and can be called by anyone to enable orchestration.
     * @param _wallet The target wallet.
     * @param _guardian The guardian.
     */
    function confirmGuardianAddition(address _wallet, address _guardian) external onlyWhenUnlocked(_wallet) {
        bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "addition"));
        GuardianManagerConfig storage config = guardianConfigs[_wallet];
        require(config.pending[id] > 0, "SM: unknown pending addition");
        require(config.pending[id] < block.timestamp, "SM: pending addition not over");
        require(block.timestamp < config.pending[id] + securityWindow, "SM: pending addition expired");
        guardianStorage.addGuardian(_wallet, _guardian);
        emit GuardianAdded(_wallet, _guardian);
        delete config.pending[id];
    }

    /**
     * @notice Lets the owner cancel a pending guardian addition.
     * @param _wallet The target wallet.
     * @param _guardian The guardian.
     */
    function cancelGuardianAddition(address _wallet, address _guardian) external onlyWalletOrSelf(_wallet) onlyWhenUnlocked(_wallet) {
        bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "addition"));
        GuardianManagerConfig storage config = guardianConfigs[_wallet];
        require(config.pending[id] > 0, "SM: unknown pending addition");
        delete config.pending[id];
        emit GuardianAdditionCancelled(_wallet, _guardian);
    }

    /**
     * @notice Lets the owner revoke a guardian from its wallet.
     * @dev Revokation must be confirmed by calling the confirmGuardianRevokation() method.
     * @param _wallet The target wallet.
     * @param _guardian The guardian to revoke.
     */
    function revokeGuardian(address _wallet, address _guardian) external onlyWalletOrSelf(_wallet) {
        require(isGuardian(_wallet, _guardian), "SM: must be existing guardian");
        bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "revokation"));
        GuardianManagerConfig storage config = guardianConfigs[_wallet];
        require(
            config.pending[id] == 0 || block.timestamp > config.pending[id] + securityWindow,
            "SM: duplicate pending revoke"); // TODO need to allow if confirmation window passed
        config.pending[id] = block.timestamp + securityPeriod;
        emit GuardianRevokationRequested(_wallet, _guardian, block.timestamp + securityPeriod);
    }

    /**
     * @notice Confirms the pending revokation of a guardian to a wallet.
     * The method must be called during the confirmation window and can be called by anyone to enable orchestration.
     * @param _wallet The target wallet.
     * @param _guardian The guardian.
     */
    function confirmGuardianRevokation(address _wallet, address _guardian) external {
        bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "revokation"));
        GuardianManagerConfig storage config = guardianConfigs[_wallet];
        require(config.pending[id] > 0, "SM: unknown pending revoke");
        require(config.pending[id] < block.timestamp, "SM: pending revoke not over");
        require(block.timestamp < config.pending[id] + securityWindow, "SM: pending revoke expired");
        guardianStorage.revokeGuardian(_wallet, _guardian);
        emit GuardianRevoked(_wallet, _guardian);
        delete config.pending[id];
    }

    /**
     * @notice Lets the owner cancel a pending guardian revokation.
     * @param _wallet The target wallet.
     * @param _guardian The guardian.
     */
    function cancelGuardianRevokation(address _wallet, address _guardian) external onlyWalletOrSelf(_wallet) onlyWhenUnlocked(_wallet) {
        bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "revokation"));
        GuardianManagerConfig storage config = guardianConfigs[_wallet];
        require(config.pending[id] > 0, "SM: unknown pending revoke");
        delete config.pending[id];
        emit GuardianRevokationCancelled(_wallet, _guardian);
    }

    /**
     * @notice Checks if an address is a guardian for a wallet.
     * @param _wallet The target wallet.
     * @param _guardian The address to check.
     * @return _isGuardian `true` if the address is a guardian for the wallet otherwise `false`.
     */
    function isGuardian(address _wallet, address _guardian) public view returns (bool _isGuardian) {
        return guardianStorage.isGuardian(_wallet, _guardian);
    }

    /**
     * @notice Counts the number of active guardians for a wallet.
     * @param _wallet The target wallet.
     * @return _count The number of active guardians for a wallet.
     */
    function guardianCount(address _wallet) external view returns (uint256 _count) {
        return guardianStorage.guardianCount(_wallet);
    }

    /**
     * @notice Get the active guardians for a wallet.
     * @param _wallet The target wallet.
     * @return _guardians the active guardians for a wallet.
     */
    function getGuardians(address _wallet) external view returns (address[] memory _guardians) {
        return guardianStorage.getGuardians(_wallet);
    }

    // *************** Internal Functions ********************* //

    function validateNewOwner(address _wallet, address _newOwner) internal view {
        require(_newOwner != address(0), "SM: new owner cannot be null");
        require(!isGuardian(_wallet, _newOwner), "SM: new owner cannot be guardian");
    }

    function _setLock(address _wallet, uint256 _releaseAfter, bytes4 _locker) internal {
        locks[_wallet] = Lock(SafeCast.toUint64(_releaseAfter), _locker);
    }
}

// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.18;

import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "../interfaces/UserOperation.sol";
import "../wallet/IWallet.sol";
import "./ISignatureModule.sol";
import "hardhat/console.sol";

abstract contract SignatureModule is ISignatureModule{
    //is ISignatureModule {
    using ECDSA for bytes32;
    //return value in case of signature failure, with no time-range.
    // equivalent to _packValidationData(true,0,0);
    uint256 internal constant SIG_VALIDATION_FAILED = 1;

    constructor() {}

    function isValidSignature(
        UserOperation calldata _userOp,
        bytes32 _userOpHash
    ) public view override returns (uint256 validationData) {
        bytes32 hash = _userOpHash.toEthSignedMessageHash();
        address _owner = IWallet(msg.sender).owner();
        if (_owner != hash.recover(_userOp.signature))
            return SIG_VALIDATION_FAILED;
        return 0;
    }

    function isSignatureModule() external pure override returns (bool) {
        return true;
    }
}

// Copyright (C) 2018  Argent Labs Ltd. <https://argent.xyz>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.9.0;

/**
 * @title IWallet
 * @notice Interface for the BaseWallet
 */
interface IWallet {
    /**
     * @notice Returns the wallet owner.
     * @return The wallet owner address.
     */
    function owner() external view returns (address);

    /**
     * @notice Returns the number of authorised modules.
     * @return The number of authorised modules.
     */
    function modules() external view returns (uint);

    /**
     * @notice Sets a new owner for the wallet.
     * @param _newOwner The new owner.
     */
    function setOwner(address _newOwner) external;

    /**
     * @notice Checks if a module is authorised on the wallet.
     * @param _module The module address to check.
     * @return `true` if the module is authorised, otherwise `false`.
     */
    function authorised(address _module) external view returns (bool);

    /**
     * @notice Returns the module responsible for a static call redirection.
     * @param _sig The signature of the static call.
     * @return the module doing the redirection
     */
    function enabled(bytes4 _sig) external view returns (address);

    /**
     * @notice Enables/Disables a module.
     * @param _module The target module.
     * @param _value Set to `true` to authorise the module.
     */
    function authoriseModule(address _module, bool _value) external;

    /**
    * @notice Enables a static method by specifying the target module to which the call must be delegated.
    * @param _module The target module.
    * @param _method The static method signature.
    */
    function enableStaticCall(address _module, bytes4 _method) external;
}

File 36 of 36 : console.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

library console {
    address constant CONSOLE_ADDRESS =
        0x000000000000000000636F6e736F6c652e6c6f67;

    function _sendLogPayloadImplementation(bytes memory payload) internal view {
        address consoleAddress = CONSOLE_ADDRESS;
        /// @solidity memory-safe-assembly
        assembly {
            pop(
                staticcall(
                    gas(),
                    consoleAddress,
                    add(payload, 32),
                    mload(payload),
                    0,
                    0
                )
            )
        }
    }

    function _castToPure(
      function(bytes memory) internal view fnIn
    ) internal pure returns (function(bytes memory) pure fnOut) {
        assembly {
            fnOut := fnIn
        }
    }

    function _sendLogPayload(bytes memory payload) internal pure {
        _castToPure(_sendLogPayloadImplementation)(payload);
    }

    function log() internal pure {
        _sendLogPayload(abi.encodeWithSignature("log()"));
    }
    function logInt(int256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
    }

    function logUint(uint256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
    }

    function logString(string memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function logBool(bool p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function logAddress(address p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function logBytes(bytes memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
    }

    function logBytes1(bytes1 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
    }

    function logBytes2(bytes2 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
    }

    function logBytes3(bytes3 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
    }

    function logBytes4(bytes4 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
    }

    function logBytes5(bytes5 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
    }

    function logBytes6(bytes6 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
    }

    function logBytes7(bytes7 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
    }

    function logBytes8(bytes8 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
    }

    function logBytes9(bytes9 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
    }

    function logBytes10(bytes10 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
    }

    function logBytes11(bytes11 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
    }

    function logBytes12(bytes12 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
    }

    function logBytes13(bytes13 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
    }

    function logBytes14(bytes14 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
    }

    function logBytes15(bytes15 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
    }

    function logBytes16(bytes16 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
    }

    function logBytes17(bytes17 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
    }

    function logBytes18(bytes18 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
    }

    function logBytes19(bytes19 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
    }

    function logBytes20(bytes20 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
    }

    function logBytes21(bytes21 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
    }

    function logBytes22(bytes22 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
    }

    function logBytes23(bytes23 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
    }

    function logBytes24(bytes24 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
    }

    function logBytes25(bytes25 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
    }

    function logBytes26(bytes26 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
    }

    function logBytes27(bytes27 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
    }

    function logBytes28(bytes28 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
    }

    function logBytes29(bytes29 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
    }

    function logBytes30(bytes30 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
    }

    function logBytes31(bytes31 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
    }

    function logBytes32(bytes32 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
    }

    function log(uint256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
    }

    function log(string memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function log(bool p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function log(address p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function log(uint256 p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1));
    }

    function log(uint256 p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1));
    }

    function log(uint256 p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1));
    }

    function log(uint256 p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1));
    }

    function log(string memory p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1));
    }

    function log(string memory p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
    }

    function log(string memory p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
    }

    function log(string memory p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
    }

    function log(bool p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1));
    }

    function log(bool p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
    }

    function log(bool p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
    }

    function log(bool p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
    }

    function log(address p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1));
    }

    function log(address p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
    }

    function log(address p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
    }

    function log(address p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
    }

    function log(uint256 p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
    }

    function log(string memory p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2));
    }

    function log(string memory p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
    }

    function log(string memory p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
    }

    function log(string memory p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
    }

    function log(bool p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2));
    }

    function log(bool p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
    }

    function log(bool p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
    }

    function log(bool p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
    }

    function log(bool p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2));
    }

    function log(bool p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
    }

    function log(bool p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
    }

    function log(bool p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2));
    }

    function log(address p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2));
    }

    function log(address p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
    }

    function log(address p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
    }

    function log(address p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
    }

    function log(address p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2));
    }

    function log(address p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
    }

    function log(address p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
    }

    function log(address p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
    }

    function log(address p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2));
    }

    function log(address p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
    }

    function log(address p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
    }

    function log(address p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
    }

}

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

Contract ABI

API
[{"inputs":[{"internalType":"contract IModuleRegistry","name":"_registry","type":"address"},{"internalType":"contract IGuardianStorage","name":"_guardianStorage","type":"address"},{"internalType":"contract ITransferStorage","name":"_userWhitelist","type":"address"},{"internalType":"contract IAuthoriser","name":"_authoriser","type":"address"},{"internalType":"uint256","name":"_securityPeriod","type":"uint256"},{"internalType":"uint256","name":"_securityWindow","type":"uint256"},{"internalType":"uint256","name":"_recoveryPeriod","type":"uint256"},{"internalType":"uint256","name":"_lockPeriod","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"uint64","name":"whitelistAfter","type":"uint64"}],"name":"AddedToWhitelist","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"}],"name":"GuardianAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"}],"name":"GuardianAdditionCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"},{"indexed":false,"internalType":"uint256","name":"executeAfter","type":"uint256"}],"name":"GuardianAdditionRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"}],"name":"GuardianRevokationCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"},{"indexed":false,"internalType":"uint256","name":"executeAfter","type":"uint256"}],"name":"GuardianRevokationRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"}],"name":"GuardianRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint64","name":"releaseAfter","type":"uint64"}],"name":"Locked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"name","type":"bytes32"}],"name":"ModuleCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"OwnershipTransfered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"_recovery","type":"address"}],"name":"RecoveryCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"_recovery","type":"address"},{"indexed":false,"internalType":"uint64","name":"executeAfter","type":"uint64"}],"name":"RecoveryExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"_recovery","type":"address"}],"name":"RecoveryFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"refundAddress","type":"address"},{"indexed":false,"internalType":"address","name":"refundToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"refundAmount","type":"uint256"}],"name":"Refund","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"}],"name":"RemovedFromWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"address","name":"sessionKey","type":"address"}],"name":"SessionCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"address","name":"sessionKey","type":"address"},{"indexed":false,"internalType":"uint64","name":"expires","type":"uint64"}],"name":"SessionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"bytes","name":"returnData","type":"bytes"},{"indexed":false,"internalType":"bytes32","name":"signedHash","type":"bytes32"}],"name":"TransactionExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"}],"name":"Unlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"_newImplementation","type":"address"}],"name":"WalletUpgraded","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"addGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_module","type":"address"}],"name":"addModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_target","type":"address"}],"name":"addToWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"cancelGuardianAddition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"cancelGuardianRevokation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"cancelRecovery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"clearSession","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"confirmGuardianAddition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"confirmGuardianRevokation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bytes","name":"_signatures","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_recovery","type":"address"}],"name":"executeRecovery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"finalizeRecovery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"getGuardians","outputs":[{"internalType":"address[]","name":"_guardians","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"getLock","outputs":[{"internalType":"uint64","name":"_releaseAfter","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"getRecovery","outputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"uint64","name":"_executeAfter","type":"uint64"},{"internalType":"uint32","name":"_guardianCount","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"getRequiredSignatures","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"enum BaseModule.OwnerSignature","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"getSession","outputs":[{"internalType":"address","name":"key","type":"address"},{"internalType":"uint64","name":"expires","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"guardianCount","outputs":[{"internalType":"uint256","name":"_count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"bytes32","name":"_signHash","type":"bytes32"}],"name":"isExecutedTx","outputs":[{"internalType":"bool","name":"executed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"isGuardian","outputs":[{"internalType":"bool","name":"_isGuardian","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"isLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isSignatureModule","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_msgHash","type":"bytes32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"callGasLimit","type":"uint256"},{"internalType":"uint256","name":"verificationGasLimit","type":"uint256"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct UserOperation","name":"_userOp","type":"tuple"},{"internalType":"bytes32","name":"_userOpHash","type":"bytes32"}],"name":"isValidSignature","outputs":[{"internalType":"uint256","name":"validationData","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_target","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"_isWhitelisted","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"lock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct EnterpriseTransactionManager.Call[]","name":"_transactions","type":"tuple[]"}],"name":"multiCall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct EnterpriseTransactionManager.Call[]","name":"_transactions","type":"tuple[]"}],"name":"multiCallWithGuardians","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct EnterpriseTransactionManager.Call[]","name":"_transactions","type":"tuple[]"},{"internalType":"address","name":"_sessionUser","type":"address"},{"internalType":"uint64","name":"_duration","type":"uint64"}],"name":"multiCallWithGuardiansAndStartSession","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct EnterpriseTransactionManager.Call[]","name":"_transactions","type":"tuple[]"}],"name":"multiCallWithSession","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"recoverToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_target","type":"address"}],"name":"removeFromWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"revokeGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_methodId","type":"bytes4"}],"name":"supportsStaticCall","outputs":[{"internalType":"bool","name":"_isSupported","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"unlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_newImplementation","type":"address"}],"name":"upgradeWallet","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6102806040523480156200001257600080fd5b5060405162005fc838038062005fc883398101604081905262000035916200039c565b83828585846040518060400160405280600c81526020016b52656c617965724b6e6f627360a01b81525080604051806040016040528060018152602001603160f81b8152508f8f8f8f6f456e74657270726973654d6f64756c6560801b846001600160a01b03166080816001600160a01b031681525050836001600160a01b031660a0816001600160a01b031681525050826001600160a01b031660c0816001600160a01b031681525050816001600160a01b031660e0816001600160a01b0316815250507f3019c8fc80239e3dff8f781212ae2004839c2cb61d6c70acd279ac65392145df816040516200012c91815260200190565b60405180910390a1505050505062000154600283620002ed60201b620035e41790919060201c565b6101a05262000171816003620002ed602090811b620035e417901c565b6101c052815160208084019190912061016052815190820120610180524661012052620002026101605161018051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b61010052505030610140525083811015620002645760405162461bcd60e51b815260206004820152601860248201527f534d3a20696e736563757265206c6f636b20706572696f64000000000000000060448201526064015b60405180910390fd5b6200027082846200042b565b841015620002c15760405162461bcd60e51b815260206004820152601d60248201527f534d3a20696e73656375726520736563757269747920706572696f647300000060448201526064016200025b565b6101e0939093526102009290925261024091909152610220526102605250620006339650505050505050565b60006020835110156200030d5762000305836200033d565b905062000337565b8262000324836200038060201b620036151760201c565b90620003319082620004f2565b5060ff90505b92915050565b600080829050601f815111156200036b578260405163305a27a960e01b81526004016200025b9190620005be565b805162000378826200060e565b179392505050565b90565b6001600160a01b03811681146200039957600080fd5b50565b600080600080600080600080610100898b031215620003ba57600080fd5b8851620003c78162000383565b60208a0151909850620003da8162000383565b60408a0151909750620003ed8162000383565b60608a0151909650620004008162000383565b60808a015160a08b015160c08c015160e0909c01519a9d999c50979a91999098919650945092505050565b808201808211156200033757634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200047857607f821691505b6020821081036200049957634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620004ed57600081815260208120601f850160051c81016020861015620004c85750805b601f850160051c820191505b81811015620004e957828155600101620004d4565b5050505b505050565b81516001600160401b038111156200050e576200050e6200044d565b62000526816200051f845462000463565b846200049f565b602080601f8311600181146200055e5760008415620005455750858301515b600019600386901b1c1916600185901b178555620004e9565b600085815260208120601f198616915b828110156200058f578886015182559484019460019091019084016200056e565b5085821015620005ae5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208083528351808285015260005b81811015620005ed57858101830151858201604001528201620005cf565b506000604082860101526040601f19601f8301168501019250505092915050565b80516020808301519190811015620004995760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e0516102005161022051610240516102605161585c6200076c60003960006119590152600081816109de0152818161159e01528181611e1f0152612f5a015260008181610a5701528181610abf01528181612fd3015261303b015260008181612b010152818161349401526134f6015260006129ab0152600061232d01526000612302015260006147820152600061475a015260006146b5015260006146df0152600061470901526000505060008181612bb10152613d58015260008181611638015281816116ff01528181611eb901528181612a15015281816132860152818161339701528181613c7b0152613fce01526000818161184301528181611a4a0152612510015261585c6000f3fe608060405234801561001057600080fd5b50600436106102485760003560e01c806384b0196e1161013b578063b6b35272116100b8578063d4ee97341161007c578063d4ee9734146106db578063f143ddba146106ee578063f18858ab14610701578063f435f5a714610721578063f8d3277d1461073457610248565b8063b6b352721461067c578063ba8210881461068f578063c6845210146106a2578063c90db447146106b5578063d4bfea48146106c857610248565b80639be65a60116100ff5780639be65a6014610616578063a3f4df7e14610629578063a5efb23514610643578063a6eb069014610656578063b0ba4da01461066957610248565b806384b0196e146104fa578063873bd184146105155780638c8e13b91461051c5780639769c3fe146105835780639add38d51461060357610248565b80634b3ef054116101c95780636b9db4e61161018d5780636b9db4e6146104835780636d435421146104ae5780636ff6ec7c146104c157806370135f52146104d45780637d1c2e78146104e757610248565b80634b3ef054146103f05780635040fb761461040357806357518243146104245780635a1db8c41461043757806360c0fdc01461044a57610248565b80632960739b116102105780632960739b146103835780632f6c493c14610396578063315a7af3146103a95780633b73d67f146103bc5780634a4fbeec146103dd57610248565b80631626ba7e146102e957806319ab453c1461031a5780631d97d8cc1461032d5780632437b75c1461034057806325b5093414610360575b600061028a6000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061074792505050565b90506001600160e01b03198116630a85bd0160e11b14806102bb57506001600160e01b0319811663f23a6e6160e01b145b806102d657506001600160e01b0319811663bc197c8160e01b145b156102e75760046000803760206000f35b005b6102fc6102f7366004614c76565b6107a8565b6040516001600160e01b031990911681526020015b60405180910390f35b6102e7610328366004614d14565b610881565b6102e761033b366004614d31565b6108e7565b61035361034e366004614dae565b610afd565b6040516103119190614e84565b61037361036e366004614ee6565b610b66565b6040519015158152602001610311565b6102e7610391366004614d31565b610bed565b6102e76103a4366004614d14565b610d34565b6102e76103b7366004614d14565b610ea1565b6103cf6103ca366004614f51565b611065565b604051610311929190614fbb565b6103736103eb366004614d14565b611483565b6102e76103fe366004614d31565b61148e565b610416610411366004614d14565b6116dd565b604051908152602001610311565b6102e7610432366004614d31565b61176c565b6102e7610445366004614d31565b6119d4565b610373610458366004614fed565b6001600160a01b03919091166000908152600460209081526040808320938352929052205460ff1690565b610496610491366004614d14565b611b69565b6040516001600160401b039091168152602001610311565b6102e76104bc366004614d31565b611ba4565b6103536104cf366004615019565b611c8c565b6102e76104e2366004614d31565b611ce8565b6103736104f5366004615060565b611f5f565b6105026122f4565b60405161031197969594939291906150f5565b6001610373565b61055c61052a366004614d14565b6001600160a01b0390811660009081526020819052604090205490811691600160a01b9091046001600160401b031690565b604080516001600160a01b0390931683526001600160401b03909116602083015201610311565b6105d0610591366004614d14565b6001600160a01b0390811660009081526005602052604090205490811691600160a01b82046001600160401b031691600160e01b900463ffffffff1690565b604080516001600160a01b0390941684526001600160401b03909216602084015263ffffffff1690820152606001610311565b61041661061136600461518b565b61237d565b6102e7610624366004614d14565b61248e565b6104166f456e74657270726973654d6f64756c6560801b81565b610353610651366004615019565b612595565b6102e7610664366004614d31565b6127c5565b6102e7610677366004614d31565b61290c565b61037361068a366004614d31565b612b85565b6102e761069d366004614d14565b612c35565b6102e76106b0366004614d31565b612ce6565b6102e76106c3366004614d14565b61307a565b6102e76106d6366004614d31565b61317e565b6103736106e9366004614d31565b61325c565b6103536106fc366004615019565b6132fa565b61071461070f366004614d14565b613375565b60405161031191906151c7565b6102e761072f366004614d14565b613408565b6102e7610742366004614d31565b61353b565b60006004825110156107a05760405162461bcd60e51b815260206004820152601d60248201527f5574696c733a20496e76616c69642066756e6374696f6e50726566697800000060448201526064015b60405180910390fd5b506020015190565b600081516041146107fb5760405162461bcd60e51b815260206004820152601c60248201527f544d3a20696e76616c6964207369676e6174757265206c656e677468000000006044820152606401610797565b600061080984846000613618565b9050610815338261374d565b6108565760405162461bcd60e51b81526020600482015260126024820152712a269d1024b73b30b634b21039b4b3b732b960711b6044820152606401610797565b7f1626ba7e356f5979dd355a3d2bfb43e80420a480c3b854edce286a82d74968699150505b92915050565b80336001600160a01b038216146108da5760405162461bcd60e51b815260206004820152601960248201527f424d3a2063616c6c6572206d7573742062652077616c6c6574000000000000006044820152606401610797565b6108e3826137cc565b5050565b81303314806108fe5750336001600160a01b038216145b61091a5760405162461bcd60e51b815260040161079790615214565b610924838361325c565b6109705760405162461bcd60e51b815260206004820152601d60248201527f534d3a206d757374206265206578697374696e6720677561726469616e0000006044820152606401610797565b6000838360405160200161098592919061524b565b60408051601f1981840301815291815281516020928301206001600160a01b0387166000908152600684528281208282529384905291909120549092501580610a065750600082815260208290526040902054610a03907f000000000000000000000000000000000000000000000000000000000000000090615296565b42115b610a525760405162461bcd60e51b815260206004820152601c60248201527f534d3a206475706c69636174652070656e64696e67207265766f6b65000000006044820152606401610797565b610a7c7f000000000000000000000000000000000000000000000000000000000000000042615296565b6000838152602083905260409020556001600160a01b038085169086167f9746f6868f544595794833da53250bd19e72334733336cfd5dd6fbc5f6a6ac42610ae47f000000000000000000000000000000000000000000000000000000000000000042615296565b6040519081526020015b60405180910390a35050505050565b6060303314610b1e5760405162461bcd60e51b8152600401610797906152a9565b85610b2881613835565b15610b455760405162461bcd60e51b8152600401610797906152d5565b610b5087858561385e565b610b5b8787876139cb565b979650505050505050565b60006001600160e01b03198216630b135d3f60e11b1480610b9757506001600160e01b03198216630a85bd0160e11b145b80610bb257506001600160e01b031982166301ffc9a760e01b145b80610bcd57506001600160e01b0319821663f23a6e6160e01b145b8061087b57506001600160e01b0319821663bc197c8160e01b1492915050565b8130331480610c045750336001600160a01b038216145b610c205760405162461bcd60e51b815260040161079790615214565b82610c2a81613835565b15610c475760405162461bcd60e51b8152600401610797906152d5565b60008484604051602001610c5c92919061524b565b60408051601f1981840301815291815281516020928301206001600160a01b038816600090815260068452828120828252938490529190912054909250610ce55760405162461bcd60e51b815260206004820152601a60248201527f534d3a20756e6b6e6f776e2070656e64696e67207265766f6b650000000000006044820152606401610797565b600082815260208290526040808220829055516001600160a01b0380881692908916917fc0b205956d5e27c296695de329b5a014584a4f51824b1725a0eefc1174d6dbd59190a3505050505050565b8030331480610d485750610d48813361325c565b610d905760405162461bcd60e51b815260206004820152601960248201527829a69d1036bab9ba1031329033bab0b93234b0b717b9b2b63360391b6044820152606401610797565b81610d9a81613835565b610de65760405162461bcd60e51b815260206004820152601960248201527f424d3a2077616c6c6574206d757374206265206c6f636b6564000000000000006044820152606401610797565b6001600160a01b038316600090815260016020526040902054600160401b900460e01b6001600160e01b03191663f435f5a760e01b14610e5c5760405162461bcd60e51b8152602060048201526011602482015270534d3a2063616e6e6f7420756e6c6f636b60781b6044820152606401610797565b610e6883600080613bb3565b6040516001600160a01b038416907f7e6adfec7e3f286831a0200a754127c171a2da564078722cb97704741bbdb0ea90600090a2505050565b6001600160a01b0381166000908152600560205260409020548190600160a01b90046001600160401b0316610f125760405162461bcd60e51b8152602060048201526017602482015276534d3a206e6f206f6e676f696e67207265636f7665727960481b6044820152606401610797565b6001600160a01b038216600090815260056020526040902080546001600160401b03600160a01b90910481164290911611610f8f5760405162461bcd60e51b815260206004820152601b60248201527f534d3a206f6e676f696e67207265636f7665727920706572696f6400000000006044820152606401610797565b80546001600160a01b0384811660009081526005602052604081205516610fb584613c2e565b6040516313af403560e01b81526001600160a01b0382811660048301528516906313af403590602401600060405180830381600087803b158015610ff857600080fd5b505af115801561100c573d6000803e3d6000fd5b5050505061101f8460008060e01b613bb3565b806001600160a01b0316846001600160a01b03167fd8667de85dae2d56d76e700d16de53d21ac2ce4d5549cb0bf51c55fdc37f0bc160405160405180910390a350505050565b60008060006110a985858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061074792505050565b90506001600160e01b0319811663a5efb23560e01b14806110da57506001600160e01b03198116635751824360e01b145b806110f557506001600160e01b0319811663f8d3277d60e01b145b8061111057506001600160e01b03198116631750421160e31b145b1561113f576001600160a01b038616330361113257600080925092505061147b565b600180925092505061147b565b63240244e160e21b6001600160e01b0319821601611183576001600160a01b03861633036111755760006004925092505061147b565b60016004925092505061147b565b63027a2d9360e51b6001600160e01b03198216016112055760006111a687613c55565b9050600081116111f85760405162461bcd60e51b815260206004820152601e60248201527f414d3a206e6f20677561726469616e7320736574206f6e2077616c6c657400006044820152606401610797565b92506003915061147b9050565b6336f24bb960e01b6001600160e01b0319821601611296576001600160a01b03861660009081526005602052604081205461125f9061125290600160e01b900463ffffffff166001615300565b63ffffffff166002613ce9565b90506001600160a01b03871633036112895761127c60018261531d565b600393509350505061147b565b92506002915061147b9050565b6001600160e01b03198116630c68452160e41b14806112c557506001600160e01b03198116630765f63360e21b145b806112e057506001600160e01b03198116630a6eb06960e41b145b806112fb57506001600160e01b03198116632960739b60e01b145b8061131657506001600160e01b03198116636d43542160e01b145b8061133157506001600160e01b031981166316876e3160e21b145b8061134c57506001600160e01b03198116631a97fd4960e31b145b8061136757506001600160e01b031981166378a1eedd60e11b145b8061138257506001600160e01b0319811663090dedd760e21b145b156113a057600061139287613c55565b93506003925061147b915050565b6001600160e01b0319811663315a7af360e01b14806113cf57506001600160e01b03198116633809afa960e11b145b806113ea57506001600160e01b031981166312cfbc1560e21b145b156113fc57600080925092505061147b565b6001600160e01b0319811663f435f5a760e01b148061142b57506001600160e01b03198116630bdb124f60e21b145b1561143e5760016003925092505061147b565b60405162461bcd60e51b815260206004820152601260248201527114d34e881d5b9adb9bdddb881b595d1a1bd960721b6044820152606401610797565b935093915050565b600061087b82613835565b600082826040516020016114a392919061524b565b60408051601f1981840301815291815281516020928301206001600160a01b03861660009081526006845282812082825293849052919091205490925061152c5760405162461bcd60e51b815260206004820152601a60248201527f534d3a20756e6b6e6f776e2070656e64696e67207265766f6b650000000000006044820152606401610797565b60008281526020829052604090205442116115895760405162461bcd60e51b815260206004820152601b60248201527f534d3a2070656e64696e67207265766f6b65206e6f74206f76657200000000006044820152606401610797565b6000828152602082905260409020546115c3907f000000000000000000000000000000000000000000000000000000000000000090615296565b42106116115760405162461bcd60e51b815260206004820152601a60248201527f534d3a2070656e64696e67207265766f6b6520657870697265640000000000006044820152606401610797565b604051630765f63360e21b81526001600160a01b03858116600483015284811660248301527f00000000000000000000000000000000000000000000000000000000000000001690631d97d8cc90604401600060405180830381600087803b15801561167c57600080fd5b505af1158015611690573d6000803e3d6000fd5b50506040516001600160a01b038087169350871691507f548f10dcba266544123ad8cf8284f25c4baa659cba25dbdf16a06ea11235de9b90600090a3600091825260205260408120555050565b6040516328207dbb60e11b81526001600160a01b0382811660048301526000917f000000000000000000000000000000000000000000000000000000000000000090911690635040fb7690602401602060405180830381865afa158015611748573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087b9190615330565b81303314806117805750611780813361374d565b61179c5760405162461bcd60e51b815260040161079790615349565b826117a681613835565b156117c35760405162461bcd60e51b8152600401610797906152d5565b836001600160a01b0316836001600160a01b0316036118245760405162461bcd60e51b815260206004820152601b60248201527f544d3a2043616e6e6f742077686974656c6973742077616c6c657400000000006044820152606401610797565b604051630bcd4ebb60e01b81526001600160a01b0384811660048301527f00000000000000000000000000000000000000000000000000000000000000001690630bcd4ebb90602401602060405180830381865afa15801561188a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ae9190615380565b156118fb5760405162461bcd60e51b815260206004820152601b60248201527f544d3a2043616e6e6f742077686974656c697374206d6f64756c6500000000006044820152606401610797565b6119058484612b85565b156119525760405162461bcd60e51b815260206004820152601e60248201527f544d3a2074617267657420616c72656164792077686974656c697374656400006044820152606401610797565b600061197e7f000000000000000000000000000000000000000000000000000000000000000042615296565b905061198b858583613d2a565b6040516001600160401b03821681526001600160a01b0380861691908716907f1f57f9641d3e8733ed672fef5ac85464bd7215ef2f21e83428e8408248b13dcd90602001610aee565b81303314806119e857506119e8813361374d565b611a045760405162461bcd60e51b815260040161079790615349565b82611a0e81613835565b15611a2b5760405162461bcd60e51b8152600401610797906152d5565b604051630bcd4ebb60e01b81526001600160a01b0384811660048301527f00000000000000000000000000000000000000000000000000000000000000001690630bcd4ebb90602401602060405180830381865afa158015611a91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab59190615380565b611b015760405162461bcd60e51b815260206004820152601c60248201527f414d3a206d6f64756c65206973206e6f742072656769737465726564000000006044820152606401610797565b604051631f17732d60e01b81526001600160a01b03848116600483015260016024830152851690631f17732d90604401600060405180830381600087803b158015611b4b57600080fd5b505af1158015611b5f573d6000803e3d6000fd5b5050505050505050565b6000611b7482613835565b611b7f57600061087b565b506001600160a01b03166000908152600160205260409020546001600160401b031690565b303314611bc35760405162461bcd60e51b8152600401610797906152a9565b81611bcd81613835565b15611bea5760405162461bcd60e51b8152600401610797906152d5565b611bf48383613db9565b6040516313af403560e01b81526001600160a01b0383811660048301528416906313af403590602401600060405180830381600087803b158015611c3757600080fd5b505af1158015611c4b573d6000803e3d6000fd5b50506040516001600160a01b038086169350861691507f0d18b5fd22306e373229b9439188228edca81207d1667f604daf6cef8aa3ee6790600090a3505050565b6060303314611cad5760405162461bcd60e51b8152600401610797906152a9565b83611cb781613835565b15611cd45760405162461bcd60e51b8152600401610797906152d5565b611cdf8585856139cb565b95945050505050565b81611cf281613835565b15611d0f5760405162461bcd60e51b8152600401610797906152d5565b60008383604051602001611d249291906153a2565b60408051601f1981840301815291815281516020928301206001600160a01b038716600090815260068452828120828252938490529190912054909250611dad5760405162461bcd60e51b815260206004820152601c60248201527f534d3a20756e6b6e6f776e2070656e64696e67206164646974696f6e000000006044820152606401610797565b6000828152602082905260409020544211611e0a5760405162461bcd60e51b815260206004820152601d60248201527f534d3a2070656e64696e67206164646974696f6e206e6f74206f7665720000006044820152606401610797565b600082815260208290526040902054611e44907f000000000000000000000000000000000000000000000000000000000000000090615296565b4210611e925760405162461bcd60e51b815260206004820152601c60248201527f534d3a2070656e64696e67206164646974696f6e2065787069726564000000006044820152606401610797565b604051630c68452160e41b81526001600160a01b03868116600483015285811660248301527f0000000000000000000000000000000000000000000000000000000000000000169063c684521090604401600060405180830381600087803b158015611efd57600080fd5b505af1158015611f11573d6000803e3d6000fd5b50506040516001600160a01b038088169350881691507fbc3292102fa77e083913064b282926717cdfaede4d35f553d66366c0a3da755a90600090a360009182526020526040812055505050565b6000611f6c888888613e66565b611fb85760405162461bcd60e51b815260206004820152601e60248201527f524d3a20546172676574206f66205f6461746120213d205f77616c6c657400006044820152606401610797565b611fc188613835565b1561200e5760405162461bcd60e51b815260206004820152601860248201527f524d3a204c6f636b65642077616c6c657420726566756e6400000000000000006044820152606401610797565b600080600060606120208c8c8c611065565b9094509250831515806120445750600083600481111561204257612042614fa5565b145b6120905760405162461bcd60e51b815260206004820152601f60248201527f524d3a2057726f6e67207369676e617475726520726571756972656d656e74006044820152606401610797565b8561209c8560416153d5565b146120e95760405162461bcd60e51b815260206004820152601e60248201527f524d3a2057726f6e67206e756d626572206f66207369676e61747572657300006044820152606401610797565b60007fbf1af91af6bb21cb6f3df695a3f72929c8cc95124bb13aad4c9d2ff670a214318d8d8d60405161211d9291906153ec565b60405190819003812061215f9392918e908e906020019485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b604051602081830303815290604052805190602001209050600061218282613ee7565b9050600485600481111561219857612198614fa5565b036121ed576121a68e613f14565b6121e85760405162461bcd60e51b815260206004820152601360248201527229269d1024b73b30b634b21039b2b9b9b4b7b760691b6044820152606401610797565b61223f565b6121fa8e828b8b89613f74565b61223f5760405162461bcd60e51b8152602060048201526016602482015275524d3a20496e76616c6964207369676e61747572657360501b6044820152606401610797565b6040513090612251908f908f906153ec565b6000604051808303816000865af19150503d806000811461228e576040519150601f19603f3d011682016040523d82523d6000602084013e612293565b606091505b5080945081955050508315158e6001600160a01b03167f7da4525a280527268ba2e963ee6c1b18f43c9507bcb1d2560f652ab17c76e90a85846040516122da9291906153fc565b60405180910390a350919c9b505050505050505050505050565b6000606080828080836123287f000000000000000000000000000000000000000000000000000000000000000060026142c8565b6123537f000000000000000000000000000000000000000000000000000000000000000060036142c8565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c829052603c81206000336001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612410919061541e565b905061246061242361014087018761543b565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869392505061436c9050565b6001600160a01b0316816001600160a01b0316146124835760019250505061087b565b506000949350505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156124d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124f99190615330565b60405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390529192509083169063a9059cbb906044016020604051808303816000875af115801561256c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125909190615380565b505050565b60603033146125b65760405162461bcd60e51b8152600401610797906152a9565b836125c081613835565b156125dd5760405162461bcd60e51b8152600401610797906152d5565b6000836001600160401b038111156125f7576125f7614c09565b60405190808252806020026020018201604052801561262a57816020015b60608152602001906001900390816126155790505b50905060005b848110156127bb573086868381811061264b5761264b615481565b905060200281019061265d9190615497565b61266b906020810190614d14565b6001600160a01b0316036126c15760405162461bcd60e51b815260206004820152601760248201527f544d3a2063616c6c206e6f7420617574686f72697365640000000000000000006044820152606401610797565b61278b878787848181106126d7576126d7615481565b90506020028101906126e99190615497565b6126f7906020810190614d14565b88888581811061270957612709615481565b905060200281019061271b9190615497565b6020013589898681811061273157612731615481565b90506020028101906127439190615497565b61275190604081019061543b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061439092505050565b82828151811061279d5761279d615481565b602002602001018190525080806127b3906154b7565b915050612630565b5095945050505050565b81303314806127dc5750336001600160a01b038216145b6127f85760405162461bcd60e51b815260040161079790615214565b8261280281613835565b1561281f5760405162461bcd60e51b8152600401610797906152d5565b600084846040516020016128349291906153a2565b60408051601f1981840301815291815281516020928301206001600160a01b0388166000908152600684528281208282529384905291909120549092506128bd5760405162461bcd60e51b815260206004820152601c60248201527f534d3a20756e6b6e6f776e2070656e64696e67206164646974696f6e000000006044820152606401610797565b600082815260208290526040808220829055516001600160a01b0380881692908916917faa13b27c23e9e3f3d5f3861a53b7a2931e019170a6a19ed64942e26a1dd5987a9190a3505050505050565b30331461292b5760405162461bcd60e51b8152600401610797906152a9565b6001600160a01b0382166000908152600560205260409020548290600160a01b90046001600160401b03161561299a5760405162461bcd60e51b8152602060048201526014602482015273534d3a206f6e676f696e67207265636f7665727960601b6044820152606401610797565b6129a48383613db9565b60006129d07f000000000000000000000000000000000000000000000000000000000000000042615296565b604080516060810182526001600160a01b0380871682526001600160401b038416602083015282516328207dbb60e11b815288821660048201529394509092918301917f000000000000000000000000000000000000000000000000000000000000000090911690635040fb7690602401602060405180830381865afa158015612a5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a829190615330565b63ffffffff9081169091526001600160a01b0380871660009081526005602090815260409182902085518154928701519690930151909416600160e01b026001600160e01b036001600160401b03909616600160a01b026001600160e01b031990921692909316919091171792909216919091179055612b3384612b267f000000000000000000000000000000000000000000000000000000000000000042615296565b630585d26d60e51b613bb3565b6040516001600160401b03821681526001600160a01b0380851691908616907f5f59bfd9baba55ae30bb440923cbbe30987d50e12a4e9134ffac3fd9afc3526d9060200160405180910390a350505050565b6040516309fa507560e11b81526001600160a01b038381166004830152828116602483015260009182917f000000000000000000000000000000000000000000000000000000000000000016906313f4a0ea90604401602060405180830381865afa158015612bf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c1c9190615330565b9050600081118015612c2d57504281105b949350505050565b8030331480612c495750612c49813361374d565b612c655760405162461bcd60e51b815260040161079790615349565b81612c6f81613835565b15612c8c5760405162461bcd60e51b8152600401610797906152d5565b6001600160a01b038381166000818152602081815260409182902054915191909316815290917feb290a597820eccc6b8b31f942bd97c633d5138f4d849751f770f3cb3900e57a910160405180910390a261259083613c2e565b8130331480612cfd5750336001600160a01b038216145b612d195760405162461bcd60e51b815260040161079790615214565b82612d2381613835565b15612d405760405162461bcd60e51b8152600401610797906152d5565b612d6c6040518060400160405280600b81526020016a30b23223bab0b93234b0b760a91b8152506144e8565b612d76848461374d565b15612dc35760405162461bcd60e51b815260206004820152601c60248201527f534d3a20677561726469616e2063616e6e6f74206265206f776e6572000000006044820152606401610797565b612dcd848461325c565b15612e135760405162461bcd60e51b815260206004820152601660248201527529a69d10323ab83634b1b0ba329033bab0b93234b0b760511b6044820152606401610797565b60408051600481526024810182526020810180516001600160e01b0316638da5cb5b60e01b17905290516000916001600160a01b038616916161a891612e58916154d0565b60006040518083038160008787f1925050503d8060008114612e96576040519150601f19603f3d011682016040523d82523d6000602084013e612e9b565b606091505b5050905080612eec5760405162461bcd60e51b815260206004820152601d60248201527f534d3a206d75737420626520454f412f417267656e742077616c6c65740000006044820152606401610797565b60008585604051602001612f019291906153a2565b60408051601f1981840301815291815281516020928301206001600160a01b0389166000908152600684528281208282529384905291909120549092501580612f825750600082815260208290526040902054612f7f907f000000000000000000000000000000000000000000000000000000000000000090615296565b42115b612fce5760405162461bcd60e51b815260206004820152601e60248201527f534d3a206475706c69636174652070656e64696e67206164646974696f6e00006044820152606401610797565b612ff87f000000000000000000000000000000000000000000000000000000000000000042615296565b6000838152602083905260409020556001600160a01b038087169088167fe4166e4bc55a182bd13d933553241bb3441b91d15fbc74c5c752f96965563bde6130607f000000000000000000000000000000000000000000000000000000000000000042615296565b60405190815260200160405180910390a350505050505050565b3033146130995760405162461bcd60e51b8152600401610797906152a9565b6001600160a01b0381166000908152600560205260409020548190600160a01b90046001600160401b031661310a5760405162461bcd60e51b8152602060048201526017602482015276534d3a206e6f206f6e676f696e67207265636f7665727960481b6044820152606401610797565b6001600160a01b0380831660009081526005602052604081208054908290559091169061313990849080613bb3565b806001600160a01b0316836001600160a01b03167fc45926607303da71dbeffd2ed5c6b00f581982586b697655d19ae4c4d558f25960405160405180910390a3505050565b30331461319d5760405162461bcd60e51b8152600401610797906152a9565b816131a781613835565b156131c45760405162461bcd60e51b8152600401610797906152d5565b604051631b2ce7f360e11b81526001600160a01b038381166004830152841690633659cfe690602401600060405180830381600087803b15801561320757600080fd5b505af115801561321b573d6000803e3d6000fd5b50506040516001600160a01b038086169350861691507f5c92b3979a73cef77d1416cc6817a9094d4fd8d62e4d93189c8e2b06c5c5919790600090a3505050565b60405163353ba5cd60e21b81526001600160a01b03838116600483015282811660248301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063d4ee973490604401602060405180830381865afa1580156132cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f39190615380565b9392505050565b606030331461331b5760405162461bcd60e51b8152600401610797906152a9565b8361332581613835565b156133425760405162461bcd60e51b8152600401610797906152d5565b61336c604051806040016040528060098152602001681b5d5b1d1a50d85b1b60ba1b8152506144e8565b611cd48361452e565b60405163f18858ab60e01b81526001600160a01b0382811660048301526060917f00000000000000000000000000000000000000000000000000000000000000009091169063f18858ab90602401600060405180830381865afa1580156133e0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261087b91908101906154e2565b803033148061341c575061341c813361325c565b6134645760405162461bcd60e51b815260206004820152601960248201527829a69d1036bab9ba1031329033bab0b93234b0b717b9b2b63360391b6044820152606401610797565b8161346e81613835565b1561348b5760405162461bcd60e51b8152600401610797906152d5565b6134c6836134b97f000000000000000000000000000000000000000000000000000000000000000042615296565b63f435f5a760e01b613bb3565b6001600160a01b0383167f6395bace6e0acbe4f22761b149d3cc2e88c7dde6bf4d8481825eef404cf989a161351b7f000000000000000000000000000000000000000000000000000000000000000042615296565b6040516001600160401b03909116815260200160405180910390a2505050565b813033148061354f575061354f813361374d565b61356b5760405162461bcd60e51b815260040161079790615349565b8261357581613835565b156135925760405162461bcd60e51b8152600401610797906152d5565b61359e84846000613d2a565b826001600160a01b0316846001600160a01b03167fd288ab5da2e1f37cf384a1565a3f905ad289b092fbdd31950dbbfef148c04f8860405160405180910390a350505050565b6000602083511015613600576135f983614573565b905061087b565b8161360b848261561b565b5060ff905061087b565b90565b6041808202830160208101516040820151919092015160009260ff9190911691601b83148061364a57508260ff16601c145b6136965760405162461bcd60e51b815260206004820152601f60248201527f5574696c733a2062616420762076616c756520696e207369676e6174757265006044820152606401610797565b604080516000808252602082018084528a905260ff861692820192909252606081018490526080810183905260019060a0016020604051602081039080840390855afa1580156136ea573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610b5b5760405162461bcd60e51b815260206004820152601b60248201527f5574696c733a2065637265636f7665722072657475726e6564203000000000006044820152606401610797565b6000816001600160a01b0316836001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613797573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137bb919061541e565b6001600160a01b0316149392505050565b6040516309ed185960e11b8152306004820152630b135d3f60e11b60248201526001600160a01b038216906313da30b290604401600060405180830381600087803b15801561381a57600080fd5b505af115801561382e573d6000803e3d6000fd5b5050505050565b6001600160a01b03166000908152600160205260409020546001600160401b0342811691161190565b6001600160a01b0382166138b45760405162461bcd60e51b815260206004820152601860248201527f544d3a20496e76616c69642073657373696f6e207573657200000000000000006044820152606401610797565b6000816001600160401b03161161390d5760405162461bcd60e51b815260206004820152601c60248201527f544d3a20496e76616c69642073657373696f6e206475726174696f6e000000006044820152606401610797565b600061392a6139256001600160401b03841642615296565b6145b1565b6040805180820182526001600160a01b038681168083526001600160401b0385811660208086018281528c86166000818152808452899020975188549251909516600160a01b026001600160e01b031990921694909616939093179290921790945584519182528101929092529293507f2ecea11087d1dc1431b517cbb5a559a9e33e58a1afeaac288f782c1c8bed8b8a910160405180910390a250505050565b60606000826001600160401b038111156139e7576139e7614c09565b604051908082528060200260200182016040528015613a1a57816020015b6060815260200190600190039081613a055790505b509050613a268361452e565b60005b83811015613baa57613a6b858583818110613a4657613a46615481565b9050602002810190613a589190615497565b613a66906020810190614d14565b61461d565b613ada858583818110613a8057613a80615481565b9050602002810190613a929190615497565b613aa090604081019061543b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061466592505050565b613b0a858583818110613aef57613aef615481565b9050602002810190613b019190615497565b6020013561452e565b613b7a86868684818110613b2057613b20615481565b9050602002810190613b329190615497565b613b40906020810190614d14565b878785818110613b5257613b52615481565b9050602002810190613b649190615497565b6020013588888681811061273157612731615481565b828281518110613b8c57613b8c615481565b60200260200101819052508080613ba2906154b7565b915050613a29565b50949350505050565b6040518060400160405280613bc7846145b1565b6001600160401b0390811682526001600160e01b03199093166020918201526001600160a01b039094166000908152600185526040902081518154929095015160e01c600160401b026001600160601b031990921694909216939093179290921790915550565b6001600160a01b0316600090815260208190526040902080546001600160e01b0319169055565b6040516328207dbb60e11b81526001600160a01b03828116600483015260009161087b917f00000000000000000000000000000000000000000000000000000000000000001690635040fb7690602401602060405180830381865afa158015613cc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce69190615330565b60025b600080613cf683856156f0565b9050613d028385615704565b600003613d1057905061087b565b613d1b816001615296565b91505061087b565b5092915050565b604051631017f7cd60e31b81526001600160a01b0384811660048301528381166024830152604482018390527f000000000000000000000000000000000000000000000000000000000000000016906380bfbe6890606401600060405180830381600087803b158015613d9c57600080fd5b505af1158015613db0573d6000803e3d6000fd5b50505050505050565b6001600160a01b038116613e0f5760405162461bcd60e51b815260206004820152601c60248201527f534d3a206e6577206f776e65722063616e6e6f74206265206e756c6c000000006044820152606401610797565b613e19828261325c565b156108e35760405162461bcd60e51b815260206004820181905260248201527f534d3a206e6577206f776e65722063616e6e6f7420626520677561726469616e6044820152606401610797565b60006024821015613eb25760405162461bcd60e51b815260206004820152601660248201527514934e88125b9d985b1a590819185d1855d85b1b195d60521b6044820152606401610797565b6000613ec18360048187615718565b810190613ece9190614d14565b6001600160a01b03908116908616149150509392505050565b600061087b613ef46146a8565b8360405161190160f01b8152600281019290925260228201526042902090565b6001600160a01b038181166000818152602081815260408083208151808301909252549485168152600160a01b9094046001600160401b0316908401529190331480156132f357504281602001516001600160401b031610159392505050565b6000828103613f8557506001611cdf565b600060606001846004811115613f9d57613f9d614fa5565b141580613faa5750604185115b156140405760405163f18858ab60e01b81526001600160a01b0389811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063f18858ab90602401600060405180830381865afa158015614015573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261403d91908101906154e2565b90505b6001600160a01b03881660009081526004602090815260408083208a845290915290205460ff16156140c85760405162461bcd60e51b815260206004820152602b60248201527f524d3a2076616c69646174655369676e6174757265733a20747820616c72656160448201526a191e48195e1958dd5d195960aa1b6064820152608401610797565b60005b6140d66041876156f0565b8110156142b95760408051604180825260808201909252600091602082018180368337019050509050876041830201604181602084013750816000036141e25760006141848b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614159573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061417d919061541e565b8b846147d8565b9050600187600481111561419a5761419a614fa5565b036141ba5780156141ac5750506142a7565b600095505050505050611cdf565b60028760048111156141ce576141ce614fa5565b036141e05780156141e05750506142a7565b505b6000805b84518110156142905761421385828151811061420457614204615481565b60200260200101518c856147d8565b1561427e57856001600160a01b031685828151811061423457614234615481565b60200260200101516001600160a01b0316116142595760009650505050505050611cdf565b84818151811061426b5761426b615481565b6020026020010151955060019150614290565b80614288816154b7565b9150506141e6565b50806142a457600095505050505050611cdf565b50505b806142b1816154b7565b9150506140cb565b50600198975050505050505050565b606060ff83146142db576135f983614839565b8180546142e790615593565b80601f016020809104026020016040519081016040528092919081815260200182805461431390615593565b80156143605780601f1061433557610100808354040283529160200191614360565b820191906000526020600020905b81548152906001019060200180831161434357829003601f168201915b5050505050905061087b565b600080600061437b8585614878565b91509150614388816148bd565b509392505050565b606060006143c16040518060400160405280600c81526020016b1a5b9d9bdad955d85b1b195d60a21b8152506144e8565b856001600160a01b03168585856040516024016143e093929190615742565b60408051601f198184030181529181526020820180516001600160e01b03166347b7819960e11b1790525161441591906154d0565b6000604051808303816000865af19150503d8060008114614452576040519150601f19603f3d011682016040523d82523d6000602084013e614457565b606091505b509250905080801561446a575060008251115b1561448a57818060200190518101906144839190615769565b9150613baa565b81511561449b573d6000803e3d6000fd5b80613baa5760405162461bcd60e51b815260206004820152601a60248201527f424d3a2077616c6c657420696e766f6b652072657665727465640000000000006044820152606401610797565b61452b816040516024016144fc91906157d6565b60408051601f198184030181529190526020810180516001600160e01b031663104c13eb60e21b179052614a07565b50565b61452b8160405160240161454491815260200190565b60408051601f198184030181529190526020810180516001600160e01b031663f82c50f160e01b179052614a07565b600080829050601f8151111561459e578260405163305a27a960e01b815260040161079791906157d6565b80516145a9826157e9565b179392505050565b60006001600160401b038211156146195760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610797565b5090565b6040516001600160a01b038216602482015261452b9060440160408051601f198184030181529190526020810180516001600160e01b031663161765e160e11b179052614a07565b61452b8160405160240161467991906157d6565b60408051601f198184030181529190526020810180516001600160e01b03166305f3bfab60e11b179052614a07565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561470157507f000000000000000000000000000000000000000000000000000000000000000046145b1561472b57507f000000000000000000000000000000000000000000000000000000000000000090565b6147d3604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b60008060006147e78585614878565b9092509050600081600481111561480057614800614fa5565b14801561481e5750856001600160a01b0316826001600160a01b0316145b8061482f575061482f868686614a10565b9695505050505050565b6060600061484683614afc565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b60008082516041036148ae5760208301516040840151606085015160001a6148a287828585614b24565b945094505050506148b6565b506000905060025b9250929050565b60008160048111156148d1576148d1614fa5565b036148d95750565b60018160048111156148ed576148ed614fa5565b0361493a5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610797565b600281600481111561494e5761494e614fa5565b0361499b5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610797565b60038160048111156149af576149af614fa5565b0361452b5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610797565b61452b81614be8565b6000806000856001600160a01b0316631626ba7e60e01b8686604051602401614a3a92919061580d565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614a7891906154d0565b600060405180830381855afa9150503d8060008114614ab3576040519150601f19603f3d011682016040523d82523d6000602084013e614ab8565b606091505b5091509150818015614acc57506020815110155b801561482f57508051630b135d3f60e11b90614af19083016020908101908401615330565b149695505050505050565b600060ff8216601f81111561087b57604051632cd44ac360e21b815260040160405180910390fd5b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614b5b5750600090506003614bdf565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614baf573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614bd857600060019250925050614bdf565b9150600090505b94509492505050565b60006a636f6e736f6c652e6c6f679050600080835160208501845afa505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614c4757614c47614c09565b604052919050565b60006001600160401b03821115614c6857614c68614c09565b50601f01601f191660200190565b60008060408385031215614c8957600080fd5b8235915060208301356001600160401b03811115614ca657600080fd5b8301601f81018513614cb757600080fd5b8035614cca614cc582614c4f565b614c1f565b818152866020838501011115614cdf57600080fd5b816020840160208301376000602083830101528093505050509250929050565b6001600160a01b038116811461452b57600080fd5b600060208284031215614d2657600080fd5b81356132f381614cff565b60008060408385031215614d4457600080fd5b8235614d4f81614cff565b91506020830135614d5f81614cff565b809150509250929050565b60008083601f840112614d7c57600080fd5b5081356001600160401b03811115614d9357600080fd5b6020830191508360208260051b85010111156148b657600080fd5b600080600080600060808688031215614dc657600080fd5b8535614dd181614cff565b945060208601356001600160401b0380821115614ded57600080fd5b614df989838a01614d6a565b909650945060408801359150614e0e82614cff565b9092506060870135908082168214614e2557600080fd5b50809150509295509295909350565b60005b83811015614e4f578181015183820152602001614e37565b50506000910152565b60008151808452614e70816020860160208601614e34565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614ed957603f19888603018452614ec7858351614e58565b94509285019290850190600101614eab565b5092979650505050505050565b600060208284031215614ef857600080fd5b81356001600160e01b0319811681146132f357600080fd5b60008083601f840112614f2257600080fd5b5081356001600160401b03811115614f3957600080fd5b6020830191508360208285010111156148b657600080fd5b600080600060408486031215614f6657600080fd5b8335614f7181614cff565b925060208401356001600160401b03811115614f8c57600080fd5b614f9886828701614f10565b9497909650939450505050565b634e487b7160e01b600052602160045260246000fd5b8281526040810160058310614fe057634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b6000806040838503121561500057600080fd5b823561500b81614cff565b946020939093013593505050565b60008060006040848603121561502e57600080fd5b833561503981614cff565b925060208401356001600160401b0381111561505457600080fd5b614f9886828701614d6a565b600080600080600080600060a0888a03121561507b57600080fd5b873561508681614cff565b965060208801356001600160401b03808211156150a257600080fd5b6150ae8b838c01614f10565b909850965060408a0135955060608a0135945060808a01359150808211156150d557600080fd5b506150e28a828b01614f10565b989b979a50959850939692959293505050565b60ff60f81b881681526000602060e08184015261511560e084018a614e58565b8381036040850152615127818a614e58565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b818110156151795783518352928401929184019160010161515d565b50909c9b505050505050505050505050565b6000806040838503121561519e57600080fd5b82356001600160401b038111156151b457600080fd5b8301610160818603121561500b57600080fd5b6020808252825182820181905260009190848201906040850190845b818110156152085783516001600160a01b0316835292840192918401916001016151e3565b50909695505050505050565b60208082526017908201527f424d3a206d7573742062652077616c6c65742f73656c66000000000000000000604082015260600190565b6001600160601b0319606093841b811682529190921b166014820152693932bb37b5b0ba34b7b760b11b602882015260320190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561087b5761087b615280565b602080825260129082015271424d3a206d757374206265206d6f64756c6560701b604082015260600190565b60208082526011908201527010934e881dd85b1b195d081b1bd8dad959607a1b604082015260600190565b63ffffffff818116838216019080821115613d2357613d23615280565b8181038181111561087b5761087b615280565b60006020828403121561534257600080fd5b5051919050565b6020808252601d908201527f424d3a206d7573742062652077616c6c6574206f776e65722f73656c66000000604082015260600190565b60006020828403121561539257600080fd5b815180151581146132f357600080fd5b6001600160601b0319606093841b811682529190921b1660148201526730b23234ba34b7b760c11b602882015260300190565b808202811582820484141761087b5761087b615280565b8183823760009101908152919050565b60408152600061540f6040830185614e58565b90508260208301529392505050565b60006020828403121561543057600080fd5b81516132f381614cff565b6000808335601e1984360301811261545257600080fd5b8301803591506001600160401b0382111561546c57600080fd5b6020019150368190038213156148b657600080fd5b634e487b7160e01b600052603260045260246000fd5b60008235605e198336030181126154ad57600080fd5b9190910192915050565b6000600182016154c9576154c9615280565b5060010190565b600082516154ad818460208701614e34565b600060208083850312156154f557600080fd5b82516001600160401b038082111561550c57600080fd5b818501915085601f83011261552057600080fd5b81518181111561553257615532614c09565b8060051b9150615543848301614c1f565b818152918301840191848101908884111561555d57600080fd5b938501935b83851015615587578451925061557783614cff565b8282529385019390850190615562565b98975050505050505050565b600181811c908216806155a757607f821691505b6020821081036155c757634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561259057600081815260208120601f850160051c810160208610156155f45750805b601f850160051c820191505b8181101561561357828155600101615600565b505050505050565b81516001600160401b0381111561563457615634614c09565b615648816156428454615593565b846155cd565b602080601f83116001811461567d57600084156156655750858301515b600019600386901b1c1916600185901b178555615613565b600085815260208120601f198616915b828110156156ac5788860151825594840194600190910190840161568d565b50858210156156ca5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601260045260246000fd5b6000826156ff576156ff6156da565b500490565b600082615713576157136156da565b500690565b6000808585111561572857600080fd5b8386111561573557600080fd5b5050820193919092039150565b60018060a01b0384168152826020820152606060408201526000611cdf6060830184614e58565b60006020828403121561577b57600080fd5b81516001600160401b0381111561579157600080fd5b8201601f810184136157a257600080fd5b80516157b0614cc582614c4f565b8181528560208385010111156157c557600080fd5b611cdf826020830160208601614e34565b6020815260006132f36020830184614e58565b805160208083015191908110156155c75760001960209190910360031b1b16919050565b828152604060208201526000612c2d6040830184614e5856fea26469706673582212205eaf7721bad67e446fbb0611cd25254152f0ec99df9e7f28146f9d90d9bcc19264736f6c63430008120033000000000000000000000000d2122ea1d515b756c7ba11474e3eb4135699ce60000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f00000000000000000000000044a9990b0c59474e097653f8df2ee00620e6e613000000000000000000000000798d2d716a13c62324bd98a47f209548ef6d359c0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102485760003560e01c806384b0196e1161013b578063b6b35272116100b8578063d4ee97341161007c578063d4ee9734146106db578063f143ddba146106ee578063f18858ab14610701578063f435f5a714610721578063f8d3277d1461073457610248565b8063b6b352721461067c578063ba8210881461068f578063c6845210146106a2578063c90db447146106b5578063d4bfea48146106c857610248565b80639be65a60116100ff5780639be65a6014610616578063a3f4df7e14610629578063a5efb23514610643578063a6eb069014610656578063b0ba4da01461066957610248565b806384b0196e146104fa578063873bd184146105155780638c8e13b91461051c5780639769c3fe146105835780639add38d51461060357610248565b80634b3ef054116101c95780636b9db4e61161018d5780636b9db4e6146104835780636d435421146104ae5780636ff6ec7c146104c157806370135f52146104d45780637d1c2e78146104e757610248565b80634b3ef054146103f05780635040fb761461040357806357518243146104245780635a1db8c41461043757806360c0fdc01461044a57610248565b80632960739b116102105780632960739b146103835780632f6c493c14610396578063315a7af3146103a95780633b73d67f146103bc5780634a4fbeec146103dd57610248565b80631626ba7e146102e957806319ab453c1461031a5780631d97d8cc1461032d5780632437b75c1461034057806325b5093414610360575b600061028a6000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061074792505050565b90506001600160e01b03198116630a85bd0160e11b14806102bb57506001600160e01b0319811663f23a6e6160e01b145b806102d657506001600160e01b0319811663bc197c8160e01b145b156102e75760046000803760206000f35b005b6102fc6102f7366004614c76565b6107a8565b6040516001600160e01b031990911681526020015b60405180910390f35b6102e7610328366004614d14565b610881565b6102e761033b366004614d31565b6108e7565b61035361034e366004614dae565b610afd565b6040516103119190614e84565b61037361036e366004614ee6565b610b66565b6040519015158152602001610311565b6102e7610391366004614d31565b610bed565b6102e76103a4366004614d14565b610d34565b6102e76103b7366004614d14565b610ea1565b6103cf6103ca366004614f51565b611065565b604051610311929190614fbb565b6103736103eb366004614d14565b611483565b6102e76103fe366004614d31565b61148e565b610416610411366004614d14565b6116dd565b604051908152602001610311565b6102e7610432366004614d31565b61176c565b6102e7610445366004614d31565b6119d4565b610373610458366004614fed565b6001600160a01b03919091166000908152600460209081526040808320938352929052205460ff1690565b610496610491366004614d14565b611b69565b6040516001600160401b039091168152602001610311565b6102e76104bc366004614d31565b611ba4565b6103536104cf366004615019565b611c8c565b6102e76104e2366004614d31565b611ce8565b6103736104f5366004615060565b611f5f565b6105026122f4565b60405161031197969594939291906150f5565b6001610373565b61055c61052a366004614d14565b6001600160a01b0390811660009081526020819052604090205490811691600160a01b9091046001600160401b031690565b604080516001600160a01b0390931683526001600160401b03909116602083015201610311565b6105d0610591366004614d14565b6001600160a01b0390811660009081526005602052604090205490811691600160a01b82046001600160401b031691600160e01b900463ffffffff1690565b604080516001600160a01b0390941684526001600160401b03909216602084015263ffffffff1690820152606001610311565b61041661061136600461518b565b61237d565b6102e7610624366004614d14565b61248e565b6104166f456e74657270726973654d6f64756c6560801b81565b610353610651366004615019565b612595565b6102e7610664366004614d31565b6127c5565b6102e7610677366004614d31565b61290c565b61037361068a366004614d31565b612b85565b6102e761069d366004614d14565b612c35565b6102e76106b0366004614d31565b612ce6565b6102e76106c3366004614d14565b61307a565b6102e76106d6366004614d31565b61317e565b6103736106e9366004614d31565b61325c565b6103536106fc366004615019565b6132fa565b61071461070f366004614d14565b613375565b60405161031191906151c7565b6102e761072f366004614d14565b613408565b6102e7610742366004614d31565b61353b565b60006004825110156107a05760405162461bcd60e51b815260206004820152601d60248201527f5574696c733a20496e76616c69642066756e6374696f6e50726566697800000060448201526064015b60405180910390fd5b506020015190565b600081516041146107fb5760405162461bcd60e51b815260206004820152601c60248201527f544d3a20696e76616c6964207369676e6174757265206c656e677468000000006044820152606401610797565b600061080984846000613618565b9050610815338261374d565b6108565760405162461bcd60e51b81526020600482015260126024820152712a269d1024b73b30b634b21039b4b3b732b960711b6044820152606401610797565b7f1626ba7e356f5979dd355a3d2bfb43e80420a480c3b854edce286a82d74968699150505b92915050565b80336001600160a01b038216146108da5760405162461bcd60e51b815260206004820152601960248201527f424d3a2063616c6c6572206d7573742062652077616c6c6574000000000000006044820152606401610797565b6108e3826137cc565b5050565b81303314806108fe5750336001600160a01b038216145b61091a5760405162461bcd60e51b815260040161079790615214565b610924838361325c565b6109705760405162461bcd60e51b815260206004820152601d60248201527f534d3a206d757374206265206578697374696e6720677561726469616e0000006044820152606401610797565b6000838360405160200161098592919061524b565b60408051601f1981840301815291815281516020928301206001600160a01b0387166000908152600684528281208282529384905291909120549092501580610a065750600082815260208290526040902054610a03907f000000000000000000000000000000000000000000000000000000000000001490615296565b42115b610a525760405162461bcd60e51b815260206004820152601c60248201527f534d3a206475706c69636174652070656e64696e67207265766f6b65000000006044820152606401610797565b610a7c7f000000000000000000000000000000000000000000000000000000000000001442615296565b6000838152602083905260409020556001600160a01b038085169086167f9746f6868f544595794833da53250bd19e72334733336cfd5dd6fbc5f6a6ac42610ae47f000000000000000000000000000000000000000000000000000000000000001442615296565b6040519081526020015b60405180910390a35050505050565b6060303314610b1e5760405162461bcd60e51b8152600401610797906152a9565b85610b2881613835565b15610b455760405162461bcd60e51b8152600401610797906152d5565b610b5087858561385e565b610b5b8787876139cb565b979650505050505050565b60006001600160e01b03198216630b135d3f60e11b1480610b9757506001600160e01b03198216630a85bd0160e11b145b80610bb257506001600160e01b031982166301ffc9a760e01b145b80610bcd57506001600160e01b0319821663f23a6e6160e01b145b8061087b57506001600160e01b0319821663bc197c8160e01b1492915050565b8130331480610c045750336001600160a01b038216145b610c205760405162461bcd60e51b815260040161079790615214565b82610c2a81613835565b15610c475760405162461bcd60e51b8152600401610797906152d5565b60008484604051602001610c5c92919061524b565b60408051601f1981840301815291815281516020928301206001600160a01b038816600090815260068452828120828252938490529190912054909250610ce55760405162461bcd60e51b815260206004820152601a60248201527f534d3a20756e6b6e6f776e2070656e64696e67207265766f6b650000000000006044820152606401610797565b600082815260208290526040808220829055516001600160a01b0380881692908916917fc0b205956d5e27c296695de329b5a014584a4f51824b1725a0eefc1174d6dbd59190a3505050505050565b8030331480610d485750610d48813361325c565b610d905760405162461bcd60e51b815260206004820152601960248201527829a69d1036bab9ba1031329033bab0b93234b0b717b9b2b63360391b6044820152606401610797565b81610d9a81613835565b610de65760405162461bcd60e51b815260206004820152601960248201527f424d3a2077616c6c6574206d757374206265206c6f636b6564000000000000006044820152606401610797565b6001600160a01b038316600090815260016020526040902054600160401b900460e01b6001600160e01b03191663f435f5a760e01b14610e5c5760405162461bcd60e51b8152602060048201526011602482015270534d3a2063616e6e6f7420756e6c6f636b60781b6044820152606401610797565b610e6883600080613bb3565b6040516001600160a01b038416907f7e6adfec7e3f286831a0200a754127c171a2da564078722cb97704741bbdb0ea90600090a2505050565b6001600160a01b0381166000908152600560205260409020548190600160a01b90046001600160401b0316610f125760405162461bcd60e51b8152602060048201526017602482015276534d3a206e6f206f6e676f696e67207265636f7665727960481b6044820152606401610797565b6001600160a01b038216600090815260056020526040902080546001600160401b03600160a01b90910481164290911611610f8f5760405162461bcd60e51b815260206004820152601b60248201527f534d3a206f6e676f696e67207265636f7665727920706572696f6400000000006044820152606401610797565b80546001600160a01b0384811660009081526005602052604081205516610fb584613c2e565b6040516313af403560e01b81526001600160a01b0382811660048301528516906313af403590602401600060405180830381600087803b158015610ff857600080fd5b505af115801561100c573d6000803e3d6000fd5b5050505061101f8460008060e01b613bb3565b806001600160a01b0316846001600160a01b03167fd8667de85dae2d56d76e700d16de53d21ac2ce4d5549cb0bf51c55fdc37f0bc160405160405180910390a350505050565b60008060006110a985858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061074792505050565b90506001600160e01b0319811663a5efb23560e01b14806110da57506001600160e01b03198116635751824360e01b145b806110f557506001600160e01b0319811663f8d3277d60e01b145b8061111057506001600160e01b03198116631750421160e31b145b1561113f576001600160a01b038616330361113257600080925092505061147b565b600180925092505061147b565b63240244e160e21b6001600160e01b0319821601611183576001600160a01b03861633036111755760006004925092505061147b565b60016004925092505061147b565b63027a2d9360e51b6001600160e01b03198216016112055760006111a687613c55565b9050600081116111f85760405162461bcd60e51b815260206004820152601e60248201527f414d3a206e6f20677561726469616e7320736574206f6e2077616c6c657400006044820152606401610797565b92506003915061147b9050565b6336f24bb960e01b6001600160e01b0319821601611296576001600160a01b03861660009081526005602052604081205461125f9061125290600160e01b900463ffffffff166001615300565b63ffffffff166002613ce9565b90506001600160a01b03871633036112895761127c60018261531d565b600393509350505061147b565b92506002915061147b9050565b6001600160e01b03198116630c68452160e41b14806112c557506001600160e01b03198116630765f63360e21b145b806112e057506001600160e01b03198116630a6eb06960e41b145b806112fb57506001600160e01b03198116632960739b60e01b145b8061131657506001600160e01b03198116636d43542160e01b145b8061133157506001600160e01b031981166316876e3160e21b145b8061134c57506001600160e01b03198116631a97fd4960e31b145b8061136757506001600160e01b031981166378a1eedd60e11b145b8061138257506001600160e01b0319811663090dedd760e21b145b156113a057600061139287613c55565b93506003925061147b915050565b6001600160e01b0319811663315a7af360e01b14806113cf57506001600160e01b03198116633809afa960e11b145b806113ea57506001600160e01b031981166312cfbc1560e21b145b156113fc57600080925092505061147b565b6001600160e01b0319811663f435f5a760e01b148061142b57506001600160e01b03198116630bdb124f60e21b145b1561143e5760016003925092505061147b565b60405162461bcd60e51b815260206004820152601260248201527114d34e881d5b9adb9bdddb881b595d1a1bd960721b6044820152606401610797565b935093915050565b600061087b82613835565b600082826040516020016114a392919061524b565b60408051601f1981840301815291815281516020928301206001600160a01b03861660009081526006845282812082825293849052919091205490925061152c5760405162461bcd60e51b815260206004820152601a60248201527f534d3a20756e6b6e6f776e2070656e64696e67207265766f6b650000000000006044820152606401610797565b60008281526020829052604090205442116115895760405162461bcd60e51b815260206004820152601b60248201527f534d3a2070656e64696e67207265766f6b65206e6f74206f76657200000000006044820152606401610797565b6000828152602082905260409020546115c3907f000000000000000000000000000000000000000000000000000000000000001490615296565b42106116115760405162461bcd60e51b815260206004820152601a60248201527f534d3a2070656e64696e67207265766f6b6520657870697265640000000000006044820152606401610797565b604051630765f63360e21b81526001600160a01b03858116600483015284811660248301527f000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f1690631d97d8cc90604401600060405180830381600087803b15801561167c57600080fd5b505af1158015611690573d6000803e3d6000fd5b50506040516001600160a01b038087169350871691507f548f10dcba266544123ad8cf8284f25c4baa659cba25dbdf16a06ea11235de9b90600090a3600091825260205260408120555050565b6040516328207dbb60e11b81526001600160a01b0382811660048301526000917f000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f90911690635040fb7690602401602060405180830381865afa158015611748573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087b9190615330565b81303314806117805750611780813361374d565b61179c5760405162461bcd60e51b815260040161079790615349565b826117a681613835565b156117c35760405162461bcd60e51b8152600401610797906152d5565b836001600160a01b0316836001600160a01b0316036118245760405162461bcd60e51b815260206004820152601b60248201527f544d3a2043616e6e6f742077686974656c6973742077616c6c657400000000006044820152606401610797565b604051630bcd4ebb60e01b81526001600160a01b0384811660048301527f000000000000000000000000d2122ea1d515b756c7ba11474e3eb4135699ce601690630bcd4ebb90602401602060405180830381865afa15801561188a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ae9190615380565b156118fb5760405162461bcd60e51b815260206004820152601b60248201527f544d3a2043616e6e6f742077686974656c697374206d6f64756c6500000000006044820152606401610797565b6119058484612b85565b156119525760405162461bcd60e51b815260206004820152601e60248201527f544d3a2074617267657420616c72656164792077686974656c697374656400006044820152606401610797565b600061197e7f000000000000000000000000000000000000000000000000000000000000001442615296565b905061198b858583613d2a565b6040516001600160401b03821681526001600160a01b0380861691908716907f1f57f9641d3e8733ed672fef5ac85464bd7215ef2f21e83428e8408248b13dcd90602001610aee565b81303314806119e857506119e8813361374d565b611a045760405162461bcd60e51b815260040161079790615349565b82611a0e81613835565b15611a2b5760405162461bcd60e51b8152600401610797906152d5565b604051630bcd4ebb60e01b81526001600160a01b0384811660048301527f000000000000000000000000d2122ea1d515b756c7ba11474e3eb4135699ce601690630bcd4ebb90602401602060405180830381865afa158015611a91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab59190615380565b611b015760405162461bcd60e51b815260206004820152601c60248201527f414d3a206d6f64756c65206973206e6f742072656769737465726564000000006044820152606401610797565b604051631f17732d60e01b81526001600160a01b03848116600483015260016024830152851690631f17732d90604401600060405180830381600087803b158015611b4b57600080fd5b505af1158015611b5f573d6000803e3d6000fd5b5050505050505050565b6000611b7482613835565b611b7f57600061087b565b506001600160a01b03166000908152600160205260409020546001600160401b031690565b303314611bc35760405162461bcd60e51b8152600401610797906152a9565b81611bcd81613835565b15611bea5760405162461bcd60e51b8152600401610797906152d5565b611bf48383613db9565b6040516313af403560e01b81526001600160a01b0383811660048301528416906313af403590602401600060405180830381600087803b158015611c3757600080fd5b505af1158015611c4b573d6000803e3d6000fd5b50506040516001600160a01b038086169350861691507f0d18b5fd22306e373229b9439188228edca81207d1667f604daf6cef8aa3ee6790600090a3505050565b6060303314611cad5760405162461bcd60e51b8152600401610797906152a9565b83611cb781613835565b15611cd45760405162461bcd60e51b8152600401610797906152d5565b611cdf8585856139cb565b95945050505050565b81611cf281613835565b15611d0f5760405162461bcd60e51b8152600401610797906152d5565b60008383604051602001611d249291906153a2565b60408051601f1981840301815291815281516020928301206001600160a01b038716600090815260068452828120828252938490529190912054909250611dad5760405162461bcd60e51b815260206004820152601c60248201527f534d3a20756e6b6e6f776e2070656e64696e67206164646974696f6e000000006044820152606401610797565b6000828152602082905260409020544211611e0a5760405162461bcd60e51b815260206004820152601d60248201527f534d3a2070656e64696e67206164646974696f6e206e6f74206f7665720000006044820152606401610797565b600082815260208290526040902054611e44907f000000000000000000000000000000000000000000000000000000000000001490615296565b4210611e925760405162461bcd60e51b815260206004820152601c60248201527f534d3a2070656e64696e67206164646974696f6e2065787069726564000000006044820152606401610797565b604051630c68452160e41b81526001600160a01b03868116600483015285811660248301527f000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f169063c684521090604401600060405180830381600087803b158015611efd57600080fd5b505af1158015611f11573d6000803e3d6000fd5b50506040516001600160a01b038088169350881691507fbc3292102fa77e083913064b282926717cdfaede4d35f553d66366c0a3da755a90600090a360009182526020526040812055505050565b6000611f6c888888613e66565b611fb85760405162461bcd60e51b815260206004820152601e60248201527f524d3a20546172676574206f66205f6461746120213d205f77616c6c657400006044820152606401610797565b611fc188613835565b1561200e5760405162461bcd60e51b815260206004820152601860248201527f524d3a204c6f636b65642077616c6c657420726566756e6400000000000000006044820152606401610797565b600080600060606120208c8c8c611065565b9094509250831515806120445750600083600481111561204257612042614fa5565b145b6120905760405162461bcd60e51b815260206004820152601f60248201527f524d3a2057726f6e67207369676e617475726520726571756972656d656e74006044820152606401610797565b8561209c8560416153d5565b146120e95760405162461bcd60e51b815260206004820152601e60248201527f524d3a2057726f6e67206e756d626572206f66207369676e61747572657300006044820152606401610797565b60007fbf1af91af6bb21cb6f3df695a3f72929c8cc95124bb13aad4c9d2ff670a214318d8d8d60405161211d9291906153ec565b60405190819003812061215f9392918e908e906020019485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b604051602081830303815290604052805190602001209050600061218282613ee7565b9050600485600481111561219857612198614fa5565b036121ed576121a68e613f14565b6121e85760405162461bcd60e51b815260206004820152601360248201527229269d1024b73b30b634b21039b2b9b9b4b7b760691b6044820152606401610797565b61223f565b6121fa8e828b8b89613f74565b61223f5760405162461bcd60e51b8152602060048201526016602482015275524d3a20496e76616c6964207369676e61747572657360501b6044820152606401610797565b6040513090612251908f908f906153ec565b6000604051808303816000865af19150503d806000811461228e576040519150601f19603f3d011682016040523d82523d6000602084013e612293565b606091505b5080945081955050508315158e6001600160a01b03167f7da4525a280527268ba2e963ee6c1b18f43c9507bcb1d2560f652ab17c76e90a85846040516122da9291906153fc565b60405180910390a350919c9b505050505050505050505050565b6000606080828080836123287f52656c617965724b6e6f6273000000000000000000000000000000000000000c60026142c8565b6123537f310000000000000000000000000000000000000000000000000000000000000160036142c8565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c829052603c81206000336001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612410919061541e565b905061246061242361014087018761543b565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869392505061436c9050565b6001600160a01b0316816001600160a01b0316146124835760019250505061087b565b506000949350505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156124d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124f99190615330565b60405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000d2122ea1d515b756c7ba11474e3eb4135699ce6081166004830152602482018390529192509083169063a9059cbb906044016020604051808303816000875af115801561256c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125909190615380565b505050565b60603033146125b65760405162461bcd60e51b8152600401610797906152a9565b836125c081613835565b156125dd5760405162461bcd60e51b8152600401610797906152d5565b6000836001600160401b038111156125f7576125f7614c09565b60405190808252806020026020018201604052801561262a57816020015b60608152602001906001900390816126155790505b50905060005b848110156127bb573086868381811061264b5761264b615481565b905060200281019061265d9190615497565b61266b906020810190614d14565b6001600160a01b0316036126c15760405162461bcd60e51b815260206004820152601760248201527f544d3a2063616c6c206e6f7420617574686f72697365640000000000000000006044820152606401610797565b61278b878787848181106126d7576126d7615481565b90506020028101906126e99190615497565b6126f7906020810190614d14565b88888581811061270957612709615481565b905060200281019061271b9190615497565b6020013589898681811061273157612731615481565b90506020028101906127439190615497565b61275190604081019061543b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061439092505050565b82828151811061279d5761279d615481565b602002602001018190525080806127b3906154b7565b915050612630565b5095945050505050565b81303314806127dc5750336001600160a01b038216145b6127f85760405162461bcd60e51b815260040161079790615214565b8261280281613835565b1561281f5760405162461bcd60e51b8152600401610797906152d5565b600084846040516020016128349291906153a2565b60408051601f1981840301815291815281516020928301206001600160a01b0388166000908152600684528281208282529384905291909120549092506128bd5760405162461bcd60e51b815260206004820152601c60248201527f534d3a20756e6b6e6f776e2070656e64696e67206164646974696f6e000000006044820152606401610797565b600082815260208290526040808220829055516001600160a01b0380881692908916917faa13b27c23e9e3f3d5f3861a53b7a2931e019170a6a19ed64942e26a1dd5987a9190a3505050505050565b30331461292b5760405162461bcd60e51b8152600401610797906152a9565b6001600160a01b0382166000908152600560205260409020548290600160a01b90046001600160401b03161561299a5760405162461bcd60e51b8152602060048201526014602482015273534d3a206f6e676f696e67207265636f7665727960601b6044820152606401610797565b6129a48383613db9565b60006129d07f000000000000000000000000000000000000000000000000000000000000002842615296565b604080516060810182526001600160a01b0380871682526001600160401b038416602083015282516328207dbb60e11b815288821660048201529394509092918301917f000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f90911690635040fb7690602401602060405180830381865afa158015612a5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a829190615330565b63ffffffff9081169091526001600160a01b0380871660009081526005602090815260409182902085518154928701519690930151909416600160e01b026001600160e01b036001600160401b03909616600160a01b026001600160e01b031990921692909316919091171792909216919091179055612b3384612b267f000000000000000000000000000000000000000000000000000000000000002842615296565b630585d26d60e51b613bb3565b6040516001600160401b03821681526001600160a01b0380851691908616907f5f59bfd9baba55ae30bb440923cbbe30987d50e12a4e9134ffac3fd9afc3526d9060200160405180910390a350505050565b6040516309fa507560e11b81526001600160a01b038381166004830152828116602483015260009182917f00000000000000000000000044a9990b0c59474e097653f8df2ee00620e6e61316906313f4a0ea90604401602060405180830381865afa158015612bf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c1c9190615330565b9050600081118015612c2d57504281105b949350505050565b8030331480612c495750612c49813361374d565b612c655760405162461bcd60e51b815260040161079790615349565b81612c6f81613835565b15612c8c5760405162461bcd60e51b8152600401610797906152d5565b6001600160a01b038381166000818152602081815260409182902054915191909316815290917feb290a597820eccc6b8b31f942bd97c633d5138f4d849751f770f3cb3900e57a910160405180910390a261259083613c2e565b8130331480612cfd5750336001600160a01b038216145b612d195760405162461bcd60e51b815260040161079790615214565b82612d2381613835565b15612d405760405162461bcd60e51b8152600401610797906152d5565b612d6c6040518060400160405280600b81526020016a30b23223bab0b93234b0b760a91b8152506144e8565b612d76848461374d565b15612dc35760405162461bcd60e51b815260206004820152601c60248201527f534d3a20677561726469616e2063616e6e6f74206265206f776e6572000000006044820152606401610797565b612dcd848461325c565b15612e135760405162461bcd60e51b815260206004820152601660248201527529a69d10323ab83634b1b0ba329033bab0b93234b0b760511b6044820152606401610797565b60408051600481526024810182526020810180516001600160e01b0316638da5cb5b60e01b17905290516000916001600160a01b038616916161a891612e58916154d0565b60006040518083038160008787f1925050503d8060008114612e96576040519150601f19603f3d011682016040523d82523d6000602084013e612e9b565b606091505b5050905080612eec5760405162461bcd60e51b815260206004820152601d60248201527f534d3a206d75737420626520454f412f417267656e742077616c6c65740000006044820152606401610797565b60008585604051602001612f019291906153a2565b60408051601f1981840301815291815281516020928301206001600160a01b0389166000908152600684528281208282529384905291909120549092501580612f825750600082815260208290526040902054612f7f907f000000000000000000000000000000000000000000000000000000000000001490615296565b42115b612fce5760405162461bcd60e51b815260206004820152601e60248201527f534d3a206475706c69636174652070656e64696e67206164646974696f6e00006044820152606401610797565b612ff87f000000000000000000000000000000000000000000000000000000000000001442615296565b6000838152602083905260409020556001600160a01b038087169088167fe4166e4bc55a182bd13d933553241bb3441b91d15fbc74c5c752f96965563bde6130607f000000000000000000000000000000000000000000000000000000000000001442615296565b60405190815260200160405180910390a350505050505050565b3033146130995760405162461bcd60e51b8152600401610797906152a9565b6001600160a01b0381166000908152600560205260409020548190600160a01b90046001600160401b031661310a5760405162461bcd60e51b8152602060048201526017602482015276534d3a206e6f206f6e676f696e67207265636f7665727960481b6044820152606401610797565b6001600160a01b0380831660009081526005602052604081208054908290559091169061313990849080613bb3565b806001600160a01b0316836001600160a01b03167fc45926607303da71dbeffd2ed5c6b00f581982586b697655d19ae4c4d558f25960405160405180910390a3505050565b30331461319d5760405162461bcd60e51b8152600401610797906152a9565b816131a781613835565b156131c45760405162461bcd60e51b8152600401610797906152d5565b604051631b2ce7f360e11b81526001600160a01b038381166004830152841690633659cfe690602401600060405180830381600087803b15801561320757600080fd5b505af115801561321b573d6000803e3d6000fd5b50506040516001600160a01b038086169350861691507f5c92b3979a73cef77d1416cc6817a9094d4fd8d62e4d93189c8e2b06c5c5919790600090a3505050565b60405163353ba5cd60e21b81526001600160a01b03838116600483015282811660248301526000917f000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f9091169063d4ee973490604401602060405180830381865afa1580156132cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f39190615380565b9392505050565b606030331461331b5760405162461bcd60e51b8152600401610797906152a9565b8361332581613835565b156133425760405162461bcd60e51b8152600401610797906152d5565b61336c604051806040016040528060098152602001681b5d5b1d1a50d85b1b60ba1b8152506144e8565b611cd48361452e565b60405163f18858ab60e01b81526001600160a01b0382811660048301526060917f000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f9091169063f18858ab90602401600060405180830381865afa1580156133e0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261087b91908101906154e2565b803033148061341c575061341c813361325c565b6134645760405162461bcd60e51b815260206004820152601960248201527829a69d1036bab9ba1031329033bab0b93234b0b717b9b2b63360391b6044820152606401610797565b8161346e81613835565b1561348b5760405162461bcd60e51b8152600401610797906152d5565b6134c6836134b97f000000000000000000000000000000000000000000000000000000000000002842615296565b63f435f5a760e01b613bb3565b6001600160a01b0383167f6395bace6e0acbe4f22761b149d3cc2e88c7dde6bf4d8481825eef404cf989a161351b7f000000000000000000000000000000000000000000000000000000000000002842615296565b6040516001600160401b03909116815260200160405180910390a2505050565b813033148061354f575061354f813361374d565b61356b5760405162461bcd60e51b815260040161079790615349565b8261357581613835565b156135925760405162461bcd60e51b8152600401610797906152d5565b61359e84846000613d2a565b826001600160a01b0316846001600160a01b03167fd288ab5da2e1f37cf384a1565a3f905ad289b092fbdd31950dbbfef148c04f8860405160405180910390a350505050565b6000602083511015613600576135f983614573565b905061087b565b8161360b848261561b565b5060ff905061087b565b90565b6041808202830160208101516040820151919092015160009260ff9190911691601b83148061364a57508260ff16601c145b6136965760405162461bcd60e51b815260206004820152601f60248201527f5574696c733a2062616420762076616c756520696e207369676e6174757265006044820152606401610797565b604080516000808252602082018084528a905260ff861692820192909252606081018490526080810183905260019060a0016020604051602081039080840390855afa1580156136ea573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610b5b5760405162461bcd60e51b815260206004820152601b60248201527f5574696c733a2065637265636f7665722072657475726e6564203000000000006044820152606401610797565b6000816001600160a01b0316836001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613797573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137bb919061541e565b6001600160a01b0316149392505050565b6040516309ed185960e11b8152306004820152630b135d3f60e11b60248201526001600160a01b038216906313da30b290604401600060405180830381600087803b15801561381a57600080fd5b505af115801561382e573d6000803e3d6000fd5b5050505050565b6001600160a01b03166000908152600160205260409020546001600160401b0342811691161190565b6001600160a01b0382166138b45760405162461bcd60e51b815260206004820152601860248201527f544d3a20496e76616c69642073657373696f6e207573657200000000000000006044820152606401610797565b6000816001600160401b03161161390d5760405162461bcd60e51b815260206004820152601c60248201527f544d3a20496e76616c69642073657373696f6e206475726174696f6e000000006044820152606401610797565b600061392a6139256001600160401b03841642615296565b6145b1565b6040805180820182526001600160a01b038681168083526001600160401b0385811660208086018281528c86166000818152808452899020975188549251909516600160a01b026001600160e01b031990921694909616939093179290921790945584519182528101929092529293507f2ecea11087d1dc1431b517cbb5a559a9e33e58a1afeaac288f782c1c8bed8b8a910160405180910390a250505050565b60606000826001600160401b038111156139e7576139e7614c09565b604051908082528060200260200182016040528015613a1a57816020015b6060815260200190600190039081613a055790505b509050613a268361452e565b60005b83811015613baa57613a6b858583818110613a4657613a46615481565b9050602002810190613a589190615497565b613a66906020810190614d14565b61461d565b613ada858583818110613a8057613a80615481565b9050602002810190613a929190615497565b613aa090604081019061543b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061466592505050565b613b0a858583818110613aef57613aef615481565b9050602002810190613b019190615497565b6020013561452e565b613b7a86868684818110613b2057613b20615481565b9050602002810190613b329190615497565b613b40906020810190614d14565b878785818110613b5257613b52615481565b9050602002810190613b649190615497565b6020013588888681811061273157612731615481565b828281518110613b8c57613b8c615481565b60200260200101819052508080613ba2906154b7565b915050613a29565b50949350505050565b6040518060400160405280613bc7846145b1565b6001600160401b0390811682526001600160e01b03199093166020918201526001600160a01b039094166000908152600185526040902081518154929095015160e01c600160401b026001600160601b031990921694909216939093179290921790915550565b6001600160a01b0316600090815260208190526040902080546001600160e01b0319169055565b6040516328207dbb60e11b81526001600160a01b03828116600483015260009161087b917f000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f1690635040fb7690602401602060405180830381865afa158015613cc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce69190615330565b60025b600080613cf683856156f0565b9050613d028385615704565b600003613d1057905061087b565b613d1b816001615296565b91505061087b565b5092915050565b604051631017f7cd60e31b81526001600160a01b0384811660048301528381166024830152604482018390527f00000000000000000000000044a9990b0c59474e097653f8df2ee00620e6e61316906380bfbe6890606401600060405180830381600087803b158015613d9c57600080fd5b505af1158015613db0573d6000803e3d6000fd5b50505050505050565b6001600160a01b038116613e0f5760405162461bcd60e51b815260206004820152601c60248201527f534d3a206e6577206f776e65722063616e6e6f74206265206e756c6c000000006044820152606401610797565b613e19828261325c565b156108e35760405162461bcd60e51b815260206004820181905260248201527f534d3a206e6577206f776e65722063616e6e6f7420626520677561726469616e6044820152606401610797565b60006024821015613eb25760405162461bcd60e51b815260206004820152601660248201527514934e88125b9d985b1a590819185d1855d85b1b195d60521b6044820152606401610797565b6000613ec18360048187615718565b810190613ece9190614d14565b6001600160a01b03908116908616149150509392505050565b600061087b613ef46146a8565b8360405161190160f01b8152600281019290925260228201526042902090565b6001600160a01b038181166000818152602081815260408083208151808301909252549485168152600160a01b9094046001600160401b0316908401529190331480156132f357504281602001516001600160401b031610159392505050565b6000828103613f8557506001611cdf565b600060606001846004811115613f9d57613f9d614fa5565b141580613faa5750604185115b156140405760405163f18858ab60e01b81526001600160a01b0389811660048301527f000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f169063f18858ab90602401600060405180830381865afa158015614015573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261403d91908101906154e2565b90505b6001600160a01b03881660009081526004602090815260408083208a845290915290205460ff16156140c85760405162461bcd60e51b815260206004820152602b60248201527f524d3a2076616c69646174655369676e6174757265733a20747820616c72656160448201526a191e48195e1958dd5d195960aa1b6064820152608401610797565b60005b6140d66041876156f0565b8110156142b95760408051604180825260808201909252600091602082018180368337019050509050876041830201604181602084013750816000036141e25760006141848b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614159573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061417d919061541e565b8b846147d8565b9050600187600481111561419a5761419a614fa5565b036141ba5780156141ac5750506142a7565b600095505050505050611cdf565b60028760048111156141ce576141ce614fa5565b036141e05780156141e05750506142a7565b505b6000805b84518110156142905761421385828151811061420457614204615481565b60200260200101518c856147d8565b1561427e57856001600160a01b031685828151811061423457614234615481565b60200260200101516001600160a01b0316116142595760009650505050505050611cdf565b84818151811061426b5761426b615481565b6020026020010151955060019150614290565b80614288816154b7565b9150506141e6565b50806142a457600095505050505050611cdf565b50505b806142b1816154b7565b9150506140cb565b50600198975050505050505050565b606060ff83146142db576135f983614839565b8180546142e790615593565b80601f016020809104026020016040519081016040528092919081815260200182805461431390615593565b80156143605780601f1061433557610100808354040283529160200191614360565b820191906000526020600020905b81548152906001019060200180831161434357829003601f168201915b5050505050905061087b565b600080600061437b8585614878565b91509150614388816148bd565b509392505050565b606060006143c16040518060400160405280600c81526020016b1a5b9d9bdad955d85b1b195d60a21b8152506144e8565b856001600160a01b03168585856040516024016143e093929190615742565b60408051601f198184030181529181526020820180516001600160e01b03166347b7819960e11b1790525161441591906154d0565b6000604051808303816000865af19150503d8060008114614452576040519150601f19603f3d011682016040523d82523d6000602084013e614457565b606091505b509250905080801561446a575060008251115b1561448a57818060200190518101906144839190615769565b9150613baa565b81511561449b573d6000803e3d6000fd5b80613baa5760405162461bcd60e51b815260206004820152601a60248201527f424d3a2077616c6c657420696e766f6b652072657665727465640000000000006044820152606401610797565b61452b816040516024016144fc91906157d6565b60408051601f198184030181529190526020810180516001600160e01b031663104c13eb60e21b179052614a07565b50565b61452b8160405160240161454491815260200190565b60408051601f198184030181529190526020810180516001600160e01b031663f82c50f160e01b179052614a07565b600080829050601f8151111561459e578260405163305a27a960e01b815260040161079791906157d6565b80516145a9826157e9565b179392505050565b60006001600160401b038211156146195760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610797565b5090565b6040516001600160a01b038216602482015261452b9060440160408051601f198184030181529190526020810180516001600160e01b031663161765e160e11b179052614a07565b61452b8160405160240161467991906157d6565b60408051601f198184030181529190526020810180516001600160e01b03166305f3bfab60e11b179052614a07565b6000306001600160a01b037f00000000000000000000000062bebf3fb38df89c13be114d3761528df7f75c2f1614801561470157507f0000000000000000000000000000000000000000000000000000000000aa36a746145b1561472b57507fcc6cc0e803a10acb2036622ffe00698f2d6010390e3cc955702735cc0b24df1c90565b6147d3604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f55c4f5592be9e78c3c80aa7e492430b3b9282cc84dcc3f39731f366bb92cd1d5918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b60008060006147e78585614878565b9092509050600081600481111561480057614800614fa5565b14801561481e5750856001600160a01b0316826001600160a01b0316145b8061482f575061482f868686614a10565b9695505050505050565b6060600061484683614afc565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b60008082516041036148ae5760208301516040840151606085015160001a6148a287828585614b24565b945094505050506148b6565b506000905060025b9250929050565b60008160048111156148d1576148d1614fa5565b036148d95750565b60018160048111156148ed576148ed614fa5565b0361493a5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610797565b600281600481111561494e5761494e614fa5565b0361499b5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610797565b60038160048111156149af576149af614fa5565b0361452b5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610797565b61452b81614be8565b6000806000856001600160a01b0316631626ba7e60e01b8686604051602401614a3a92919061580d565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614a7891906154d0565b600060405180830381855afa9150503d8060008114614ab3576040519150601f19603f3d011682016040523d82523d6000602084013e614ab8565b606091505b5091509150818015614acc57506020815110155b801561482f57508051630b135d3f60e11b90614af19083016020908101908401615330565b149695505050505050565b600060ff8216601f81111561087b57604051632cd44ac360e21b815260040160405180910390fd5b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614b5b5750600090506003614bdf565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614baf573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614bd857600060019250925050614bdf565b9150600090505b94509492505050565b60006a636f6e736f6c652e6c6f679050600080835160208501845afa505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614c4757614c47614c09565b604052919050565b60006001600160401b03821115614c6857614c68614c09565b50601f01601f191660200190565b60008060408385031215614c8957600080fd5b8235915060208301356001600160401b03811115614ca657600080fd5b8301601f81018513614cb757600080fd5b8035614cca614cc582614c4f565b614c1f565b818152866020838501011115614cdf57600080fd5b816020840160208301376000602083830101528093505050509250929050565b6001600160a01b038116811461452b57600080fd5b600060208284031215614d2657600080fd5b81356132f381614cff565b60008060408385031215614d4457600080fd5b8235614d4f81614cff565b91506020830135614d5f81614cff565b809150509250929050565b60008083601f840112614d7c57600080fd5b5081356001600160401b03811115614d9357600080fd5b6020830191508360208260051b85010111156148b657600080fd5b600080600080600060808688031215614dc657600080fd5b8535614dd181614cff565b945060208601356001600160401b0380821115614ded57600080fd5b614df989838a01614d6a565b909650945060408801359150614e0e82614cff565b9092506060870135908082168214614e2557600080fd5b50809150509295509295909350565b60005b83811015614e4f578181015183820152602001614e37565b50506000910152565b60008151808452614e70816020860160208601614e34565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614ed957603f19888603018452614ec7858351614e58565b94509285019290850190600101614eab565b5092979650505050505050565b600060208284031215614ef857600080fd5b81356001600160e01b0319811681146132f357600080fd5b60008083601f840112614f2257600080fd5b5081356001600160401b03811115614f3957600080fd5b6020830191508360208285010111156148b657600080fd5b600080600060408486031215614f6657600080fd5b8335614f7181614cff565b925060208401356001600160401b03811115614f8c57600080fd5b614f9886828701614f10565b9497909650939450505050565b634e487b7160e01b600052602160045260246000fd5b8281526040810160058310614fe057634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b6000806040838503121561500057600080fd5b823561500b81614cff565b946020939093013593505050565b60008060006040848603121561502e57600080fd5b833561503981614cff565b925060208401356001600160401b0381111561505457600080fd5b614f9886828701614d6a565b600080600080600080600060a0888a03121561507b57600080fd5b873561508681614cff565b965060208801356001600160401b03808211156150a257600080fd5b6150ae8b838c01614f10565b909850965060408a0135955060608a0135945060808a01359150808211156150d557600080fd5b506150e28a828b01614f10565b989b979a50959850939692959293505050565b60ff60f81b881681526000602060e08184015261511560e084018a614e58565b8381036040850152615127818a614e58565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b818110156151795783518352928401929184019160010161515d565b50909c9b505050505050505050505050565b6000806040838503121561519e57600080fd5b82356001600160401b038111156151b457600080fd5b8301610160818603121561500b57600080fd5b6020808252825182820181905260009190848201906040850190845b818110156152085783516001600160a01b0316835292840192918401916001016151e3565b50909695505050505050565b60208082526017908201527f424d3a206d7573742062652077616c6c65742f73656c66000000000000000000604082015260600190565b6001600160601b0319606093841b811682529190921b166014820152693932bb37b5b0ba34b7b760b11b602882015260320190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561087b5761087b615280565b602080825260129082015271424d3a206d757374206265206d6f64756c6560701b604082015260600190565b60208082526011908201527010934e881dd85b1b195d081b1bd8dad959607a1b604082015260600190565b63ffffffff818116838216019080821115613d2357613d23615280565b8181038181111561087b5761087b615280565b60006020828403121561534257600080fd5b5051919050565b6020808252601d908201527f424d3a206d7573742062652077616c6c6574206f776e65722f73656c66000000604082015260600190565b60006020828403121561539257600080fd5b815180151581146132f357600080fd5b6001600160601b0319606093841b811682529190921b1660148201526730b23234ba34b7b760c11b602882015260300190565b808202811582820484141761087b5761087b615280565b8183823760009101908152919050565b60408152600061540f6040830185614e58565b90508260208301529392505050565b60006020828403121561543057600080fd5b81516132f381614cff565b6000808335601e1984360301811261545257600080fd5b8301803591506001600160401b0382111561546c57600080fd5b6020019150368190038213156148b657600080fd5b634e487b7160e01b600052603260045260246000fd5b60008235605e198336030181126154ad57600080fd5b9190910192915050565b6000600182016154c9576154c9615280565b5060010190565b600082516154ad818460208701614e34565b600060208083850312156154f557600080fd5b82516001600160401b038082111561550c57600080fd5b818501915085601f83011261552057600080fd5b81518181111561553257615532614c09565b8060051b9150615543848301614c1f565b818152918301840191848101908884111561555d57600080fd5b938501935b83851015615587578451925061557783614cff565b8282529385019390850190615562565b98975050505050505050565b600181811c908216806155a757607f821691505b6020821081036155c757634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561259057600081815260208120601f850160051c810160208610156155f45750805b601f850160051c820191505b8181101561561357828155600101615600565b505050505050565b81516001600160401b0381111561563457615634614c09565b615648816156428454615593565b846155cd565b602080601f83116001811461567d57600084156156655750858301515b600019600386901b1c1916600185901b178555615613565b600085815260208120601f198616915b828110156156ac5788860151825594840194600190910190840161568d565b50858210156156ca5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601260045260246000fd5b6000826156ff576156ff6156da565b500490565b600082615713576157136156da565b500690565b6000808585111561572857600080fd5b8386111561573557600080fd5b5050820193919092039150565b60018060a01b0384168152826020820152606060408201526000611cdf6060830184614e58565b60006020828403121561577b57600080fd5b81516001600160401b0381111561579157600080fd5b8201601f810184136157a257600080fd5b80516157b0614cc582614c4f565b8181528560208385010111156157c557600080fd5b611cdf826020830160208601614e34565b6020815260006132f36020830184614e58565b805160208083015191908110156155c75760001960209190910360031b1b16919050565b828152604060208201526000612c2d6040830184614e5856fea26469706673582212205eaf7721bad67e446fbb0611cd25254152f0ec99df9e7f28146f9d90d9bcc19264736f6c63430008120033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000d2122ea1d515b756c7ba11474e3eb4135699ce60000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f00000000000000000000000044a9990b0c59474e097653f8df2ee00620e6e613000000000000000000000000798d2d716a13c62324bd98a47f209548ef6d359c0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028

-----Decoded View---------------
Arg [0] : _registry (address): 0xd2122ea1D515b756C7BA11474E3eB4135699cE60
Arg [1] : _guardianStorage (address): 0x872005fdC178b16C7Eb7318172d42494d407886F
Arg [2] : _userWhitelist (address): 0x44A9990B0C59474e097653F8dF2eE00620E6E613
Arg [3] : _authoriser (address): 0x798D2d716A13c62324BD98a47f209548EF6D359c
Arg [4] : _securityPeriod (uint256): 20
Arg [5] : _securityWindow (uint256): 20
Arg [6] : _recoveryPeriod (uint256): 40
Arg [7] : _lockPeriod (uint256): 40

-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000d2122ea1d515b756c7ba11474e3eb4135699ce60
Arg [1] : 000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f
Arg [2] : 00000000000000000000000044a9990b0c59474e097653f8df2ee00620e6e613
Arg [3] : 000000000000000000000000798d2d716a13c62324bd98a47f209548ef6d359c
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000028
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000028


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

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.