Contract of Argent's Argent Module. Submitted by Kleros Curate.
Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 243,559 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Execute | 21248201 | 9 mins ago | IN | 0 ETH | 0.00243491 | ||||
Execute | 21248173 | 14 mins ago | IN | 0 ETH | 0.00127154 | ||||
Execute | 21247438 | 2 hrs ago | IN | 0 ETH | 0.00154801 | ||||
Execute | 21247388 | 2 hrs ago | IN | 0 ETH | 0.00129845 | ||||
Execute | 21247269 | 3 hrs ago | IN | 0 ETH | 0.00106702 | ||||
Finalize Recover... | 21247263 | 3 hrs ago | IN | 0 ETH | 0.00051036 | ||||
Execute | 21247044 | 4 hrs ago | IN | 0 ETH | 0.00161311 | ||||
Execute | 21246989 | 4 hrs ago | IN | 0 ETH | 0.00118007 | ||||
Finalize Recover... | 21246983 | 4 hrs ago | IN | 0 ETH | 0.00053453 | ||||
Execute | 21246881 | 4 hrs ago | IN | 0 ETH | 0.00170302 | ||||
Execute | 21246835 | 4 hrs ago | IN | 0 ETH | 0.00147423 | ||||
Execute | 21246297 | 6 hrs ago | IN | 0 ETH | 0.00199443 | ||||
Execute | 21246294 | 6 hrs ago | IN | 0 ETH | 0.00226184 | ||||
Execute | 21246183 | 6 hrs ago | IN | 0 ETH | 0.00251437 | ||||
Execute | 21245784 | 8 hrs ago | IN | 0 ETH | 0.00249577 | ||||
Execute | 21245657 | 8 hrs ago | IN | 0 ETH | 0.00174364 | ||||
Execute | 21245636 | 8 hrs ago | IN | 0 ETH | 0.00317971 | ||||
Execute | 21245627 | 8 hrs ago | IN | 0 ETH | 0.0016322 | ||||
Execute | 21245616 | 8 hrs ago | IN | 0 ETH | 0.00161912 | ||||
Execute | 21245550 | 9 hrs ago | IN | 0 ETH | 0.0027083 | ||||
Execute | 21245292 | 9 hrs ago | IN | 0 ETH | 0.00274578 | ||||
Execute | 21245170 | 10 hrs ago | IN | 0 ETH | 0.00185931 | ||||
Execute | 21245128 | 10 hrs ago | IN | 0 ETH | 0.00189837 | ||||
Execute | 21245122 | 10 hrs ago | IN | 0 ETH | 0.00230713 | ||||
Execute | 21245118 | 10 hrs ago | IN | 0 ETH | 0.00406248 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
ArgentModule
Compiler Version
v0.8.3+commit.8d00100c
Optimization Enabled:
Yes with 300 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// Copyright (C) 2021 Argent Labs Ltd. <https://argent.xyz> // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.3; import "./common/Utils.sol"; import "./common/BaseModule.sol"; import "./RelayerManager.sol"; import "./SecurityManager.sol"; import "./TransactionManager.sol"; /** * @title ArgentModule * @notice Single module for the Argent wallet. * @author Julien Niset - <[email protected]> */ contract ArgentModule is BaseModule, RelayerManager, SecurityManager, TransactionManager { bytes32 constant public NAME = "ArgentModule"; constructor ( IModuleRegistry _registry, IGuardianStorage _guardianStorage, ITransferStorage _userWhitelist, IAuthoriser _authoriser, address _uniswapRouter, uint256 _securityPeriod, uint256 _securityWindow, uint256 _recoveryPeriod, uint256 _lockPeriod ) BaseModule(_registry, _guardianStorage, _userWhitelist, _authoriser, NAME) SecurityManager(_recoveryPeriod, _securityPeriod, _securityWindow, _lockPeriod) TransactionManager(_securityPeriod) RelayerManager(_uniswapRouter) { } /** * @inheritdoc IModule */ function init(address _wallet) external override onlyWallet(_wallet) { enableDefaultStaticCalls(_wallet); } /** * @inheritdoc IModule */ function addModule(address _wallet, address _module) external override onlyWalletOwnerOrSelf(_wallet) onlyWhenUnlocked(_wallet) { require(registry.isRegisteredModule(_module), "AM: module is not registered"); IWallet(_wallet).authoriseModule(_module, true); } /** * @inheritdoc RelayerManager */ function getRequiredSignatures(address _wallet, bytes calldata _data) public view override returns (uint256, OwnerSignature) { bytes4 methodId = Utils.functionPrefix(_data); if (methodId == TransactionManager.multiCall.selector || methodId == TransactionManager.addToWhitelist.selector || methodId == TransactionManager.removeFromWhitelist.selector || methodId == TransactionManager.enableERC1155TokenReceiver.selector || methodId == TransactionManager.clearSession.selector || methodId == ArgentModule.addModule.selector || methodId == SecurityManager.addGuardian.selector || methodId == SecurityManager.revokeGuardian.selector || methodId == SecurityManager.cancelGuardianAddition.selector || methodId == SecurityManager.cancelGuardianRevokation.selector) { // owner return (1, OwnerSignature.Required); } if (methodId == TransactionManager.multiCallWithSession.selector) { return (1, OwnerSignature.Session); } if (methodId == SecurityManager.executeRecovery.selector) { // majority of guardians uint numberOfSignaturesRequired = _majorityOfGuardians(_wallet); require(numberOfSignaturesRequired > 0, "AM: no guardians set on wallet"); return (numberOfSignaturesRequired, OwnerSignature.Disallowed); } if (methodId == SecurityManager.cancelRecovery.selector) { // majority of (owner + guardians) uint numberOfSignaturesRequired = Utils.ceil(recoveryConfigs[_wallet].guardianCount + 1, 2); return (numberOfSignaturesRequired, OwnerSignature.Optional); } if (methodId == TransactionManager.multiCallWithGuardians.selector || methodId == TransactionManager.multiCallWithGuardiansAndStartSession.selector || methodId == SecurityManager.transferOwnership.selector) { // owner + majority of guardians uint majorityGuardians = _majorityOfGuardians(_wallet); uint numberOfSignaturesRequired = majorityGuardians + 1; return (numberOfSignaturesRequired, OwnerSignature.Required); } if (methodId == SecurityManager.finalizeRecovery.selector || methodId == SecurityManager.confirmGuardianAddition.selector || methodId == SecurityManager.confirmGuardianRevokation.selector) { // anyone return (0, OwnerSignature.Anyone); } if (methodId == SecurityManager.lock.selector || methodId == SecurityManager.unlock.selector) { // any guardian return (1, OwnerSignature.Disallowed); } revert("SM: unknown method"); } function _majorityOfGuardians(address _wallet) internal view returns (uint) { return Utils.ceil(guardianStorage.guardianCount(_wallet), 2); } }
// Copyright (C) 2021 Argent Labs Ltd. <https://argent.xyz> // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.3; interface IAuthoriser { function isAuthorised(address _sender, address _spender, address _to, bytes calldata _data) external view returns (bool); function areAuthorised( address _spender, address[] calldata _spenders, address[] calldata _to, bytes[] calldata _data ) external view returns (bool); }
// Copyright (C) 2020 Argent Labs Ltd. <https://argent.xyz> // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.5.4 <0.9.0; /** * @title IModuleRegistry * @notice Interface for the registry of authorised modules. */ interface IModuleRegistry { function registerModule(address _module, bytes32 _name) external; function deregisterModule(address _module) external; function registerUpgrader(address _upgrader, bytes32 _name) external; function deregisterUpgrader(address _upgrader) external; function recoverToken(address _token) external; function moduleInfo(address _module) external view returns (bytes32); function upgraderInfo(address _upgrader) external view returns (bytes32); function isRegisteredModule(address _module) external view returns (bool); function isRegisteredModule(address[] calldata _modules) external view returns (bool); function isRegisteredUpgrader(address _upgrader) external view returns (bool); }
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz> // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.5.4 <0.9.0; interface IGuardianStorage { /** * @notice Lets an authorised module add a guardian to a wallet. * @param _wallet The target wallet. * @param _guardian The guardian to add. */ function addGuardian(address _wallet, address _guardian) external; /** * @notice Lets an authorised module revoke a guardian from a wallet. * @param _wallet The target wallet. * @param _guardian The guardian to revoke. */ function revokeGuardian(address _wallet, address _guardian) external; /** * @notice Checks if an account is a guardian for a wallet. * @param _wallet The target wallet. * @param _guardian The account. * @return true if the account is a guardian for a wallet. */ function isGuardian(address _wallet, address _guardian) external view returns (bool); function isLocked(address _wallet) external view returns (bool); function getLock(address _wallet) external view returns (uint256); function getLocker(address _wallet) external view returns (address); function setLock(address _wallet, uint256 _releaseAfter) external; function getGuardians(address _wallet) external view returns (address[] memory); function guardianCount(address _wallet) external view returns (uint256); }
// Copyright (C) 2020 Argent Labs Ltd. <https://argent.xyz> // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.5.4 <0.9.0; /** * @title ITransferStorage * @notice TransferStorage interface */ interface ITransferStorage { function setWhitelist(address _wallet, address _target, uint256 _value) external; function getWhitelist(address _wallet, address _target) external view returns (uint256); }
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz> // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.3; import "@openzeppelin/contracts/utils/math/Math.sol"; import "./common/Utils.sol"; import "./common/BaseModule.sol"; import "./common/SimpleOracle.sol"; import "../infrastructure/storage/IGuardianStorage.sol"; /** * @title RelayerManager * @notice Abstract Module to execute transactions signed by ETH-less accounts and sent by a relayer. * @author Julien Niset <[email protected]>, Olivier VDB <[email protected]> */ abstract contract RelayerManager is BaseModule, SimpleOracle { uint256 constant internal BLOCKBOUND = 10000; mapping (address => RelayerConfig) internal relayer; struct RelayerConfig { uint256 nonce; mapping (bytes32 => bool) executedTx; } // Used to avoid stack too deep error struct StackExtension { uint256 requiredSignatures; OwnerSignature ownerSignatureRequirement; bytes32 signHash; bool success; bytes returnData; } event TransactionExecuted(address indexed wallet, bool indexed success, bytes returnData, bytes32 signedHash); event Refund(address indexed wallet, address indexed refundAddress, address refundToken, uint256 refundAmount); // *************** Constructor ************************ // constructor(address _uniswapRouter) SimpleOracle(_uniswapRouter) { } /* ***************** External methods ************************* */ /** * @notice Gets the number of valid signatures that must be provided to execute a * specific relayed transaction. * @param _wallet The target wallet. * @param _data The data of the relayed transaction. * @return The number of required signatures and the wallet owner signature requirement. */ function getRequiredSignatures(address _wallet, bytes calldata _data) public view virtual returns (uint256, OwnerSignature); /** * @notice Executes a relayed transaction. * @param _wallet The target wallet. * @param _data The data for the relayed transaction * @param _nonce The nonce used to prevent replay attacks. * @param _signatures The signatures as a concatenated byte array. * @param _gasPrice The max gas price (in token) to use for the gas refund. * @param _gasLimit The max gas limit to use for the gas refund. * @param _refundToken The token to use for the gas refund. * @param _refundAddress The address refunded to prevent front-running. */ function execute( address _wallet, bytes calldata _data, uint256 _nonce, bytes calldata _signatures, uint256 _gasPrice, uint256 _gasLimit, address _refundToken, address _refundAddress ) external returns (bool) { // initial gas = 21k + non_zero_bytes * 16 + zero_bytes * 4 // ~= 21k + calldata.length * [1/3 * 16 + 2/3 * 4] uint256 startGas = gasleft() + 21000 + msg.data.length * 8; require(startGas >= _gasLimit, "RM: not enough gas provided"); require(verifyData(_wallet, _data), "RM: Target of _data != _wallet"); require(!_isLocked(_wallet) || _gasPrice == 0, "RM: Locked wallet refund"); StackExtension memory stack; (stack.requiredSignatures, stack.ownerSignatureRequirement) = getRequiredSignatures(_wallet, _data); require(stack.requiredSignatures > 0 || stack.ownerSignatureRequirement == OwnerSignature.Anyone, "RM: Wrong signature requirement"); require(stack.requiredSignatures * 65 == _signatures.length, "RM: Wrong number of signatures"); stack.signHash = getSignHash( address(this), 0, _data, _nonce, _gasPrice, _gasLimit, _refundToken, _refundAddress); require(checkAndUpdateUniqueness( _wallet, _nonce, stack.signHash, stack.requiredSignatures, stack.ownerSignatureRequirement), "RM: Duplicate request"); if (stack.ownerSignatureRequirement == OwnerSignature.Session) { require(validateSession(_wallet, stack.signHash, _signatures), "RM: Invalid session"); } else { require(validateSignatures(_wallet, stack.signHash, _signatures, stack.ownerSignatureRequirement), "RM: Invalid signatures"); } (stack.success, stack.returnData) = address(this).call(_data); refund( _wallet, startGas, _gasPrice, _gasLimit, _refundToken, _refundAddress, stack.requiredSignatures, stack.ownerSignatureRequirement); emit TransactionExecuted(_wallet, stack.success, stack.returnData, stack.signHash); return stack.success; } /** * @notice Gets the current nonce for a wallet. * @param _wallet The target wallet. */ function getNonce(address _wallet) external view returns (uint256 nonce) { return relayer[_wallet].nonce; } /** * @notice Checks if a transaction identified by its sign hash has already been executed. * @param _wallet The target wallet. * @param _signHash The sign hash of the transaction. */ function isExecutedTx(address _wallet, bytes32 _signHash) external view returns (bool executed) { return relayer[_wallet].executedTx[_signHash]; } /** * @notice Gets the last stored session for a wallet. * @param _wallet The target wallet. */ function getSession(address _wallet) external view returns (address key, uint64 expires) { return (sessions[_wallet].key, sessions[_wallet].expires); } /* ***************** Internal & Private methods ************************* */ /** * @notice Generates the signed hash of a relayed transaction according to ERC 1077. * @param _from The starting address for the relayed transaction (should be the relayer module) * @param _value The value for the relayed transaction. * @param _data The data for the relayed transaction which includes the wallet address. * @param _nonce The nonce used to prevent replay attacks. * @param _gasPrice The max gas price (in token) to use for the gas refund. * @param _gasLimit The max gas limit to use for the gas refund. * @param _refundToken The token to use for the gas refund. * @param _refundAddress The address refunded to prevent front-running. */ function getSignHash( address _from, uint256 _value, bytes memory _data, uint256 _nonce, uint256 _gasPrice, uint256 _gasLimit, address _refundToken, address _refundAddress ) internal view returns (bytes32) { return keccak256( abi.encodePacked( "\x19Ethereum Signed Message:\n32", keccak256(abi.encodePacked( bytes1(0x19), bytes1(0), _from, _value, _data, block.chainid, _nonce, _gasPrice, _gasLimit, _refundToken, _refundAddress)) )); } /** * @notice Checks if the relayed transaction is unique. If yes the state is updated. * For actions requiring 1 signature by the owner or a session key we use the incremental nonce. * For all other actions we check/store the signHash in a mapping. * @param _wallet The target wallet. * @param _nonce The nonce. * @param _signHash The signed hash of the transaction. * @param requiredSignatures The number of signatures required. * @param ownerSignatureRequirement The wallet owner signature requirement. * @return true if the transaction is unique. */ function checkAndUpdateUniqueness( address _wallet, uint256 _nonce, bytes32 _signHash, uint256 requiredSignatures, OwnerSignature ownerSignatureRequirement ) internal returns (bool) { if (requiredSignatures == 1 && (ownerSignatureRequirement == OwnerSignature.Required || ownerSignatureRequirement == OwnerSignature.Session)) { // use the incremental nonce if (_nonce <= relayer[_wallet].nonce) { return false; } uint256 nonceBlock = (_nonce & 0xffffffffffffffffffffffffffffffff00000000000000000000000000000000) >> 128; if (nonceBlock > block.number + BLOCKBOUND) { return false; } relayer[_wallet].nonce = _nonce; return true; } else { // use the txHash map if (relayer[_wallet].executedTx[_signHash] == true) { return false; } relayer[_wallet].executedTx[_signHash] = true; return true; } } /** * @notice Validates the signatures provided with a relayed transaction. * @param _wallet The target wallet. * @param _signHash The signed hash representing the relayed transaction. * @param _signatures The signatures as a concatenated bytes array. * @param _option An OwnerSignature enum indicating whether the owner is required, optional or disallowed. * @return A boolean indicating whether the signatures are valid. */ function validateSignatures(address _wallet, bytes32 _signHash, bytes memory _signatures, OwnerSignature _option) internal view returns (bool) { if (_signatures.length == 0) { return true; } address lastSigner = address(0); address[] memory guardians; if (_option != OwnerSignature.Required || _signatures.length > 65) { guardians = guardianStorage.getGuardians(_wallet); // guardians are only read if they may be needed } bool isGuardian; for (uint256 i = 0; i < _signatures.length / 65; i++) { address signer = Utils.recoverSigner(_signHash, _signatures, i); if (i == 0) { if (_option == OwnerSignature.Required) { // First signer must be owner if (_isOwner(_wallet, signer)) { continue; } return false; } else if (_option == OwnerSignature.Optional) { // First signer can be owner if (_isOwner(_wallet, signer)) { continue; } } } if (signer <= lastSigner) { return false; // Signers must be different } lastSigner = signer; (isGuardian, guardians) = Utils.isGuardianOrGuardianSigner(guardians, signer); if (!isGuardian) { return false; } } return true; } /** * @notice Validates the signature provided when a session key was used. * @param _wallet The target wallet. * @param _signHash The signed hash representing the relayed transaction. * @param _signatures The signatures as a concatenated bytes array. * @return A boolean indicating whether the signature is valid. */ function validateSession(address _wallet, bytes32 _signHash, bytes calldata _signatures) internal view returns (bool) { Session memory session = sessions[_wallet]; address signer = Utils.recoverSigner(_signHash, _signatures, 0); return (signer == session.key && session.expires >= block.timestamp); } /** * @notice Refunds the gas used to the Relayer. * @param _wallet The target wallet. * @param _startGas The gas provided at the start of the execution. * @param _gasPrice The max gas price (in token) for the refund. * @param _gasLimit The max gas limit for the refund. * @param _refundToken The token to use for the gas refund. * @param _refundAddress The address refunded to prevent front-running. * @param _requiredSignatures The number of signatures required. * @param _option An OwnerSignature enum indicating the signature requirement. */ function refund( address _wallet, uint _startGas, uint _gasPrice, uint _gasLimit, address _refundToken, address _refundAddress, uint256 _requiredSignatures, OwnerSignature _option ) internal { // Only refund when the owner is one of the signers or a session key was used if (_gasPrice > 0 && (_option == OwnerSignature.Required || _option == OwnerSignature.Session)) { address refundAddress = _refundAddress == address(0) ? msg.sender : _refundAddress; if (_requiredSignatures == 1 && _option == OwnerSignature.Required) { // refundAddress must be whitelisted/authorised if (!authoriser.isAuthorised(_wallet, refundAddress, address(0), EMPTY_BYTES)) { uint whitelistAfter = userWhitelist.getWhitelist(_wallet, refundAddress); require(whitelistAfter > 0 && whitelistAfter < block.timestamp, "RM: refund not authorised"); } } uint256 refundAmount; if (_refundToken == ETH_TOKEN) { // 23k as an upper bound to cover the rest of refund logic uint256 gasConsumed = _startGas - gasleft() + 23000; refundAmount = Math.min(gasConsumed, _gasLimit) * (Math.min(_gasPrice, tx.gasprice)); invokeWallet(_wallet, refundAddress, refundAmount, EMPTY_BYTES); } else { // 37.5k as an upper bound to cover the rest of refund logic uint256 gasConsumed = _startGas - gasleft() + 37500; uint256 tokenGasPrice = inToken(_refundToken, tx.gasprice); refundAmount = Math.min(gasConsumed, _gasLimit) * (Math.min(_gasPrice, tokenGasPrice)); bytes memory methodData = abi.encodeWithSelector(ERC20.transfer.selector, refundAddress, refundAmount); bytes memory transferSuccessBytes = invokeWallet(_wallet, _refundToken, 0, methodData); // Check token refund is successful, when `transfer` returns a success bool result if (transferSuccessBytes.length > 0) { require(abi.decode(transferSuccessBytes, (bool)), "RM: Refund transfer failed"); } } emit Refund(_wallet, refundAddress, _refundToken, refundAmount); } } /** * @notice Checks that the wallet address provided as the first parameter of _data matches _wallet * @return false if the addresses are different. */ function verifyData(address _wallet, bytes calldata _data) internal pure returns (bool) { require(_data.length >= 36, "RM: Invalid dataWallet"); address dataWallet = abi.decode(_data[4:], (address)); return dataWallet == _wallet; } }
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz> // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.3; import "@openzeppelin/contracts/utils/math/SafeCast.sol"; import "./common/Utils.sol"; import "./common/BaseModule.sol"; import "../wallet/IWallet.sol"; /** * @title SecurityManager * @notice Abstract module implementing the key security features of the wallet: guardians, lock and recovery. * @author Julien Niset - <[email protected]> * @author Olivier Van Den Biggelaar - <[email protected]> */ abstract contract SecurityManager is BaseModule { struct RecoveryConfig { address recovery; uint64 executeAfter; uint32 guardianCount; } struct GuardianManagerConfig { // The time at which a guardian addition or revokation will be confirmable by the owner mapping (bytes32 => uint256) pending; } // Wallet specific storage for recovery mapping (address => RecoveryConfig) internal recoveryConfigs; // Wallet specific storage for pending guardian addition/revokation mapping (address => GuardianManagerConfig) internal guardianConfigs; // Recovery period uint256 internal immutable recoveryPeriod; // Lock period uint256 internal immutable lockPeriod; // The security period to add/remove guardians uint256 internal immutable securityPeriod; // The security window uint256 internal immutable securityWindow; // *************** Events *************************** // event RecoveryExecuted(address indexed wallet, address indexed _recovery, uint64 executeAfter); event RecoveryFinalized(address indexed wallet, address indexed _recovery); event RecoveryCanceled(address indexed wallet, address indexed _recovery); event OwnershipTransfered(address indexed wallet, address indexed _newOwner); event Locked(address indexed wallet, uint64 releaseAfter); event Unlocked(address indexed wallet); event GuardianAdditionRequested(address indexed wallet, address indexed guardian, uint256 executeAfter); event GuardianRevokationRequested(address indexed wallet, address indexed guardian, uint256 executeAfter); event GuardianAdditionCancelled(address indexed wallet, address indexed guardian); event GuardianRevokationCancelled(address indexed wallet, address indexed guardian); event GuardianAdded(address indexed wallet, address indexed guardian); event GuardianRevoked(address indexed wallet, address indexed guardian); // *************** Modifiers ************************ // /** * @notice Throws if there is no ongoing recovery procedure. */ modifier onlyWhenRecovery(address _wallet) { require(recoveryConfigs[_wallet].executeAfter > 0, "SM: no ongoing recovery"); _; } /** * @notice Throws if there is an ongoing recovery procedure. */ modifier notWhenRecovery(address _wallet) { require(recoveryConfigs[_wallet].executeAfter == 0, "SM: ongoing recovery"); _; } /** * @notice Throws if the caller is not a guardian for the wallet or the module itself. */ modifier onlyGuardianOrSelf(address _wallet) { require(_isSelf(msg.sender) || isGuardian(_wallet, msg.sender), "SM: must be guardian/self"); _; } // *************** Constructor ************************ // constructor( uint256 _recoveryPeriod, uint256 _securityPeriod, uint256 _securityWindow, uint256 _lockPeriod ) { // For the wallet to be secure we must have recoveryPeriod >= securityPeriod + securityWindow // where securityPeriod and securityWindow are the security parameters of adding/removing guardians. require(_lockPeriod >= _recoveryPeriod, "SM: insecure lock period"); require(_recoveryPeriod >= _securityPeriod + _securityWindow, "SM: insecure security periods"); recoveryPeriod = _recoveryPeriod; lockPeriod = _lockPeriod; securityWindow = _securityWindow; securityPeriod = _securityPeriod; } // *************** External functions ************************ // // *************** Recovery functions ************************ // /** * @notice Lets the guardians start the execution of the recovery procedure. * Once triggered the recovery is pending for the security period before it can be finalised. * Must be confirmed by N guardians, where N = ceil(Nb Guardians / 2). * @param _wallet The target wallet. * @param _recovery The address to which ownership should be transferred. */ function executeRecovery(address _wallet, address _recovery) external onlySelf() notWhenRecovery(_wallet) { validateNewOwner(_wallet, _recovery); uint64 executeAfter = uint64(block.timestamp + recoveryPeriod); recoveryConfigs[_wallet] = RecoveryConfig(_recovery, executeAfter, uint32(guardianStorage.guardianCount(_wallet))); _setLock(_wallet, block.timestamp + lockPeriod, SecurityManager.executeRecovery.selector); emit RecoveryExecuted(_wallet, _recovery, executeAfter); } /** * @notice Finalizes an ongoing recovery procedure if the security period is over. * The method is public and callable by anyone to enable orchestration. * @param _wallet The target wallet. */ function finalizeRecovery(address _wallet) external onlyWhenRecovery(_wallet) { RecoveryConfig storage config = recoveryConfigs[_wallet]; require(uint64(block.timestamp) > config.executeAfter, "SM: ongoing recovery period"); address recoveryOwner = config.recovery; delete recoveryConfigs[_wallet]; _clearSession(_wallet); IWallet(_wallet).setOwner(recoveryOwner); _setLock(_wallet, 0, bytes4(0)); emit RecoveryFinalized(_wallet, recoveryOwner); } /** * @notice Lets the owner cancel an ongoing recovery procedure. * Must be confirmed by N guardians, where N = ceil(Nb Guardian at executeRecovery + 1) / 2) - 1. * @param _wallet The target wallet. */ function cancelRecovery(address _wallet) external onlySelf() onlyWhenRecovery(_wallet) { address recoveryOwner = recoveryConfigs[_wallet].recovery; delete recoveryConfigs[_wallet]; _setLock(_wallet, 0, bytes4(0)); emit RecoveryCanceled(_wallet, recoveryOwner); } /** * @notice Lets the owner transfer the wallet ownership. This is executed immediately. * @param _wallet The target wallet. * @param _newOwner The address to which ownership should be transferred. */ function transferOwnership(address _wallet, address _newOwner) external onlySelf() onlyWhenUnlocked(_wallet) { validateNewOwner(_wallet, _newOwner); IWallet(_wallet).setOwner(_newOwner); emit OwnershipTransfered(_wallet, _newOwner); } /** * @notice Gets the details of the ongoing recovery procedure if any. * @param _wallet The target wallet. */ function getRecovery(address _wallet) external view returns(address _address, uint64 _executeAfter, uint32 _guardianCount) { RecoveryConfig storage config = recoveryConfigs[_wallet]; return (config.recovery, config.executeAfter, config.guardianCount); } // *************** Lock functions ************************ // /** * @notice Lets a guardian lock a wallet. * @param _wallet The target wallet. */ function lock(address _wallet) external onlyGuardianOrSelf(_wallet) onlyWhenUnlocked(_wallet) { _setLock(_wallet, block.timestamp + lockPeriod, SecurityManager.lock.selector); emit Locked(_wallet, uint64(block.timestamp + lockPeriod)); } /** * @notice Lets a guardian unlock a locked wallet. * @param _wallet The target wallet. */ function unlock(address _wallet) external onlyGuardianOrSelf(_wallet) onlyWhenLocked(_wallet) { require(locks[_wallet].locker == SecurityManager.lock.selector, "SM: cannot unlock"); _setLock(_wallet, 0, bytes4(0)); emit Unlocked(_wallet); } /** * @notice Returns the release time of a wallet lock or 0 if the wallet is unlocked. * @param _wallet The target wallet. * @return _releaseAfter The epoch time at which the lock will release (in seconds). */ function getLock(address _wallet) external view returns(uint64 _releaseAfter) { return _isLocked(_wallet) ? locks[_wallet].release : 0; } /** * @notice Checks if a wallet is locked. * @param _wallet The target wallet. * @return _isLocked `true` if the wallet is locked otherwise `false`. */ function isLocked(address _wallet) external view returns (bool) { return _isLocked(_wallet); } // *************** Guardian functions ************************ // /** * @notice Lets the owner add a guardian to its wallet. * The first guardian is added immediately. All following additions must be confirmed * by calling the confirmGuardianAddition() method. * @param _wallet The target wallet. * @param _guardian The guardian to add. */ function addGuardian(address _wallet, address _guardian) external onlyWalletOwnerOrSelf(_wallet) onlyWhenUnlocked(_wallet) { require(!_isOwner(_wallet, _guardian), "SM: guardian cannot be owner"); require(!isGuardian(_wallet, _guardian), "SM: duplicate guardian"); // Guardians must either be an EOA or a contract with an owner() // method that returns an address with a 25000 gas stipend. // Note that this test is not meant to be strict and can be bypassed by custom malicious contracts. (bool success,) = _guardian.call{gas: 25000}(abi.encodeWithSignature("owner()")); require(success, "SM: must be EOA/Argent wallet"); bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "addition")); GuardianManagerConfig storage config = guardianConfigs[_wallet]; require( config.pending[id] == 0 || block.timestamp > config.pending[id] + securityWindow, "SM: duplicate pending addition"); config.pending[id] = block.timestamp + securityPeriod; emit GuardianAdditionRequested(_wallet, _guardian, block.timestamp + securityPeriod); } /** * @notice Confirms the pending addition of a guardian to a wallet. * The method must be called during the confirmation window and can be called by anyone to enable orchestration. * @param _wallet The target wallet. * @param _guardian The guardian. */ function confirmGuardianAddition(address _wallet, address _guardian) external onlyWhenUnlocked(_wallet) { bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "addition")); GuardianManagerConfig storage config = guardianConfigs[_wallet]; require(config.pending[id] > 0, "SM: unknown pending addition"); require(config.pending[id] < block.timestamp, "SM: pending addition not over"); require(block.timestamp < config.pending[id] + securityWindow, "SM: pending addition expired"); guardianStorage.addGuardian(_wallet, _guardian); emit GuardianAdded(_wallet, _guardian); delete config.pending[id]; } /** * @notice Lets the owner cancel a pending guardian addition. * @param _wallet The target wallet. * @param _guardian The guardian. */ function cancelGuardianAddition(address _wallet, address _guardian) external onlyWalletOwnerOrSelf(_wallet) onlyWhenUnlocked(_wallet) { bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "addition")); GuardianManagerConfig storage config = guardianConfigs[_wallet]; require(config.pending[id] > 0, "SM: unknown pending addition"); delete config.pending[id]; emit GuardianAdditionCancelled(_wallet, _guardian); } /** * @notice Lets the owner revoke a guardian from its wallet. * @dev Revokation must be confirmed by calling the confirmGuardianRevokation() method. * @param _wallet The target wallet. * @param _guardian The guardian to revoke. */ function revokeGuardian(address _wallet, address _guardian) external onlyWalletOwnerOrSelf(_wallet) { require(isGuardian(_wallet, _guardian), "SM: must be existing guardian"); bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "revokation")); GuardianManagerConfig storage config = guardianConfigs[_wallet]; require( config.pending[id] == 0 || block.timestamp > config.pending[id] + securityWindow, "SM: duplicate pending revoke"); // TODO need to allow if confirmation window passed config.pending[id] = block.timestamp + securityPeriod; emit GuardianRevokationRequested(_wallet, _guardian, block.timestamp + securityPeriod); } /** * @notice Confirms the pending revokation of a guardian to a wallet. * The method must be called during the confirmation window and can be called by anyone to enable orchestration. * @param _wallet The target wallet. * @param _guardian The guardian. */ function confirmGuardianRevokation(address _wallet, address _guardian) external { bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "revokation")); GuardianManagerConfig storage config = guardianConfigs[_wallet]; require(config.pending[id] > 0, "SM: unknown pending revoke"); require(config.pending[id] < block.timestamp, "SM: pending revoke not over"); require(block.timestamp < config.pending[id] + securityWindow, "SM: pending revoke expired"); guardianStorage.revokeGuardian(_wallet, _guardian); emit GuardianRevoked(_wallet, _guardian); delete config.pending[id]; } /** * @notice Lets the owner cancel a pending guardian revokation. * @param _wallet The target wallet. * @param _guardian The guardian. */ function cancelGuardianRevokation(address _wallet, address _guardian) external onlyWalletOwnerOrSelf(_wallet) onlyWhenUnlocked(_wallet) { bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "revokation")); GuardianManagerConfig storage config = guardianConfigs[_wallet]; require(config.pending[id] > 0, "SM: unknown pending revoke"); delete config.pending[id]; emit GuardianRevokationCancelled(_wallet, _guardian); } /** * @notice Checks if an address is a guardian for a wallet. * @param _wallet The target wallet. * @param _guardian The address to check. * @return _isGuardian `true` if the address is a guardian for the wallet otherwise `false`. */ function isGuardian(address _wallet, address _guardian) public view returns (bool _isGuardian) { return guardianStorage.isGuardian(_wallet, _guardian); } /** * @notice Checks if an address is a guardian or an account authorised to sign on behalf of a smart-contract guardian. * @param _wallet The target wallet. * @param _guardian the address to test * @return _isGuardian `true` if the address is a guardian for the wallet otherwise `false`. */ function isGuardianOrGuardianSigner(address _wallet, address _guardian) external view returns (bool _isGuardian) { (_isGuardian, ) = Utils.isGuardianOrGuardianSigner(guardianStorage.getGuardians(_wallet), _guardian); } /** * @notice Counts the number of active guardians for a wallet. * @param _wallet The target wallet. * @return _count The number of active guardians for a wallet. */ function guardianCount(address _wallet) external view returns (uint256 _count) { return guardianStorage.guardianCount(_wallet); } /** * @notice Get the active guardians for a wallet. * @param _wallet The target wallet. * @return _guardians the active guardians for a wallet. */ function getGuardians(address _wallet) external view returns (address[] memory _guardians) { return guardianStorage.getGuardians(_wallet); } // *************** Internal Functions ********************* // function validateNewOwner(address _wallet, address _newOwner) internal view { require(_newOwner != address(0), "SM: new owner cannot be null"); require(!isGuardian(_wallet, _newOwner), "SM: new owner cannot be guardian"); } function _setLock(address _wallet, uint256 _releaseAfter, bytes4 _locker) internal { locks[_wallet] = Lock(SafeCast.toUint64(_releaseAfter), _locker); } }
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz> // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.3; import "@openzeppelin/contracts/utils/math/SafeCast.sol"; import "./common/Utils.sol"; import "./common/BaseModule.sol"; import "../../lib_0.5/other/ERC20.sol"; /** * @title TransactionManager * @notice Module to execute transactions in sequence to e.g. transfer tokens (ETH, ERC20, ERC721, ERC1155) or call third-party contracts. * @author Julien Niset - <[email protected]> */ abstract contract TransactionManager is BaseModule { // Static calls bytes4 private constant ERC1271_IS_VALID_SIGNATURE = bytes4(keccak256("isValidSignature(bytes32,bytes)")); bytes4 private constant ERC721_RECEIVED = bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")); bytes4 private constant ERC1155_RECEIVED = bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)")); bytes4 private constant ERC1155_BATCH_RECEIVED = bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)")); bytes4 private constant ERC165_INTERFACE = bytes4(keccak256("supportsInterface(bytes4)")); struct Call { address to; uint256 value; bytes data; } // The time delay for adding a trusted contact uint256 internal immutable whitelistPeriod; // *************** Events *************************** // event AddedToWhitelist(address indexed wallet, address indexed target, uint64 whitelistAfter); event RemovedFromWhitelist(address indexed wallet, address indexed target); event SessionCreated(address indexed wallet, address sessionKey, uint64 expires); event SessionCleared(address indexed wallet, address sessionKey); // *************** Constructor ************************ // constructor(uint256 _whitelistPeriod) { whitelistPeriod = _whitelistPeriod; } // *************** External functions ************************ // /** * @notice Makes the target wallet execute a sequence of transactions authorised by the wallet owner. * The method reverts if any of the inner transactions reverts. * The method reverts if any of the inner transaction is not to a trusted contact or an authorised dapp. * @param _wallet The target wallet. * @param _transactions The sequence of transactions. */ function multiCall( address _wallet, Call[] calldata _transactions ) external onlySelf() onlyWhenUnlocked(_wallet) returns (bytes[] memory) { bytes[] memory results = new bytes[](_transactions.length); for(uint i = 0; i < _transactions.length; i++) { address spender = Utils.recoverSpender(_transactions[i].to, _transactions[i].data); require( (_transactions[i].value == 0 || spender == _transactions[i].to) && (isWhitelisted(_wallet, spender) || authoriser.isAuthorised(_wallet, spender, _transactions[i].to, _transactions[i].data)), "TM: call not authorised"); results[i] = invokeWallet(_wallet, _transactions[i].to, _transactions[i].value, _transactions[i].data); } return results; } /** * @notice Makes the target wallet execute a sequence of transactions authorised by a session key. * The method reverts if any of the inner transactions reverts. * @param _wallet The target wallet. * @param _transactions The sequence of transactions. */ function multiCallWithSession( address _wallet, Call[] calldata _transactions ) external onlySelf() onlyWhenUnlocked(_wallet) returns (bytes[] memory) { return multiCallWithApproval(_wallet, _transactions); } /** * @notice Makes the target wallet execute a sequence of transactions approved by a majority of guardians. * The method reverts if any of the inner transactions reverts. * @param _wallet The target wallet. * @param _transactions The sequence of transactions. */ function multiCallWithGuardians( address _wallet, Call[] calldata _transactions ) external onlySelf() onlyWhenUnlocked(_wallet) returns (bytes[] memory) { return multiCallWithApproval(_wallet, _transactions); } /** * @notice Makes the target wallet execute a sequence of transactions approved by a majority of guardians. * The method reverts if any of the inner transactions reverts. * Upon success a new session is started. * @param _wallet The target wallet. * @param _transactions The sequence of transactions. */ function multiCallWithGuardiansAndStartSession( address _wallet, Call[] calldata _transactions, address _sessionUser, uint64 _duration ) external onlySelf() onlyWhenUnlocked(_wallet) returns (bytes[] memory) { startSession(_wallet, _sessionUser, _duration); return multiCallWithApproval(_wallet, _transactions); } /** * @notice Clears the active session of a wallet if any. * @param _wallet The target wallet. */ function clearSession(address _wallet) external onlyWalletOwnerOrSelf(_wallet) onlyWhenUnlocked(_wallet) { emit SessionCleared(_wallet, sessions[_wallet].key); _clearSession(_wallet); } /** * @notice Adds an address to the list of trusted contacts. * @param _wallet The target wallet. * @param _target The address to add. */ function addToWhitelist(address _wallet, address _target) external onlyWalletOwnerOrSelf(_wallet) onlyWhenUnlocked(_wallet) { require(_target != _wallet, "TM: Cannot whitelist wallet"); require(!registry.isRegisteredModule(_target), "TM: Cannot whitelist module"); require(!isWhitelisted(_wallet, _target), "TM: target already whitelisted"); uint256 whitelistAfter = block.timestamp + whitelistPeriod; setWhitelist(_wallet, _target, whitelistAfter); emit AddedToWhitelist(_wallet, _target, uint64(whitelistAfter)); } /** * @notice Removes an address from the list of trusted contacts. * @param _wallet The target wallet. * @param _target The address to remove. */ function removeFromWhitelist(address _wallet, address _target) external onlyWalletOwnerOrSelf(_wallet) onlyWhenUnlocked(_wallet) { setWhitelist(_wallet, _target, 0); emit RemovedFromWhitelist(_wallet, _target); } /** * @notice Checks if an address is a trusted contact for a wallet. * @param _wallet The target wallet. * @param _target The address. * @return _isWhitelisted true if the address is a trusted contact. */ function isWhitelisted(address _wallet, address _target) public view returns (bool _isWhitelisted) { uint whitelistAfter = userWhitelist.getWhitelist(_wallet, _target); return whitelistAfter > 0 && whitelistAfter < block.timestamp; } /* * @notice Enable the static calls required to make the wallet compatible with the ERC1155TokenReceiver * interface (see https://eips.ethereum.org/EIPS/eip-1155#erc-1155-token-receiver). This method only * needs to be called for wallets deployed in version lower or equal to 2.4.0 as the ERC1155 static calls * are not available by default for these versions of BaseWallet * @param _wallet The target wallet. */ function enableERC1155TokenReceiver(address _wallet) external onlyWalletOwnerOrSelf(_wallet) onlyWhenUnlocked(_wallet) { IWallet(_wallet).enableStaticCall(address(this), ERC165_INTERFACE); IWallet(_wallet).enableStaticCall(address(this), ERC1155_RECEIVED); IWallet(_wallet).enableStaticCall(address(this), ERC1155_BATCH_RECEIVED); } /** * @inheritdoc IModule */ function supportsStaticCall(bytes4 _methodId) external pure override returns (bool _isSupported) { return _methodId == ERC1271_IS_VALID_SIGNATURE || _methodId == ERC721_RECEIVED || _methodId == ERC165_INTERFACE || _methodId == ERC1155_RECEIVED || _methodId == ERC1155_BATCH_RECEIVED; } /** ******************* Callbacks ************************** */ /** * @notice Returns true if this contract implements the interface defined by * `interfaceId` (see https://eips.ethereum.org/EIPS/eip-165). */ function supportsInterface(bytes4 _interfaceID) external pure returns (bool) { return _interfaceID == ERC165_INTERFACE || _interfaceID == (ERC1155_RECEIVED ^ ERC1155_BATCH_RECEIVED); } /** * @notice Implementation of EIP 1271. * Should return whether the signature provided is valid for the provided data. * @param _msgHash Hash of a message signed on the behalf of address(this) * @param _signature Signature byte array associated with _msgHash */ function isValidSignature(bytes32 _msgHash, bytes memory _signature) external view returns (bytes4) { require(_signature.length == 65, "TM: invalid signature length"); address signer = Utils.recoverSigner(_msgHash, _signature, 0); require(_isOwner(msg.sender, signer), "TM: Invalid signer"); return ERC1271_IS_VALID_SIGNATURE; } fallback() external { bytes4 methodId = Utils.functionPrefix(msg.data); if(methodId == ERC721_RECEIVED || methodId == ERC1155_RECEIVED || methodId == ERC1155_BATCH_RECEIVED) { // solhint-disable-next-line no-inline-assembly assembly { calldatacopy(0, 0, 0x04) return (0, 0x20) } } } // *************** Internal Functions ********************* // function enableDefaultStaticCalls(address _wallet) internal { // setup the static calls that are available for free for all wallets IWallet(_wallet).enableStaticCall(address(this), ERC1271_IS_VALID_SIGNATURE); IWallet(_wallet).enableStaticCall(address(this), ERC721_RECEIVED); } function multiCallWithApproval(address _wallet, Call[] calldata _transactions) internal returns (bytes[] memory) { bytes[] memory results = new bytes[](_transactions.length); for(uint i = 0; i < _transactions.length; i++) { results[i] = invokeWallet(_wallet, _transactions[i].to, _transactions[i].value, _transactions[i].data); } return results; } function startSession(address _wallet, address _sessionUser, uint64 _duration) internal { require(_sessionUser != address(0), "TM: Invalid session user"); require(_duration > 0, "TM: Invalid session duration"); uint64 expiry = SafeCast.toUint64(block.timestamp + _duration); sessions[_wallet] = Session(_sessionUser, expiry); emit SessionCreated(_wallet, _sessionUser, expiry); } function setWhitelist(address _wallet, address _target, uint256 _whitelistAfter) internal { userWhitelist.setWhitelist(_wallet, _target, _whitelistAfter); } }
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz> // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.3; import "../../wallet/IWallet.sol"; import "../../infrastructure/IModuleRegistry.sol"; import "../../infrastructure/storage/IGuardianStorage.sol"; import "../../infrastructure/IAuthoriser.sol"; import "../../infrastructure/storage/ITransferStorage.sol"; import "./IModule.sol"; import "../../../lib_0.5/other/ERC20.sol"; /** * @title BaseModule * @notice Base Module contract that contains methods common to all Modules. * @author Julien Niset - <[email protected]>, Olivier VDB - <[email protected]> */ abstract contract BaseModule is IModule { // Empty calldata bytes constant internal EMPTY_BYTES = ""; // Mock token address for ETH address constant internal ETH_TOKEN = address(0); // The module registry IModuleRegistry internal immutable registry; // The guardians storage IGuardianStorage internal immutable guardianStorage; // The trusted contacts storage ITransferStorage internal immutable userWhitelist; // The authoriser IAuthoriser internal immutable authoriser; event ModuleCreated(bytes32 name); enum OwnerSignature { Anyone, // Anyone Required, // Owner required Optional, // Owner and/or guardians Disallowed, // Guardians only Session // Session only } struct Session { address key; uint64 expires; } // Maps wallet to session mapping (address => Session) internal sessions; struct Lock { // the lock's release timestamp uint64 release; // the signature of the method that set the last lock bytes4 locker; } // Wallet specific lock storage mapping (address => Lock) internal locks; /** * @notice Throws if the wallet is not locked. */ modifier onlyWhenLocked(address _wallet) { require(_isLocked(_wallet), "BM: wallet must be locked"); _; } /** * @notice Throws if the wallet is locked. */ modifier onlyWhenUnlocked(address _wallet) { require(!_isLocked(_wallet), "BM: wallet locked"); _; } /** * @notice Throws if the sender is not the module itself. */ modifier onlySelf() { require(_isSelf(msg.sender), "BM: must be module"); _; } /** * @notice Throws if the sender is not the module itself or the owner of the target wallet. */ modifier onlyWalletOwnerOrSelf(address _wallet) { require(_isSelf(msg.sender) || _isOwner(_wallet, msg.sender), "BM: must be wallet owner/self"); _; } /** * @dev Throws if the sender is not the target wallet of the call. */ modifier onlyWallet(address _wallet) { require(msg.sender == _wallet, "BM: caller must be wallet"); _; } constructor( IModuleRegistry _registry, IGuardianStorage _guardianStorage, ITransferStorage _userWhitelist, IAuthoriser _authoriser, bytes32 _name ) { registry = _registry; guardianStorage = _guardianStorage; userWhitelist = _userWhitelist; authoriser = _authoriser; emit ModuleCreated(_name); } /** * @notice Moves tokens that have been sent to the module by mistake. * @param _token The target token. */ function recoverToken(address _token) external { uint total = ERC20(_token).balanceOf(address(this)); ERC20(_token).transfer(address(registry), total); } function _clearSession(address _wallet) internal { delete sessions[_wallet]; } /** * @notice Helper method to check if an address is the owner of a target wallet. * @param _wallet The target wallet. * @param _addr The address. */ function _isOwner(address _wallet, address _addr) internal view returns (bool) { return IWallet(_wallet).owner() == _addr; } /** * @notice Helper method to check if a wallet is locked. * @param _wallet The target wallet. */ function _isLocked(address _wallet) internal view returns (bool) { return locks[_wallet].release > uint64(block.timestamp); } /** * @notice Helper method to check if an address is the module itself. * @param _addr The target address. */ function _isSelf(address _addr) internal view returns (bool) { return _addr == address(this); } /** * @notice Helper method to invoke a wallet. * @param _wallet The target wallet. * @param _to The target address for the transaction. * @param _value The value of the transaction. * @param _data The data of the transaction. */ function invokeWallet(address _wallet, address _to, uint256 _value, bytes memory _data) internal returns (bytes memory _res) { bool success; (success, _res) = _wallet.call(abi.encodeWithSignature("invoke(address,uint256,bytes)", _to, _value, _data)); if (success && _res.length > 0) { //_res is empty if _wallet is an "old" BaseWallet that can't return output values (_res) = abi.decode(_res, (bytes)); } else if (_res.length > 0) { // solhint-disable-next-line no-inline-assembly assembly { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } else if (!success) { revert("BM: wallet invoke reverted"); } } }
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz> // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.3; /** * @title IModule * @notice Interface for a Module. * @author Julien Niset - <[email protected]>, Olivier VDB - <[email protected]> */ interface IModule { /** * @notice Adds a module to a wallet. Cannot execute when wallet is locked (or under recovery) * @param _wallet The target wallet. * @param _module The modules to authorise. */ function addModule(address _wallet, address _module) external; /** * @notice Inits a Module for a wallet by e.g. setting some wallet specific parameters in storage. * @param _wallet The wallet. */ function init(address _wallet) external; /** * @notice Returns whether the module implements a callback for a given static call method. * @param _methodId The method id. */ function supportsStaticCall(bytes4 _methodId) external view returns (bool _isSupported); }
// Copyright (C) 2021 Argent Labs Ltd. <https://argent.xyz> // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.3; import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router01.sol"; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol"; contract SimpleOracle { address internal immutable weth; address internal immutable uniswapV2Factory; constructor(address _uniswapRouter) { weth = IUniswapV2Router01(_uniswapRouter).WETH(); uniswapV2Factory = IUniswapV2Router01(_uniswapRouter).factory(); } function inToken(address _token, uint256 _ethAmount) internal view returns (uint256) { (uint256 wethReserve, uint256 tokenReserve) = getReservesForTokenPool(_token); return _ethAmount * tokenReserve / wethReserve; } function getReservesForTokenPool(address _token) internal view returns (uint256 wethReserve, uint256 tokenReserve) { if (weth < _token) { address pair = getPairForSorted(weth, _token); (wethReserve, tokenReserve,) = IUniswapV2Pair(pair).getReserves(); } else { address pair = getPairForSorted(_token, weth); (tokenReserve, wethReserve,) = IUniswapV2Pair(pair).getReserves(); } require(wethReserve != 0 && tokenReserve != 0, "SO: no liquidity"); } function getPairForSorted(address tokenA, address tokenB) internal virtual view returns (address pair) { pair = address(uint160(uint256(keccak256(abi.encodePacked( hex'ff', uniswapV2Factory, keccak256(abi.encodePacked(tokenA, tokenB)), hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' ))))); } }
// Copyright (C) 2020 Argent Labs Ltd. <https://argent.xyz> // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.3; /** * @title Utils * @notice Common utility methods used by modules. */ library Utils { // ERC20, ERC721 & ERC1155 transfers & approvals bytes4 private constant ERC20_TRANSFER = bytes4(keccak256("transfer(address,uint256)")); bytes4 private constant ERC20_APPROVE = bytes4(keccak256("approve(address,uint256)")); bytes4 private constant ERC721_SET_APPROVAL_FOR_ALL = bytes4(keccak256("setApprovalForAll(address,bool)")); bytes4 private constant ERC721_TRANSFER_FROM = bytes4(keccak256("transferFrom(address,address,uint256)")); bytes4 private constant ERC721_SAFE_TRANSFER_FROM = bytes4(keccak256("safeTransferFrom(address,address,uint256)")); bytes4 private constant ERC721_SAFE_TRANSFER_FROM_BYTES = bytes4(keccak256("safeTransferFrom(address,address,uint256,bytes)")); bytes4 private constant ERC1155_SAFE_TRANSFER_FROM = bytes4(keccak256("safeTransferFrom(address,address,uint256,uint256,bytes)")); bytes4 private constant OWNER_SIG = 0x8da5cb5b; /** * @notice Helper method to recover the signer at a given position from a list of concatenated signatures. * @param _signedHash The signed hash * @param _signatures The concatenated signatures. * @param _index The index of the signature to recover. */ function recoverSigner(bytes32 _signedHash, bytes memory _signatures, uint _index) internal pure returns (address) { uint8 v; bytes32 r; bytes32 s; // we jump 32 (0x20) as the first slot of bytes contains the length // we jump 65 (0x41) per signature // for v we load 32 bytes ending with v (the first 31 come from s) then apply a mask // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(_signatures, add(0x20,mul(0x41,_index)))) s := mload(add(_signatures, add(0x40,mul(0x41,_index)))) v := and(mload(add(_signatures, add(0x41,mul(0x41,_index)))), 0xff) } require(v == 27 || v == 28, "Utils: bad v value in signature"); address recoveredAddress = ecrecover(_signedHash, v, r, s); require(recoveredAddress != address(0), "Utils: ecrecover returned 0"); return recoveredAddress; } /** * @notice Helper method to recover the spender from a contract call. * The method returns the contract unless the call is to a standard method of a ERC20/ERC721/ERC1155 token * in which case the spender is recovered from the data. * @param _to The target contract. * @param _data The data payload. */ function recoverSpender(address _to, bytes memory _data) internal pure returns (address spender) { if(_data.length >= 68) { bytes4 methodId; // solhint-disable-next-line no-inline-assembly assembly { methodId := mload(add(_data, 0x20)) } if( methodId == ERC20_TRANSFER || methodId == ERC20_APPROVE || methodId == ERC721_SET_APPROVAL_FOR_ALL) { // solhint-disable-next-line no-inline-assembly assembly { spender := mload(add(_data, 0x24)) } return spender; } if( methodId == ERC721_TRANSFER_FROM || methodId == ERC721_SAFE_TRANSFER_FROM || methodId == ERC721_SAFE_TRANSFER_FROM_BYTES || methodId == ERC1155_SAFE_TRANSFER_FROM) { // solhint-disable-next-line no-inline-assembly assembly { spender := mload(add(_data, 0x44)) } return spender; } } spender = _to; } /** * @notice Helper method to parse data and extract the method signature. */ function functionPrefix(bytes memory _data) internal pure returns (bytes4 prefix) { require(_data.length >= 4, "Utils: Invalid functionPrefix"); // solhint-disable-next-line no-inline-assembly assembly { prefix := mload(add(_data, 0x20)) } } /** * @notice Checks if an address is a contract. * @param _addr The address. */ function isContract(address _addr) internal view returns (bool) { uint32 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(_addr) } return (size > 0); } /** * @notice Checks if an address is a guardian or an account authorised to sign on behalf of a smart-contract guardian * given a list of guardians. * @param _guardians the list of guardians * @param _guardian the address to test * @return true and the list of guardians minus the found guardian upon success, false and the original list of guardians if not found. */ function isGuardianOrGuardianSigner(address[] memory _guardians, address _guardian) internal view returns (bool, address[] memory) { if (_guardians.length == 0 || _guardian == address(0)) { return (false, _guardians); } bool isFound = false; address[] memory updatedGuardians = new address[](_guardians.length - 1); uint256 index = 0; for (uint256 i = 0; i < _guardians.length; i++) { if (!isFound) { // check if _guardian is an account guardian if (_guardian == _guardians[i]) { isFound = true; continue; } // check if _guardian is the owner of a smart contract guardian if (isContract(_guardians[i]) && isGuardianOwner(_guardians[i], _guardian)) { isFound = true; continue; } } if (index < updatedGuardians.length) { updatedGuardians[index] = _guardians[i]; index++; } } return isFound ? (true, updatedGuardians) : (false, _guardians); } /** * @notice Checks if an address is the owner of a guardian contract. * The method does not revert if the call to the owner() method consumes more then 25000 gas. * @param _guardian The guardian contract * @param _owner The owner to verify. */ function isGuardianOwner(address _guardian, address _owner) internal view returns (bool) { address owner = address(0); // solhint-disable-next-line no-inline-assembly assembly { let ptr := mload(0x40) mstore(ptr,OWNER_SIG) let result := staticcall(25000, _guardian, ptr, 0x20, ptr, 0x20) if eq(result, 1) { owner := mload(ptr) } } return owner == _owner; } /** * @notice Returns ceil(a / b). */ function ceil(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a / b; if (a % b == 0) { return c; } else { return c + 1; } } }
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz> // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.5.4 <0.9.0; /** * @title IWallet * @notice Interface for the BaseWallet */ interface IWallet { /** * @notice Returns the wallet owner. * @return The wallet owner address. */ function owner() external view returns (address); /** * @notice Returns the number of authorised modules. * @return The number of authorised modules. */ function modules() external view returns (uint); /** * @notice Sets a new owner for the wallet. * @param _newOwner The new owner. */ function setOwner(address _newOwner) external; /** * @notice Checks if a module is authorised on the wallet. * @param _module The module address to check. * @return `true` if the module is authorised, otherwise `false`. */ function authorised(address _module) external view returns (bool); /** * @notice Returns the module responsible for a static call redirection. * @param _sig The signature of the static call. * @return the module doing the redirection */ function enabled(bytes4 _sig) external view returns (address); /** * @notice Enables/Disables a module. * @param _module The target module. * @param _value Set to `true` to authorise the module. */ function authoriseModule(address _module, bool _value) external; /** * @notice Enables a static method by specifying the target module to which the call must be delegated. * @param _module The target module. * @param _method The static method signature. */ function enableStaticCall(address _module, bytes4 _method) external; }
pragma solidity >=0.5.4 <0.9.0; /** * ERC20 contract interface. */ interface ERC20 { function totalSupply() external view returns (uint); function decimals() external view returns (uint); function balanceOf(address tokenOwner) external view returns (uint balance); function allowance(address tokenOwner, address spender) external view returns (uint remaining); function transfer(address to, uint tokens) external returns (bool success); function approve(address spender, uint tokens) external returns (bool success); function transferFrom(address from, address to, uint tokens) external returns (bool success); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @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, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCast { /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits. */ function toUint8(uint256 value) internal pure returns (uint8) { require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128) { require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\'t fit in 128 bits"); return int128(value); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64) { require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\'t fit in 64 bits"); return int64(value); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32) { require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\'t fit in 32 bits"); return int32(value); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16) { require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\'t fit in 16 bits"); return int16(value); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits. * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8) { require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\'t fit in 8 bits"); return int8(value); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { require(value < 2**255, "SafeCast: value doesn't fit in an int256"); return int256(value); } }
pragma solidity >=0.5.0; interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; function skim(address to) external; function sync() external; function initialize(address, address) external; }
pragma solidity >=0.6.2; interface IUniswapV2Router01 { function factory() external pure returns (address); function WETH() external pure returns (address); function addLiquidity( address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB, uint liquidity); function addLiquidityETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external payable returns (uint amountToken, uint amountETH, uint liquidity); function removeLiquidity( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB); function removeLiquidityETH( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountToken, uint amountETH); function removeLiquidityWithPermit( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountA, uint amountB); function removeLiquidityETHWithPermit( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountToken, uint amountETH); function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapTokensForExactTokens( uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); }
{ "remappings": [], "optimizer": { "enabled": true, "runs": 300 }, "evmVersion": "istanbul", "libraries": { "": {} }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IModuleRegistry","name":"_registry","type":"address"},{"internalType":"contract IGuardianStorage","name":"_guardianStorage","type":"address"},{"internalType":"contract ITransferStorage","name":"_userWhitelist","type":"address"},{"internalType":"contract IAuthoriser","name":"_authoriser","type":"address"},{"internalType":"address","name":"_uniswapRouter","type":"address"},{"internalType":"uint256","name":"_securityPeriod","type":"uint256"},{"internalType":"uint256","name":"_securityWindow","type":"uint256"},{"internalType":"uint256","name":"_recoveryPeriod","type":"uint256"},{"internalType":"uint256","name":"_lockPeriod","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"uint64","name":"whitelistAfter","type":"uint64"}],"name":"AddedToWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"}],"name":"GuardianAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"}],"name":"GuardianAdditionCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"},{"indexed":false,"internalType":"uint256","name":"executeAfter","type":"uint256"}],"name":"GuardianAdditionRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"}],"name":"GuardianRevokationCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"},{"indexed":false,"internalType":"uint256","name":"executeAfter","type":"uint256"}],"name":"GuardianRevokationRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"}],"name":"GuardianRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint64","name":"releaseAfter","type":"uint64"}],"name":"Locked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"name","type":"bytes32"}],"name":"ModuleCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"OwnershipTransfered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"_recovery","type":"address"}],"name":"RecoveryCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"_recovery","type":"address"},{"indexed":false,"internalType":"uint64","name":"executeAfter","type":"uint64"}],"name":"RecoveryExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"_recovery","type":"address"}],"name":"RecoveryFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"refundAddress","type":"address"},{"indexed":false,"internalType":"address","name":"refundToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"refundAmount","type":"uint256"}],"name":"Refund","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"}],"name":"RemovedFromWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"address","name":"sessionKey","type":"address"}],"name":"SessionCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"address","name":"sessionKey","type":"address"},{"indexed":false,"internalType":"uint64","name":"expires","type":"uint64"}],"name":"SessionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"bytes","name":"returnData","type":"bytes"},{"indexed":false,"internalType":"bytes32","name":"signedHash","type":"bytes32"}],"name":"TransactionExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"}],"name":"Unlocked","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"addGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_module","type":"address"}],"name":"addModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_target","type":"address"}],"name":"addToWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"cancelGuardianAddition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"cancelGuardianRevokation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"cancelRecovery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"clearSession","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"confirmGuardianAddition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"confirmGuardianRevokation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"enableERC1155TokenReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"bytes","name":"_signatures","type":"bytes"},{"internalType":"uint256","name":"_gasPrice","type":"uint256"},{"internalType":"uint256","name":"_gasLimit","type":"uint256"},{"internalType":"address","name":"_refundToken","type":"address"},{"internalType":"address","name":"_refundAddress","type":"address"}],"name":"execute","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_recovery","type":"address"}],"name":"executeRecovery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"finalizeRecovery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"getGuardians","outputs":[{"internalType":"address[]","name":"_guardians","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"getLock","outputs":[{"internalType":"uint64","name":"_releaseAfter","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"getRecovery","outputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"uint64","name":"_executeAfter","type":"uint64"},{"internalType":"uint32","name":"_guardianCount","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"getRequiredSignatures","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"enum BaseModule.OwnerSignature","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"getSession","outputs":[{"internalType":"address","name":"key","type":"address"},{"internalType":"uint64","name":"expires","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"guardianCount","outputs":[{"internalType":"uint256","name":"_count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"bytes32","name":"_signHash","type":"bytes32"}],"name":"isExecutedTx","outputs":[{"internalType":"bool","name":"executed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"isGuardian","outputs":[{"internalType":"bool","name":"_isGuardian","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"isGuardianOrGuardianSigner","outputs":[{"internalType":"bool","name":"_isGuardian","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"isLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_msgHash","type":"bytes32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_target","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"_isWhitelisted","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"lock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct TransactionManager.Call[]","name":"_transactions","type":"tuple[]"}],"name":"multiCall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct TransactionManager.Call[]","name":"_transactions","type":"tuple[]"}],"name":"multiCallWithGuardians","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct TransactionManager.Call[]","name":"_transactions","type":"tuple[]"},{"internalType":"address","name":"_sessionUser","type":"address"},{"internalType":"uint64","name":"_duration","type":"uint64"}],"name":"multiCallWithGuardiansAndStartSession","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct TransactionManager.Call[]","name":"_transactions","type":"tuple[]"}],"name":"multiCallWithSession","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"recoverToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_target","type":"address"}],"name":"removeFromWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"revokeGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_methodId","type":"bytes4"}],"name":"supportsStaticCall","outputs":[{"internalType":"bool","name":"_isSupported","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"unlock","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101e06040523480156200001257600080fd5b50604051620064fa380380620064fa833981016040819052620000359162000323565b838285858489808f8f8f8f6b417267656e744d6f64756c6560a01b846001600160a01b03166080816001600160a01b031660601b81525050836001600160a01b031660a0816001600160a01b031660601b81525050826001600160a01b031660c0816001600160a01b031660601b81525050816001600160a01b031660e0816001600160a01b031660601b815250507f3019c8fc80239e3dff8f781212ae2004839c2cb61d6c70acd279ac65392145df81604051620000f691815260200190565b60405180910390a15050505050806001600160a01b031663ad5c46486040518163ffffffff1660e01b815260040160206040518083038186803b1580156200013d57600080fd5b505afa15801562000152573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001789190620002fd565b6001600160a01b0316610100816001600160a01b031660601b81525050806001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b158015620001cf57600080fd5b505afa158015620001e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200020a9190620002fd565b60601b6001600160601b03191661012052505083811015620002735760405162461bcd60e51b815260206004820152601860248201527f534d3a20696e736563757265206c6f636b20706572696f64000000000000000060448201526064015b60405180910390fd5b6200027f8284620003c9565b841015620002d05760405162461bcd60e51b815260206004820152601d60248201527f534d3a20696e73656375726520736563757269747920706572696f647300000060448201526064016200026a565b61014093909352610160929092526101a091909152610180526101c0525062000407975050505050505050565b6000602082840312156200030f578081fd5b81516200031c81620003ee565b9392505050565b60008060008060008060008060006101208a8c03121562000342578485fd5b89516200034f81620003ee565b60208b01519099506200036281620003ee565b60408b01519098506200037581620003ee565b60608b01519097506200038881620003ee565b60808b01519096506200039b81620003ee565b8095505060a08a0151935060c08a0151925060e08a015191506101008a015190509295985092959850929598565b60008219821115620003e957634e487b7160e01b81526011600452602481fd5b500190565b6001600160a01b03811681146200040457600080fd5b50565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405161016051610180516101a0516101c051615fb962000541600039600061196d0152600081816109f101528181611593015281816120680152612fc3015260008181610a6a01528181610ad20152818161303c01526130a4015260008181612b61015281816139ea0152613a4c015260006129fc015260006153cd0152600081816151c3015281816151f801526152b00152600081816125430152614b57015260008181612c11015281816142650152614c0e01526000818161162d015281816116f40152818161210201528181612a66015281816132360152818161382c015281816138da0152818161418301526148e201526000818161184801528181611c3a015261226d0152615fb96000f3fe608060405234801561001057600080fd5b50600436106102485760003560e01c80636ff6ec7c1161013b578063ba821088116100b8578063eac01e471161007c578063eac01e47146106cb578063f143ddba14610517578063f18858ab146106de578063f435f5a7146106fe578063f8d3277d1461071157610248565b8063ba8210881461066c578063c68452101461067f578063c90db44714610692578063d4ee9734146106a5578063e0724b6e146106b857610248565b8063a3f4df7e116100ff578063a3f4df7e1461060a578063a5efb23514610620578063a6eb069014610633578063b0ba4da014610646578063b6b352721461065957610248565b80636ff6ec7c1461051757806370135f521461052a5780638c8e13b91461053d5780639769c3fe146105775780639be65a60146105f757610248565b80633b73d67f116101c957806359b4958a1161018d57806359b4958a146104765780635a1db8c41461048957806360c0fdc01461049c5780636b9db4e6146104d95780636d4354211461050457610248565b80633b73d67f146104095780634a4fbeec1461042a5780634b3ef0541461043d5780635040fb7614610450578063575182431461046357610248565b806325b509341161021057806325b50934146103865780632960739b146103995780632d0335ab146103ac5780632f6c493c146103e3578063315a7af3146103f657610248565b806301ffc9a7146102ea5780631626ba7e1461031257806319ab453c1461033e5780631d97d8cc146103535780632437b75c14610366575b600061028a6000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061072492505050565b90506001600160e01b03198116630a85bd0160e11b14806102bb57506001600160e01b0319811663f23a6e6160e01b145b806102d657506001600160e01b0319811663bc197c8160e01b145b156102e75760046000803760206000f35b50005b6102fd6102f83660046158e7565b610785565b60405190151581526020015b60405180910390f35b610325610320366004615864565b6107be565b6040516001600160e01b03199091168152602001610309565b61035161034c36600461551a565b610897565b005b610351610361366004615552565b6108fd565b6103796103743660046155dc565b610b10565b6040516103099190615c51565b6102fd6103943660046158e7565b610b9e565b6103516103a7366004615552565b610c22565b6103d56103ba36600461551a565b6001600160a01b031660009081526002602052604090205490565b604051908152602001610309565b6103516103f136600461551a565b610d66565b61035161040436600461551a565b610ed7565b61041c61041736600461568a565b6110ab565b604051610309929190615d36565b6102fd61043836600461551a565b611478565b61035161044b366004615552565b611483565b6103d561045e36600461551a565b6116d2565b610351610471366004615552565b611770565b61035161048436600461551a565b6119e8565b610351610497366004615552565b611bc4565b6102fd6104aa36600461565f565b6001600160a01b0391909116600090815260026020908152604080832093835260019093019052205460ff1690565b6104ec6104e736600461551a565b611d68565b6040516001600160401b039091168152602001610309565b610351610512366004615552565b611da3565b61037961052536600461558a565b611eb0565b610351610538366004615552565b611f31565b61055061054b36600461551a565b6121a8565b604080516001600160a01b0390931683526001600160401b03909116602083015201610309565b6105c461058536600461551a565b6001600160a01b0390811660009081526003602052604090205490811691600160a01b82046001600160401b031691600160e01b900463ffffffff1690565b604080516001600160a01b0390941684526001600160401b03909216602084015263ffffffff1690820152606001610309565b61035161060536600461551a565b6121dc565b6103d56b417267656e744d6f64756c6560a01b81565b61037961062e36600461558a565b612301565b610351610641366004615552565b6127eb565b610351610654366004615552565b61292f565b6102fd610667366004615552565b612be5565b61035161067a36600461551a565b612ca4565b61035161068d366004615552565b612d77565b6103516106a036600461551a565b6130e3565b6102fd6106b3366004615552565b61320c565b6102fd6106c63660046156cf565b6132b9565b6102fd6106d9366004615552565b613806565b6106f16106ec36600461551a565b6138b8565b6040516103099190615c04565b61035161070c36600461551a565b61395a565b61035161071f366004615552565b613a91565b600060048251101561077d5760405162461bcd60e51b815260206004820152601d60248201527f5574696c733a20496e76616c69642066756e6374696f6e50726566697800000060448201526064015b60405180910390fd5b506020015190565b60006001600160e01b031982166301ffc9a760e01b14806107b657506001600160e01b03198216630271189760e51b145b90505b919050565b600081516041146108115760405162461bcd60e51b815260206004820152601c60248201527f544d3a20696e76616c6964207369676e6174757265206c656e677468000000006044820152606401610774565b600061081f84846000613b3a565b905061082b3382613c6f565b61086c5760405162461bcd60e51b81526020600482015260126024820152712a269d1024b73b30b634b21039b4b3b732b960711b6044820152606401610774565b7f1626ba7e356f5979dd355a3d2bfb43e80420a480c3b854edce286a82d74968699150505b92915050565b80336001600160a01b038216146108f05760405162461bcd60e51b815260206004820152601960248201527f424d3a2063616c6c6572206d7573742062652077616c6c6574000000000000006044820152606401610774565b6108f982613cfd565b5050565b813033148061091157506109118133613c6f565b61092d5760405162461bcd60e51b815260040161077490615cd4565b610937838361320c565b6109835760405162461bcd60e51b815260206004820152601d60248201527f534d3a206d757374206265206578697374696e6720677561726469616e0000006044820152606401610774565b60008383604051602001610998929190615a0a565b60408051601f1981840301815291815281516020928301206001600160a01b0387166000908152600484528281208282529384905291909120549092501580610a195750600082815260208290526040902054610a16907f000000000000000000000000000000000000000000000000000000000000000090615e40565b42115b610a655760405162461bcd60e51b815260206004820152601c60248201527f534d3a206475706c69636174652070656e64696e67207265766f6b65000000006044820152606401610774565b610a8f7f000000000000000000000000000000000000000000000000000000000000000042615e40565b6000838152602083905260409020556001600160a01b038085169086167f9746f6868f544595794833da53250bd19e72334733336cfd5dd6fbc5f6a6ac42610af77f000000000000000000000000000000000000000000000000000000000000000042615e40565b6040519081526020015b60405180910390a35050505050565b6060303314610b565760405162461bcd60e51b8152602060048201526012602482015271424d3a206d757374206265206d6f64756c6560701b6044820152606401610774565b85610b6081613e00565b15610b7d5760405162461bcd60e51b815260040161077490615d0b565b610b88878585613e29565b610b93878787613f96565b979650505050505050565b60006001600160e01b03198216630b135d3f60e11b1480610bcf57506001600160e01b03198216630a85bd0160e11b145b80610bea57506001600160e01b031982166301ffc9a760e01b145b80610c0557506001600160e01b0319821663f23a6e6160e01b145b806107b65750506001600160e01b03191663bc197c8160e01b1490565b8130331480610c365750610c368133613c6f565b610c525760405162461bcd60e51b815260040161077490615cd4565b82610c5c81613e00565b15610c795760405162461bcd60e51b815260040161077490615d0b565b60008484604051602001610c8e929190615a0a565b60408051601f1981840301815291815281516020928301206001600160a01b038816600090815260048452828120828252938490529190912054909250610d175760405162461bcd60e51b815260206004820152601a60248201527f534d3a20756e6b6e6f776e2070656e64696e67207265766f6b650000000000006044820152606401610774565b600082815260208290526040808220829055516001600160a01b0380881692908916917fc0b205956d5e27c296695de329b5a014584a4f51824b1725a0eefc1174d6dbd59190a3505050505050565b8030331480610d7a5750610d7a813361320c565b610dc65760405162461bcd60e51b815260206004820152601960248201527f534d3a206d75737420626520677561726469616e2f73656c66000000000000006044820152606401610774565b81610dd081613e00565b610e1c5760405162461bcd60e51b815260206004820152601960248201527f424d3a2077616c6c6574206d757374206265206c6f636b6564000000000000006044820152606401610774565b6001600160a01b038316600090815260016020526040902054600160401b900460e01b6001600160e01b03191663f435f5a760e01b14610e925760405162461bcd60e51b8152602060048201526011602482015270534d3a2063616e6e6f7420756e6c6f636b60781b6044820152606401610774565b610e9e836000806140e2565b6040516001600160a01b038416907f7e6adfec7e3f286831a0200a754127c171a2da564078722cb97704741bbdb0ea90600090a2505050565b6001600160a01b0381166000908152600360205260409020548190600160a01b90046001600160401b0316610f485760405162461bcd60e51b8152602060048201526017602482015276534d3a206e6f206f6e676f696e67207265636f7665727960481b6044820152606401610774565b6001600160a01b038216600090815260036020526040902080546001600160401b03600160a01b90910481164290911611610fc55760405162461bcd60e51b815260206004820152601b60248201527f534d3a206f6e676f696e67207265636f7665727920706572696f6400000000006044820152606401610774565b80546001600160a01b03848116600090815260036020908152604080832083905590829052902080546001600160e01b0319169055166040516313af403560e01b81526001600160a01b0382811660048301528516906313af403590602401600060405180830381600087803b15801561103e57600080fd5b505af1158015611052573d6000803e3d6000fd5b505050506110658460008060e01b6140e2565b806001600160a01b0316846001600160a01b03167fd8667de85dae2d56d76e700d16de53d21ac2ce4d5549cb0bf51c55fdc37f0bc160405160405180910390a350505050565b60008060006110ef85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061072492505050565b90506001600160e01b0319811663a5efb23560e01b148061112057506001600160e01b03198116635751824360e01b145b8061113b57506001600160e01b0319811663f8d3277d60e01b145b8061115657506001600160e01b03198116632cda4ac560e11b145b8061117157506001600160e01b03198116631750421160e31b145b8061118c57506001600160e01b031981166316876e3160e21b145b806111a757506001600160e01b03198116630c68452160e41b145b806111c257506001600160e01b03198116630765f63360e21b145b806111dd57506001600160e01b03198116630a6eb06960e41b145b806111f857506001600160e01b03198116632960739b60e01b145b1561120a576001809250925050611470565b6001600160e01b03198116631bfdbb1f60e21b141561123157600160049250925050611470565b6001600160e01b03198116630585d26d60e51b14156112b45760006112558761415d565b9050600081116112a75760405162461bcd60e51b815260206004820152601e60248201527f414d3a206e6f20677561726469616e7320736574206f6e2077616c6c657400006044820152606401610774565b9250600391506114709050565b6001600160e01b0319811663c90db44760e01b141561131d576001600160a01b03861660009081526003602052604081205461130f9061130290600160e01b900463ffffffff166001615e58565b63ffffffff166002614200565b935060029250611470915050565b6001600160e01b031981166378a1eedd60e11b148061134c57506001600160e01b0319811663090dedd760e21b145b8061136757506001600160e01b03198116636d43542160e01b145b156113955760006113778761415d565b90506000611386826001615e40565b94506001935061147092505050565b6001600160e01b0319811663315a7af360e01b14806113c457506001600160e01b03198116633809afa960e11b145b806113df57506001600160e01b031981166312cfbc1560e21b145b156113f1576000809250925050611470565b6001600160e01b0319811663f435f5a760e01b148061142057506001600160e01b03198116630bdb124f60e21b145b1561143357600160039250925050611470565b60405162461bcd60e51b815260206004820152601260248201527114d34e881d5b9adb9bdddb881b595d1a1bd960721b6044820152606401610774565b935093915050565b60006107b682613e00565b60008282604051602001611498929190615a0a565b60408051601f1981840301815291815281516020928301206001600160a01b0386166000908152600484528281208282529384905291909120549092506115215760405162461bcd60e51b815260206004820152601a60248201527f534d3a20756e6b6e6f776e2070656e64696e67207265766f6b650000000000006044820152606401610774565b600082815260208290526040902054421161157e5760405162461bcd60e51b815260206004820152601b60248201527f534d3a2070656e64696e67207265766f6b65206e6f74206f76657200000000006044820152606401610774565b6000828152602082905260409020546115b8907f000000000000000000000000000000000000000000000000000000000000000090615e40565b42106116065760405162461bcd60e51b815260206004820152601a60248201527f534d3a2070656e64696e67207265766f6b6520657870697265640000000000006044820152606401610774565b604051630765f63360e21b81526001600160a01b03858116600483015284811660248301527f00000000000000000000000000000000000000000000000000000000000000001690631d97d8cc90604401600060405180830381600087803b15801561167157600080fd5b505af1158015611685573d6000803e3d6000fd5b50506040516001600160a01b038087169350871691507f548f10dcba266544123ad8cf8284f25c4baa659cba25dbdf16a06ea11235de9b90600090a3600091825260205260408120555050565b6040516328207dbb60e11b81526001600160a01b0382811660048301526000917f000000000000000000000000000000000000000000000000000000000000000090911690635040fb769060240160206040518083038186803b15801561173857600080fd5b505afa15801561174c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b691906159c6565b813033148061178457506117848133613c6f565b6117a05760405162461bcd60e51b815260040161077490615cd4565b826117aa81613e00565b156117c75760405162461bcd60e51b815260040161077490615d0b565b836001600160a01b0316836001600160a01b031614156118295760405162461bcd60e51b815260206004820152601b60248201527f544d3a2043616e6e6f742077686974656c6973742077616c6c657400000000006044820152606401610774565b604051630bcd4ebb60e01b81526001600160a01b0384811660048301527f00000000000000000000000000000000000000000000000000000000000000001690630bcd4ebb9060240160206040518083038186803b15801561188a57600080fd5b505afa15801561189e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c29190615844565b1561190f5760405162461bcd60e51b815260206004820152601b60248201527f544d3a2043616e6e6f742077686974656c697374206d6f64756c6500000000006044820152606401610774565b6119198484612be5565b156119665760405162461bcd60e51b815260206004820152601e60248201527f544d3a2074617267657420616c72656164792077686974656c697374656400006044820152606401610774565b60006119927f000000000000000000000000000000000000000000000000000000000000000042615e40565b905061199f858583614237565b6040516001600160401b03821681526001600160a01b0380861691908716907f1f57f9641d3e8733ed672fef5ac85464bd7215ef2f21e83428e8408248b13dcd90602001610b01565b80303314806119fc57506119fc8133613c6f565b611a185760405162461bcd60e51b815260040161077490615cd4565b81611a2281613e00565b15611a3f5760405162461bcd60e51b815260040161077490615d0b565b6040516309ed185960e11b81526001600160a01b038416906313da30b290611a8d9030907f01ffc9a7a5cef8baa21ed3c5c0d7e23accb804b619e9333b597f47a0d84076e290600401615bb9565b600060405180830381600087803b158015611aa757600080fd5b505af1158015611abb573d6000803e3d6000fd5b50506040516309ed185960e11b81526001600160a01b03861692506313da30b29150611b0d9030907ff23a6e612e1ff4830e658fe43f4e3cb4a5f8170bd5d9e69fb5d7a7fa9e4fdf9790600401615bb9565b600060405180830381600087803b158015611b2757600080fd5b505af1158015611b3b573d6000803e3d6000fd5b50506040516309ed185960e11b81526001600160a01b03861692506313da30b29150611b8d9030907fbc197c819b3e337a6f9652dd10becd7eef83032af3b9d958d3d42f669414662190600401615bb9565b600060405180830381600087803b158015611ba757600080fd5b505af1158015611bbb573d6000803e3d6000fd5b50505050505050565b8130331480611bd85750611bd88133613c6f565b611bf45760405162461bcd60e51b815260040161077490615cd4565b82611bfe81613e00565b15611c1b5760405162461bcd60e51b815260040161077490615d0b565b604051630bcd4ebb60e01b81526001600160a01b0384811660048301527f00000000000000000000000000000000000000000000000000000000000000001690630bcd4ebb9060240160206040518083038186803b158015611c7c57600080fd5b505afa158015611c90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb49190615844565b611d005760405162461bcd60e51b815260206004820152601c60248201527f414d3a206d6f64756c65206973206e6f742072656769737465726564000000006044820152606401610774565b604051631f17732d60e01b81526001600160a01b03848116600483015260016024830152851690631f17732d90604401600060405180830381600087803b158015611d4a57600080fd5b505af1158015611d5e573d6000803e3d6000fd5b5050505050505050565b6000611d7382613e00565b611d7e5760006107b6565b506001600160a01b03166000908152600160205260409020546001600160401b031690565b303314611de75760405162461bcd60e51b8152602060048201526012602482015271424d3a206d757374206265206d6f64756c6560701b6044820152606401610774565b81611df181613e00565b15611e0e5760405162461bcd60e51b815260040161077490615d0b565b611e188383614294565b6040516313af403560e01b81526001600160a01b0383811660048301528416906313af403590602401600060405180830381600087803b158015611e5b57600080fd5b505af1158015611e6f573d6000803e3d6000fd5b50506040516001600160a01b038086169350861691507f0d18b5fd22306e373229b9439188228edca81207d1667f604daf6cef8aa3ee6790600090a3505050565b6060303314611ef65760405162461bcd60e51b8152602060048201526012602482015271424d3a206d757374206265206d6f64756c6560701b6044820152606401610774565b83611f0081613e00565b15611f1d5760405162461bcd60e51b815260040161077490615d0b565b611f28858585613f96565b95945050505050565b81611f3b81613e00565b15611f585760405162461bcd60e51b815260040161077490615d0b565b60008383604051602001611f6d929190615a3f565b60408051601f1981840301815291815281516020928301206001600160a01b038716600090815260048452828120828252938490529190912054909250611ff65760405162461bcd60e51b815260206004820152601c60248201527f534d3a20756e6b6e6f776e2070656e64696e67206164646974696f6e000000006044820152606401610774565b60008281526020829052604090205442116120535760405162461bcd60e51b815260206004820152601d60248201527f534d3a2070656e64696e67206164646974696f6e206e6f74206f7665720000006044820152606401610774565b60008281526020829052604090205461208d907f000000000000000000000000000000000000000000000000000000000000000090615e40565b42106120db5760405162461bcd60e51b815260206004820152601c60248201527f534d3a2070656e64696e67206164646974696f6e2065787069726564000000006044820152606401610774565b604051630c68452160e41b81526001600160a01b03868116600483015285811660248301527f0000000000000000000000000000000000000000000000000000000000000000169063c684521090604401600060405180830381600087803b15801561214657600080fd5b505af115801561215a573d6000803e3d6000fd5b50506040516001600160a01b038088169350881691507fbc3292102fa77e083913064b282926717cdfaede4d35f553d66366c0a3da755a90600090a360009182526020526040812055505050565b6001600160a01b0381811660009081526020819052604090205490811690600160a01b90046001600160401b03165b915091565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b15801561221e57600080fd5b505afa158015612232573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225691906159c6565b60405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390529192509083169063a9059cbb90604401602060405180830381600087803b1580156122c457600080fd5b505af11580156122d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122fc9190615844565b505050565b60603033146123475760405162461bcd60e51b8152602060048201526012602482015271424d3a206d757374206265206d6f64756c6560701b6044820152606401610774565b8361235181613e00565b1561236e5760405162461bcd60e51b815260040161077490615d0b565b6000836001600160401b0381111561239657634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156123c957816020015b60608152602001906001900390816123b45790505b50905060005b848110156127e15760006124968787848181106123fc57634e487b7160e01b600052603260045260246000fd5b905060200281019061240e9190615dac565b61241c90602081019061551a565b88888581811061243c57634e487b7160e01b600052603260045260246000fd5b905060200281019061244e9190615dac565b61245c906040810190615d68565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061434192505050565b90508686838181106124b857634e487b7160e01b600052603260045260246000fd5b90506020028101906124ca9190615dac565b60200135158061252a57508686838181106124f557634e487b7160e01b600052603260045260246000fd5b90506020028101906125079190615dac565b61251590602081019061551a565b6001600160a01b0316816001600160a01b0316145b8015612662575061253b8882612be5565b8061266257507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635cfdc4d089838a8a8781811061259257634e487b7160e01b600052603260045260246000fd5b90506020028101906125a49190615dac565b6125b290602081019061551a565b8b8b888181106125d257634e487b7160e01b600052603260045260246000fd5b90506020028101906125e49190615dac565b6125f2906040810190615d68565b6040518663ffffffff1660e01b8152600401612612959493929190615b28565b60206040518083038186803b15801561262a57600080fd5b505afa15801561263e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126629190615844565b6126ae5760405162461bcd60e51b815260206004820152601760248201527f544d3a2063616c6c206e6f7420617574686f72697365640000000000000000006044820152606401610774565b6127a2888888858181106126d257634e487b7160e01b600052603260045260246000fd5b90506020028101906126e49190615dac565b6126f290602081019061551a565b89898681811061271257634e487b7160e01b600052603260045260246000fd5b90506020028101906127249190615dac565b602001358a8a8781811061274857634e487b7160e01b600052603260045260246000fd5b905060200281019061275a9190615dac565b612768906040810190615d68565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061442b92505050565b8383815181106127c257634e487b7160e01b600052603260045260246000fd5b60200260200101819052505080806127d990615efa565b9150506123cf565b5095945050505050565b81303314806127ff57506127ff8133613c6f565b61281b5760405162461bcd60e51b815260040161077490615cd4565b8261282581613e00565b156128425760405162461bcd60e51b815260040161077490615d0b565b60008484604051602001612857929190615a3f565b60408051601f1981840301815291815281516020928301206001600160a01b0388166000908152600484528281208282529384905291909120549092506128e05760405162461bcd60e51b815260206004820152601c60248201527f534d3a20756e6b6e6f776e2070656e64696e67206164646974696f6e000000006044820152606401610774565b600082815260208290526040808220829055516001600160a01b0380881692908916917faa13b27c23e9e3f3d5f3861a53b7a2931e019170a6a19ed64942e26a1dd5987a9190a3505050505050565b3033146129735760405162461bcd60e51b8152602060048201526012602482015271424d3a206d757374206265206d6f64756c6560701b6044820152606401610774565b6001600160a01b0382166000908152600360205260409020548290600160a01b90046001600160401b0316156129eb5760405162461bcd60e51b815260206004820152601460248201527f534d3a206f6e676f696e67207265636f766572790000000000000000000000006044820152606401610774565b6129f58383614294565b6000612a217f000000000000000000000000000000000000000000000000000000000000000042615e40565b604080516060810182526001600160a01b0380871682526001600160401b038416602083015282516328207dbb60e11b815288821660048201529394509092918301917f000000000000000000000000000000000000000000000000000000000000000090911690635040fb769060240160206040518083038186803b158015612aaa57600080fd5b505afa158015612abe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ae291906159c6565b63ffffffff9081169091526001600160a01b0380871660009081526003602090815260409182902085518154928701519690930151909416600160e01b026001600160e01b036001600160401b03909616600160a01b026001600160e01b031990921692909316919091171792909216919091179055612b9384612b867f000000000000000000000000000000000000000000000000000000000000000042615e40565b630585d26d60e51b6140e2565b6040516001600160401b03821681526001600160a01b0380851691908616907f5f59bfd9baba55ae30bb440923cbbe30987d50e12a4e9134ffac3fd9afc3526d9060200160405180910390a350505050565b6040516309fa507560e11b81526001600160a01b038381166004830152828116602483015260009182917f000000000000000000000000000000000000000000000000000000000000000016906313f4a0ea9060440160206040518083038186803b158015612c5357600080fd5b505afa158015612c67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c8b91906159c6565b9050600081118015612c9c57504281105b949350505050565b8030331480612cb85750612cb88133613c6f565b612cd45760405162461bcd60e51b815260040161077490615cd4565b81612cde81613e00565b15612cfb5760405162461bcd60e51b815260040161077490615d0b565b6001600160a01b038381166000818152602081815260409182902054915191909316815290917feb290a597820eccc6b8b31f942bd97c633d5138f4d849751f770f3cb3900e57a910160405180910390a26122fc836001600160a01b0316600090815260208190526040902080546001600160e01b0319169055565b8130331480612d8b5750612d8b8133613c6f565b612da75760405162461bcd60e51b815260040161077490615cd4565b82612db181613e00565b15612dce5760405162461bcd60e51b815260040161077490615d0b565b612dd88484613c6f565b15612e255760405162461bcd60e51b815260206004820152601c60248201527f534d3a20677561726469616e2063616e6e6f74206265206f776e6572000000006044820152606401610774565b612e2f848461320c565b15612e7c5760405162461bcd60e51b815260206004820152601660248201527f534d3a206475706c696361746520677561726469616e000000000000000000006044820152606401610774565b60408051600481526024810182526020810180516001600160e01b0316638da5cb5b60e01b17905290516000916001600160a01b038616916161a891612ec191615b0c565b60006040518083038160008787f1925050503d8060008114612eff576040519150601f19603f3d011682016040523d82523d6000602084013e612f04565b606091505b5050905080612f555760405162461bcd60e51b815260206004820152601d60248201527f534d3a206d75737420626520454f412f417267656e742077616c6c65740000006044820152606401610774565b60008585604051602001612f6a929190615a3f565b60408051601f1981840301815291815281516020928301206001600160a01b0389166000908152600484528281208282529384905291909120549092501580612feb5750600082815260208290526040902054612fe8907f000000000000000000000000000000000000000000000000000000000000000090615e40565b42115b6130375760405162461bcd60e51b815260206004820152601e60248201527f534d3a206475706c69636174652070656e64696e67206164646974696f6e00006044820152606401610774565b6130617f000000000000000000000000000000000000000000000000000000000000000042615e40565b6000838152602083905260409020556001600160a01b038087169088167fe4166e4bc55a182bd13d933553241bb3441b91d15fbc74c5c752f96965563bde6130c97f000000000000000000000000000000000000000000000000000000000000000042615e40565b60405190815260200160405180910390a350505050505050565b3033146131275760405162461bcd60e51b8152602060048201526012602482015271424d3a206d757374206265206d6f64756c6560701b6044820152606401610774565b6001600160a01b0381166000908152600360205260409020548190600160a01b90046001600160401b03166131985760405162461bcd60e51b8152602060048201526017602482015276534d3a206e6f206f6e676f696e67207265636f7665727960481b6044820152606401610774565b6001600160a01b038083166000908152600360205260408120805490829055909116906131c7908490806140e2565b806001600160a01b0316836001600160a01b03167fc45926607303da71dbeffd2ed5c6b00f581982586b697655d19ae4c4d558f25960405160405180910390a3505050565b60405163353ba5cd60e21b81526001600160a01b03838116600483015282811660248301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063d4ee97349060440160206040518083038186803b15801561327a57600080fd5b505afa15801561328e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b29190615844565b9392505050565b6000806132c7366008615e94565b5a6132d490615208615e40565b6132de9190615e40565b9050848110156133305760405162461bcd60e51b815260206004820152601b60248201527f524d3a206e6f7420656e6f756768206761732070726f766964656400000000006044820152606401610774565b61333b8c8c8c614556565b6133875760405162461bcd60e51b815260206004820152601e60248201527f524d3a20546172676574206f66205f6461746120213d205f77616c6c657400006044820152606401610774565b6133908c613e00565b158061339a575085155b6133e65760405162461bcd60e51b815260206004820152601860248201527f524d3a204c6f636b65642077616c6c657420726566756e6400000000000000006044820152606401610774565b6134176040805160a08101909152600080825260208201908152600060208201819052604082015260609081015290565b6134228d8d8d6110ab565b826020810182600481111561344757634e487b7160e01b600052602160045260246000fd5b600481111561346657634e487b7160e01b600052602160045260246000fd5b90529190915250805115158061349f575060008160200151600481111561349d57634e487b7160e01b600052602160045260246000fd5b145b6134eb5760405162461bcd60e51b815260206004820152601f60248201527f524d3a2057726f6e67207369676e617475726520726571756972656d656e74006044820152606401610774565b805188906134fa906041615e94565b146135475760405162461bcd60e51b815260206004820152601e60248201527f524d3a2057726f6e67206e756d626572206f66207369676e61747572657300006044820152606401610774565b61359c3060008e8e8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508d8b8b8b8b6145de565b8160400181815250506135be8d8b836040015184600001518560200151614677565b61360a5760405162461bcd60e51b815260206004820152601560248201527f524d3a204475706c6963617465207265717565737400000000000000000000006044820152606401610774565b60048160200151600481111561363057634e487b7160e01b600052602160045260246000fd5b141561368d576136468d82604001518b8b6147bb565b6136885760405162461bcd60e51b815260206004820152601360248201527229269d1024b73b30b634b21039b2b9b9b4b7b760691b6044820152606401610774565b613722565b6136d68d82604001518b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506020850151614876565b6137225760405162461bcd60e51b815260206004820152601660248201527f524d3a20496e76616c6964207369676e617475726573000000000000000000006044820152606401610774565b6040513090613734908e908e90615afc565b6000604051808303816000865af19150503d8060008114613771576040519150601f19603f3d011682016040523d82523d6000602084013e613776565b606091505b50608083015215156060820152805160208201516137a0918f9185918b918b918b918b9190614a86565b806060015115158d6001600160a01b03167f7da4525a280527268ba2e963ee6c1b18f43c9507bcb1d2560f652ab17c76e90a836080015184604001516040516137ea929190615cb2565b60405180910390a3606001519c9b505050505050505050505050565b60405163f18858ab60e01b81526001600160a01b0383811660048301526000916138b0917f0000000000000000000000000000000000000000000000000000000000000000169063f18858ab9060240160006040518083038186803b15801561386e57600080fd5b505afa158015613882573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526138aa9190810190615791565b83614ebb565b509392505050565b60405163f18858ab60e01b81526001600160a01b0382811660048301526060917f00000000000000000000000000000000000000000000000000000000000000009091169063f18858ab9060240160006040518083038186803b15801561391e57600080fd5b505afa158015613932573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107b69190810190615791565b803033148061396e575061396e813361320c565b6139ba5760405162461bcd60e51b815260206004820152601960248201527f534d3a206d75737420626520677561726469616e2f73656c66000000000000006044820152606401610774565b816139c481613e00565b156139e15760405162461bcd60e51b815260040161077490615d0b565b613a1c83613a0f7f000000000000000000000000000000000000000000000000000000000000000042615e40565b63f435f5a760e01b6140e2565b6001600160a01b0383167f6395bace6e0acbe4f22761b149d3cc2e88c7dde6bf4d8481825eef404cf989a1613a717f000000000000000000000000000000000000000000000000000000000000000042615e40565b6040516001600160401b03909116815260200160405180910390a2505050565b8130331480613aa55750613aa58133613c6f565b613ac15760405162461bcd60e51b815260040161077490615cd4565b82613acb81613e00565b15613ae85760405162461bcd60e51b815260040161077490615d0b565b613af484846000614237565b826001600160a01b0316846001600160a01b03167fd288ab5da2e1f37cf384a1565a3f905ad289b092fbdd31950dbbfef148c04f8860405160405180910390a350505050565b6041808202830160208101516040820151919092015160009260ff9190911691601b831480613b6c57508260ff16601c145b613bb85760405162461bcd60e51b815260206004820152601f60248201527f5574696c733a2062616420762076616c756520696e207369676e6174757265006044820152606401610774565b604080516000808252602082018084528a905260ff861692820192909252606081018490526080810183905260019060a0016020604051602081039080840390855afa158015613c0c573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610b935760405162461bcd60e51b815260206004820152601b60248201527f5574696c733a2065637265636f7665722072657475726e6564203000000000006044820152606401610774565b6000816001600160a01b0316836001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015613cb457600080fd5b505afa158015613cc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cec9190615536565b6001600160a01b0316149392505050565b6040516309ed185960e11b81526001600160a01b038216906313da30b290613d4b9030907f1626ba7e356f5979dd355a3d2bfb43e80420a480c3b854edce286a82d749686990600401615bb9565b600060405180830381600087803b158015613d6557600080fd5b505af1158015613d79573d6000803e3d6000fd5b50506040516309ed185960e11b81526001600160a01b03841692506313da30b29150613dcb9030907f150b7a023d4804d13e8c85fb27262cb750cf6ba9f9dd3bb30d90f482ceeb4b1f90600401615bb9565b600060405180830381600087803b158015613de557600080fd5b505af1158015613df9573d6000803e3d6000fd5b5050505050565b6001600160a01b03166000908152600160205260409020546001600160401b0342811691161190565b6001600160a01b038216613e7f5760405162461bcd60e51b815260206004820152601860248201527f544d3a20496e76616c69642073657373696f6e207573657200000000000000006044820152606401610774565b6000816001600160401b031611613ed85760405162461bcd60e51b815260206004820152601c60248201527f544d3a20496e76616c69642073657373696f6e206475726174696f6e000000006044820152606401610774565b6000613ef5613ef06001600160401b03841642615e40565b6150cb565b6040805180820182526001600160a01b038681168083526001600160401b0385811660208086018281528c86166000818152808452899020975188549251909516600160a01b026001600160e01b031990921694909616939093179290921790945584519182528101929092529293507f2ecea11087d1dc1431b517cbb5a559a9e33e58a1afeaac288f782c1c8bed8b8a910160405180910390a250505050565b60606000826001600160401b03811115613fc057634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015613ff357816020015b6060815260200190600190039081613fde5790505b50905060005b838110156140d95761409b8686868481811061402557634e487b7160e01b600052603260045260246000fd5b90506020028101906140379190615dac565b61404590602081019061551a565b87878581811061406557634e487b7160e01b600052603260045260246000fd5b90506020028101906140779190615dac565b6020013588888681811061274857634e487b7160e01b600052603260045260246000fd5b8282815181106140bb57634e487b7160e01b600052603260045260246000fd5b602002602001018190525080806140d190615efa565b915050613ff9565b50949350505050565b60405180604001604052806140f6846150cb565b6001600160401b0390811682526001600160e01b03199093166020918201526001600160a01b039094166000908152600185526040902081518154929095015160e01c600160401b026001600160601b031990921694909216939093179290921790915550565b6040516328207dbb60e11b81526001600160a01b0382811660048301526000916107b6917f00000000000000000000000000000000000000000000000000000000000000001690635040fb769060240160206040518083038186803b1580156141c557600080fd5b505afa1580156141d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141fd91906159c6565b60025b60008061420d8385615e80565b90506142198385615f15565b614224579050610891565b61422f816001615e40565b915050610891565b604051631017f7cd60e31b81526001600160a01b0384811660048301528381166024830152604482018390527f000000000000000000000000000000000000000000000000000000000000000016906380bfbe6890606401611b8d565b6001600160a01b0381166142ea5760405162461bcd60e51b815260206004820152601c60248201527f534d3a206e6577206f776e65722063616e6e6f74206265206e756c6c000000006044820152606401610774565b6142f4828261320c565b156108f95760405162461bcd60e51b815260206004820181905260248201527f534d3a206e6577206f776e65722063616e6e6f7420626520677561726469616e6044820152606401610774565b600060448251106144245760208201516001600160e01b0319811663a9059cbb60e01b148061438057506001600160e01b0319811663095ea7b360e01b145b8061439b57506001600160e01b0319811663a22cb46560e01b145b156143ac5750506024810151610891565b6001600160e01b031981166323b872dd60e01b14806143db57506001600160e01b03198116632142170760e11b145b806143f657506001600160e01b03198116635c46a7ef60e11b145b8061441157506001600160e01b03198116637921219560e11b145b156144225750506044810151610891565b505b5090919050565b60606000856001600160a01b031685858560405160240161444e93929190615bdc565b60408051601f198184030181529181526020820180516001600160e01b03166347b7819960e11b179052516144839190615b0c565b6000604051808303816000865af19150503d80600081146144c0576040519150601f19603f3d011682016040523d82523d6000602084013e6144c5565b606091505b50925090508080156144d8575060008251115b156144f857818060200190518101906144f1919061590f565b91506140d9565b815115614509573d6000803e3d6000fd5b806140d95760405162461bcd60e51b815260206004820152601a60248201527f424d3a2077616c6c657420696e766f6b652072657665727465640000000000006044820152606401610774565b600060248210156145a95760405162461bcd60e51b815260206004820152601660248201527f524d3a20496e76616c6964206461746157616c6c6574000000000000000000006044820152606401610774565b60006145b88360048187615e18565b8101906145c5919061551a565b6001600160a01b03908116908616149150509392505050565b60405160009061460a90601960f81b9083908c908c908c9046908d908d908d908d908d90602001615a72565b60408051601f198184030181529082905280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000091830191909152603c820152605c0160405160208183030381529060405280519060200120905098975050505050505050565b60008260011480156146d1575060018260048111156146a657634e487b7160e01b600052602160045260246000fd5b14806146d1575060048260048111156146cf57634e487b7160e01b600052602160045260246000fd5b145b15614743576001600160a01b03861660009081526002602052604090205485116146fd57506000611f28565b608085901c61470e61271043615e40565b81111561471f576000915050611f28565b50506001600160a01b03851660009081526002602052604090208490556001611f28565b6001600160a01b038616600090815260026020908152604080832087845260019081019092529091205460ff161515141561478057506000611f28565b5050506001600160a01b0392909216600090815260026020908152604080832094835260019485019091529020805460ff1916831790555090565b6001600160a01b038481166000908152602081815260408083208151808301835290549485168152600160a01b9094046001600160401b0316848301528051601f86018390048302810183019091528481529192918391614838918891889088908190840183828082843760009201829052509250613b3a915050565b905081600001516001600160a01b0316816001600160a01b0316148015610b9357504282602001516001600160401b03161015979650505050505050565b600082516000141561488a57506001612c9c565b6000606060018460048111156148b057634e487b7160e01b600052602160045260246000fd5b1415806148be575060418551115b156149635760405163f18858ab60e01b81526001600160a01b0388811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063f18858ab9060240160006040518083038186803b15801561492457600080fd5b505afa158015614938573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526149609190810190615791565b90505b6000805b604187516149759190615e80565b811015614a77576000614989898984613b3a565b905081614a185760018760048111156149b257634e487b7160e01b600052602160045260246000fd5b14156149db576149c28a82613c6f565b156149cd5750614a65565b600095505050505050612c9c565b60028760048111156149fd57634e487b7160e01b600052602160045260246000fd5b1415614a1857614a0d8a82613c6f565b15614a185750614a65565b846001600160a01b0316816001600160a01b031611614a3f57600095505050505050612c9c565b809450614a4c8482614ebb565b9450925082614a6357600095505050505050612c9c565b505b80614a6f81615efa565b915050614967565b50600198975050505050505050565b600086118015614ade57506001816004811115614ab357634e487b7160e01b600052602160045260246000fd5b1480614ade57506004816004811115614adc57634e487b7160e01b600052602160045260246000fd5b145b15611d5e5760006001600160a01b03841615614afa5783614afc565b335b9050826001148015614b2d57506001826004811115614b2b57634e487b7160e01b600052602160045260246000fd5b145b15614ce95760408051602081018252600080825291516305cfdc4d60e41b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692635cfdc4d092614b90928e9287929091600401615b7b565b60206040518083038186803b158015614ba857600080fd5b505afa158015614bbc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614be09190615844565b614ce9576040516309fa507560e11b81526001600160a01b038a8116600483015282811660248301526000917f0000000000000000000000000000000000000000000000000000000000000000909116906313f4a0ea9060440160206040518083038186803b158015614c5257600080fd5b505afa158015614c66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c8a91906159c6565b9050600081118015614c9b57504281105b614ce75760405162461bcd60e51b815260206004820152601960248201527f524d3a20726566756e64206e6f7420617574686f7269736564000000000000006044820152606401610774565b505b60006001600160a01b038616614d565760005a614d06908b615eb3565b614d12906159d8615e40565b9050614d1e893a615133565b614d28828a615133565b614d329190615e94565b9150614d4f8b84846040518060200160405280600081525061442b565b5050614e64565b60005a614d63908b615eb3565b614d6f9061927c615e40565b90506000614d7d883a615142565b9050614d898a82615133565b614d93838b615133565b614d9d9190615e94565b604080516001600160a01b038716602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790529093506000614df58e8b838561442b565b805190915015614e5f5780806020019051810190614e139190615844565b614e5f5760405162461bcd60e51b815260206004820152601a60248201527f524d3a20526566756e64207472616e73666572206661696c65640000000000006044820152606401610774565b505050505b604080516001600160a01b0388811682526020820184905280851692908d16917f22edd2bbb0b0afbdcf90d91da8a5e2100f8d8f67cdc766dee1742e9a36d6add3910160405180910390a350505050505050505050565b60006060835160001480614ed657506001600160a01b038316155b15614ee6575060009050826150c4565b60008060018651614ef79190615eb3565b6001600160401b03811115614f1c57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015614f45578160200160208202803683370190505b5090506000805b87518110156150aa578361502157878181518110614f7a57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316876001600160a01b03161415614fa45760019350615098565b614fdb888281518110614fc757634e487b7160e01b600052603260045260246000fd5b60200260200101513b63ffffffff16151590565b8015615013575061501388828151811061500557634e487b7160e01b600052603260045260246000fd5b60200260200101518861516a565b156150215760019350615098565b82518210156150985787818151811061504a57634e487b7160e01b600052603260045260246000fd5b602002602001015183838151811061507257634e487b7160e01b600052603260045260246000fd5b6001600160a01b03909216602092830291909101909101528161509481615efa565b9250505b806150a281615efa565b915050614f4c565b50826150b8576000876150bc565b6001825b945094505050505b9250929050565b6000600160401b821061512f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610774565b5090565b600081831061442457816132b2565b6000806000615150856151b4565b9092509050816151608286615e94565b611f289190615e80565b604051638da5cb5b60e01b815260009081906020818181886161a8fa600181141561519457815192505b5050826001600160a01b0316816001600160a01b03161491505092915050565b600080826001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031610156152a857600061521d7f0000000000000000000000000000000000000000000000000000000000000000856153a7565b9050806001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561525857600080fd5b505afa15801561526c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906152909190615978565b506001600160701b03918216945016915061535a9050565b60006152d4847f00000000000000000000000000000000000000000000000000000000000000006153a7565b9050806001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561530f57600080fd5b505afa158015615323573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906153479190615978565b506001600160701b039081169450169150505b811580159061536857508015155b6121d75760405162461bcd60e51b815260206004820152601060248201526f534f3a206e6f206c697175696469747960801b6044820152606401610774565b6040516001600160601b0319606084811b8216602084015283901b1660348201526000907f000000000000000000000000000000000000000000000000000000000000000090604801604051602081830303815290604052805190602001206040516020016154639291906001600160f81b0319815260609290921b6001600160601b031916600183015260158201527f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f603582015260550190565b60408051601f1981840301815291905280516020909101209392505050565b60008083601f840112615493578182fd5b5081356001600160401b038111156154a9578182fd5b6020830191508360208260051b85010111156150c457600080fd5b60008083601f8401126154d5578182fd5b5081356001600160401b038111156154eb578182fd5b6020830191508360208285010111156150c457600080fd5b80516001600160701b03811681146107b957600080fd5b60006020828403121561552b578081fd5b81356132b281615f6b565b600060208284031215615547578081fd5b81516132b281615f6b565b60008060408385031215615564578081fd5b823561556f81615f6b565b9150602083013561557f81615f6b565b809150509250929050565b60008060006040848603121561559e578081fd5b83356155a981615f6b565b925060208401356001600160401b038111156155c3578182fd5b6155cf86828701615482565b9497909650939450505050565b6000806000806000608086880312156155f3578081fd5b85356155fe81615f6b565b945060208601356001600160401b0380821115615619578283fd5b61562589838a01615482565b90965094506040880135915061563a82615f6b565b9092506060870135908082168214615650578283fd5b50809150509295509295909350565b60008060408385031215615671578182fd5b823561567c81615f6b565b946020939093013593505050565b60008060006040848603121561569e578081fd5b83356156a981615f6b565b925060208401356001600160401b038111156156c3578182fd5b6155cf868287016154c4565b6000806000806000806000806000806101008b8d0312156156ee578788fd5b8a356156f981615f6b565b995060208b01356001600160401b038082111561571457898afd5b6157208e838f016154c4565b909b50995060408d0135985060608d013591508082111561573f578687fd5b5061574c8d828e016154c4565b90975095505060808b0135935060a08b0135925060c08b013561576e81615f6b565b915060e08b013561577e81615f6b565b809150509295989b9194979a5092959850565b600060208083850312156157a3578182fd5b82516001600160401b03808211156157b9578384fd5b818501915085601f8301126157cc578384fd5b8151818111156157de576157de615f55565b8060051b91506157ef848301615dc1565b8181528481019084860184860187018a1015615809578788fd5b8795505b83861015615837578051945061582285615f6b565b8483526001959095019491860191860161580d565b5098975050505050505050565b600060208284031215615855578081fd5b815180151581146132b2578182fd5b60008060408385031215615876578182fd5b8235915060208301356001600160401b03811115615892578182fd5b8301601f810185136158a2578182fd5b80356158b56158b082615df1565b615dc1565b8181528660208385010111156158c9578384fd5b81602084016020830137908101602001929092525090939092509050565b6000602082840312156158f8578081fd5b81356001600160e01b0319811681146132b2578182fd5b600060208284031215615920578081fd5b81516001600160401b03811115615935578182fd5b8201601f81018413615945578182fd5b80516159536158b082615df1565b818152856020838501011115615967578384fd5b611f28826020830160208601615eca565b60008060006060848603121561598c578081fd5b61599584615503565b92506159a360208501615503565b9150604084015163ffffffff811681146159bb578182fd5b809150509250925092565b6000602082840312156159d7578081fd5b5051919050565b600081518084526159f6816020860160208601615eca565b601f01601f19169290920160200192915050565b6001600160601b0319606093841b811682529190921b166014820152693932bb37b5b0ba34b7b760b11b602882015260320190565b6001600160601b0319606093841b811682529190921b1660148201526730b23234ba34b7b760c11b602882015260300190565b600060ff60f81b808e168352808d166001840152506bffffffffffffffffffffffff19808c60601b1660028401528a60168401528951615ab9816036860160208e01615eca565b909201603681019890985250605687019590955260768601939093526096850191909152606090811b831660b68501521b1660ca82015260de0195945050505050565b6000828483379101908152919050565b60008251615b1e818460208701615eca565b9190910192915050565b60006001600160a01b038088168352808716602084015280861660408401525060806060830152826080830152828460a084013781830160a090810191909152601f909201601f19160101949350505050565b60006001600160a01b038087168352808616602084015280851660408401525060806060830152615baf60808301846159de565b9695505050505050565b6001600160a01b039290921682526001600160e01b031916602082015260400190565b60006001600160a01b038516825283602083015260606040830152611f2860608301846159de565b6020808252825182820181905260009190848201906040850190845b81811015615c455783516001600160a01b031683529284019291840191600101615c20565b50909695505050505050565b6000602080830181845280855180835260408601915060408160051b8701019250838701855b82811015615ca557603f19888603018452615c938583516159de565b94509285019290850190600101615c77565b5092979650505050505050565b600060408252615cc560408301856159de565b90508260208301529392505050565b6020808252601d908201527f424d3a206d7573742062652077616c6c6574206f776e65722f73656c66000000604082015260600190565b60208082526011908201527010934e881dd85b1b195d081b1bd8dad959607a1b604082015260600190565b8281526040810160058310615d5b57634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b6000808335601e19843603018112615d7e578283fd5b8301803591506001600160401b03821115615d97578283fd5b6020019150368190038213156150c457600080fd5b60008235605e19833603018112615b1e578182fd5b604051601f8201601f191681016001600160401b0381118282101715615de957615de9615f55565b604052919050565b60006001600160401b03821115615e0a57615e0a615f55565b50601f01601f191660200190565b60008085851115615e27578182fd5b83861115615e33578182fd5b5050820193919092039150565b60008219821115615e5357615e53615f29565b500190565b600063ffffffff808316818516808303821115615e7757615e77615f29565b01949350505050565b600082615e8f57615e8f615f3f565b500490565b6000816000190483118215151615615eae57615eae615f29565b500290565b600082821015615ec557615ec5615f29565b500390565b60005b83811015615ee5578181015183820152602001615ecd565b83811115615ef4576000848401525b50505050565b6000600019821415615f0e57615f0e615f29565b5060010190565b600082615f2457615f24615f3f565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114615f8057600080fd5b5056fea264697066735822122081d4fd652d7092f6bc4fbd840c7ca9e79421eccf5ef61d2be2b36c17356df9f564736f6c63430008030033000000000000000000000000c17d432bd8e8850fd7b32b0270f5afac65db010500000000000000000000000044da3a8051ba88eab0440db3779cab9d679ae76f000000000000000000000000391f0e86da951c03b1183c60b195090671adea880000000000000000000000003d31d91003f9327623caec2e326b6bc681bc31670000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d000000000000000000000000000000000000000000000000000000000001fa40000000000000000000000000000000000000000000000000000000000000a8c0000000000000000000000000000000000000000000000000000000000002a3000000000000000000000000000000000000000000000000000000000000069780
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102485760003560e01c80636ff6ec7c1161013b578063ba821088116100b8578063eac01e471161007c578063eac01e47146106cb578063f143ddba14610517578063f18858ab146106de578063f435f5a7146106fe578063f8d3277d1461071157610248565b8063ba8210881461066c578063c68452101461067f578063c90db44714610692578063d4ee9734146106a5578063e0724b6e146106b857610248565b8063a3f4df7e116100ff578063a3f4df7e1461060a578063a5efb23514610620578063a6eb069014610633578063b0ba4da014610646578063b6b352721461065957610248565b80636ff6ec7c1461051757806370135f521461052a5780638c8e13b91461053d5780639769c3fe146105775780639be65a60146105f757610248565b80633b73d67f116101c957806359b4958a1161018d57806359b4958a146104765780635a1db8c41461048957806360c0fdc01461049c5780636b9db4e6146104d95780636d4354211461050457610248565b80633b73d67f146104095780634a4fbeec1461042a5780634b3ef0541461043d5780635040fb7614610450578063575182431461046357610248565b806325b509341161021057806325b50934146103865780632960739b146103995780632d0335ab146103ac5780632f6c493c146103e3578063315a7af3146103f657610248565b806301ffc9a7146102ea5780631626ba7e1461031257806319ab453c1461033e5780631d97d8cc146103535780632437b75c14610366575b600061028a6000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061072492505050565b90506001600160e01b03198116630a85bd0160e11b14806102bb57506001600160e01b0319811663f23a6e6160e01b145b806102d657506001600160e01b0319811663bc197c8160e01b145b156102e75760046000803760206000f35b50005b6102fd6102f83660046158e7565b610785565b60405190151581526020015b60405180910390f35b610325610320366004615864565b6107be565b6040516001600160e01b03199091168152602001610309565b61035161034c36600461551a565b610897565b005b610351610361366004615552565b6108fd565b6103796103743660046155dc565b610b10565b6040516103099190615c51565b6102fd6103943660046158e7565b610b9e565b6103516103a7366004615552565b610c22565b6103d56103ba36600461551a565b6001600160a01b031660009081526002602052604090205490565b604051908152602001610309565b6103516103f136600461551a565b610d66565b61035161040436600461551a565b610ed7565b61041c61041736600461568a565b6110ab565b604051610309929190615d36565b6102fd61043836600461551a565b611478565b61035161044b366004615552565b611483565b6103d561045e36600461551a565b6116d2565b610351610471366004615552565b611770565b61035161048436600461551a565b6119e8565b610351610497366004615552565b611bc4565b6102fd6104aa36600461565f565b6001600160a01b0391909116600090815260026020908152604080832093835260019093019052205460ff1690565b6104ec6104e736600461551a565b611d68565b6040516001600160401b039091168152602001610309565b610351610512366004615552565b611da3565b61037961052536600461558a565b611eb0565b610351610538366004615552565b611f31565b61055061054b36600461551a565b6121a8565b604080516001600160a01b0390931683526001600160401b03909116602083015201610309565b6105c461058536600461551a565b6001600160a01b0390811660009081526003602052604090205490811691600160a01b82046001600160401b031691600160e01b900463ffffffff1690565b604080516001600160a01b0390941684526001600160401b03909216602084015263ffffffff1690820152606001610309565b61035161060536600461551a565b6121dc565b6103d56b417267656e744d6f64756c6560a01b81565b61037961062e36600461558a565b612301565b610351610641366004615552565b6127eb565b610351610654366004615552565b61292f565b6102fd610667366004615552565b612be5565b61035161067a36600461551a565b612ca4565b61035161068d366004615552565b612d77565b6103516106a036600461551a565b6130e3565b6102fd6106b3366004615552565b61320c565b6102fd6106c63660046156cf565b6132b9565b6102fd6106d9366004615552565b613806565b6106f16106ec36600461551a565b6138b8565b6040516103099190615c04565b61035161070c36600461551a565b61395a565b61035161071f366004615552565b613a91565b600060048251101561077d5760405162461bcd60e51b815260206004820152601d60248201527f5574696c733a20496e76616c69642066756e6374696f6e50726566697800000060448201526064015b60405180910390fd5b506020015190565b60006001600160e01b031982166301ffc9a760e01b14806107b657506001600160e01b03198216630271189760e51b145b90505b919050565b600081516041146108115760405162461bcd60e51b815260206004820152601c60248201527f544d3a20696e76616c6964207369676e6174757265206c656e677468000000006044820152606401610774565b600061081f84846000613b3a565b905061082b3382613c6f565b61086c5760405162461bcd60e51b81526020600482015260126024820152712a269d1024b73b30b634b21039b4b3b732b960711b6044820152606401610774565b7f1626ba7e356f5979dd355a3d2bfb43e80420a480c3b854edce286a82d74968699150505b92915050565b80336001600160a01b038216146108f05760405162461bcd60e51b815260206004820152601960248201527f424d3a2063616c6c6572206d7573742062652077616c6c6574000000000000006044820152606401610774565b6108f982613cfd565b5050565b813033148061091157506109118133613c6f565b61092d5760405162461bcd60e51b815260040161077490615cd4565b610937838361320c565b6109835760405162461bcd60e51b815260206004820152601d60248201527f534d3a206d757374206265206578697374696e6720677561726469616e0000006044820152606401610774565b60008383604051602001610998929190615a0a565b60408051601f1981840301815291815281516020928301206001600160a01b0387166000908152600484528281208282529384905291909120549092501580610a195750600082815260208290526040902054610a16907f000000000000000000000000000000000000000000000000000000000000a8c090615e40565b42115b610a655760405162461bcd60e51b815260206004820152601c60248201527f534d3a206475706c69636174652070656e64696e67207265766f6b65000000006044820152606401610774565b610a8f7f000000000000000000000000000000000000000000000000000000000001fa4042615e40565b6000838152602083905260409020556001600160a01b038085169086167f9746f6868f544595794833da53250bd19e72334733336cfd5dd6fbc5f6a6ac42610af77f000000000000000000000000000000000000000000000000000000000001fa4042615e40565b6040519081526020015b60405180910390a35050505050565b6060303314610b565760405162461bcd60e51b8152602060048201526012602482015271424d3a206d757374206265206d6f64756c6560701b6044820152606401610774565b85610b6081613e00565b15610b7d5760405162461bcd60e51b815260040161077490615d0b565b610b88878585613e29565b610b93878787613f96565b979650505050505050565b60006001600160e01b03198216630b135d3f60e11b1480610bcf57506001600160e01b03198216630a85bd0160e11b145b80610bea57506001600160e01b031982166301ffc9a760e01b145b80610c0557506001600160e01b0319821663f23a6e6160e01b145b806107b65750506001600160e01b03191663bc197c8160e01b1490565b8130331480610c365750610c368133613c6f565b610c525760405162461bcd60e51b815260040161077490615cd4565b82610c5c81613e00565b15610c795760405162461bcd60e51b815260040161077490615d0b565b60008484604051602001610c8e929190615a0a565b60408051601f1981840301815291815281516020928301206001600160a01b038816600090815260048452828120828252938490529190912054909250610d175760405162461bcd60e51b815260206004820152601a60248201527f534d3a20756e6b6e6f776e2070656e64696e67207265766f6b650000000000006044820152606401610774565b600082815260208290526040808220829055516001600160a01b0380881692908916917fc0b205956d5e27c296695de329b5a014584a4f51824b1725a0eefc1174d6dbd59190a3505050505050565b8030331480610d7a5750610d7a813361320c565b610dc65760405162461bcd60e51b815260206004820152601960248201527f534d3a206d75737420626520677561726469616e2f73656c66000000000000006044820152606401610774565b81610dd081613e00565b610e1c5760405162461bcd60e51b815260206004820152601960248201527f424d3a2077616c6c6574206d757374206265206c6f636b6564000000000000006044820152606401610774565b6001600160a01b038316600090815260016020526040902054600160401b900460e01b6001600160e01b03191663f435f5a760e01b14610e925760405162461bcd60e51b8152602060048201526011602482015270534d3a2063616e6e6f7420756e6c6f636b60781b6044820152606401610774565b610e9e836000806140e2565b6040516001600160a01b038416907f7e6adfec7e3f286831a0200a754127c171a2da564078722cb97704741bbdb0ea90600090a2505050565b6001600160a01b0381166000908152600360205260409020548190600160a01b90046001600160401b0316610f485760405162461bcd60e51b8152602060048201526017602482015276534d3a206e6f206f6e676f696e67207265636f7665727960481b6044820152606401610774565b6001600160a01b038216600090815260036020526040902080546001600160401b03600160a01b90910481164290911611610fc55760405162461bcd60e51b815260206004820152601b60248201527f534d3a206f6e676f696e67207265636f7665727920706572696f6400000000006044820152606401610774565b80546001600160a01b03848116600090815260036020908152604080832083905590829052902080546001600160e01b0319169055166040516313af403560e01b81526001600160a01b0382811660048301528516906313af403590602401600060405180830381600087803b15801561103e57600080fd5b505af1158015611052573d6000803e3d6000fd5b505050506110658460008060e01b6140e2565b806001600160a01b0316846001600160a01b03167fd8667de85dae2d56d76e700d16de53d21ac2ce4d5549cb0bf51c55fdc37f0bc160405160405180910390a350505050565b60008060006110ef85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061072492505050565b90506001600160e01b0319811663a5efb23560e01b148061112057506001600160e01b03198116635751824360e01b145b8061113b57506001600160e01b0319811663f8d3277d60e01b145b8061115657506001600160e01b03198116632cda4ac560e11b145b8061117157506001600160e01b03198116631750421160e31b145b8061118c57506001600160e01b031981166316876e3160e21b145b806111a757506001600160e01b03198116630c68452160e41b145b806111c257506001600160e01b03198116630765f63360e21b145b806111dd57506001600160e01b03198116630a6eb06960e41b145b806111f857506001600160e01b03198116632960739b60e01b145b1561120a576001809250925050611470565b6001600160e01b03198116631bfdbb1f60e21b141561123157600160049250925050611470565b6001600160e01b03198116630585d26d60e51b14156112b45760006112558761415d565b9050600081116112a75760405162461bcd60e51b815260206004820152601e60248201527f414d3a206e6f20677561726469616e7320736574206f6e2077616c6c657400006044820152606401610774565b9250600391506114709050565b6001600160e01b0319811663c90db44760e01b141561131d576001600160a01b03861660009081526003602052604081205461130f9061130290600160e01b900463ffffffff166001615e58565b63ffffffff166002614200565b935060029250611470915050565b6001600160e01b031981166378a1eedd60e11b148061134c57506001600160e01b0319811663090dedd760e21b145b8061136757506001600160e01b03198116636d43542160e01b145b156113955760006113778761415d565b90506000611386826001615e40565b94506001935061147092505050565b6001600160e01b0319811663315a7af360e01b14806113c457506001600160e01b03198116633809afa960e11b145b806113df57506001600160e01b031981166312cfbc1560e21b145b156113f1576000809250925050611470565b6001600160e01b0319811663f435f5a760e01b148061142057506001600160e01b03198116630bdb124f60e21b145b1561143357600160039250925050611470565b60405162461bcd60e51b815260206004820152601260248201527114d34e881d5b9adb9bdddb881b595d1a1bd960721b6044820152606401610774565b935093915050565b60006107b682613e00565b60008282604051602001611498929190615a0a565b60408051601f1981840301815291815281516020928301206001600160a01b0386166000908152600484528281208282529384905291909120549092506115215760405162461bcd60e51b815260206004820152601a60248201527f534d3a20756e6b6e6f776e2070656e64696e67207265766f6b650000000000006044820152606401610774565b600082815260208290526040902054421161157e5760405162461bcd60e51b815260206004820152601b60248201527f534d3a2070656e64696e67207265766f6b65206e6f74206f76657200000000006044820152606401610774565b6000828152602082905260409020546115b8907f000000000000000000000000000000000000000000000000000000000000a8c090615e40565b42106116065760405162461bcd60e51b815260206004820152601a60248201527f534d3a2070656e64696e67207265766f6b6520657870697265640000000000006044820152606401610774565b604051630765f63360e21b81526001600160a01b03858116600483015284811660248301527f00000000000000000000000044da3a8051ba88eab0440db3779cab9d679ae76f1690631d97d8cc90604401600060405180830381600087803b15801561167157600080fd5b505af1158015611685573d6000803e3d6000fd5b50506040516001600160a01b038087169350871691507f548f10dcba266544123ad8cf8284f25c4baa659cba25dbdf16a06ea11235de9b90600090a3600091825260205260408120555050565b6040516328207dbb60e11b81526001600160a01b0382811660048301526000917f00000000000000000000000044da3a8051ba88eab0440db3779cab9d679ae76f90911690635040fb769060240160206040518083038186803b15801561173857600080fd5b505afa15801561174c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b691906159c6565b813033148061178457506117848133613c6f565b6117a05760405162461bcd60e51b815260040161077490615cd4565b826117aa81613e00565b156117c75760405162461bcd60e51b815260040161077490615d0b565b836001600160a01b0316836001600160a01b031614156118295760405162461bcd60e51b815260206004820152601b60248201527f544d3a2043616e6e6f742077686974656c6973742077616c6c657400000000006044820152606401610774565b604051630bcd4ebb60e01b81526001600160a01b0384811660048301527f000000000000000000000000c17d432bd8e8850fd7b32b0270f5afac65db01051690630bcd4ebb9060240160206040518083038186803b15801561188a57600080fd5b505afa15801561189e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c29190615844565b1561190f5760405162461bcd60e51b815260206004820152601b60248201527f544d3a2043616e6e6f742077686974656c697374206d6f64756c6500000000006044820152606401610774565b6119198484612be5565b156119665760405162461bcd60e51b815260206004820152601e60248201527f544d3a2074617267657420616c72656164792077686974656c697374656400006044820152606401610774565b60006119927f000000000000000000000000000000000000000000000000000000000001fa4042615e40565b905061199f858583614237565b6040516001600160401b03821681526001600160a01b0380861691908716907f1f57f9641d3e8733ed672fef5ac85464bd7215ef2f21e83428e8408248b13dcd90602001610b01565b80303314806119fc57506119fc8133613c6f565b611a185760405162461bcd60e51b815260040161077490615cd4565b81611a2281613e00565b15611a3f5760405162461bcd60e51b815260040161077490615d0b565b6040516309ed185960e11b81526001600160a01b038416906313da30b290611a8d9030907f01ffc9a7a5cef8baa21ed3c5c0d7e23accb804b619e9333b597f47a0d84076e290600401615bb9565b600060405180830381600087803b158015611aa757600080fd5b505af1158015611abb573d6000803e3d6000fd5b50506040516309ed185960e11b81526001600160a01b03861692506313da30b29150611b0d9030907ff23a6e612e1ff4830e658fe43f4e3cb4a5f8170bd5d9e69fb5d7a7fa9e4fdf9790600401615bb9565b600060405180830381600087803b158015611b2757600080fd5b505af1158015611b3b573d6000803e3d6000fd5b50506040516309ed185960e11b81526001600160a01b03861692506313da30b29150611b8d9030907fbc197c819b3e337a6f9652dd10becd7eef83032af3b9d958d3d42f669414662190600401615bb9565b600060405180830381600087803b158015611ba757600080fd5b505af1158015611bbb573d6000803e3d6000fd5b50505050505050565b8130331480611bd85750611bd88133613c6f565b611bf45760405162461bcd60e51b815260040161077490615cd4565b82611bfe81613e00565b15611c1b5760405162461bcd60e51b815260040161077490615d0b565b604051630bcd4ebb60e01b81526001600160a01b0384811660048301527f000000000000000000000000c17d432bd8e8850fd7b32b0270f5afac65db01051690630bcd4ebb9060240160206040518083038186803b158015611c7c57600080fd5b505afa158015611c90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb49190615844565b611d005760405162461bcd60e51b815260206004820152601c60248201527f414d3a206d6f64756c65206973206e6f742072656769737465726564000000006044820152606401610774565b604051631f17732d60e01b81526001600160a01b03848116600483015260016024830152851690631f17732d90604401600060405180830381600087803b158015611d4a57600080fd5b505af1158015611d5e573d6000803e3d6000fd5b5050505050505050565b6000611d7382613e00565b611d7e5760006107b6565b506001600160a01b03166000908152600160205260409020546001600160401b031690565b303314611de75760405162461bcd60e51b8152602060048201526012602482015271424d3a206d757374206265206d6f64756c6560701b6044820152606401610774565b81611df181613e00565b15611e0e5760405162461bcd60e51b815260040161077490615d0b565b611e188383614294565b6040516313af403560e01b81526001600160a01b0383811660048301528416906313af403590602401600060405180830381600087803b158015611e5b57600080fd5b505af1158015611e6f573d6000803e3d6000fd5b50506040516001600160a01b038086169350861691507f0d18b5fd22306e373229b9439188228edca81207d1667f604daf6cef8aa3ee6790600090a3505050565b6060303314611ef65760405162461bcd60e51b8152602060048201526012602482015271424d3a206d757374206265206d6f64756c6560701b6044820152606401610774565b83611f0081613e00565b15611f1d5760405162461bcd60e51b815260040161077490615d0b565b611f28858585613f96565b95945050505050565b81611f3b81613e00565b15611f585760405162461bcd60e51b815260040161077490615d0b565b60008383604051602001611f6d929190615a3f565b60408051601f1981840301815291815281516020928301206001600160a01b038716600090815260048452828120828252938490529190912054909250611ff65760405162461bcd60e51b815260206004820152601c60248201527f534d3a20756e6b6e6f776e2070656e64696e67206164646974696f6e000000006044820152606401610774565b60008281526020829052604090205442116120535760405162461bcd60e51b815260206004820152601d60248201527f534d3a2070656e64696e67206164646974696f6e206e6f74206f7665720000006044820152606401610774565b60008281526020829052604090205461208d907f000000000000000000000000000000000000000000000000000000000000a8c090615e40565b42106120db5760405162461bcd60e51b815260206004820152601c60248201527f534d3a2070656e64696e67206164646974696f6e2065787069726564000000006044820152606401610774565b604051630c68452160e41b81526001600160a01b03868116600483015285811660248301527f00000000000000000000000044da3a8051ba88eab0440db3779cab9d679ae76f169063c684521090604401600060405180830381600087803b15801561214657600080fd5b505af115801561215a573d6000803e3d6000fd5b50506040516001600160a01b038088169350881691507fbc3292102fa77e083913064b282926717cdfaede4d35f553d66366c0a3da755a90600090a360009182526020526040812055505050565b6001600160a01b0381811660009081526020819052604090205490811690600160a01b90046001600160401b03165b915091565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b15801561221e57600080fd5b505afa158015612232573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225691906159c6565b60405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000c17d432bd8e8850fd7b32b0270f5afac65db010581166004830152602482018390529192509083169063a9059cbb90604401602060405180830381600087803b1580156122c457600080fd5b505af11580156122d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122fc9190615844565b505050565b60603033146123475760405162461bcd60e51b8152602060048201526012602482015271424d3a206d757374206265206d6f64756c6560701b6044820152606401610774565b8361235181613e00565b1561236e5760405162461bcd60e51b815260040161077490615d0b565b6000836001600160401b0381111561239657634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156123c957816020015b60608152602001906001900390816123b45790505b50905060005b848110156127e15760006124968787848181106123fc57634e487b7160e01b600052603260045260246000fd5b905060200281019061240e9190615dac565b61241c90602081019061551a565b88888581811061243c57634e487b7160e01b600052603260045260246000fd5b905060200281019061244e9190615dac565b61245c906040810190615d68565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061434192505050565b90508686838181106124b857634e487b7160e01b600052603260045260246000fd5b90506020028101906124ca9190615dac565b60200135158061252a57508686838181106124f557634e487b7160e01b600052603260045260246000fd5b90506020028101906125079190615dac565b61251590602081019061551a565b6001600160a01b0316816001600160a01b0316145b8015612662575061253b8882612be5565b8061266257507f0000000000000000000000003d31d91003f9327623caec2e326b6bc681bc31676001600160a01b0316635cfdc4d089838a8a8781811061259257634e487b7160e01b600052603260045260246000fd5b90506020028101906125a49190615dac565b6125b290602081019061551a565b8b8b888181106125d257634e487b7160e01b600052603260045260246000fd5b90506020028101906125e49190615dac565b6125f2906040810190615d68565b6040518663ffffffff1660e01b8152600401612612959493929190615b28565b60206040518083038186803b15801561262a57600080fd5b505afa15801561263e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126629190615844565b6126ae5760405162461bcd60e51b815260206004820152601760248201527f544d3a2063616c6c206e6f7420617574686f72697365640000000000000000006044820152606401610774565b6127a2888888858181106126d257634e487b7160e01b600052603260045260246000fd5b90506020028101906126e49190615dac565b6126f290602081019061551a565b89898681811061271257634e487b7160e01b600052603260045260246000fd5b90506020028101906127249190615dac565b602001358a8a8781811061274857634e487b7160e01b600052603260045260246000fd5b905060200281019061275a9190615dac565b612768906040810190615d68565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061442b92505050565b8383815181106127c257634e487b7160e01b600052603260045260246000fd5b60200260200101819052505080806127d990615efa565b9150506123cf565b5095945050505050565b81303314806127ff57506127ff8133613c6f565b61281b5760405162461bcd60e51b815260040161077490615cd4565b8261282581613e00565b156128425760405162461bcd60e51b815260040161077490615d0b565b60008484604051602001612857929190615a3f565b60408051601f1981840301815291815281516020928301206001600160a01b0388166000908152600484528281208282529384905291909120549092506128e05760405162461bcd60e51b815260206004820152601c60248201527f534d3a20756e6b6e6f776e2070656e64696e67206164646974696f6e000000006044820152606401610774565b600082815260208290526040808220829055516001600160a01b0380881692908916917faa13b27c23e9e3f3d5f3861a53b7a2931e019170a6a19ed64942e26a1dd5987a9190a3505050505050565b3033146129735760405162461bcd60e51b8152602060048201526012602482015271424d3a206d757374206265206d6f64756c6560701b6044820152606401610774565b6001600160a01b0382166000908152600360205260409020548290600160a01b90046001600160401b0316156129eb5760405162461bcd60e51b815260206004820152601460248201527f534d3a206f6e676f696e67207265636f766572790000000000000000000000006044820152606401610774565b6129f58383614294565b6000612a217f000000000000000000000000000000000000000000000000000000000002a30042615e40565b604080516060810182526001600160a01b0380871682526001600160401b038416602083015282516328207dbb60e11b815288821660048201529394509092918301917f00000000000000000000000044da3a8051ba88eab0440db3779cab9d679ae76f90911690635040fb769060240160206040518083038186803b158015612aaa57600080fd5b505afa158015612abe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ae291906159c6565b63ffffffff9081169091526001600160a01b0380871660009081526003602090815260409182902085518154928701519690930151909416600160e01b026001600160e01b036001600160401b03909616600160a01b026001600160e01b031990921692909316919091171792909216919091179055612b9384612b867f000000000000000000000000000000000000000000000000000000000006978042615e40565b630585d26d60e51b6140e2565b6040516001600160401b03821681526001600160a01b0380851691908616907f5f59bfd9baba55ae30bb440923cbbe30987d50e12a4e9134ffac3fd9afc3526d9060200160405180910390a350505050565b6040516309fa507560e11b81526001600160a01b038381166004830152828116602483015260009182917f000000000000000000000000391f0e86da951c03b1183c60b195090671adea8816906313f4a0ea9060440160206040518083038186803b158015612c5357600080fd5b505afa158015612c67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c8b91906159c6565b9050600081118015612c9c57504281105b949350505050565b8030331480612cb85750612cb88133613c6f565b612cd45760405162461bcd60e51b815260040161077490615cd4565b81612cde81613e00565b15612cfb5760405162461bcd60e51b815260040161077490615d0b565b6001600160a01b038381166000818152602081815260409182902054915191909316815290917feb290a597820eccc6b8b31f942bd97c633d5138f4d849751f770f3cb3900e57a910160405180910390a26122fc836001600160a01b0316600090815260208190526040902080546001600160e01b0319169055565b8130331480612d8b5750612d8b8133613c6f565b612da75760405162461bcd60e51b815260040161077490615cd4565b82612db181613e00565b15612dce5760405162461bcd60e51b815260040161077490615d0b565b612dd88484613c6f565b15612e255760405162461bcd60e51b815260206004820152601c60248201527f534d3a20677561726469616e2063616e6e6f74206265206f776e6572000000006044820152606401610774565b612e2f848461320c565b15612e7c5760405162461bcd60e51b815260206004820152601660248201527f534d3a206475706c696361746520677561726469616e000000000000000000006044820152606401610774565b60408051600481526024810182526020810180516001600160e01b0316638da5cb5b60e01b17905290516000916001600160a01b038616916161a891612ec191615b0c565b60006040518083038160008787f1925050503d8060008114612eff576040519150601f19603f3d011682016040523d82523d6000602084013e612f04565b606091505b5050905080612f555760405162461bcd60e51b815260206004820152601d60248201527f534d3a206d75737420626520454f412f417267656e742077616c6c65740000006044820152606401610774565b60008585604051602001612f6a929190615a3f565b60408051601f1981840301815291815281516020928301206001600160a01b0389166000908152600484528281208282529384905291909120549092501580612feb5750600082815260208290526040902054612fe8907f000000000000000000000000000000000000000000000000000000000000a8c090615e40565b42115b6130375760405162461bcd60e51b815260206004820152601e60248201527f534d3a206475706c69636174652070656e64696e67206164646974696f6e00006044820152606401610774565b6130617f000000000000000000000000000000000000000000000000000000000001fa4042615e40565b6000838152602083905260409020556001600160a01b038087169088167fe4166e4bc55a182bd13d933553241bb3441b91d15fbc74c5c752f96965563bde6130c97f000000000000000000000000000000000000000000000000000000000001fa4042615e40565b60405190815260200160405180910390a350505050505050565b3033146131275760405162461bcd60e51b8152602060048201526012602482015271424d3a206d757374206265206d6f64756c6560701b6044820152606401610774565b6001600160a01b0381166000908152600360205260409020548190600160a01b90046001600160401b03166131985760405162461bcd60e51b8152602060048201526017602482015276534d3a206e6f206f6e676f696e67207265636f7665727960481b6044820152606401610774565b6001600160a01b038083166000908152600360205260408120805490829055909116906131c7908490806140e2565b806001600160a01b0316836001600160a01b03167fc45926607303da71dbeffd2ed5c6b00f581982586b697655d19ae4c4d558f25960405160405180910390a3505050565b60405163353ba5cd60e21b81526001600160a01b03838116600483015282811660248301526000917f00000000000000000000000044da3a8051ba88eab0440db3779cab9d679ae76f9091169063d4ee97349060440160206040518083038186803b15801561327a57600080fd5b505afa15801561328e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b29190615844565b9392505050565b6000806132c7366008615e94565b5a6132d490615208615e40565b6132de9190615e40565b9050848110156133305760405162461bcd60e51b815260206004820152601b60248201527f524d3a206e6f7420656e6f756768206761732070726f766964656400000000006044820152606401610774565b61333b8c8c8c614556565b6133875760405162461bcd60e51b815260206004820152601e60248201527f524d3a20546172676574206f66205f6461746120213d205f77616c6c657400006044820152606401610774565b6133908c613e00565b158061339a575085155b6133e65760405162461bcd60e51b815260206004820152601860248201527f524d3a204c6f636b65642077616c6c657420726566756e6400000000000000006044820152606401610774565b6134176040805160a08101909152600080825260208201908152600060208201819052604082015260609081015290565b6134228d8d8d6110ab565b826020810182600481111561344757634e487b7160e01b600052602160045260246000fd5b600481111561346657634e487b7160e01b600052602160045260246000fd5b90529190915250805115158061349f575060008160200151600481111561349d57634e487b7160e01b600052602160045260246000fd5b145b6134eb5760405162461bcd60e51b815260206004820152601f60248201527f524d3a2057726f6e67207369676e617475726520726571756972656d656e74006044820152606401610774565b805188906134fa906041615e94565b146135475760405162461bcd60e51b815260206004820152601e60248201527f524d3a2057726f6e67206e756d626572206f66207369676e61747572657300006044820152606401610774565b61359c3060008e8e8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508d8b8b8b8b6145de565b8160400181815250506135be8d8b836040015184600001518560200151614677565b61360a5760405162461bcd60e51b815260206004820152601560248201527f524d3a204475706c6963617465207265717565737400000000000000000000006044820152606401610774565b60048160200151600481111561363057634e487b7160e01b600052602160045260246000fd5b141561368d576136468d82604001518b8b6147bb565b6136885760405162461bcd60e51b815260206004820152601360248201527229269d1024b73b30b634b21039b2b9b9b4b7b760691b6044820152606401610774565b613722565b6136d68d82604001518b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506020850151614876565b6137225760405162461bcd60e51b815260206004820152601660248201527f524d3a20496e76616c6964207369676e617475726573000000000000000000006044820152606401610774565b6040513090613734908e908e90615afc565b6000604051808303816000865af19150503d8060008114613771576040519150601f19603f3d011682016040523d82523d6000602084013e613776565b606091505b50608083015215156060820152805160208201516137a0918f9185918b918b918b918b9190614a86565b806060015115158d6001600160a01b03167f7da4525a280527268ba2e963ee6c1b18f43c9507bcb1d2560f652ab17c76e90a836080015184604001516040516137ea929190615cb2565b60405180910390a3606001519c9b505050505050505050505050565b60405163f18858ab60e01b81526001600160a01b0383811660048301526000916138b0917f00000000000000000000000044da3a8051ba88eab0440db3779cab9d679ae76f169063f18858ab9060240160006040518083038186803b15801561386e57600080fd5b505afa158015613882573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526138aa9190810190615791565b83614ebb565b509392505050565b60405163f18858ab60e01b81526001600160a01b0382811660048301526060917f00000000000000000000000044da3a8051ba88eab0440db3779cab9d679ae76f9091169063f18858ab9060240160006040518083038186803b15801561391e57600080fd5b505afa158015613932573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107b69190810190615791565b803033148061396e575061396e813361320c565b6139ba5760405162461bcd60e51b815260206004820152601960248201527f534d3a206d75737420626520677561726469616e2f73656c66000000000000006044820152606401610774565b816139c481613e00565b156139e15760405162461bcd60e51b815260040161077490615d0b565b613a1c83613a0f7f000000000000000000000000000000000000000000000000000000000006978042615e40565b63f435f5a760e01b6140e2565b6001600160a01b0383167f6395bace6e0acbe4f22761b149d3cc2e88c7dde6bf4d8481825eef404cf989a1613a717f000000000000000000000000000000000000000000000000000000000006978042615e40565b6040516001600160401b03909116815260200160405180910390a2505050565b8130331480613aa55750613aa58133613c6f565b613ac15760405162461bcd60e51b815260040161077490615cd4565b82613acb81613e00565b15613ae85760405162461bcd60e51b815260040161077490615d0b565b613af484846000614237565b826001600160a01b0316846001600160a01b03167fd288ab5da2e1f37cf384a1565a3f905ad289b092fbdd31950dbbfef148c04f8860405160405180910390a350505050565b6041808202830160208101516040820151919092015160009260ff9190911691601b831480613b6c57508260ff16601c145b613bb85760405162461bcd60e51b815260206004820152601f60248201527f5574696c733a2062616420762076616c756520696e207369676e6174757265006044820152606401610774565b604080516000808252602082018084528a905260ff861692820192909252606081018490526080810183905260019060a0016020604051602081039080840390855afa158015613c0c573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610b935760405162461bcd60e51b815260206004820152601b60248201527f5574696c733a2065637265636f7665722072657475726e6564203000000000006044820152606401610774565b6000816001600160a01b0316836001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015613cb457600080fd5b505afa158015613cc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cec9190615536565b6001600160a01b0316149392505050565b6040516309ed185960e11b81526001600160a01b038216906313da30b290613d4b9030907f1626ba7e356f5979dd355a3d2bfb43e80420a480c3b854edce286a82d749686990600401615bb9565b600060405180830381600087803b158015613d6557600080fd5b505af1158015613d79573d6000803e3d6000fd5b50506040516309ed185960e11b81526001600160a01b03841692506313da30b29150613dcb9030907f150b7a023d4804d13e8c85fb27262cb750cf6ba9f9dd3bb30d90f482ceeb4b1f90600401615bb9565b600060405180830381600087803b158015613de557600080fd5b505af1158015613df9573d6000803e3d6000fd5b5050505050565b6001600160a01b03166000908152600160205260409020546001600160401b0342811691161190565b6001600160a01b038216613e7f5760405162461bcd60e51b815260206004820152601860248201527f544d3a20496e76616c69642073657373696f6e207573657200000000000000006044820152606401610774565b6000816001600160401b031611613ed85760405162461bcd60e51b815260206004820152601c60248201527f544d3a20496e76616c69642073657373696f6e206475726174696f6e000000006044820152606401610774565b6000613ef5613ef06001600160401b03841642615e40565b6150cb565b6040805180820182526001600160a01b038681168083526001600160401b0385811660208086018281528c86166000818152808452899020975188549251909516600160a01b026001600160e01b031990921694909616939093179290921790945584519182528101929092529293507f2ecea11087d1dc1431b517cbb5a559a9e33e58a1afeaac288f782c1c8bed8b8a910160405180910390a250505050565b60606000826001600160401b03811115613fc057634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015613ff357816020015b6060815260200190600190039081613fde5790505b50905060005b838110156140d95761409b8686868481811061402557634e487b7160e01b600052603260045260246000fd5b90506020028101906140379190615dac565b61404590602081019061551a565b87878581811061406557634e487b7160e01b600052603260045260246000fd5b90506020028101906140779190615dac565b6020013588888681811061274857634e487b7160e01b600052603260045260246000fd5b8282815181106140bb57634e487b7160e01b600052603260045260246000fd5b602002602001018190525080806140d190615efa565b915050613ff9565b50949350505050565b60405180604001604052806140f6846150cb565b6001600160401b0390811682526001600160e01b03199093166020918201526001600160a01b039094166000908152600185526040902081518154929095015160e01c600160401b026001600160601b031990921694909216939093179290921790915550565b6040516328207dbb60e11b81526001600160a01b0382811660048301526000916107b6917f00000000000000000000000044da3a8051ba88eab0440db3779cab9d679ae76f1690635040fb769060240160206040518083038186803b1580156141c557600080fd5b505afa1580156141d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141fd91906159c6565b60025b60008061420d8385615e80565b90506142198385615f15565b614224579050610891565b61422f816001615e40565b915050610891565b604051631017f7cd60e31b81526001600160a01b0384811660048301528381166024830152604482018390527f000000000000000000000000391f0e86da951c03b1183c60b195090671adea8816906380bfbe6890606401611b8d565b6001600160a01b0381166142ea5760405162461bcd60e51b815260206004820152601c60248201527f534d3a206e6577206f776e65722063616e6e6f74206265206e756c6c000000006044820152606401610774565b6142f4828261320c565b156108f95760405162461bcd60e51b815260206004820181905260248201527f534d3a206e6577206f776e65722063616e6e6f7420626520677561726469616e6044820152606401610774565b600060448251106144245760208201516001600160e01b0319811663a9059cbb60e01b148061438057506001600160e01b0319811663095ea7b360e01b145b8061439b57506001600160e01b0319811663a22cb46560e01b145b156143ac5750506024810151610891565b6001600160e01b031981166323b872dd60e01b14806143db57506001600160e01b03198116632142170760e11b145b806143f657506001600160e01b03198116635c46a7ef60e11b145b8061441157506001600160e01b03198116637921219560e11b145b156144225750506044810151610891565b505b5090919050565b60606000856001600160a01b031685858560405160240161444e93929190615bdc565b60408051601f198184030181529181526020820180516001600160e01b03166347b7819960e11b179052516144839190615b0c565b6000604051808303816000865af19150503d80600081146144c0576040519150601f19603f3d011682016040523d82523d6000602084013e6144c5565b606091505b50925090508080156144d8575060008251115b156144f857818060200190518101906144f1919061590f565b91506140d9565b815115614509573d6000803e3d6000fd5b806140d95760405162461bcd60e51b815260206004820152601a60248201527f424d3a2077616c6c657420696e766f6b652072657665727465640000000000006044820152606401610774565b600060248210156145a95760405162461bcd60e51b815260206004820152601660248201527f524d3a20496e76616c6964206461746157616c6c6574000000000000000000006044820152606401610774565b60006145b88360048187615e18565b8101906145c5919061551a565b6001600160a01b03908116908616149150509392505050565b60405160009061460a90601960f81b9083908c908c908c9046908d908d908d908d908d90602001615a72565b60408051601f198184030181529082905280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000091830191909152603c820152605c0160405160208183030381529060405280519060200120905098975050505050505050565b60008260011480156146d1575060018260048111156146a657634e487b7160e01b600052602160045260246000fd5b14806146d1575060048260048111156146cf57634e487b7160e01b600052602160045260246000fd5b145b15614743576001600160a01b03861660009081526002602052604090205485116146fd57506000611f28565b608085901c61470e61271043615e40565b81111561471f576000915050611f28565b50506001600160a01b03851660009081526002602052604090208490556001611f28565b6001600160a01b038616600090815260026020908152604080832087845260019081019092529091205460ff161515141561478057506000611f28565b5050506001600160a01b0392909216600090815260026020908152604080832094835260019485019091529020805460ff1916831790555090565b6001600160a01b038481166000908152602081815260408083208151808301835290549485168152600160a01b9094046001600160401b0316848301528051601f86018390048302810183019091528481529192918391614838918891889088908190840183828082843760009201829052509250613b3a915050565b905081600001516001600160a01b0316816001600160a01b0316148015610b9357504282602001516001600160401b03161015979650505050505050565b600082516000141561488a57506001612c9c565b6000606060018460048111156148b057634e487b7160e01b600052602160045260246000fd5b1415806148be575060418551115b156149635760405163f18858ab60e01b81526001600160a01b0388811660048301527f00000000000000000000000044da3a8051ba88eab0440db3779cab9d679ae76f169063f18858ab9060240160006040518083038186803b15801561492457600080fd5b505afa158015614938573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526149609190810190615791565b90505b6000805b604187516149759190615e80565b811015614a77576000614989898984613b3a565b905081614a185760018760048111156149b257634e487b7160e01b600052602160045260246000fd5b14156149db576149c28a82613c6f565b156149cd5750614a65565b600095505050505050612c9c565b60028760048111156149fd57634e487b7160e01b600052602160045260246000fd5b1415614a1857614a0d8a82613c6f565b15614a185750614a65565b846001600160a01b0316816001600160a01b031611614a3f57600095505050505050612c9c565b809450614a4c8482614ebb565b9450925082614a6357600095505050505050612c9c565b505b80614a6f81615efa565b915050614967565b50600198975050505050505050565b600086118015614ade57506001816004811115614ab357634e487b7160e01b600052602160045260246000fd5b1480614ade57506004816004811115614adc57634e487b7160e01b600052602160045260246000fd5b145b15611d5e5760006001600160a01b03841615614afa5783614afc565b335b9050826001148015614b2d57506001826004811115614b2b57634e487b7160e01b600052602160045260246000fd5b145b15614ce95760408051602081018252600080825291516305cfdc4d60e41b81526001600160a01b037f0000000000000000000000003d31d91003f9327623caec2e326b6bc681bc31671692635cfdc4d092614b90928e9287929091600401615b7b565b60206040518083038186803b158015614ba857600080fd5b505afa158015614bbc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614be09190615844565b614ce9576040516309fa507560e11b81526001600160a01b038a8116600483015282811660248301526000917f000000000000000000000000391f0e86da951c03b1183c60b195090671adea88909116906313f4a0ea9060440160206040518083038186803b158015614c5257600080fd5b505afa158015614c66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c8a91906159c6565b9050600081118015614c9b57504281105b614ce75760405162461bcd60e51b815260206004820152601960248201527f524d3a20726566756e64206e6f7420617574686f7269736564000000000000006044820152606401610774565b505b60006001600160a01b038616614d565760005a614d06908b615eb3565b614d12906159d8615e40565b9050614d1e893a615133565b614d28828a615133565b614d329190615e94565b9150614d4f8b84846040518060200160405280600081525061442b565b5050614e64565b60005a614d63908b615eb3565b614d6f9061927c615e40565b90506000614d7d883a615142565b9050614d898a82615133565b614d93838b615133565b614d9d9190615e94565b604080516001600160a01b038716602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790529093506000614df58e8b838561442b565b805190915015614e5f5780806020019051810190614e139190615844565b614e5f5760405162461bcd60e51b815260206004820152601a60248201527f524d3a20526566756e64207472616e73666572206661696c65640000000000006044820152606401610774565b505050505b604080516001600160a01b0388811682526020820184905280851692908d16917f22edd2bbb0b0afbdcf90d91da8a5e2100f8d8f67cdc766dee1742e9a36d6add3910160405180910390a350505050505050505050565b60006060835160001480614ed657506001600160a01b038316155b15614ee6575060009050826150c4565b60008060018651614ef79190615eb3565b6001600160401b03811115614f1c57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015614f45578160200160208202803683370190505b5090506000805b87518110156150aa578361502157878181518110614f7a57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316876001600160a01b03161415614fa45760019350615098565b614fdb888281518110614fc757634e487b7160e01b600052603260045260246000fd5b60200260200101513b63ffffffff16151590565b8015615013575061501388828151811061500557634e487b7160e01b600052603260045260246000fd5b60200260200101518861516a565b156150215760019350615098565b82518210156150985787818151811061504a57634e487b7160e01b600052603260045260246000fd5b602002602001015183838151811061507257634e487b7160e01b600052603260045260246000fd5b6001600160a01b03909216602092830291909101909101528161509481615efa565b9250505b806150a281615efa565b915050614f4c565b50826150b8576000876150bc565b6001825b945094505050505b9250929050565b6000600160401b821061512f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610774565b5090565b600081831061442457816132b2565b6000806000615150856151b4565b9092509050816151608286615e94565b611f289190615e80565b604051638da5cb5b60e01b815260009081906020818181886161a8fa600181141561519457815192505b5050826001600160a01b0316816001600160a01b03161491505092915050565b600080826001600160a01b03167f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031610156152a857600061521d7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2856153a7565b9050806001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561525857600080fd5b505afa15801561526c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906152909190615978565b506001600160701b03918216945016915061535a9050565b60006152d4847f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26153a7565b9050806001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561530f57600080fd5b505afa158015615323573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906153479190615978565b506001600160701b039081169450169150505b811580159061536857508015155b6121d75760405162461bcd60e51b815260206004820152601060248201526f534f3a206e6f206c697175696469747960801b6044820152606401610774565b6040516001600160601b0319606084811b8216602084015283901b1660348201526000907f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f90604801604051602081830303815290604052805190602001206040516020016154639291906001600160f81b0319815260609290921b6001600160601b031916600183015260158201527f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f603582015260550190565b60408051601f1981840301815291905280516020909101209392505050565b60008083601f840112615493578182fd5b5081356001600160401b038111156154a9578182fd5b6020830191508360208260051b85010111156150c457600080fd5b60008083601f8401126154d5578182fd5b5081356001600160401b038111156154eb578182fd5b6020830191508360208285010111156150c457600080fd5b80516001600160701b03811681146107b957600080fd5b60006020828403121561552b578081fd5b81356132b281615f6b565b600060208284031215615547578081fd5b81516132b281615f6b565b60008060408385031215615564578081fd5b823561556f81615f6b565b9150602083013561557f81615f6b565b809150509250929050565b60008060006040848603121561559e578081fd5b83356155a981615f6b565b925060208401356001600160401b038111156155c3578182fd5b6155cf86828701615482565b9497909650939450505050565b6000806000806000608086880312156155f3578081fd5b85356155fe81615f6b565b945060208601356001600160401b0380821115615619578283fd5b61562589838a01615482565b90965094506040880135915061563a82615f6b565b9092506060870135908082168214615650578283fd5b50809150509295509295909350565b60008060408385031215615671578182fd5b823561567c81615f6b565b946020939093013593505050565b60008060006040848603121561569e578081fd5b83356156a981615f6b565b925060208401356001600160401b038111156156c3578182fd5b6155cf868287016154c4565b6000806000806000806000806000806101008b8d0312156156ee578788fd5b8a356156f981615f6b565b995060208b01356001600160401b038082111561571457898afd5b6157208e838f016154c4565b909b50995060408d0135985060608d013591508082111561573f578687fd5b5061574c8d828e016154c4565b90975095505060808b0135935060a08b0135925060c08b013561576e81615f6b565b915060e08b013561577e81615f6b565b809150509295989b9194979a5092959850565b600060208083850312156157a3578182fd5b82516001600160401b03808211156157b9578384fd5b818501915085601f8301126157cc578384fd5b8151818111156157de576157de615f55565b8060051b91506157ef848301615dc1565b8181528481019084860184860187018a1015615809578788fd5b8795505b83861015615837578051945061582285615f6b565b8483526001959095019491860191860161580d565b5098975050505050505050565b600060208284031215615855578081fd5b815180151581146132b2578182fd5b60008060408385031215615876578182fd5b8235915060208301356001600160401b03811115615892578182fd5b8301601f810185136158a2578182fd5b80356158b56158b082615df1565b615dc1565b8181528660208385010111156158c9578384fd5b81602084016020830137908101602001929092525090939092509050565b6000602082840312156158f8578081fd5b81356001600160e01b0319811681146132b2578182fd5b600060208284031215615920578081fd5b81516001600160401b03811115615935578182fd5b8201601f81018413615945578182fd5b80516159536158b082615df1565b818152856020838501011115615967578384fd5b611f28826020830160208601615eca565b60008060006060848603121561598c578081fd5b61599584615503565b92506159a360208501615503565b9150604084015163ffffffff811681146159bb578182fd5b809150509250925092565b6000602082840312156159d7578081fd5b5051919050565b600081518084526159f6816020860160208601615eca565b601f01601f19169290920160200192915050565b6001600160601b0319606093841b811682529190921b166014820152693932bb37b5b0ba34b7b760b11b602882015260320190565b6001600160601b0319606093841b811682529190921b1660148201526730b23234ba34b7b760c11b602882015260300190565b600060ff60f81b808e168352808d166001840152506bffffffffffffffffffffffff19808c60601b1660028401528a60168401528951615ab9816036860160208e01615eca565b909201603681019890985250605687019590955260768601939093526096850191909152606090811b831660b68501521b1660ca82015260de0195945050505050565b6000828483379101908152919050565b60008251615b1e818460208701615eca565b9190910192915050565b60006001600160a01b038088168352808716602084015280861660408401525060806060830152826080830152828460a084013781830160a090810191909152601f909201601f19160101949350505050565b60006001600160a01b038087168352808616602084015280851660408401525060806060830152615baf60808301846159de565b9695505050505050565b6001600160a01b039290921682526001600160e01b031916602082015260400190565b60006001600160a01b038516825283602083015260606040830152611f2860608301846159de565b6020808252825182820181905260009190848201906040850190845b81811015615c455783516001600160a01b031683529284019291840191600101615c20565b50909695505050505050565b6000602080830181845280855180835260408601915060408160051b8701019250838701855b82811015615ca557603f19888603018452615c938583516159de565b94509285019290850190600101615c77565b5092979650505050505050565b600060408252615cc560408301856159de565b90508260208301529392505050565b6020808252601d908201527f424d3a206d7573742062652077616c6c6574206f776e65722f73656c66000000604082015260600190565b60208082526011908201527010934e881dd85b1b195d081b1bd8dad959607a1b604082015260600190565b8281526040810160058310615d5b57634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b6000808335601e19843603018112615d7e578283fd5b8301803591506001600160401b03821115615d97578283fd5b6020019150368190038213156150c457600080fd5b60008235605e19833603018112615b1e578182fd5b604051601f8201601f191681016001600160401b0381118282101715615de957615de9615f55565b604052919050565b60006001600160401b03821115615e0a57615e0a615f55565b50601f01601f191660200190565b60008085851115615e27578182fd5b83861115615e33578182fd5b5050820193919092039150565b60008219821115615e5357615e53615f29565b500190565b600063ffffffff808316818516808303821115615e7757615e77615f29565b01949350505050565b600082615e8f57615e8f615f3f565b500490565b6000816000190483118215151615615eae57615eae615f29565b500290565b600082821015615ec557615ec5615f29565b500390565b60005b83811015615ee5578181015183820152602001615ecd565b83811115615ef4576000848401525b50505050565b6000600019821415615f0e57615f0e615f29565b5060010190565b600082615f2457615f24615f3f565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114615f8057600080fd5b5056fea264697066735822122081d4fd652d7092f6bc4fbd840c7ca9e79421eccf5ef61d2be2b36c17356df9f564736f6c63430008030033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c17d432bd8e8850fd7b32b0270f5afac65db010500000000000000000000000044da3a8051ba88eab0440db3779cab9d679ae76f000000000000000000000000391f0e86da951c03b1183c60b195090671adea880000000000000000000000003d31d91003f9327623caec2e326b6bc681bc31670000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d000000000000000000000000000000000000000000000000000000000001fa40000000000000000000000000000000000000000000000000000000000000a8c0000000000000000000000000000000000000000000000000000000000002a3000000000000000000000000000000000000000000000000000000000000069780
-----Decoded View---------------
Arg [0] : _registry (address): 0xc17D432Bd8e8850Fd7b32B0270f5AfAc65DB0105
Arg [1] : _guardianStorage (address): 0x44DA3A8051bA88EAB0440DB3779cAB9D679ae76f
Arg [2] : _userWhitelist (address): 0x391f0e86dA951C03b1183C60b195090671ADea88
Arg [3] : _authoriser (address): 0x3d31D91003f9327623CaEc2e326B6BC681Bc3167
Arg [4] : _uniswapRouter (address): 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
Arg [5] : _securityPeriod (uint256): 129600
Arg [6] : _securityWindow (uint256): 43200
Arg [7] : _recoveryPeriod (uint256): 172800
Arg [8] : _lockPeriod (uint256): 432000
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 000000000000000000000000c17d432bd8e8850fd7b32b0270f5afac65db0105
Arg [1] : 00000000000000000000000044da3a8051ba88eab0440db3779cab9d679ae76f
Arg [2] : 000000000000000000000000391f0e86da951c03b1183c60b195090671adea88
Arg [3] : 0000000000000000000000003d31d91003f9327623caec2e326b6bc681bc3167
Arg [4] : 0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d
Arg [5] : 000000000000000000000000000000000000000000000000000000000001fa40
Arg [6] : 000000000000000000000000000000000000000000000000000000000000a8c0
Arg [7] : 000000000000000000000000000000000000000000000000000000000002a300
Arg [8] : 0000000000000000000000000000000000000000000000000000000000069780
Loading...
Loading
Loading...
Loading
OVERVIEW
Contract of Argent's Argent Module.Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $16.6 | 0.01 | $0.166 |
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.