ETH Price: $2,680.05 (-0.78%)

Contract

0x3718f4bf9140f333bca79Cb279F09f0bB8E6dDEE
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
166852832023-02-22 16:52:59584 days ago1677084779  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AvoWallet

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
File 1 of 13 : AvoWallet.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17;

import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { ERC721Holder } from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";

import { IAvoWalletV2 } from "../interfaces/IAvoWalletV2.sol";
import { IAvoVersionsRegistry } from "../interfaces/IAvoVersionsRegistry.sol";
import { InstaFlashReceiverInterface } from "../external/InstaFlashReceiverInterface.sol";
import { SelfUpgradeable } from "./SelfUpgradeable.sol";
import { VariablesV1, AvoWallet__InvalidParams } from "./VariablesV1.sol";

/// @title  AvoWallet
/// @notice Smart wallet supporting meta transactions with EIP712 signature. Supports receiving NFTs.
///         The `cast` method allows the owner of the wallet to execute multiple arbitrary actions
///         Relayers are expected to call the forwarder contract `execute`, which deploys an AvoWallet if necessary first.
///         Upgradeable by calling `upgradeTo` (or `upgradeToAndCall`) through a `cast` call, see SelfUpgradeable.sol
/// @dev    This contract implements parts of EIP-2770 in a minimized form. E.g. domainSeparator is immutable etc.
///         This contract does not implement ERC2771, because trusting an upgradeable "forwarder"
///         bears a security risk for this non-custodial wallet
///         Signature related logic is based off of OpenZeppelin EIP712Upgradeable.
///         This contract validates all signatures for defaultChainId of 634 instead of current block.chainid from opcode (EIP-1344)
///         For replay protection, the current block.chainid instead is used in the EIP-712 salt
/// @dev    Note For any new implementation, the upgrade method MUST be in the implementation itself,
///         otherwise it can not be upgraded anymore! also see SelfUpgradeable
///
/// @dev    IMPORTANT: do not move around order of first 3 inheritance to keep storage layout: VariablesV1, SelfUpgradeable, Initializable
contract AvoWallet is VariablesV1, SelfUpgradeable, Initializable, ERC721Holder, InstaFlashReceiverInterface {
    using Address for address;
    using Strings for uint256;

    /***********************************|
    |               ERRORS              |
    |__________________________________*/

    error AvoWallet__InvalidSignature();
    error AvoWallet__Expired();
    error AvoWallet__Unauthorized();
    error AvoWallet__InsufficientGasSent();
    error AvoWallet__OutOfGas();

    /***********************************|
    |             CONSTANTS             |
    |__________________________________*/

    // constants for EIP712 values
    string public constant DOMAIN_SEPARATOR_NAME = "Avocado-Safe";
    string public constant DOMAIN_SEPARATOR_VERSION = "2.0.0";

    /// @dev overwrite chain id for EIP712 is always set to 634
    uint256 public constant DEFAULT_CHAIN_ID = 634;

    /// @dev _TYPE_HASH is copied from OpenZeppelin EIP712 but with added salt as last param (we use it for block.chainid)
    bytes32 public constant TYPE_HASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)");

    /// @dev EIP712 typehash for cast calls including struct for Action
    bytes32 public constant CAST_TYPE_HASH =
        keccak256(
            "Cast(Action[] actions,CastParams params,uint256 avoSafeNonce)Action(address target,bytes data,uint256 value,uint256 operation)CastParams(uint256 validUntil,uint256 gas,address source,uint256 id,bytes metadata)"
        );

    /// @dev EIP712 typehash for Action struct
    bytes32 public constant ACTION_TYPE_HASH =
        keccak256("Action(address target,bytes data,uint256 value,uint256 operation)");
    /// @dev EIP712 typehash for CastParams struct
    bytes32 public constant CAST_PARAMS_TYPE_HASH =
        keccak256("CastParams(uint256 validUntil,uint256 gas,address source,uint256 id,bytes metadata)");

    // hashed EIP712 values
    bytes32 internal constant DOMAIN_SEPARATOR_NAME_HASHED = keccak256(bytes(DOMAIN_SEPARATOR_NAME));
    bytes32 internal constant DOMAIN_SEPARATOR_VERSION_HASHED = keccak256(bytes(DOMAIN_SEPARATOR_VERSION));
    /// @dev amount of gas to keep in cast caller method as reserve for emitting CastFailed event
    uint256 internal constant CAST_RESERVE_GAS = 12000;

    /***********************************|
    |               EVENTS              |
    |__________________________________*/

    /// @notice emitted when all actions for cast() are executed successfully
    event CastExecuted(address indexed source, address indexed caller, bytes metadata);

    /// @notice emitted if one of the actions in cast() fails. reason will be prefixed with the index of the action.
    /// e.g. if action 1 fails, then the reason will be 1_reason
    /// if an action in the flashloan callback fails, it will be prefixed with with two numbers:
    /// e.g. if action 1 is the flashloan, and action 2 of flashloan actions fails, the reason will be 1_2_reason
    event CastFailed(address indexed source, address indexed caller, string reason, bytes metadata);

    /***********************************|
    |    CONSTRUCTOR / INITIALIZERS     |
    |__________________________________*/

    /// @notice                        constructor sets avoVersionsRegistry and avoForwarder (immutable).
    ///                                also see SelfUpgradeable constructor for details about setting avoVersionsRegistry
    /// @param avoVersionsRegistry_    address of the avoVersionsRegistry contract
    /// @param avoForwarder_           address of the avoForwarder (proxy) contract
    ///                                to forward tx with valid signatures. must be valid version in AvoVersionsRegistry.
    constructor(IAvoVersionsRegistry avoVersionsRegistry_, address avoForwarder_)
        VariablesV1(avoVersionsRegistry_, avoForwarder_)
    {
        // Ensure logic contract initializer is not abused by disabling initializing
        // see https://forum.openzeppelin.com/t/security-advisory-initialize-uups-implementation-contracts/15301
        // and https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#initializing_the_implementation_contract
        _disableInitializers();
    }

    /// @inheritdoc IAvoWalletV2
    function initialize(address owner_) public initializer {
        // owner must be EOA
        if (owner_.isContract() || owner_ == address(0)) {
            revert AvoWallet__InvalidParams();
        }

        owner = owner_;
    }

    /// @inheritdoc IAvoWalletV2
    function initializeWithVersion(address owner_, address avoWalletVersion_) public initializer {
        // owner must be EOA
        if (owner_.isContract() || owner_ == address(0)) {
            revert AvoWallet__InvalidParams();
        }

        owner = owner_;

        _avoWalletImpl = avoWalletVersion_;
    }

    /***********************************|
    |            PUBLIC API             |
    |__________________________________*/

    receive() external payable {}

    /// @inheritdoc IAvoWalletV2
    function domainSeparatorV4() public view returns (bytes32) {
        return _domainSeparatorV4();
    }

    /// @inheritdoc IAvoWalletV2
    function verify(
        Action[] calldata actions_,
        CastParams calldata params_,
        bytes calldata signature_
    ) external view returns (bool) {
        // do not use modifier to avoid stack too deep
        _validateParams(actions_, params_.validUntil);

        bytes32 digest_ = _getSigDigest(actions_, params_);

        if (!_verifySig(digest_, signature_)) {
            revert AvoWallet__InvalidSignature();
        }
        return true;
    }

    /// @inheritdoc IAvoWalletV2
    function cast(
        Action[] calldata actions_,
        CastParams calldata params_,
        bytes calldata signature_
    ) external payable returns (bool success_, string memory revertReason_) {
        {
            if (msg.sender == avoForwarder) {
                // if sender is forwarder, first thing we must do is compare actual sent gas to user instructed gas
                // adding 500 to gasleft for approx. already used gas
                if ((gasleft() + 500) < params_.gas) {
                    // relayer has not sent enough gas to cover gas limit as user instructed
                    revert AvoWallet__InsufficientGasSent();
                }

                _validateParams(actions_, params_.validUntil);

                // if cast is called through forwarder signature must be valid
                bytes32 digest_ = _getSigDigest(actions_, params_);

                if (!_verifySig(digest_, signature_)) {
                    revert AvoWallet__InvalidSignature();
                }
            } else if (msg.sender == owner) {
                _validateParams(actions_, params_.validUntil);
            } else {
                // sender must be either owner or allowed forwarder
                revert AvoWallet__Unauthorized();
            }
        }

        // set status verified to 1 for call to _callTargets to avoid having to check signature etc. again
        _status = 1;

        // nonce increases *always* if signature is valid
        avoSafeNonce++;

        // execute _callTargets via a low-level call to create a separate execution frame
        // this is used to revert all the actions if one action fails without reverting the whole transaction
        bytes memory calldata_ = abi.encodeCall(AvoWallet._callTargets, (actions_, params_.id));
        bytes memory result_;
        // using inline assembly for delegatecall to define custom gas amount that should stay here in caller
        assembly {
            success_ := delegatecall(
                // reserve at least ~12k gas to make sure we can emit CastFailed event even for out of gas cases
                sub(gas(), CAST_RESERVE_GAS),
                sload(_avoWalletImpl.slot),
                add(calldata_, 0x20),
                mload(calldata_),
                0,
                0
            )
            let size := returndatasize()

            result_ := mload(0x40)
            mstore(0x40, add(result_, and(add(add(size, 0x20), 0x1f), not(0x1f))))
            mstore(result_, size)
            returndatacopy(add(result_, 0x20), 0, size)
        }

        if (!success_) {
            if (result_.length == 0) {
                // @dev this case might be caused by edge-case out of gas errors that we were unable to catch
                // but could potentially also have other reasons
                revertReason_ = "AVO__REASON_NOT_DEFINED";
            } else if (bytes4(result_) == bytes4(0x8707015b)) {
                // 0x8707015b = selector for custom error AvoWallet__OutOfGas
                revertReason_ = "AVO__OUT_OF_GAS";
            } else {
                assembly {
                    result_ := add(result_, 0x04)
                }
                revertReason_ = abi.decode(result_, (string));
            }

            emit CastFailed(params_.source, msg.sender, revertReason_, params_.metadata);
        } else {
            emit CastExecuted(params_.source, msg.sender, params_.metadata);
        }
    }

    /***********************************|
    |         FLASHLOAN CALLBACK        |
    |__________________________________*/

    /// @dev                 callback used by Instadapp Flashloan Aggregator, executes operations while owning
    ///                      the flashloaned amounts. data_ must contain actions, one of them must pay back flashloan
    // /// @param assets_       assets_ received a flashloan for
    // /// @param amounts_      flashloaned amounts for each asset
    // /// @param premiums_     fees to pay for the flashloan
    /// @param initiator_    flashloan initiator -> must be this contract
    /// @param data_         data bytes containing the abi.encoded actions that are executed similarly to .callTargets
    function executeOperation(
        address[] calldata, /*  assets_ */
        uint256[] calldata, /*  amounts_ */
        uint256[] calldata, /*  premiums_ */
        address initiator_,
        bytes calldata data_
    ) external returns (bool) {
        // @dev using the valid case inverted via one ! instead of invalid case with 3 ! to optimize gas usage
        if (!((_status == 20 || _status == 21) && initiator_ == address(this))) {
            revert AvoWallet__Unauthorized();
        }

        // _status is set to original id_ pre-flashloan trigger in _callTargets
        uint256 id_ = _status;

        // reset status immediately
        _status = 0;

        // decode actions to be executed after getting the flashloan
        Action[] memory actions_ = abi.decode(data_, (Action[]));

        StorageSnapshot memory storageSnapshot_;
        if (id_ == 21) {
            // store values before execution to make sure storage vars are not modified by a delegatecall
            storageSnapshot_.owner = owner;
            storageSnapshot_.avoWalletImpl = _avoWalletImpl;
            storageSnapshot_.avoSafeNonce = avoSafeNonce;
        }

        uint256 actionsLength_ = actions_.length;
        for (uint256 i; i < actionsLength_; ) {
            Action memory action_ = actions_[i];

            // execute action
            bool success_;
            bytes memory result_;
            if (action_.operation == 0) {
                // no enforcing of id_ needed here because code would revert earlier if id is not 20 or 21
                (success_, result_) = action_.target.call{ value: action_.value }(action_.data);
            } else if (action_.operation == 1 && id_ == 21) {
                // delegatecall (operation =1 & id = mixed)
                (success_, result_) = action_.target.delegatecall(action_.data);
            } else {
                // either operation does not exist or the id was not set according to what the action wants to execute
                if (action_.operation > 2) {
                    revert(string.concat(i.toString(), "_AVO__OPERATION_NOT_EXIST"));
                } else if (action_.operation == 2) {
                    revert(string.concat(i.toString(), "_AVO__NO_FLASHLOAN_IN_FLASHLOAN"));
                } else {
                    // enforce that id must be set according to operation
                    revert(string.concat(i.toString(), "_AVO__ID_ACTION_MISMATCH"));
                }
            }

            if (!success_) {
                revert(string.concat(i.toString(), _getRevertReasonFromReturnedData(result_)));
            }

            unchecked {
                ++i;
            }
        }

        // if actions include delegatecall, make sure storage was not modified
        if (
            (storageSnapshot_.avoSafeNonce > 0) &&
            !(storageSnapshot_.avoWalletImpl == _avoWalletImpl &&
                storageSnapshot_.owner == owner &&
                storageSnapshot_.avoSafeNonce == avoSafeNonce &&
                _status == 0)
        ) {
            revert("AVO__MODIFIED_STORAGE");
        }

        return true;
    }

    /***********************************|
    |         INDIRECT INTERNAL         |
    |__________________________________*/

    /// @dev                  executes a low-level .call or .delegateCall on all actions, can only be called by this contract
    ///                       this is called like an external call to create a separate execution frame.
    ///                       this way we can revert all the actions if one fails without reverting the whole transaction
    /// @param actions_       the actions to execute (target, data, value)
    /// @param id_            id for actions, e.g. 0 = CALL, 1 = MIXED (call and delegatecall), 20 = FLASHLOAN_CALL, 21 = FLASHLOAN_MIXED
    function _callTargets(Action[] calldata actions_, uint256 id_) external payable {
        // status must be verified or 0x000000000000000000000000000000000000dEaD used for backend gas estimations
        if (!(_status == 1 || tx.origin == 0x000000000000000000000000000000000000dEaD)) {
            revert AvoWallet__Unauthorized();
        }

        bool isCallId_ = id_ < 2 || id_ == 20 || id_ == 21;
        bool isDelegateCallId_ = id_ == 1 || id_ == 21;

        // reset status immediately
        _status = 0;

        StorageSnapshot memory storageSnapshot_;
        if (isDelegateCallId_) {
            // store values before execution to make sure storage vars are not modified by a delegatecall
            storageSnapshot_.owner = owner;
            storageSnapshot_.avoWalletImpl = _avoWalletImpl;
            storageSnapshot_.avoSafeNonce = avoSafeNonce;
        }

        uint256 actionsLength_ = actions_.length;
        for (uint256 i; i < actionsLength_; ) {
            Action memory action_ = actions_[i];

            // execute action
            bool success_;
            bytes memory result_;
            uint256 actionMinGasLeft_;
            if (action_.operation == 0 && isCallId_) {
                // call (operation =0 & id = call or mixed)
                // @dev try catch does not work for .call
                unchecked {
                    // store amount of gas that stays with caller, according to EIP150 to detect out of gas errors
                    actionMinGasLeft_ = gasleft() / 64;
                }
                (success_, result_) = action_.target.call{ value: action_.value }(action_.data);
            } else if (action_.operation == 1 && isDelegateCallId_) {
                // delegatecall (operation =1 & id = delegateCall(1) or mixed(2))
                unchecked {
                    // store amount of gas that stays with caller, according to EIP150 to detect out of gas errors
                    actionMinGasLeft_ = gasleft() / 64;
                }
                (success_, result_) = action_.target.delegatecall(action_.data);
            } else if (action_.operation == 2 && (id_ == 20 || id_ == 21)) {
                // flashloan is always execute via .call, flashloan aggregator uses msg.sender, so .delegatecall
                // wouldn't send funds to this contract but rather to the original sender
                _status = uint8(id_);
                unchecked {
                    // store amount of gas that stays with caller, according to EIP150 to detect out of gas errors
                    actionMinGasLeft_ = gasleft() / 64;
                }
                (success_, result_) = action_.target.call{ value: action_.value }(action_.data);
            } else {
                // either operation does not exist or the id was not set according to what the action wants to execute
                if (action_.operation > 2) {
                    revert(string.concat(i.toString(), "_AVO__OPERATION_NOT_EXIST"));
                } else {
                    // enforce that id must be set according to operation
                    revert(string.concat(i.toString(), "_AVO__ID_ACTION_MISMATCH"));
                }
            }

            if (!success_) {
                if (gasleft() < actionMinGasLeft_) {
                    // action ran out of gas, trigger revert with specific custom error
                    revert AvoWallet__OutOfGas();
                }

                revert(string.concat(i.toString(), _getRevertReasonFromReturnedData(result_)));
            }

            unchecked {
                ++i;
            }
        }

        // if actions include delegatecall, make sure storage was not modified
        if (
            (storageSnapshot_.avoSafeNonce > 0) &&
            !(storageSnapshot_.avoWalletImpl == _avoWalletImpl &&
                storageSnapshot_.owner == owner &&
                storageSnapshot_.avoSafeNonce == avoSafeNonce &&
                _status == 0)
        ) {
            revert("AVO__MODIFIED_STORAGE");
        }
    }

    /***********************************|
    |              INTERNAL             |
    |__________________________________*/

    /// @dev                Validates input params to cast and verify calls. Reverts on invalid values.
    /// @param actions_     the actions to execute (target, data, value)
    /// @param validUntil_  As EIP-2770: the highest block number the request can be forwarded in,
    ///                     or 0 if request validity is not time-limited
    function _validateParams(Action[] calldata actions_, uint256 validUntil_) internal view {
        if (actions_.length == 0) {
            revert AvoWallet__InvalidParams();
        }

        // make sure request is still valid
        if (validUntil_ > 0 && validUntil_ < block.timestamp) {
            revert AvoWallet__Expired();
        }
    }

    /// @dev                Verifies a EIP712 signature
    /// @param digest_      the EIP712 digest for the signature
    /// @param signature_   the EIP712 signature, see verifySig method
    /// @return             true if the signature is valid, false otherwise
    function _verifySig(bytes32 digest_, bytes calldata signature_) internal view returns (bool) {
        address recoveredSigner_ = ECDSA.recover(digest_, signature_);

        return recoveredSigner_ == owner;
    }

    /// @dev                  gets the digest to verify an EIP712 signature
    /// @param actions_       the actions to execute (target, data, value)
    /// @param params_        Cast params: validUntil, gas, source, id and metadata
    /// @return               bytes32 digest to verify signature
    function _getSigDigest(Action[] calldata actions_, CastParams calldata params_) internal view returns (bytes32) {
        return
            ECDSA.toTypedDataHash(
                // domain separator
                _domainSeparatorV4(),
                // structHash
                keccak256(
                    abi.encode(
                        CAST_TYPE_HASH,
                        // actions
                        getActionsHash_(actions_),
                        // CastParams
                        keccak256(
                            abi.encode(
                                CAST_PARAMS_TYPE_HASH,
                                params_.validUntil,
                                params_.gas,
                                params_.source,
                                params_.id,
                                keccak256(params_.metadata)
                            )
                        ),
                        avoSafeNonce
                    )
                )
            );
    }

    /// @dev                gets the keccak256 hash for actions array struct for EIP712 signature digest
    /// @param actions_     the actions to execute (target, data, value)
    /// @return             bytes32 hash for actions array struct to verify signature
    function getActionsHash_(Action[] calldata actions_) internal pure returns (bytes32) {
        // get keccak256s for actions
        uint256 actionsLength_ = actions_.length;
        bytes32[] memory keccakActions_ = new bytes32[](actionsLength_);
        for (uint256 i; i < actionsLength_; ) {
            keccakActions_[i] = keccak256(
                abi.encode(
                    ACTION_TYPE_HASH,
                    actions_[i].target,
                    keccak256(actions_[i].data),
                    actions_[i].value,
                    actions_[i].operation
                )
            );

            unchecked {
                ++i;
            }
        }

        return keccak256(abi.encodePacked(keccakActions_));
    }

    /// @notice Returns the domain separator for the chain with id 634
    function _domainSeparatorV4() internal view returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    TYPE_HASH,
                    DOMAIN_SEPARATOR_NAME_HASHED,
                    DOMAIN_SEPARATOR_VERSION_HASHED,
                    DEFAULT_CHAIN_ID,
                    address(this),
                    keccak256(abi.encodePacked(block.chainid))
                )
            );
    }

    /// @dev Get the revert reason from the returnedData (supports Panic, Error & Custom Errors)
    /// Based on https://github.com/superfluid-finance/protocol-monorepo/blob/dev/packages/ethereum-contracts/contracts/libs/CallUtils.sol
    /// This is needed in order to provide some human-readable revert message from a call
    /// @param returnedData_ revert data of the call
    /// @return reason_      revert reason
    function _getRevertReasonFromReturnedData(bytes memory returnedData_)
        internal
        pure
        returns (string memory reason_)
    {
        if (returnedData_.length < 4) {
            // case 1: catch all
            return "_REASON_NOT_DEFINED";
        } else {
            bytes4 errorSelector;
            assembly {
                errorSelector := mload(add(returnedData_, 0x20))
            }
            if (
                errorSelector == bytes4(0x4e487b71) /* `seth sig "Panic(uint256)"` */
            ) {
                // case 2: Panic(uint256) (Defined since 0.8.0)
                // solhint-disable-next-line max-line-length
                // ref: https://docs.soliditylang.org/en/v0.8.0/control-structures.html#panic-via-assert-and-error-via-require)
                reason_ = "_TARGET_PANICKED: 0x__";
                uint256 errorCode;
                assembly {
                    errorCode := mload(add(returnedData_, 0x24))
                    let reasonWord := mload(add(reason_, 0x20))
                    // [0..9] is converted to ['0'..'9']
                    // [0xa..0xf] is not correctly converted to ['a'..'f']
                    // but since panic code doesn't have those cases, we will ignore them for now!
                    let e1 := add(and(errorCode, 0xf), 0x30)
                    let e2 := shl(8, add(shr(4, and(errorCode, 0xf0)), 0x30))
                    reasonWord := or(
                        and(reasonWord, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000),
                        or(e2, e1)
                    )
                    mstore(add(reason_, 0x20), reasonWord)
                }
            } else {
                if (returnedData_.length > 68) {
                    // case 3: Error(string) (Defined at least since 0.7.0)
                    assembly {
                        returnedData_ := add(returnedData_, 0x04)
                    }
                    reason_ = string.concat("_", abi.decode(returnedData_, (string)));
                } else {
                    // case 4: Custom errors (Defined since 0.8.0)
                    reason_ = string.concat("_CUSTOM_ERROR:", fromCode(errorSelector));
                }
            }
        }
    }

    /// @dev used to convert bytes4 selector to string
    /// based on https://ethereum.stackexchange.com/a/111876
    function fromCode(bytes4 code) internal pure returns (string memory) {
        bytes memory result = new bytes(10);
        result[0] = bytes1("0");
        result[1] = bytes1("x");
        for (uint256 i = 0; i < 4; ++i) {
            result[2 * i + 2] = toHexDigit(uint8(code[i]) / 16);
            result[2 * i + 3] = toHexDigit(uint8(code[i]) % 16);
        }
        return string(result);
    }

    /// @dev used to convert bytes4 selector to string
    function toHexDigit(uint8 d) internal pure returns (bytes1) {
        if (0 <= d && d <= 9) {
            return bytes1(uint8(bytes1("0")) + d);
        } else if (10 <= uint8(d) && uint8(d) <= 15) {
            return bytes1(uint8(bytes1("a")) + d - 10);
        }
        revert();
    }
}

File 2 of 13 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/Address.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Internal function that returns the initialized version. Returns `_initialized`
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Internal function that returns the initialized version. Returns `_initializing`
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

File 3 of 13 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

File 4 of 13 : ERC721Holder.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/utils/ERC721Holder.sol)

pragma solidity ^0.8.0;

import "../IERC721Receiver.sol";

/**
 * @dev Implementation of the {IERC721Receiver} interface.
 *
 * Accepts all token transfers.
 * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}.
 */
contract ERC721Holder is IERC721Receiver {
    /**
     * @dev See {IERC721Receiver-onERC721Received}.
     *
     * Always returns `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address,
        address,
        uint256,
        bytes memory
    ) public virtual override returns (bytes4) {
        return this.onERC721Received.selector;
    }
}

File 5 of 13 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

pragma solidity ^0.8.0;

import "../Strings.sol";

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

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

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

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

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

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

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

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

        return (signer, RecoverError.NoError);
    }

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

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

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

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

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

import "./math/Math.sol";

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

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

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

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

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

File 9 of 13 : SelfUpgradeable.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17;

import { Address } from "@openzeppelin/contracts/utils/Address.sol";

import { VariablesV1 } from "./VariablesV1.sol";

/// @title      SelfUpgradeable
/// @notice     Simple contract to upgrade the implementation address stored at storage slot 0x0
/// @dev        Mostly based on OpenZeppelin ERC1967Upgrade contract, adapted with selfCall etc.
///             IMPORANT to keep VariablesV1 at first inheritance to ensure proxy impl address is at 0x0
abstract contract SelfUpgradeable is VariablesV1 {
    error SelfUpgradeable__Unauthorized();

    /// @notice Emitted when the implementation is upgraded to a new AvoWallet logic contract
    event Upgraded(address indexed avoWalletImpl);

    /// @notice modifier that ensures the method can only be called by the same contract itself
    modifier onlySelf() {
        _requireSelfCalled();
        _;
    }

    /// @notice                 upgrade the contract to a new implementation address, if valid version
    ///                         can only be called by contract itself (in case of AvoWallet through `cast`)
    /// @param avoWalletImpl_   New contract address
    function upgradeTo(address avoWalletImpl_) public onlySelf {
        avoVersionsRegistry.requireValidAvoWalletVersion(avoWalletImpl_);

        _avoWalletImpl = avoWalletImpl_;
        emit Upgraded(avoWalletImpl_);
    }

    /// @notice                 upgrade the contract to a new implementation address, if valid version
    ///                         and call a function afterwards
    ///                         can only be called by contract itself (in case of AvoWallet through `cast`)
    /// @param avoWalletImpl_   New contract address
    /// @param data_            callData for function call on avoWalletImpl_ after upgrading
    /// @param forceCall_       optional flag to force send call even if callData (data_) is empty
    function upgradeToAndCall(
        address avoWalletImpl_,
        bytes calldata data_,
        bool forceCall_
    ) external payable virtual onlySelf {
        upgradeTo(avoWalletImpl_);
        if (data_.length > 0 || forceCall_) {
            Address.functionDelegateCall(avoWalletImpl_, data_);
        }
    }

    /// @dev internal method for modifier logic to reduce bytecode size of contract
    function _requireSelfCalled() internal view {
        if (msg.sender != address(this)) {
            revert SelfUpgradeable__Unauthorized();
        }
    }
}

File 10 of 13 : VariablesV1.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17;

import { IAvoVersionsRegistry } from "../interfaces/IAvoVersionsRegistry.sol";
import { IAvoWalletV2 } from "../interfaces/IAvoWalletV2.sol";

error AvoWallet__InvalidParams();

/// @title      VariablesV1
/// @notice     Contains storage variables for AvoWallet.
abstract contract VariablesV1 is IAvoWalletV2 {
    /// @notice  registry holding the valid versions (addresses) for AvoWallet implementation contracts
    ///          The registry is used to verify a valid version before upgrading
    ///          immutable but could be updated in the logic contract when a new version of AvoWallet is deployed
    IAvoVersionsRegistry public immutable avoVersionsRegistry;

    /// @notice address of the AvoForwarder (proxy) that is allowed to forward tx with valid
    ///         signatures to this contract
    ///         immutable but could be updated in the logic contract when a new version of AvoWallet is deployed
    address public immutable avoForwarder;

    // the next 3 vars (avoWalletImpl, nonce, status) are tightly packed into 1 storage slot

    /// @notice address of the Avo wallet logic / implementation contract. IMPORTANT: SAME STORAGE SLOT AS FOR PROXY
    /// @dev    IMPORTANT: DO NOT MOVE THIS VARIABLE
    ///         _avoWalletImpl MUST ALWAYS be the first declared variable here in the logic contract and in the proxy!
    ///         when upgrading, the storage at memory address 0x0 is upgraded (first slot).
    ///         immutable and constants do not take up storage slots so they can come before.
    address internal _avoWalletImpl;

    /// @notice nonce that is incremented for every `cast` transaction with valid signature
    uint88 public avoSafeNonce;

    /// @dev flag set temporarily to signal various cases:
    /// 0 -> default state
    /// 1 -> signature is valid or called by owner, _callTargets can be executed
    /// 20 / 21 -> flashloan receive can be executed (set to original id param from cast())
    uint8 internal _status;

    /// @notice owner of the smart wallet
    /// @dev theoretically immutable, can only be set in initialize (at proxy clone factory deployment)
    address public owner;

    /// @dev
    /// after owner variable there still is uint8 and bool from Initializable library. Rest of slot (10 bytes) should be empty
    /// uint8 private _initialized;
    /// bool private _initializing;

    /// @dev contracts deployed before V2 contain two more variables from EIP712Upgradeable: hashed domain separator
    /// name and version which were set at initialization (Now we do this in logic contract at deployment as constant)
    /// https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/utils/cryptography/EIP712Upgradeable.sol#L32
    /// bytes32 private _HASHED_NAME;
    /// bytes32 private _HASHED_VERSION;

    /// @notice constructor sets the immutable avoVersionsRegistry address
    /// @dev    setting this on the logic contract at deployment is ok because the
    ///         AvoVersionsRegistry is upgradeable so this address is the proxy address which really shouldn't change.
    ///         Even if it would change then worst case a new AvoWallet logic contract
    ///         has to be deployed pointing to a new registry
    /// @param avoVersionsRegistry_    address of the avoVersionsRegistry contract
    /// @param avoForwarder_           address of the avoForwarder (proxy) contract
    ///                                to forward tx with valid signatures. must be valid version in AvoVersionsRegistry.
    constructor(IAvoVersionsRegistry avoVersionsRegistry_, address avoForwarder_) {
        if (address(avoVersionsRegistry_) == address(0)) {
            revert AvoWallet__InvalidParams();
        }
        avoVersionsRegistry = avoVersionsRegistry_;

        avoVersionsRegistry.requireValidAvoForwarderVersion(avoForwarder_);
        avoForwarder = avoForwarder_;
    }
}

File 11 of 13 : InstaFlashReceiverInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17;

interface InstaFlashReceiverInterface {
    function executeOperation(
        address[] calldata assets,
        uint256[] calldata amounts,
        uint256[] calldata premiums,
        address initiator,
        bytes calldata _data
    ) external returns (bool);
}

File 12 of 13 : IAvoVersionsRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17;

interface IAvoVersionsRegistry {
    /// @notice                   checks if an address is listed as allowed AvoWallet version and reverts if it is not
    /// @param avoWalletVersion_  address of the Avo wallet logic contract to check
    function requireValidAvoWalletVersion(address avoWalletVersion_) external view;

    /// @notice                      checks if an address is listed as allowed AvoForwarder version
    ///                              and reverts if it is not
    /// @param avoForwarderVersion_  address of the AvoForwarder logic contract to check
    function requireValidAvoForwarderVersion(address avoForwarderVersion_) external view;
}

File 13 of 13 : IAvoWalletV2.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17;

interface IAvoWalletV2 {
    /// @notice an executable action via low-level call, including operation (call or delegateCall), target, data and value
    struct Action {
        address target; // the targets to execute the actions on
        bytes data; // the data to be passed to the call for each target
        uint256 value; // the msg.value to be passed to the call for each target. set to 0 if none
        uint256 operation; // 0 -> .call; 1 -> .delegateCall, 2 -> flashloan (via .call), id must be 0 or 2
    }

    struct CastParams {
        /// @param validUntil     As EIP-2770: the highest block number the request can be forwarded in, or 0 if request validity is not time-limited
        ///                       Protects against relayers executing a certain transaction at a later moment not intended by the user, where it might
        ///                       have a completely different effect. (Given that the transaction is not executed right away for some reason)
        uint256 validUntil;
        /// @param gas            As EIP-2770: an amount of gas limit to set for the execution
        ///                       Protects gainst potential gas griefing attacks / the relayer getting a reward without properly executing the tx completely
        ///                       See https://ronan.eth.limo/blog/ethereum-gas-dangers/
        uint256 gas;
        /// @param source         Source like e.g. referral for this tx
        address source;
        /// @param id             id for actions, e.g. 0 = CALL, 1 = MIXED (call and delegatecall), 20 = FLASHLOAN_CALL, 21 = FLASHLOAN_MIXED
        uint256 id;
        /// @param metadata       Optional metadata for future flexibility
        bytes metadata;
    }

    /// @notice struct containing variables in storage for a snapshot
    struct StorageSnapshot {
        address avoWalletImpl;
        uint88 avoSafeNonce;
        address owner;
    }

    /// @notice             AvoSafe Owner
    function owner() external view returns (address);

    /// @notice             Domain separator name for signatures
    function DOMAIN_SEPARATOR_NAME() external view returns (string memory);

    /// @notice             Domain separator version for signatures
    function DOMAIN_SEPARATOR_VERSION() external view returns (string memory);

    /// @notice             incrementing nonce for each valid tx executed (to ensure unique)
    function avoSafeNonce() external view returns (uint88);

    /// @notice             initializer called by AvoFactory after deployment
    /// @param owner_       the owner (immutable) of this smart wallet
    function initialize(address owner_) external;

    /// @notice                     initialize contract and set new AvoWallet version
    /// @param owner_               the owner (immutable) of this smart wallet
    /// @param avoWalletVersion_    version of AvoWallet logic contract to deploy
    function initializeWithVersion(address owner_, address avoWalletVersion_) external;

    /// @notice             returns the domainSeparator for EIP712 signature
    /// @return             the bytes32 domainSeparator for EIP712 signature
    function domainSeparatorV4() external view returns (bytes32);

    /// @notice               Verify the transaction is valid and can be executed.
    ///                       Does not revert and returns successfully if the input is valid.
    ///                       Reverts if any validation has failed. For instance, if params or either signature or avoSafeNonce are incorrect.
    /// @param actions_       the actions to execute (target, data, value)
    /// @param params_        Cast params: validUntil, gas, source, id and metadata
    /// @param signature_     the EIP712 signature, see verifySig method
    /// @return               returns true if everything is valid, otherwise reverts
    function verify(
        Action[] calldata actions_,
        CastParams calldata params_,
        bytes calldata signature_
    ) external view returns (bool);

    /// @notice               executes arbitrary actions according to datas on targets
    ///                       if one action fails, the transaction doesn't revert. Instead the CastFailed event is emitted
    ///                       and all previous actions are reverted. On success, emits CastExecuted event.
    /// @dev                  validates EIP712 signature then executes a .call or .delegateCall for every action.
    /// @param actions_       the actions to execute (target, data, value)
    /// @param params_        Cast params: validUntil, gas, source, id and metadata
    /// @param signature_     the EIP712 signature, see verifySig method
    /// @return success       true if all actions were executed succesfully, false otherwise.
    /// @return revertReason  revert reason if one of the actions fail
    function cast(
        Action[] calldata actions_,
        CastParams calldata params_,
        bytes calldata signature_
    ) external payable returns (bool success, string memory revertReason);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IAvoVersionsRegistry","name":"avoVersionsRegistry_","type":"address"},{"internalType":"address","name":"avoForwarder_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AvoWallet__Expired","type":"error"},{"inputs":[],"name":"AvoWallet__InsufficientGasSent","type":"error"},{"inputs":[],"name":"AvoWallet__InvalidParams","type":"error"},{"inputs":[],"name":"AvoWallet__InvalidSignature","type":"error"},{"inputs":[],"name":"AvoWallet__OutOfGas","type":"error"},{"inputs":[],"name":"AvoWallet__Unauthorized","type":"error"},{"inputs":[],"name":"SelfUpgradeable__Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"source","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"CastExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"source","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"string","name":"reason","type":"string"},{"indexed":false,"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"CastFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"avoWalletImpl","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"ACTION_TYPE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CAST_PARAMS_TYPE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CAST_TYPE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_CHAIN_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TYPE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"operation","type":"uint256"}],"internalType":"struct IAvoWalletV2.Action[]","name":"actions_","type":"tuple[]"},{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"_callTargets","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"avoForwarder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"avoSafeNonce","outputs":[{"internalType":"uint88","name":"","type":"uint88"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"avoVersionsRegistry","outputs":[{"internalType":"contract IAvoVersionsRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"operation","type":"uint256"}],"internalType":"struct IAvoWalletV2.Action[]","name":"actions_","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"address","name":"source","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"internalType":"struct IAvoWalletV2.CastParams","name":"params_","type":"tuple"},{"internalType":"bytes","name":"signature_","type":"bytes"}],"name":"cast","outputs":[{"internalType":"bool","name":"success_","type":"bool"},{"internalType":"string","name":"revertReason_","type":"string"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"domainSeparatorV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"address","name":"initiator_","type":"address"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"executeOperation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"avoWalletVersion_","type":"address"}],"name":"initializeWithVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"avoWalletImpl_","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"avoWalletImpl_","type":"address"},{"internalType":"bytes","name":"data_","type":"bytes"},{"internalType":"bool","name":"forceCall_","type":"bool"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"operation","type":"uint256"}],"internalType":"struct IAvoWalletV2.Action[]","name":"actions_","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"address","name":"source","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"internalType":"struct IAvoWalletV2.CastParams","name":"params_","type":"tuple"},{"internalType":"bytes","name":"signature_","type":"bytes"}],"name":"verify","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c06040523480156200001157600080fd5b50604051620052213803806200522183398181016040528101906200003791906200030a565b8181600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603620000a0576040517fe6d1a59000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff168152505060805173ffffffffffffffffffffffffffffffffffffffff166303d50d34826040518263ffffffff1660e01b815260040162000111919062000362565b60006040518083038186803b1580156200012a57600080fd5b505afa1580156200013f573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250505050620001896200019160201b60201c565b505062000463565b600160159054906101000a900460ff1615620001e4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620001db9062000406565b60405180910390fd5b60ff8016600160149054906101000a900460ff1660ff161015620002595760ff600160146101000a81548160ff021916908360ff1602179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249860ff60405162000250919062000446565b60405180910390a15b565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200028d8262000260565b9050919050565b6000620002a18262000280565b9050919050565b620002b38162000294565b8114620002bf57600080fd5b50565b600081519050620002d381620002a8565b92915050565b620002e48162000280565b8114620002f057600080fd5b50565b6000815190506200030481620002d9565b92915050565b600080604083850312156200032457620003236200025b565b5b60006200033485828601620002c2565b92505060206200034785828601620002f3565b9150509250929050565b6200035c8162000280565b82525050565b600060208201905062000379600083018462000351565b92915050565b600082825260208201905092915050565b7f496e697469616c697a61626c653a20636f6e747261637420697320696e69746960008201527f616c697a696e6700000000000000000000000000000000000000000000000000602082015250565b6000620003ee6027836200037f565b9150620003fb8262000390565b604082019050919050565b600060208201905081810360008301526200042181620003df565b9050919050565b600060ff82169050919050565b620004408162000428565b82525050565b60006020820190506200045d600083018462000435565b92915050565b60805160a051614d8a62000497600039600081816108f801526114f70152600081816107b301526107df0152614d8a6000f3fe60806040526004361061012e5760003560e01c806387265c95116100ab578063a0d061931161006f578063a0d06193146103e8578063a755ecfc14610413578063a80ebaf11461043e578063b4907ddc14610469578063b92e87fa14610494578063c4d66de8146104b057610135565b806387265c95146102ed5780638da5cb5b14610318578063920f5c841461034357806394f0320e14610380578063967df2f5146103ab57610135565b806343ea1996116100f257806343ea1996146102105780634c3d3ab21461023b57806364d4c8191461026c57806368fe969a1461029757806378e890ba146102c257610135565b806306d2e4261461013a578063150b7a021461015657806321f9c7931461019357806330b540c1146101bc5780633659cfe6146101e757610135565b3661013557005b600080fd5b610154600480360381019061014f91906131e8565b6104d9565b005b34801561016257600080fd5b5061017d600480360381019061017891906133d3565b610554565b60405161018a9190613491565b60405180910390f35b34801561019f57600080fd5b506101ba60048036038101906101b591906134ac565b610568565b005b3480156101c857600080fd5b506101d16107b1565b6040516101de919061354b565b60405180910390f35b3480156101f357600080fd5b5061020e60048036038101906102099190613566565b6107d5565b005b34801561021c57600080fd5b506102256108ec565b60405161023291906135a2565b60405180910390f35b61025560048036038101906102509190613637565b6108f2565b604051610263929190613776565b60405180910390f35b34801561027857600080fd5b50610281610dbe565b60405161028e91906137bf565b60405180910390f35b3480156102a357600080fd5b506102ac610de2565b6040516102b99190613800565b60405180910390f35b3480156102ce57600080fd5b506102d7610dff565b6040516102e491906137bf565b60405180910390f35b3480156102f957600080fd5b50610302610e0e565b60405161030f919061381b565b60405180910390f35b34801561032457600080fd5b5061032d610e47565b60405161033a919061384c565b60405180910390f35b34801561034f57600080fd5b5061036a60048036038101906103659190613913565b610e6d565b6040516103779190613a0f565b60405180910390f35b34801561038c57600080fd5b506103956114f5565b6040516103a2919061384c565b60405180910390f35b3480156103b757600080fd5b506103d260048036038101906103cd9190613637565b611519565b6040516103df9190613a0f565b60405180910390f35b3480156103f457600080fd5b506103fd611588565b60405161040a91906137bf565b60405180910390f35b34801561041f57600080fd5b506104286115ac565b60405161043591906137bf565b60405180910390f35b34801561044a57600080fd5b506104536115d0565b60405161046091906137bf565b60405180910390f35b34801561047557600080fd5b5061047e6115f4565b60405161048b919061381b565b60405180910390f35b6104ae60048036038101906104a99190613a2a565b61162d565b005b3480156104bc57600080fd5b506104d760048036038101906104d29190613566565b611d77565b005b6104e1611f7f565b6104ea846107d5565b60008383905011806104f95750805b1561054e5761054c8484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050611fe6565b505b50505050565b600063150b7a0260e01b9050949350505050565b6000600160159054906101000a900460ff1615905080801561059b575060018060149054906101000a900460ff1660ff16105b806105c957506105aa30612013565b1580156105c8575060018060149054906101000a900460ff1660ff16145b5b610608576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ff90613afc565b60405180910390fd5b60018060146101000a81548160ff021916908360ff16021790555080156106445760018060156101000a81548160ff0219169083151502179055505b6106638373ffffffffffffffffffffffffffffffffffffffff16612013565b8061069a5750600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16145b156106d1576040517fe6d1a59000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080156107ac576000600160156101000a81548160ff0219169083151502179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249860016040516107a39190613b64565b60405180910390a15b505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6107dd611f7f565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663f77cbc43826040518263ffffffff1660e01b8152600401610836919061384c565b60006040518083038186803b15801561084e57600080fd5b505afa158015610862573d6000803e3d6000fd5b50505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b61027a81565b600060607f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16036109f95784602001356101f45a61095c9190613bae565b1015610994576040517f21ddd39d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109a387878760000135612036565b60006109b08888886120be565b90506109bd8186866121db565b6109f3576040517f48eca37f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610a95565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1603610a6257610a5d87878760000135612036565b610a94565b6040517f3c98e25d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b60016000601f6101000a81548160ff021916908360ff1602179055506000601481819054906101000a90046affffffffffffffffffffff1680929190610ada90613be2565b91906101000a8154816affffffffffffffffffffff02191690836affffffffffffffffffffff16021790555050600087878760600135604051602401610b2293929190613e6e565b60405160208183030381529060405263b92e87fa60e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506060600080835160208501600054612ee05a03f493503d6040519150601f19601f6020830101168201604052808252806000602084013e5083610d2a576000815103610bec576040518060400160405280601781526020017f41564f5f5f524541534f4e5f4e4f545f444546494e45440000000000000000008152509250610c9c565b638707015b60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681610c1d90613edd565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603610c7e576040518060400160405280600f81526020017f41564f5f5f4f55545f4f465f47415300000000000000000000000000000000008152509250610c9b565b60048101905080806020019051810190610c989190613fe5565b92505b5b3373ffffffffffffffffffffffffffffffffffffffff16876040016020810190610cc69190613566565b73ffffffffffffffffffffffffffffffffffffffff167f2d7a71829f41b4722f54dffdc42778f25bdd583ce89fe0782aac04a5a2fb96d8858a8060800190610d0e919061403d565b604051610d1d939291906140de565b60405180910390a3610db2565b3373ffffffffffffffffffffffffffffffffffffffff16876040016020810190610d549190613566565b73ffffffffffffffffffffffffffffffffffffffff167f9beb578acb8466a63d01ec79c2ce2359e55b9c3bbe2095e4c788830feb5fc2e6898060800190610d9b919061403d565b604051610da9929190614117565b60405180910390a35b50509550959350505050565b7fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac5647281565b600060149054906101000a90046affffffffffffffffffffff1681565b6000610e09612289565b905090565b6040518060400160405280600c81526020017f41766f6361646f2d53616665000000000000000000000000000000000000000081525081565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060146000601f9054906101000a900460ff1660ff161480610ea2575060156000601f9054906101000a900460ff1660ff16145b8015610ed957503073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16145b610f0f576040517f3c98e25d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080601f9054906101000a900460ff1660ff169050600080601f6101000a81548160ff021916908360ff16021790555060008484810190610f5191906142ba565b9050610f5b61307f565b6015830361105557600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16816040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600060149054906101000a90046affffffffffffffffffffff1681602001906affffffffffffffffffffff1690816affffffffffffffffffffff16815250505b60008251905060005b8181101561137257600084828151811061107b5761107a614303565b5b6020026020010151905060006060600083606001510361111757826000015173ffffffffffffffffffffffffffffffffffffffff16836040015184602001516040516110c7919061436e565b60006040518083038185875af1925050503d8060008114611104576040519150601f19603f3d011682016040523d82523d6000602084013e611109565b606091505b5080925081935050506112f1565b6001836060015114801561112b5750601588145b156111ab57826000015173ffffffffffffffffffffffffffffffffffffffff16836020015160405161115d919061436e565b600060405180830381855af49150503d8060008114611198576040519150601f19603f3d011682016040523d82523d6000602084013e61119d565b606091505b5080925081935050506112f0565b60028360600151111561121c576111c184612381565b6040516020016111d191906143e7565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611213919061381b565b60405180910390fd5b600283606001510361128c5761123184612381565b6040516020016112419190614433565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611283919061381b565b60405180910390fd5b61129584612381565b6040516020016112a5919061447f565b6040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112e7919061381b565b60405180910390fd5b5b81611364576112ff84612381565b6113088261244f565b6040516020016113199291906144a5565b6040516020818303038152906040526040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161135b919061381b565b60405180910390fd5b83600101935050505061105e565b50600082602001516affffffffffffffffffffff161180156114a0575060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff1614801561143f5750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16826040015173ffffffffffffffffffffffffffffffffffffffff16145b80156114815750600060149054906101000a90046affffffffffffffffffffff166affffffffffffffffffffff1682602001516affffffffffffffffffffff16145b801561149e5750600080601f9054906101000a900460ff1660ff16145b155b156114e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114d790614515565b60405180910390fd5b60019450505050509998505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600061152a86868660000135612036565b60006115378787876120be565b90506115448185856121db565b61157a576040517f48eca37f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600191505095945050505050565b7f9aa78168ddcd68af5d2a4d0ac0cb4b54bf9d84d1ddff44be4030d7884c6da9f681565b7f5ce8b8715bfac5b3e19b27a537d68f1a49e2c3ccdc13dfb6858f28073b0d78de81565b7f5c1c53221914feac61859607db2bf67fc5d2d108016fd0bab7ceb23e65e90f6581565b6040518060400160405280600581526020017f322e302e3000000000000000000000000000000000000000000000000000000081525081565b60016000601f9054906101000a900460ff1660ff16148061167b575061dead73ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16145b6116b1576040517f3c98e25d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060028210806116c25750601482145b806116cd5750601582145b9050600060018314806116e05750601583145b9050600080601f6101000a81548160ff021916908360ff16021790555061170561307f565b81156117fd57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16816040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600060149054906101000a90046affffffffffffffffffffff1681602001906affffffffffffffffffffff1690816affffffffffffffffffffff16815250505b600086869050905060005b81811015611c0057600088888381811061182557611824614303565b5b90506020028101906118379190614535565b6118409061455d565b90506000606060008084606001511480156118585750885b156118f35760405a8161186e5761186d614570565b5b049050836000015173ffffffffffffffffffffffffffffffffffffffff16846040015185602001516040516118a3919061436e565b60006040518083038185875af1925050503d80600081146118e0576040519150601f19603f3d011682016040523d82523d6000602084013e6118e5565b606091505b508093508194505050611b44565b600184606001511480156119045750875b156119985760405a8161191a57611919614570565b5b049050836000015173ffffffffffffffffffffffffffffffffffffffff16846020015160405161194a919061436e565b600060405180830381855af49150503d8060008114611985576040519150601f19603f3d011682016040523d82523d6000602084013e61198a565b606091505b508093508194505050611b43565b600284606001511480156119b7575060148a14806119b6575060158a145b5b15611a6d57896000601f6101000a81548160ff021916908360ff16021790555060405a816119e8576119e7614570565b5b049050836000015173ffffffffffffffffffffffffffffffffffffffff1684604001518560200151604051611a1d919061436e565b60006040518083038185875af1925050503d8060008114611a5a576040519150601f19603f3d011682016040523d82523d6000602084013e611a5f565b606091505b508093508194505050611b42565b600284606001511115611ade57611a8385612381565b604051602001611a9391906143e7565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ad5919061381b565b60405180910390fd5b611ae785612381565b604051602001611af7919061447f565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b39919061381b565b60405180910390fd5b5b5b82611bf157805a1015611b83576040517f8707015b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b8c85612381565b611b958361244f565b604051602001611ba69291906144a5565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611be8919061381b565b60405180910390fd5b84600101945050505050611808565b50600082602001516affffffffffffffffffffff16118015611d2e575060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff16148015611ccd5750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16826040015173ffffffffffffffffffffffffffffffffffffffff16145b8015611d0f5750600060149054906101000a90046affffffffffffffffffffff166affffffffffffffffffffff1682602001516affffffffffffffffffffff16145b8015611d2c5750600080601f9054906101000a900460ff1660ff16145b155b15611d6e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d6590614515565b60405180910390fd5b50505050505050565b6000600160159054906101000a900460ff16159050808015611daa575060018060149054906101000a900460ff1660ff16105b80611dd85750611db930612013565b158015611dd7575060018060149054906101000a900460ff1660ff16145b5b611e17576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e0e90613afc565b60405180910390fd5b60018060146101000a81548160ff021916908360ff1602179055508015611e535760018060156101000a81548160ff0219169083151502179055505b611e728273ffffffffffffffffffffffffffffffffffffffff16612013565b80611ea95750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b15611ee0576040517fe6d1a59000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508015611f7b576000600160156101000a81548160ff0219169083151502179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024986001604051611f729190613b64565b60405180910390a15b5050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611fe4576040517f9871463100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b606061200b8383604051806060016040528060278152602001614d2e602791396125fc565b905092915050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b60008383905003612073576040517fe6d1a59000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008111801561208257504281105b156120b9576040517fcc1cf67c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b60006121d26120cb612289565b7f9aa78168ddcd68af5d2a4d0ac0cb4b54bf9d84d1ddff44be4030d7884c6da9f66120f68787612682565b7f5ce8b8715bfac5b3e19b27a537d68f1a49e2c3ccdc13dfb6858f28073b0d78de866000013587602001358860400160208101906121349190613566565b89606001358a8060800190612149919061403d565b6040516121579291906145c4565b6040518091039020604051602001612174969594939291906145dd565b60405160208183030381529060405280519060200120600060149054906101000a90046affffffffffffffffffffff166040516020016121b7949392919061463e565b6040516020818303038152906040528051906020012061285d565b90509392505050565b60008061222c8585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612890565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16149150509392505050565b60007fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac564726040518060400160405280600c81526020017f41766f6361646f2d536166650000000000000000000000000000000000000000815250805190602001206040518060400160405280600581526020017f322e302e300000000000000000000000000000000000000000000000000000008152508051906020012061027a304660405160200161233b91906146a4565b60405160208183030381529060405280519060200120604051602001612366969594939291906146bf565b60405160208183030381529060405280519060200120905090565b606060006001612390846128b7565b01905060008167ffffffffffffffff8111156123af576123ae6132a8565b5b6040519080825280601f01601f1916602001820160405280156123e15781602001600182028036833780820191505090505b509050600082602001820190505b600115612444578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a858161243857612437614570565b5b049450600085036123ef575b819350505050919050565b6060600482511015612498576040518060400160405280601381526020017f5f524541534f4e5f4e4f545f444546494e45440000000000000000000000000081525090506125f7565b600060208301519050634e487b7160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361257f576040518060400160405280601681526020017f5f5441524745545f50414e49434b45443a2030785f5f00000000000000000000815250915060006024840151905060208301516030600f831601603060f0841660041c0160081b8181177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00008416179250826020870152505050506125f5565b6044835111156125c957600483019250828060200190518101906125a39190613fe5565b6040516020016125b39190614746565b60405160208183030381529060405291506125f4565b6125d281612a0a565b6040516020016125e29190614792565b60405160208183030381529060405291505b5b505b919050565b60606000808573ffffffffffffffffffffffffffffffffffffffff1685604051612626919061436e565b600060405180830381855af49150503d8060008114612661576040519150601f19603f3d011682016040523d82523d6000602084013e612666565b606091505b509150915061267786838387612c5d565b925050509392505050565b60008083839050905060008167ffffffffffffffff8111156126a7576126a66132a8565b5b6040519080825280602002602001820160405280156126d55781602001602082028036833780820191505090505b50905060005b8281101561282b577f5c1c53221914feac61859607db2bf67fc5d2d108016fd0bab7ceb23e65e90f6586868381811061271757612716614303565b5b90506020028101906127299190614535565b600001602081019061273b9190613566565b87878481811061274e5761274d614303565b5b90506020028101906127609190614535565b806020019061276f919061403d565b60405161277d9291906145c4565b604051809103902088888581811061279857612797614303565b5b90506020028101906127aa9190614535565b604001358989868181106127c1576127c0614303565b5b90506020028101906127d39190614535565b606001356040516020016127eb9594939291906147b8565b6040516020818303038152906040528051906020012082828151811061281457612813614303565b5b6020026020010181815250508060010190506126db565b508060405160200161283d91906148c3565b604051602081830303815290604052805190602001209250505092915050565b60008282604051602001612872929190614947565b60405160208183030381529060405280519060200120905092915050565b600080600061289f8585612cd2565b915091506128ac81612d23565b819250505092915050565b600080600090507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612915577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000838161290b5761290a614570565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310612952576d04ee2d6d415b85acef8100000000838161294857612947614570565b5b0492506020810190505b662386f26fc10000831061298157662386f26fc10000838161297757612976614570565b5b0492506010810190505b6305f5e10083106129aa576305f5e10083816129a05761299f614570565b5b0492506008810190505b61271083106129cf5761271083816129c5576129c4614570565b5b0492506004810190505b606483106129f257606483816129e8576129e7614570565b5b0492506002810190505b600a8310612a01576001810190505b80915050919050565b60606000600a67ffffffffffffffff811115612a2957612a286132a8565b5b6040519080825280601f01601f191660200182016040528015612a5b5781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612a9357612a92614303565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612af757612af6614303565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060005b6004811015612c5357612b606010858360048110612b4a57612b49614303565b5b1a60f81b60f81c612b5b919061497e565b612e89565b826002836002612b7091906149af565b612b7a9190613bae565b81518110612b8b57612b8a614303565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350612be86010858360048110612bd257612bd1614303565b5b1a60f81b60f81c612be391906149f1565b612e89565b826003836002612bf891906149af565b612c029190613bae565b81518110612c1357612c12614303565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080612c4c90614a22565b9050612b29565b5080915050919050565b60608315612cbf576000835103612cb757612c7785612013565b612cb6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cad90614ab6565b60405180910390fd5b5b829050612cca565b612cc98383612f4d565b5b949350505050565b6000806041835103612d135760008060006020860151925060408601519150606086015160001a9050612d0787828585612f9d565b94509450505050612d1c565b60006002915091505b9250929050565b60006004811115612d3757612d36614ad6565b5b816004811115612d4a57612d49614ad6565b5b0315612e865760016004811115612d6457612d63614ad6565b5b816004811115612d7757612d76614ad6565b5b03612db7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612dae90614b51565b60405180910390fd5b60026004811115612dcb57612dca614ad6565b5b816004811115612dde57612ddd614ad6565b5b03612e1e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e1590614bbd565b60405180910390fd5b60036004811115612e3257612e31614ad6565b5b816004811115612e4557612e44614ad6565b5b03612e85576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e7c90614c4f565b60405180910390fd5b5b50565b60008160ff16600011158015612ea3575060098260ff1611155b15612ee157817f300000000000000000000000000000000000000000000000000000000000000060f81c612ed79190614c6f565b60f81b9050612f48565b8160ff16600a11158015612ef95750600f8260ff1611155b15612f4357600a827f610000000000000000000000000000000000000000000000000000000000000060f81c612f2f9190614c6f565b612f399190614ca4565b60f81b9050612f48565b600080fd5b919050565b600082511115612f605781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f94919061381b565b60405180910390fd5b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08360001c1115612fd8576000600391509150613076565b600060018787878760405160008152602001604052604051612ffd9493929190614ce8565b6020604051602081039080840390855afa15801561301f573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361306d57600060019250925050613076565b80600092509250505b94509492505050565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160006affffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613118826130ed565b9050919050565b6131288161310d565b811461313357600080fd5b50565b6000813590506131458161311f565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126131705761316f61314b565b5b8235905067ffffffffffffffff81111561318d5761318c613150565b5b6020830191508360018202830111156131a9576131a8613155565b5b9250929050565b60008115159050919050565b6131c5816131b0565b81146131d057600080fd5b50565b6000813590506131e2816131bc565b92915050565b60008060008060608587031215613202576132016130e3565b5b600061321087828801613136565b945050602085013567ffffffffffffffff811115613231576132306130e8565b5b61323d8782880161315a565b93509350506040613250878288016131d3565b91505092959194509250565b6000819050919050565b61326f8161325c565b811461327a57600080fd5b50565b60008135905061328c81613266565b92915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6132e082613297565b810181811067ffffffffffffffff821117156132ff576132fe6132a8565b5b80604052505050565b60006133126130d9565b905061331e82826132d7565b919050565b600067ffffffffffffffff82111561333e5761333d6132a8565b5b61334782613297565b9050602081019050919050565b82818337600083830152505050565b600061337661337184613323565b613308565b90508281526020810184848401111561339257613391613292565b5b61339d848285613354565b509392505050565b600082601f8301126133ba576133b961314b565b5b81356133ca848260208601613363565b91505092915050565b600080600080608085870312156133ed576133ec6130e3565b5b60006133fb87828801613136565b945050602061340c87828801613136565b935050604061341d8782880161327d565b925050606085013567ffffffffffffffff81111561343e5761343d6130e8565b5b61344a878288016133a5565b91505092959194509250565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61348b81613456565b82525050565b60006020820190506134a66000830184613482565b92915050565b600080604083850312156134c3576134c26130e3565b5b60006134d185828601613136565b92505060206134e285828601613136565b9150509250929050565b6000819050919050565b600061351161350c613507846130ed565b6134ec565b6130ed565b9050919050565b6000613523826134f6565b9050919050565b600061353582613518565b9050919050565b6135458161352a565b82525050565b6000602082019050613560600083018461353c565b92915050565b60006020828403121561357c5761357b6130e3565b5b600061358a84828501613136565b91505092915050565b61359c8161325c565b82525050565b60006020820190506135b76000830184613593565b92915050565b60008083601f8401126135d3576135d261314b565b5b8235905067ffffffffffffffff8111156135f0576135ef613150565b5b60208301915083602082028301111561360c5761360b613155565b5b9250929050565b600080fd5b600060a0828403121561362e5761362d613613565b5b81905092915050565b600080600080600060608688031215613653576136526130e3565b5b600086013567ffffffffffffffff811115613671576136706130e8565b5b61367d888289016135bd565b9550955050602086013567ffffffffffffffff8111156136a05761369f6130e8565b5b6136ac88828901613618565b935050604086013567ffffffffffffffff8111156136cd576136cc6130e8565b5b6136d98882890161315a565b92509250509295509295909350565b6136f1816131b0565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015613731578082015181840152602081019050613716565b60008484015250505050565b6000613748826136f7565b6137528185613702565b9350613762818560208601613713565b61376b81613297565b840191505092915050565b600060408201905061378b60008301856136e8565b818103602083015261379d818461373d565b90509392505050565b6000819050919050565b6137b9816137a6565b82525050565b60006020820190506137d460008301846137b0565b92915050565b60006affffffffffffffffffffff82169050919050565b6137fa816137da565b82525050565b600060208201905061381560008301846137f1565b92915050565b60006020820190508181036000830152613835818461373d565b905092915050565b6138468161310d565b82525050565b6000602082019050613861600083018461383d565b92915050565b60008083601f84011261387d5761387c61314b565b5b8235905067ffffffffffffffff81111561389a57613899613150565b5b6020830191508360208202830111156138b6576138b5613155565b5b9250929050565b60008083601f8401126138d3576138d261314b565b5b8235905067ffffffffffffffff8111156138f0576138ef613150565b5b60208301915083602082028301111561390c5761390b613155565b5b9250929050565b600080600080600080600080600060a08a8c031215613935576139346130e3565b5b60008a013567ffffffffffffffff811115613953576139526130e8565b5b61395f8c828d01613867565b995099505060208a013567ffffffffffffffff811115613982576139816130e8565b5b61398e8c828d016138bd565b975097505060408a013567ffffffffffffffff8111156139b1576139b06130e8565b5b6139bd8c828d016138bd565b955095505060606139d08c828d01613136565b93505060808a013567ffffffffffffffff8111156139f1576139f06130e8565b5b6139fd8c828d0161315a565b92509250509295985092959850929598565b6000602082019050613a2460008301846136e8565b92915050565b600080600060408486031215613a4357613a426130e3565b5b600084013567ffffffffffffffff811115613a6157613a606130e8565b5b613a6d868287016135bd565b93509350506020613a808682870161327d565b9150509250925092565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b6000613ae6602e83613702565b9150613af182613a8a565b604082019050919050565b60006020820190508181036000830152613b1581613ad9565b9050919050565b6000819050919050565b600060ff82169050919050565b6000613b4e613b49613b4484613b1c565b6134ec565b613b26565b9050919050565b613b5e81613b33565b82525050565b6000602082019050613b796000830184613b55565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000613bb98261325c565b9150613bc48361325c565b9250828201905080821115613bdc57613bdb613b7f565b5b92915050565b6000613bed826137da565b91506affffffffffffffffffffff8203613c0a57613c09613b7f565b5b600182019050919050565b600082825260208201905092915050565b6000819050919050565b6000613c3f6020840184613136565b905092915050565b613c508161310d565b82525050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112613c8257613c81613c60565b5b83810192508235915060208301925067ffffffffffffffff821115613caa57613ca9613c56565b5b600182023603831315613cc057613cbf613c5b565b5b509250929050565b600082825260208201905092915050565b6000613ce58385613cc8565b9350613cf2838584613354565b613cfb83613297565b840190509392505050565b6000613d15602084018461327d565b905092915050565b613d268161325c565b82525050565b600060808301613d3f6000840184613c30565b613d4c6000860182613c47565b50613d5a6020840184613c65565b8583036020870152613d6d838284613cd9565b92505050613d7e6040840184613d06565b613d8b6040860182613d1d565b50613d996060840184613d06565b613da66060860182613d1d565b508091505092915050565b6000613dbd8383613d2c565b905092915050565b600082356001608003833603038112613de157613de0613c60565b5b82810191505092915050565b6000602082019050919050565b6000613e068385613c15565b935083602084028501613e1884613c26565b8060005b87811015613e5c578484038952613e338284613dc5565b613e3d8582613db1565b9450613e4883613ded565b925060208a01995050600181019050613e1c565b50829750879450505050509392505050565b60006040820190508181036000830152613e89818587613dfa565b9050613e986020830184613593565b949350505050565b600081519050919050565b6000819050602082019050919050565b6000613ec78251613456565b80915050919050565b600082821b905092915050565b6000613ee882613ea0565b82613ef284613eab565b9050613efd81613ebb565b92506004821015613f3d57613f387fffffffff0000000000000000000000000000000000000000000000000000000083600403600802613ed0565b831692505b5050919050565b600067ffffffffffffffff821115613f5f57613f5e6132a8565b5b613f6882613297565b9050602081019050919050565b6000613f88613f8384613f44565b613308565b905082815260208101848484011115613fa457613fa3613292565b5b613faf848285613713565b509392505050565b600082601f830112613fcc57613fcb61314b565b5b8151613fdc848260208601613f75565b91505092915050565b600060208284031215613ffb57613ffa6130e3565b5b600082015167ffffffffffffffff811115614019576140186130e8565b5b61402584828501613fb7565b91505092915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261405a5761405961402e565b5b80840192508235915067ffffffffffffffff82111561407c5761407b614033565b5b60208301925060018202360383131561409857614097614038565b5b509250929050565b600082825260208201905092915050565b60006140bd83856140a0565b93506140ca838584613354565b6140d383613297565b840190509392505050565b600060408201905081810360008301526140f8818661373d565b9050818103602083015261410d8184866140b1565b9050949350505050565b600060208201905081810360008301526141328184866140b1565b90509392505050565b600067ffffffffffffffff821115614156576141556132a8565b5b602082029050602081019050919050565b600080fd5b600080fd5b60006080828403121561418757614186614167565b5b6141916080613308565b905060006141a184828501613136565b600083015250602082013567ffffffffffffffff8111156141c5576141c461416c565b5b6141d1848285016133a5565b60208301525060406141e58482850161327d565b60408301525060606141f98482850161327d565b60608301525092915050565b60006142186142138461413b565b613308565b9050808382526020820190506020840283018581111561423b5761423a613155565b5b835b8181101561428257803567ffffffffffffffff8111156142605761425f61314b565b5b80860161426d8982614171565b8552602085019450505060208101905061423d565b5050509392505050565b600082601f8301126142a1576142a061314b565b5b81356142b1848260208601614205565b91505092915050565b6000602082840312156142d0576142cf6130e3565b5b600082013567ffffffffffffffff8111156142ee576142ed6130e8565b5b6142fa8482850161428c565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081905092915050565b600061434882613ea0565b6143528185614332565b9350614362818560208601613713565b80840191505092915050565b600061437a828461433d565b915081905092915050565b600081905092915050565b600061439b826136f7565b6143a58185614385565b93506143b5818560208601613713565b80840191505092915050565b7f5f41564f5f5f4f5045524154494f4e5f4e4f545f455849535400000000000000815250565b60006143f38284614390565b91506143fe826143c1565b60198201915081905092915050565b7f5f41564f5f5f4e4f5f464c4153484c4f414e5f494e5f464c4153484c4f414e00815250565b600061443f8284614390565b915061444a8261440d565b601f8201915081905092915050565b7f5f41564f5f5f49445f414354494f4e5f4d49534d415443480000000000000000815250565b600061448b8284614390565b915061449682614459565b60188201915081905092915050565b60006144b18285614390565b91506144bd8284614390565b91508190509392505050565b7f41564f5f5f4d4f4449464945445f53544f524147450000000000000000000000600082015250565b60006144ff601583613702565b915061450a826144c9565b602082019050919050565b6000602082019050818103600083015261452e816144f2565b9050919050565b6000823560016080038336030381126145515761455061402e565b5b80830191505092915050565b60006145693683614171565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006145ab8385614332565b93506145b8838584613354565b82840190509392505050565b60006145d182848661459f565b91508190509392505050565b600060c0820190506145f260008301896137b0565b6145ff6020830188613593565b61460c6040830187613593565b614619606083018661383d565b6146266080830185613593565b61463360a08301846137b0565b979650505050505050565b600060808201905061465360008301876137b0565b61466060208301866137b0565b61466d60408301856137b0565b61467a60608301846137f1565b95945050505050565b6000819050919050565b61469e6146998261325c565b614683565b82525050565b60006146b0828461468d565b60208201915081905092915050565b600060c0820190506146d460008301896137b0565b6146e160208301886137b0565b6146ee60408301876137b0565b6146fb6060830186613593565b614708608083018561383d565b61471560a08301846137b0565b979650505050505050565b7f5f00000000000000000000000000000000000000000000000000000000000000815250565b600061475182614720565b6001820191506147618284614390565b915081905092915050565b7f5f435553544f4d5f4552524f523a000000000000000000000000000000000000815250565b600061479d8261476c565b600e820191506147ad8284614390565b915081905092915050565b600060a0820190506147cd60008301886137b0565b6147da602083018761383d565b6147e760408301866137b0565b6147f46060830185613593565b6148016080830184613593565b9695505050505050565b600081519050919050565b600081905092915050565b6000819050602082019050919050565b61483a816137a6565b82525050565b600061484c8383614831565b60208301905092915050565b6000602082019050919050565b60006148708261480b565b61487a8185614816565b935061488583614821565b8060005b838110156148b657815161489d8882614840565b97506148a883614858565b925050600181019050614889565b5085935050505092915050565b60006148cf8284614865565b915081905092915050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b6000614910600283614385565b915061491b826148da565b600282019050919050565b6000819050919050565b61494161493c826137a6565b614926565b82525050565b600061495282614903565b915061495e8285614930565b60208201915061496e8284614930565b6020820191508190509392505050565b600061498982613b26565b915061499483613b26565b9250826149a4576149a3614570565b5b828204905092915050565b60006149ba8261325c565b91506149c58361325c565b92508282026149d38161325c565b915082820484148315176149ea576149e9613b7f565b5b5092915050565b60006149fc82613b26565b9150614a0783613b26565b925082614a1757614a16614570565b5b828206905092915050565b6000614a2d8261325c565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614a5f57614a5e613b7f565b5b600182019050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000614aa0601d83613702565b9150614aab82614a6a565b602082019050919050565b60006020820190508181036000830152614acf81614a93565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f45434453413a20696e76616c6964207369676e61747572650000000000000000600082015250565b6000614b3b601883613702565b9150614b4682614b05565b602082019050919050565b60006020820190508181036000830152614b6a81614b2e565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265206c656e67746800600082015250565b6000614ba7601f83613702565b9150614bb282614b71565b602082019050919050565b60006020820190508181036000830152614bd681614b9a565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265202773272076616c60008201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b6000614c39602283613702565b9150614c4482614bdd565b604082019050919050565b60006020820190508181036000830152614c6881614c2c565b9050919050565b6000614c7a82613b26565b9150614c8583613b26565b9250828201905060ff811115614c9e57614c9d613b7f565b5b92915050565b6000614caf82613b26565b9150614cba83613b26565b9250828203905060ff811115614cd357614cd2613b7f565b5b92915050565b614ce281613b26565b82525050565b6000608082019050614cfd60008301876137b0565b614d0a6020830186614cd9565b614d1760408301856137b0565b614d2460608301846137b0565b9594505050505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122058d41a9b3c50a79c18d113f7e175240d580fec99849d2d4cf9a32a5d157c631064736f6c63430008110033000000000000000000000000fbf28161ae33f492250aa12117e7a3f4593b7aa1000000000000000000000000375f6b0cd12b34dc28e34c26853a37012c24dde5

Deployed Bytecode

0x60806040526004361061012e5760003560e01c806387265c95116100ab578063a0d061931161006f578063a0d06193146103e8578063a755ecfc14610413578063a80ebaf11461043e578063b4907ddc14610469578063b92e87fa14610494578063c4d66de8146104b057610135565b806387265c95146102ed5780638da5cb5b14610318578063920f5c841461034357806394f0320e14610380578063967df2f5146103ab57610135565b806343ea1996116100f257806343ea1996146102105780634c3d3ab21461023b57806364d4c8191461026c57806368fe969a1461029757806378e890ba146102c257610135565b806306d2e4261461013a578063150b7a021461015657806321f9c7931461019357806330b540c1146101bc5780633659cfe6146101e757610135565b3661013557005b600080fd5b610154600480360381019061014f91906131e8565b6104d9565b005b34801561016257600080fd5b5061017d600480360381019061017891906133d3565b610554565b60405161018a9190613491565b60405180910390f35b34801561019f57600080fd5b506101ba60048036038101906101b591906134ac565b610568565b005b3480156101c857600080fd5b506101d16107b1565b6040516101de919061354b565b60405180910390f35b3480156101f357600080fd5b5061020e60048036038101906102099190613566565b6107d5565b005b34801561021c57600080fd5b506102256108ec565b60405161023291906135a2565b60405180910390f35b61025560048036038101906102509190613637565b6108f2565b604051610263929190613776565b60405180910390f35b34801561027857600080fd5b50610281610dbe565b60405161028e91906137bf565b60405180910390f35b3480156102a357600080fd5b506102ac610de2565b6040516102b99190613800565b60405180910390f35b3480156102ce57600080fd5b506102d7610dff565b6040516102e491906137bf565b60405180910390f35b3480156102f957600080fd5b50610302610e0e565b60405161030f919061381b565b60405180910390f35b34801561032457600080fd5b5061032d610e47565b60405161033a919061384c565b60405180910390f35b34801561034f57600080fd5b5061036a60048036038101906103659190613913565b610e6d565b6040516103779190613a0f565b60405180910390f35b34801561038c57600080fd5b506103956114f5565b6040516103a2919061384c565b60405180910390f35b3480156103b757600080fd5b506103d260048036038101906103cd9190613637565b611519565b6040516103df9190613a0f565b60405180910390f35b3480156103f457600080fd5b506103fd611588565b60405161040a91906137bf565b60405180910390f35b34801561041f57600080fd5b506104286115ac565b60405161043591906137bf565b60405180910390f35b34801561044a57600080fd5b506104536115d0565b60405161046091906137bf565b60405180910390f35b34801561047557600080fd5b5061047e6115f4565b60405161048b919061381b565b60405180910390f35b6104ae60048036038101906104a99190613a2a565b61162d565b005b3480156104bc57600080fd5b506104d760048036038101906104d29190613566565b611d77565b005b6104e1611f7f565b6104ea846107d5565b60008383905011806104f95750805b1561054e5761054c8484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050611fe6565b505b50505050565b600063150b7a0260e01b9050949350505050565b6000600160159054906101000a900460ff1615905080801561059b575060018060149054906101000a900460ff1660ff16105b806105c957506105aa30612013565b1580156105c8575060018060149054906101000a900460ff1660ff16145b5b610608576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ff90613afc565b60405180910390fd5b60018060146101000a81548160ff021916908360ff16021790555080156106445760018060156101000a81548160ff0219169083151502179055505b6106638373ffffffffffffffffffffffffffffffffffffffff16612013565b8061069a5750600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16145b156106d1576040517fe6d1a59000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080156107ac576000600160156101000a81548160ff0219169083151502179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249860016040516107a39190613b64565b60405180910390a15b505050565b7f000000000000000000000000fbf28161ae33f492250aa12117e7a3f4593b7aa181565b6107dd611f7f565b7f000000000000000000000000fbf28161ae33f492250aa12117e7a3f4593b7aa173ffffffffffffffffffffffffffffffffffffffff1663f77cbc43826040518263ffffffff1660e01b8152600401610836919061384c565b60006040518083038186803b15801561084e57600080fd5b505afa158015610862573d6000803e3d6000fd5b50505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b61027a81565b600060607f000000000000000000000000375f6b0cd12b34dc28e34c26853a37012c24dde573ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16036109f95784602001356101f45a61095c9190613bae565b1015610994576040517f21ddd39d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109a387878760000135612036565b60006109b08888886120be565b90506109bd8186866121db565b6109f3576040517f48eca37f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610a95565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1603610a6257610a5d87878760000135612036565b610a94565b6040517f3c98e25d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b60016000601f6101000a81548160ff021916908360ff1602179055506000601481819054906101000a90046affffffffffffffffffffff1680929190610ada90613be2565b91906101000a8154816affffffffffffffffffffff02191690836affffffffffffffffffffff16021790555050600087878760600135604051602401610b2293929190613e6e565b60405160208183030381529060405263b92e87fa60e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506060600080835160208501600054612ee05a03f493503d6040519150601f19601f6020830101168201604052808252806000602084013e5083610d2a576000815103610bec576040518060400160405280601781526020017f41564f5f5f524541534f4e5f4e4f545f444546494e45440000000000000000008152509250610c9c565b638707015b60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681610c1d90613edd565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603610c7e576040518060400160405280600f81526020017f41564f5f5f4f55545f4f465f47415300000000000000000000000000000000008152509250610c9b565b60048101905080806020019051810190610c989190613fe5565b92505b5b3373ffffffffffffffffffffffffffffffffffffffff16876040016020810190610cc69190613566565b73ffffffffffffffffffffffffffffffffffffffff167f2d7a71829f41b4722f54dffdc42778f25bdd583ce89fe0782aac04a5a2fb96d8858a8060800190610d0e919061403d565b604051610d1d939291906140de565b60405180910390a3610db2565b3373ffffffffffffffffffffffffffffffffffffffff16876040016020810190610d549190613566565b73ffffffffffffffffffffffffffffffffffffffff167f9beb578acb8466a63d01ec79c2ce2359e55b9c3bbe2095e4c788830feb5fc2e6898060800190610d9b919061403d565b604051610da9929190614117565b60405180910390a35b50509550959350505050565b7fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac5647281565b600060149054906101000a90046affffffffffffffffffffff1681565b6000610e09612289565b905090565b6040518060400160405280600c81526020017f41766f6361646f2d53616665000000000000000000000000000000000000000081525081565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060146000601f9054906101000a900460ff1660ff161480610ea2575060156000601f9054906101000a900460ff1660ff16145b8015610ed957503073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16145b610f0f576040517f3c98e25d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080601f9054906101000a900460ff1660ff169050600080601f6101000a81548160ff021916908360ff16021790555060008484810190610f5191906142ba565b9050610f5b61307f565b6015830361105557600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16816040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600060149054906101000a90046affffffffffffffffffffff1681602001906affffffffffffffffffffff1690816affffffffffffffffffffff16815250505b60008251905060005b8181101561137257600084828151811061107b5761107a614303565b5b6020026020010151905060006060600083606001510361111757826000015173ffffffffffffffffffffffffffffffffffffffff16836040015184602001516040516110c7919061436e565b60006040518083038185875af1925050503d8060008114611104576040519150601f19603f3d011682016040523d82523d6000602084013e611109565b606091505b5080925081935050506112f1565b6001836060015114801561112b5750601588145b156111ab57826000015173ffffffffffffffffffffffffffffffffffffffff16836020015160405161115d919061436e565b600060405180830381855af49150503d8060008114611198576040519150601f19603f3d011682016040523d82523d6000602084013e61119d565b606091505b5080925081935050506112f0565b60028360600151111561121c576111c184612381565b6040516020016111d191906143e7565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611213919061381b565b60405180910390fd5b600283606001510361128c5761123184612381565b6040516020016112419190614433565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611283919061381b565b60405180910390fd5b61129584612381565b6040516020016112a5919061447f565b6040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112e7919061381b565b60405180910390fd5b5b81611364576112ff84612381565b6113088261244f565b6040516020016113199291906144a5565b6040516020818303038152906040526040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161135b919061381b565b60405180910390fd5b83600101935050505061105e565b50600082602001516affffffffffffffffffffff161180156114a0575060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff1614801561143f5750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16826040015173ffffffffffffffffffffffffffffffffffffffff16145b80156114815750600060149054906101000a90046affffffffffffffffffffff166affffffffffffffffffffff1682602001516affffffffffffffffffffff16145b801561149e5750600080601f9054906101000a900460ff1660ff16145b155b156114e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114d790614515565b60405180910390fd5b60019450505050509998505050505050505050565b7f000000000000000000000000375f6b0cd12b34dc28e34c26853a37012c24dde581565b600061152a86868660000135612036565b60006115378787876120be565b90506115448185856121db565b61157a576040517f48eca37f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600191505095945050505050565b7f9aa78168ddcd68af5d2a4d0ac0cb4b54bf9d84d1ddff44be4030d7884c6da9f681565b7f5ce8b8715bfac5b3e19b27a537d68f1a49e2c3ccdc13dfb6858f28073b0d78de81565b7f5c1c53221914feac61859607db2bf67fc5d2d108016fd0bab7ceb23e65e90f6581565b6040518060400160405280600581526020017f322e302e3000000000000000000000000000000000000000000000000000000081525081565b60016000601f9054906101000a900460ff1660ff16148061167b575061dead73ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16145b6116b1576040517f3c98e25d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060028210806116c25750601482145b806116cd5750601582145b9050600060018314806116e05750601583145b9050600080601f6101000a81548160ff021916908360ff16021790555061170561307f565b81156117fd57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16816040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600060149054906101000a90046affffffffffffffffffffff1681602001906affffffffffffffffffffff1690816affffffffffffffffffffff16815250505b600086869050905060005b81811015611c0057600088888381811061182557611824614303565b5b90506020028101906118379190614535565b6118409061455d565b90506000606060008084606001511480156118585750885b156118f35760405a8161186e5761186d614570565b5b049050836000015173ffffffffffffffffffffffffffffffffffffffff16846040015185602001516040516118a3919061436e565b60006040518083038185875af1925050503d80600081146118e0576040519150601f19603f3d011682016040523d82523d6000602084013e6118e5565b606091505b508093508194505050611b44565b600184606001511480156119045750875b156119985760405a8161191a57611919614570565b5b049050836000015173ffffffffffffffffffffffffffffffffffffffff16846020015160405161194a919061436e565b600060405180830381855af49150503d8060008114611985576040519150601f19603f3d011682016040523d82523d6000602084013e61198a565b606091505b508093508194505050611b43565b600284606001511480156119b7575060148a14806119b6575060158a145b5b15611a6d57896000601f6101000a81548160ff021916908360ff16021790555060405a816119e8576119e7614570565b5b049050836000015173ffffffffffffffffffffffffffffffffffffffff1684604001518560200151604051611a1d919061436e565b60006040518083038185875af1925050503d8060008114611a5a576040519150601f19603f3d011682016040523d82523d6000602084013e611a5f565b606091505b508093508194505050611b42565b600284606001511115611ade57611a8385612381565b604051602001611a9391906143e7565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ad5919061381b565b60405180910390fd5b611ae785612381565b604051602001611af7919061447f565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b39919061381b565b60405180910390fd5b5b5b82611bf157805a1015611b83576040517f8707015b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b8c85612381565b611b958361244f565b604051602001611ba69291906144a5565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611be8919061381b565b60405180910390fd5b84600101945050505050611808565b50600082602001516affffffffffffffffffffff16118015611d2e575060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff16148015611ccd5750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16826040015173ffffffffffffffffffffffffffffffffffffffff16145b8015611d0f5750600060149054906101000a90046affffffffffffffffffffff166affffffffffffffffffffff1682602001516affffffffffffffffffffff16145b8015611d2c5750600080601f9054906101000a900460ff1660ff16145b155b15611d6e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d6590614515565b60405180910390fd5b50505050505050565b6000600160159054906101000a900460ff16159050808015611daa575060018060149054906101000a900460ff1660ff16105b80611dd85750611db930612013565b158015611dd7575060018060149054906101000a900460ff1660ff16145b5b611e17576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e0e90613afc565b60405180910390fd5b60018060146101000a81548160ff021916908360ff1602179055508015611e535760018060156101000a81548160ff0219169083151502179055505b611e728273ffffffffffffffffffffffffffffffffffffffff16612013565b80611ea95750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b15611ee0576040517fe6d1a59000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508015611f7b576000600160156101000a81548160ff0219169083151502179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024986001604051611f729190613b64565b60405180910390a15b5050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611fe4576040517f9871463100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b606061200b8383604051806060016040528060278152602001614d2e602791396125fc565b905092915050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b60008383905003612073576040517fe6d1a59000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008111801561208257504281105b156120b9576040517fcc1cf67c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b60006121d26120cb612289565b7f9aa78168ddcd68af5d2a4d0ac0cb4b54bf9d84d1ddff44be4030d7884c6da9f66120f68787612682565b7f5ce8b8715bfac5b3e19b27a537d68f1a49e2c3ccdc13dfb6858f28073b0d78de866000013587602001358860400160208101906121349190613566565b89606001358a8060800190612149919061403d565b6040516121579291906145c4565b6040518091039020604051602001612174969594939291906145dd565b60405160208183030381529060405280519060200120600060149054906101000a90046affffffffffffffffffffff166040516020016121b7949392919061463e565b6040516020818303038152906040528051906020012061285d565b90509392505050565b60008061222c8585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612890565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16149150509392505050565b60007fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac564726040518060400160405280600c81526020017f41766f6361646f2d536166650000000000000000000000000000000000000000815250805190602001206040518060400160405280600581526020017f322e302e300000000000000000000000000000000000000000000000000000008152508051906020012061027a304660405160200161233b91906146a4565b60405160208183030381529060405280519060200120604051602001612366969594939291906146bf565b60405160208183030381529060405280519060200120905090565b606060006001612390846128b7565b01905060008167ffffffffffffffff8111156123af576123ae6132a8565b5b6040519080825280601f01601f1916602001820160405280156123e15781602001600182028036833780820191505090505b509050600082602001820190505b600115612444578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a858161243857612437614570565b5b049450600085036123ef575b819350505050919050565b6060600482511015612498576040518060400160405280601381526020017f5f524541534f4e5f4e4f545f444546494e45440000000000000000000000000081525090506125f7565b600060208301519050634e487b7160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361257f576040518060400160405280601681526020017f5f5441524745545f50414e49434b45443a2030785f5f00000000000000000000815250915060006024840151905060208301516030600f831601603060f0841660041c0160081b8181177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00008416179250826020870152505050506125f5565b6044835111156125c957600483019250828060200190518101906125a39190613fe5565b6040516020016125b39190614746565b60405160208183030381529060405291506125f4565b6125d281612a0a565b6040516020016125e29190614792565b60405160208183030381529060405291505b5b505b919050565b60606000808573ffffffffffffffffffffffffffffffffffffffff1685604051612626919061436e565b600060405180830381855af49150503d8060008114612661576040519150601f19603f3d011682016040523d82523d6000602084013e612666565b606091505b509150915061267786838387612c5d565b925050509392505050565b60008083839050905060008167ffffffffffffffff8111156126a7576126a66132a8565b5b6040519080825280602002602001820160405280156126d55781602001602082028036833780820191505090505b50905060005b8281101561282b577f5c1c53221914feac61859607db2bf67fc5d2d108016fd0bab7ceb23e65e90f6586868381811061271757612716614303565b5b90506020028101906127299190614535565b600001602081019061273b9190613566565b87878481811061274e5761274d614303565b5b90506020028101906127609190614535565b806020019061276f919061403d565b60405161277d9291906145c4565b604051809103902088888581811061279857612797614303565b5b90506020028101906127aa9190614535565b604001358989868181106127c1576127c0614303565b5b90506020028101906127d39190614535565b606001356040516020016127eb9594939291906147b8565b6040516020818303038152906040528051906020012082828151811061281457612813614303565b5b6020026020010181815250508060010190506126db565b508060405160200161283d91906148c3565b604051602081830303815290604052805190602001209250505092915050565b60008282604051602001612872929190614947565b60405160208183030381529060405280519060200120905092915050565b600080600061289f8585612cd2565b915091506128ac81612d23565b819250505092915050565b600080600090507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612915577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000838161290b5761290a614570565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310612952576d04ee2d6d415b85acef8100000000838161294857612947614570565b5b0492506020810190505b662386f26fc10000831061298157662386f26fc10000838161297757612976614570565b5b0492506010810190505b6305f5e10083106129aa576305f5e10083816129a05761299f614570565b5b0492506008810190505b61271083106129cf5761271083816129c5576129c4614570565b5b0492506004810190505b606483106129f257606483816129e8576129e7614570565b5b0492506002810190505b600a8310612a01576001810190505b80915050919050565b60606000600a67ffffffffffffffff811115612a2957612a286132a8565b5b6040519080825280601f01601f191660200182016040528015612a5b5781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612a9357612a92614303565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612af757612af6614303565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060005b6004811015612c5357612b606010858360048110612b4a57612b49614303565b5b1a60f81b60f81c612b5b919061497e565b612e89565b826002836002612b7091906149af565b612b7a9190613bae565b81518110612b8b57612b8a614303565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350612be86010858360048110612bd257612bd1614303565b5b1a60f81b60f81c612be391906149f1565b612e89565b826003836002612bf891906149af565b612c029190613bae565b81518110612c1357612c12614303565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080612c4c90614a22565b9050612b29565b5080915050919050565b60608315612cbf576000835103612cb757612c7785612013565b612cb6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cad90614ab6565b60405180910390fd5b5b829050612cca565b612cc98383612f4d565b5b949350505050565b6000806041835103612d135760008060006020860151925060408601519150606086015160001a9050612d0787828585612f9d565b94509450505050612d1c565b60006002915091505b9250929050565b60006004811115612d3757612d36614ad6565b5b816004811115612d4a57612d49614ad6565b5b0315612e865760016004811115612d6457612d63614ad6565b5b816004811115612d7757612d76614ad6565b5b03612db7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612dae90614b51565b60405180910390fd5b60026004811115612dcb57612dca614ad6565b5b816004811115612dde57612ddd614ad6565b5b03612e1e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e1590614bbd565b60405180910390fd5b60036004811115612e3257612e31614ad6565b5b816004811115612e4557612e44614ad6565b5b03612e85576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e7c90614c4f565b60405180910390fd5b5b50565b60008160ff16600011158015612ea3575060098260ff1611155b15612ee157817f300000000000000000000000000000000000000000000000000000000000000060f81c612ed79190614c6f565b60f81b9050612f48565b8160ff16600a11158015612ef95750600f8260ff1611155b15612f4357600a827f610000000000000000000000000000000000000000000000000000000000000060f81c612f2f9190614c6f565b612f399190614ca4565b60f81b9050612f48565b600080fd5b919050565b600082511115612f605781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f94919061381b565b60405180910390fd5b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08360001c1115612fd8576000600391509150613076565b600060018787878760405160008152602001604052604051612ffd9493929190614ce8565b6020604051602081039080840390855afa15801561301f573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361306d57600060019250925050613076565b80600092509250505b94509492505050565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160006affffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613118826130ed565b9050919050565b6131288161310d565b811461313357600080fd5b50565b6000813590506131458161311f565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126131705761316f61314b565b5b8235905067ffffffffffffffff81111561318d5761318c613150565b5b6020830191508360018202830111156131a9576131a8613155565b5b9250929050565b60008115159050919050565b6131c5816131b0565b81146131d057600080fd5b50565b6000813590506131e2816131bc565b92915050565b60008060008060608587031215613202576132016130e3565b5b600061321087828801613136565b945050602085013567ffffffffffffffff811115613231576132306130e8565b5b61323d8782880161315a565b93509350506040613250878288016131d3565b91505092959194509250565b6000819050919050565b61326f8161325c565b811461327a57600080fd5b50565b60008135905061328c81613266565b92915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6132e082613297565b810181811067ffffffffffffffff821117156132ff576132fe6132a8565b5b80604052505050565b60006133126130d9565b905061331e82826132d7565b919050565b600067ffffffffffffffff82111561333e5761333d6132a8565b5b61334782613297565b9050602081019050919050565b82818337600083830152505050565b600061337661337184613323565b613308565b90508281526020810184848401111561339257613391613292565b5b61339d848285613354565b509392505050565b600082601f8301126133ba576133b961314b565b5b81356133ca848260208601613363565b91505092915050565b600080600080608085870312156133ed576133ec6130e3565b5b60006133fb87828801613136565b945050602061340c87828801613136565b935050604061341d8782880161327d565b925050606085013567ffffffffffffffff81111561343e5761343d6130e8565b5b61344a878288016133a5565b91505092959194509250565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61348b81613456565b82525050565b60006020820190506134a66000830184613482565b92915050565b600080604083850312156134c3576134c26130e3565b5b60006134d185828601613136565b92505060206134e285828601613136565b9150509250929050565b6000819050919050565b600061351161350c613507846130ed565b6134ec565b6130ed565b9050919050565b6000613523826134f6565b9050919050565b600061353582613518565b9050919050565b6135458161352a565b82525050565b6000602082019050613560600083018461353c565b92915050565b60006020828403121561357c5761357b6130e3565b5b600061358a84828501613136565b91505092915050565b61359c8161325c565b82525050565b60006020820190506135b76000830184613593565b92915050565b60008083601f8401126135d3576135d261314b565b5b8235905067ffffffffffffffff8111156135f0576135ef613150565b5b60208301915083602082028301111561360c5761360b613155565b5b9250929050565b600080fd5b600060a0828403121561362e5761362d613613565b5b81905092915050565b600080600080600060608688031215613653576136526130e3565b5b600086013567ffffffffffffffff811115613671576136706130e8565b5b61367d888289016135bd565b9550955050602086013567ffffffffffffffff8111156136a05761369f6130e8565b5b6136ac88828901613618565b935050604086013567ffffffffffffffff8111156136cd576136cc6130e8565b5b6136d98882890161315a565b92509250509295509295909350565b6136f1816131b0565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015613731578082015181840152602081019050613716565b60008484015250505050565b6000613748826136f7565b6137528185613702565b9350613762818560208601613713565b61376b81613297565b840191505092915050565b600060408201905061378b60008301856136e8565b818103602083015261379d818461373d565b90509392505050565b6000819050919050565b6137b9816137a6565b82525050565b60006020820190506137d460008301846137b0565b92915050565b60006affffffffffffffffffffff82169050919050565b6137fa816137da565b82525050565b600060208201905061381560008301846137f1565b92915050565b60006020820190508181036000830152613835818461373d565b905092915050565b6138468161310d565b82525050565b6000602082019050613861600083018461383d565b92915050565b60008083601f84011261387d5761387c61314b565b5b8235905067ffffffffffffffff81111561389a57613899613150565b5b6020830191508360208202830111156138b6576138b5613155565b5b9250929050565b60008083601f8401126138d3576138d261314b565b5b8235905067ffffffffffffffff8111156138f0576138ef613150565b5b60208301915083602082028301111561390c5761390b613155565b5b9250929050565b600080600080600080600080600060a08a8c031215613935576139346130e3565b5b60008a013567ffffffffffffffff811115613953576139526130e8565b5b61395f8c828d01613867565b995099505060208a013567ffffffffffffffff811115613982576139816130e8565b5b61398e8c828d016138bd565b975097505060408a013567ffffffffffffffff8111156139b1576139b06130e8565b5b6139bd8c828d016138bd565b955095505060606139d08c828d01613136565b93505060808a013567ffffffffffffffff8111156139f1576139f06130e8565b5b6139fd8c828d0161315a565b92509250509295985092959850929598565b6000602082019050613a2460008301846136e8565b92915050565b600080600060408486031215613a4357613a426130e3565b5b600084013567ffffffffffffffff811115613a6157613a606130e8565b5b613a6d868287016135bd565b93509350506020613a808682870161327d565b9150509250925092565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b6000613ae6602e83613702565b9150613af182613a8a565b604082019050919050565b60006020820190508181036000830152613b1581613ad9565b9050919050565b6000819050919050565b600060ff82169050919050565b6000613b4e613b49613b4484613b1c565b6134ec565b613b26565b9050919050565b613b5e81613b33565b82525050565b6000602082019050613b796000830184613b55565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000613bb98261325c565b9150613bc48361325c565b9250828201905080821115613bdc57613bdb613b7f565b5b92915050565b6000613bed826137da565b91506affffffffffffffffffffff8203613c0a57613c09613b7f565b5b600182019050919050565b600082825260208201905092915050565b6000819050919050565b6000613c3f6020840184613136565b905092915050565b613c508161310d565b82525050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112613c8257613c81613c60565b5b83810192508235915060208301925067ffffffffffffffff821115613caa57613ca9613c56565b5b600182023603831315613cc057613cbf613c5b565b5b509250929050565b600082825260208201905092915050565b6000613ce58385613cc8565b9350613cf2838584613354565b613cfb83613297565b840190509392505050565b6000613d15602084018461327d565b905092915050565b613d268161325c565b82525050565b600060808301613d3f6000840184613c30565b613d4c6000860182613c47565b50613d5a6020840184613c65565b8583036020870152613d6d838284613cd9565b92505050613d7e6040840184613d06565b613d8b6040860182613d1d565b50613d996060840184613d06565b613da66060860182613d1d565b508091505092915050565b6000613dbd8383613d2c565b905092915050565b600082356001608003833603038112613de157613de0613c60565b5b82810191505092915050565b6000602082019050919050565b6000613e068385613c15565b935083602084028501613e1884613c26565b8060005b87811015613e5c578484038952613e338284613dc5565b613e3d8582613db1565b9450613e4883613ded565b925060208a01995050600181019050613e1c565b50829750879450505050509392505050565b60006040820190508181036000830152613e89818587613dfa565b9050613e986020830184613593565b949350505050565b600081519050919050565b6000819050602082019050919050565b6000613ec78251613456565b80915050919050565b600082821b905092915050565b6000613ee882613ea0565b82613ef284613eab565b9050613efd81613ebb565b92506004821015613f3d57613f387fffffffff0000000000000000000000000000000000000000000000000000000083600403600802613ed0565b831692505b5050919050565b600067ffffffffffffffff821115613f5f57613f5e6132a8565b5b613f6882613297565b9050602081019050919050565b6000613f88613f8384613f44565b613308565b905082815260208101848484011115613fa457613fa3613292565b5b613faf848285613713565b509392505050565b600082601f830112613fcc57613fcb61314b565b5b8151613fdc848260208601613f75565b91505092915050565b600060208284031215613ffb57613ffa6130e3565b5b600082015167ffffffffffffffff811115614019576140186130e8565b5b61402584828501613fb7565b91505092915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261405a5761405961402e565b5b80840192508235915067ffffffffffffffff82111561407c5761407b614033565b5b60208301925060018202360383131561409857614097614038565b5b509250929050565b600082825260208201905092915050565b60006140bd83856140a0565b93506140ca838584613354565b6140d383613297565b840190509392505050565b600060408201905081810360008301526140f8818661373d565b9050818103602083015261410d8184866140b1565b9050949350505050565b600060208201905081810360008301526141328184866140b1565b90509392505050565b600067ffffffffffffffff821115614156576141556132a8565b5b602082029050602081019050919050565b600080fd5b600080fd5b60006080828403121561418757614186614167565b5b6141916080613308565b905060006141a184828501613136565b600083015250602082013567ffffffffffffffff8111156141c5576141c461416c565b5b6141d1848285016133a5565b60208301525060406141e58482850161327d565b60408301525060606141f98482850161327d565b60608301525092915050565b60006142186142138461413b565b613308565b9050808382526020820190506020840283018581111561423b5761423a613155565b5b835b8181101561428257803567ffffffffffffffff8111156142605761425f61314b565b5b80860161426d8982614171565b8552602085019450505060208101905061423d565b5050509392505050565b600082601f8301126142a1576142a061314b565b5b81356142b1848260208601614205565b91505092915050565b6000602082840312156142d0576142cf6130e3565b5b600082013567ffffffffffffffff8111156142ee576142ed6130e8565b5b6142fa8482850161428c565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081905092915050565b600061434882613ea0565b6143528185614332565b9350614362818560208601613713565b80840191505092915050565b600061437a828461433d565b915081905092915050565b600081905092915050565b600061439b826136f7565b6143a58185614385565b93506143b5818560208601613713565b80840191505092915050565b7f5f41564f5f5f4f5045524154494f4e5f4e4f545f455849535400000000000000815250565b60006143f38284614390565b91506143fe826143c1565b60198201915081905092915050565b7f5f41564f5f5f4e4f5f464c4153484c4f414e5f494e5f464c4153484c4f414e00815250565b600061443f8284614390565b915061444a8261440d565b601f8201915081905092915050565b7f5f41564f5f5f49445f414354494f4e5f4d49534d415443480000000000000000815250565b600061448b8284614390565b915061449682614459565b60188201915081905092915050565b60006144b18285614390565b91506144bd8284614390565b91508190509392505050565b7f41564f5f5f4d4f4449464945445f53544f524147450000000000000000000000600082015250565b60006144ff601583613702565b915061450a826144c9565b602082019050919050565b6000602082019050818103600083015261452e816144f2565b9050919050565b6000823560016080038336030381126145515761455061402e565b5b80830191505092915050565b60006145693683614171565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006145ab8385614332565b93506145b8838584613354565b82840190509392505050565b60006145d182848661459f565b91508190509392505050565b600060c0820190506145f260008301896137b0565b6145ff6020830188613593565b61460c6040830187613593565b614619606083018661383d565b6146266080830185613593565b61463360a08301846137b0565b979650505050505050565b600060808201905061465360008301876137b0565b61466060208301866137b0565b61466d60408301856137b0565b61467a60608301846137f1565b95945050505050565b6000819050919050565b61469e6146998261325c565b614683565b82525050565b60006146b0828461468d565b60208201915081905092915050565b600060c0820190506146d460008301896137b0565b6146e160208301886137b0565b6146ee60408301876137b0565b6146fb6060830186613593565b614708608083018561383d565b61471560a08301846137b0565b979650505050505050565b7f5f00000000000000000000000000000000000000000000000000000000000000815250565b600061475182614720565b6001820191506147618284614390565b915081905092915050565b7f5f435553544f4d5f4552524f523a000000000000000000000000000000000000815250565b600061479d8261476c565b600e820191506147ad8284614390565b915081905092915050565b600060a0820190506147cd60008301886137b0565b6147da602083018761383d565b6147e760408301866137b0565b6147f46060830185613593565b6148016080830184613593565b9695505050505050565b600081519050919050565b600081905092915050565b6000819050602082019050919050565b61483a816137a6565b82525050565b600061484c8383614831565b60208301905092915050565b6000602082019050919050565b60006148708261480b565b61487a8185614816565b935061488583614821565b8060005b838110156148b657815161489d8882614840565b97506148a883614858565b925050600181019050614889565b5085935050505092915050565b60006148cf8284614865565b915081905092915050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b6000614910600283614385565b915061491b826148da565b600282019050919050565b6000819050919050565b61494161493c826137a6565b614926565b82525050565b600061495282614903565b915061495e8285614930565b60208201915061496e8284614930565b6020820191508190509392505050565b600061498982613b26565b915061499483613b26565b9250826149a4576149a3614570565b5b828204905092915050565b60006149ba8261325c565b91506149c58361325c565b92508282026149d38161325c565b915082820484148315176149ea576149e9613b7f565b5b5092915050565b60006149fc82613b26565b9150614a0783613b26565b925082614a1757614a16614570565b5b828206905092915050565b6000614a2d8261325c565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614a5f57614a5e613b7f565b5b600182019050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000614aa0601d83613702565b9150614aab82614a6a565b602082019050919050565b60006020820190508181036000830152614acf81614a93565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f45434453413a20696e76616c6964207369676e61747572650000000000000000600082015250565b6000614b3b601883613702565b9150614b4682614b05565b602082019050919050565b60006020820190508181036000830152614b6a81614b2e565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265206c656e67746800600082015250565b6000614ba7601f83613702565b9150614bb282614b71565b602082019050919050565b60006020820190508181036000830152614bd681614b9a565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265202773272076616c60008201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b6000614c39602283613702565b9150614c4482614bdd565b604082019050919050565b60006020820190508181036000830152614c6881614c2c565b9050919050565b6000614c7a82613b26565b9150614c8583613b26565b9250828201905060ff811115614c9e57614c9d613b7f565b5b92915050565b6000614caf82613b26565b9150614cba83613b26565b9250828203905060ff811115614cd357614cd2613b7f565b5b92915050565b614ce281613b26565b82525050565b6000608082019050614cfd60008301876137b0565b614d0a6020830186614cd9565b614d1760408301856137b0565b614d2460608301846137b0565b9594505050505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122058d41a9b3c50a79c18d113f7e175240d580fec99849d2d4cf9a32a5d157c631064736f6c63430008110033

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

000000000000000000000000fbf28161ae33f492250aa12117e7a3f4593b7aa1000000000000000000000000375f6b0cd12b34dc28e34c26853a37012c24dde5

-----Decoded View---------------
Arg [0] : avoVersionsRegistry_ (address): 0xfbF28161ae33f492250aA12117E7a3F4593B7Aa1
Arg [1] : avoForwarder_ (address): 0x375F6B0CD12b34Dc28e34C26853a37012C24dDE5

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000fbf28161ae33f492250aa12117e7a3f4593b7aa1
Arg [1] : 000000000000000000000000375f6b0cd12b34dc28e34c26853a37012c24dde5


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

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