Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
16685283 | 584 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
AvoWallet
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// 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(); } }
// 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; } }
// 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); }
// 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; } }
// 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); } } }
// 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)); } }
// 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); } } }
// 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); } }
// 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(); } } }
// 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_; } }
// 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); }
// 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; }
// 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); }
{ "optimizer": { "enabled": false, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"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"}]
Contract Creation Code
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
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 27 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.