Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
GovernQueueFactory
Compiler Version
v0.6.8+commit.0bbfe453
Contract Source Code (Solidity Standard Json-Input format)
/* * SPDX-License-Identifier: GPL-3.0 */ pragma solidity 0.6.8; pragma experimental ABIEncoderV2; import "@aragon/govern-core/contracts/pipelines/GovernQueue.sol"; import "@aragon/govern-contract-utils/contracts/minimal-proxies/ERC1167ProxyFactory.sol"; contract GovernQueueFactory { using ERC1167ProxyFactory for address; address public base; constructor() public { setupBase(); } function newQueue(address _aclRoot, ERC3000Data.Config memory _config, bytes32 _salt) public returns (GovernQueue queue) { if (_salt != bytes32(0)) { return GovernQueue(base.clone2(_salt, abi.encodeWithSelector(queue.initialize.selector, _aclRoot, _config))); } else { return new GovernQueue(_aclRoot, _config); } } function setupBase() private { ERC3000Data.Collateral memory noCollateral; ERC3000Data.Config memory config = ERC3000Data.Config( 3600, // how many seconds to wait before being able to call `execute` noCollateral, noCollateral, address(0), "", 100000 // initial maxCalldatasize ); base = address(new GovernQueue(address(2), config)); } }
/* * SPDX-License-Identifier: GPL-3.0 */ pragma solidity 0.6.8; import "erc3k/contracts/IERC3000.sol"; import "@aragon/govern-core/contracts/Govern.sol"; import "@aragon/govern-contract-utils/contracts/minimal-proxies/ERC1167ProxyFactory.sol"; import "@aragon/govern-contract-utils/contracts/address-utils/AddressUtils.sol"; contract GovernFactory { using ERC1167ProxyFactory for address; using AddressUtils for address; address public base; constructor() public { setupBase(); } function newGovern(IERC3000 _initialExecutor, bytes32 _salt) public returns (Govern govern) { if (_salt != bytes32(0)) { return Govern(base.clone2(_salt, abi.encodeWithSelector(govern.initialize.selector, _initialExecutor)).toPayable()); } else { return new Govern(address(_initialExecutor)); } } function setupBase() private { base = address(new Govern(address(2))); } }
/* * SPDX-License-Identifier: MIT */ pragma solidity ^0.6.8; pragma experimental ABIEncoderV2; import "./ERC3000Data.sol"; abstract contract IERC3000 { /** * @notice Schedules an action for execution, allowing for challenges and vetos on a defined time window * @param container A Container struct holding both the payload being scheduled for execution and * the current configuration of the system * @return containerHash */ function schedule(ERC3000Data.Container memory container) virtual public returns (bytes32 containerHash); event Scheduled(bytes32 indexed containerHash, ERC3000Data.Payload payload); /** * @notice Executes an action after its execution delay has passed and its state hasn't been altered by a challenge or veto * @param container A ERC3000Data.Container struct holding both the payload being scheduled for execution and * the current configuration of the system * MUST be an ERC3000Executor call: payload.executor.exec(payload.actions) * @return failureMap * @return execResults */ function execute(ERC3000Data.Container memory container) virtual public returns (bytes32 failureMap, bytes[] memory execResults); event Executed(bytes32 indexed containerHash, address indexed actor); /** * @notice Challenge a container in case its scheduling is illegal as per Config.rules. Pulls collateral and dispute fees from sender into contract * @param container A ERC3000Data.Container struct holding both the payload being scheduled for execution and * the current configuration of the system * @param reason Hint for case reviewers as to why the scheduled container is illegal * @return resolverId */ function challenge(ERC3000Data.Container memory container, bytes memory reason) virtual public returns (uint256 resolverId); event Challenged(bytes32 indexed containerHash, address indexed actor, bytes reason, uint256 resolverId, ERC3000Data.Collateral collateral); /** * @notice Apply arbitrator's ruling over a challenge once it has come to a final ruling * @param container A ERC3000Data.Container struct holding both the payload being scheduled for execution and * the current configuration of the system * @param resolverId disputeId in the arbitrator in which the dispute over the container was created * @return failureMap * @return execResults */ function resolve(ERC3000Data.Container memory container, uint256 resolverId) virtual public returns (bytes32 failureMap, bytes[] memory execResults); event Resolved(bytes32 indexed containerHash, address indexed actor, bool approved); /** * @notice Apply arbitrator's ruling over a challenge once it has come to a final ruling * @param container A ERC3000Data.Container struct holding both the payload being scheduled for execution and * the current configuration of the system * @param reason Justification for the veto */ function veto(ERC3000Data.Container memory container, bytes memory reason) virtual public; event Vetoed(bytes32 indexed containerHash, address indexed actor, bytes reason); /** * @notice Apply a new configuration for all *new* containers to be scheduled * @param config A ERC3000Data.Config struct holding all the new params that will control the system * @return configHash */ function configure(ERC3000Data.Config memory config) virtual public returns (bytes32 configHash); event Configured(bytes32 indexed configHash, address indexed actor, ERC3000Data.Config config); }
/* * SPDX-License-Identifier: GPL-3.0 */ pragma solidity 0.6.8; pragma experimental ABIEncoderV2; import "erc3k/contracts/IERC3000Executor.sol"; import "erc3k/contracts/IERC3000.sol"; import "@aragon/govern-contract-utils/contracts/acl/ACL.sol"; import "@aragon/govern-contract-utils/contracts/adaptive-erc165/AdaptiveERC165.sol"; import "@aragon/govern-contract-utils/contracts/bitmaps/BitmapLib.sol"; import "@aragon/govern-contract-utils/contracts/address-utils/AddressUtils.sol"; import "@aragon/govern-contract-utils/contracts/erc20/ERC20.sol"; import "@aragon/govern-contract-utils/contracts/erc20/SafeERC20.sol"; import "./erc1271/ERC1271.sol"; contract Govern is IERC3000Executor, AdaptiveERC165, ERC1271, ACL { using BitmapLib for bytes32; using AddressUtils for address; using SafeERC20 for ERC20; string private constant ERROR_DEPOSIT_AMOUNT_ZERO = "GOVERN_DEPOSIT_AMOUNT_ZERO"; string private constant ERROR_ETH_DEPOSIT_AMOUNT_MISMATCH = "GOVERN_ETH_DEPOSIT_AMOUNT_MISMATCH"; string private constant ERROR_TOKEN_NOT_CONTRACT = "GOVERN_TOKEN_NOT_CONTRACT"; string private constant ERROR_TOKEN_DEPOSIT_FAILED = "GOVERN_TOKEN_DEPOSIT_FAILED"; string private constant ERROR_TOO_MANY_ACTIONS = "GOVERN_TOO_MANY_ACTIONS"; string private constant ERROR_ACTION_CALL_FAILED = "GOVERN_ACTION_CALL_FAILED"; string private constant ERROR_TOKEN_WITHDRAW_FAILED = "GOVERN_TOKEN_WITHDRAW_FAILED"; string private constant ERROR_ETH_WITHDRAW_FAILED = "GOVERN_ETH_WITHDRAW_FAILED"; bytes4 internal constant EXEC_ROLE = this.exec.selector; bytes4 internal constant WITHDRAW_ROLE = this.withdraw.selector; bytes4 internal constant REGISTER_STANDARD_ROLE = this.registerStandardAndCallback.selector; bytes4 internal constant SET_SIGNATURE_VALIDATOR_ROLE = this.setSignatureValidator.selector; uint256 internal constant MAX_ACTIONS = 256; ERC1271 signatureValidator; // ETHDeposited and Deposited are both needed. ETHDeposited makes sure that whoever sends funds // with `send/transfer`, receive function can still be executed without reverting due to gas cost // increases in EIP-2929. To still use `send/transfer`, access list is needed that has the address // of the contract(base contract) that is behind the proxy. event ETHDeposited(address sender, uint256 amount); event Deposited(address indexed sender, address indexed token, uint256 amount, string _reference); event Withdrawn(address indexed token, address indexed to, address from, uint256 amount, string _reference); constructor(address _initialExecutor) ACL(address(this)) public { initialize(_initialExecutor); } function initialize(address _initialExecutor) public initACL(address(this)) onlyInit("govern") { _grant(EXEC_ROLE, address(_initialExecutor)); _grant(WITHDRAW_ROLE, address(this)); // freeze the withdraw so that only GovernExecutor can call _freeze(WITHDRAW_ROLE); _grant(REGISTER_STANDARD_ROLE, address(this)); _grant(SET_SIGNATURE_VALIDATOR_ROLE, address(this)); _registerStandard(ERC3000_EXEC_INTERFACE_ID); _registerStandard(type(ERC1271).interfaceId); } receive () external payable { emit ETHDeposited(msg.sender, msg.value); } fallback () external { _handleCallback(msg.sig, msg.data); // WARN: does a low-level return, any code below would be unreacheable } function deposit(address _token, uint256 _amount, string calldata _reference) external payable { require(_amount > 0, ERROR_DEPOSIT_AMOUNT_ZERO); if (_token == address(0)) { require(msg.value == _amount, ERROR_ETH_DEPOSIT_AMOUNT_MISMATCH); } else { require(_token.isContract(), ERROR_TOKEN_NOT_CONTRACT); require(ERC20(_token).safeTransferFrom(msg.sender, address(this), _amount), ERROR_TOKEN_DEPOSIT_FAILED); } emit Deposited(msg.sender, _token, _amount, _reference); } function withdraw(address _token, address _from, address _to, uint256 _amount, string memory _reference) public auth(WITHDRAW_ROLE) { if (_token == address(0)) { (bool ok, ) = _to.call{value: _amount}(""); require(ok, ERROR_ETH_WITHDRAW_FAILED); } else { require(ERC20(_token).safeTransfer(_to, _amount), ERROR_TOKEN_WITHDRAW_FAILED); } emit Withdrawn(_token, _to, _from, _amount, _reference); } function exec(ERC3000Data.Action[] memory actions, bytes32 allowFailuresMap, bytes32 memo) override public auth(EXEC_ROLE) returns (bytes32, bytes[] memory) { require(actions.length <= MAX_ACTIONS, ERROR_TOO_MANY_ACTIONS); // need to limit since we use 256-bit bitmaps bytes[] memory execResults = new bytes[](actions.length); bytes32 failureMap = BitmapLib.empty; // start with an empty bitmap for (uint256 i = 0; i < actions.length; i++) { // TODO: optimize with assembly (bool ok, bytes memory ret) = actions[i].to.call{value: actions[i].value}(actions[i].data); require(ok || allowFailuresMap.get(uint8(i)), ERROR_ACTION_CALL_FAILED); // if a call fails, flip that bit to signal failure failureMap = ok ? failureMap : failureMap.flip(uint8(i)); execResults[i] = ret; } emit Executed(msg.sender, actions, memo, failureMap, execResults); return (failureMap, execResults); } function registerStandardAndCallback(bytes4 _interfaceId, bytes4 _callbackSig, bytes4 _magicNumber) external auth(REGISTER_STANDARD_ROLE) { _registerStandardAndCallback(_interfaceId, _callbackSig, _magicNumber); } function setSignatureValidator(ERC1271 _signatureValidator) external auth(SET_SIGNATURE_VALIDATOR_ROLE) { signatureValidator = _signatureValidator; } function isValidSignature(bytes32 _hash, bytes memory _signature) override public view returns (bytes4) { if (address(signatureValidator) == address(0)) return bytes4(0); // invalid magic number return signatureValidator.isValidSignature(_hash, _signature); // forward call to set validation contract } }
/* * SPDX-License-Identifier: MIT */ // Inspired by: https://github.com/optionality/clone-factory pragma solidity ^0.6.8; library ERC1167ProxyFactory { function clone(address _implementation) internal returns (address cloneAddr) { bytes memory createData = generateCreateData(_implementation); assembly { cloneAddr := create(0, add(createData, 0x20), 55) } require(cloneAddr != address(0), "proxy-factory: bad create"); } function clone(address _implementation, bytes memory _initData) internal returns (address cloneAddr) { cloneAddr = clone(_implementation); (bool ok, bytes memory ret) = cloneAddr.call(_initData); require(ok, _getRevertMsg(ret)); } function clone2(address _implementation, bytes32 _salt) internal returns (address cloneAddr) { bytes memory createData = generateCreateData(_implementation); assembly { cloneAddr := create2(0, add(createData, 0x20), 55, _salt) } require(cloneAddr != address(0), "proxy-factory: bad create2"); } function clone2(address _implementation, bytes32 _salt, bytes memory _initData) internal returns (address cloneAddr) { cloneAddr = clone2(_implementation, _salt); (bool ok, bytes memory ret) = cloneAddr.call(_initData); require(ok, _getRevertMsg(ret)); } function generateCreateData(address _implementation) internal pure returns (bytes memory) { return abi.encodePacked( //---- constructor ----- bytes10(0x3d602d80600a3d3981f3), //---- proxy code ----- bytes10(0x363d3d373d3d3d363d73), _implementation, bytes15(0x5af43d82803e903d91602b57fd5bf3) ); } // From: https://ethereum.stackexchange.com/a/83577 function _getRevertMsg(bytes memory _returnData) internal pure returns (string memory) { // If the _res length is less than 68, then the transaction failed silently (without a revert message) if (_returnData.length < 68) return ''; assembly { _returnData := add(_returnData, 0x04) // Slice the sighash. } return abi.decode(_returnData, (string)); // All that remains is the revert string } }
/* * SPDX-License-Identifier: MIT */ pragma solidity ^0.6.8; library AddressUtils { function toPayable(address addr) internal pure returns (address payable) { return address(bytes20(addr)); } /** * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed */ function isContract(address addr) internal view returns (bool result) { assembly { result := iszero(iszero(extcodesize(addr))) } } }
/* * SPDX-License-Identifier: MIT */ pragma solidity ^0.6.8; pragma experimental ABIEncoderV2; import "./IERC3000Executor.sol"; library ERC3000Data { // TODO: come up with a non-shitty name struct Container { Payload payload; Config config; } // WARN: Always remember to change the 'hash' function if modifying the struct struct Payload { uint256 nonce; uint256 executionTime; address submitter; IERC3000Executor executor; Action[] actions; bytes32 allowFailuresMap; bytes proof; } struct Action { address to; uint256 value; bytes data; } struct Config { uint256 executionDelay; // how many seconds to wait before being able to call `execute`. Collateral scheduleDeposit; // fees for scheduling Collateral challengeDeposit; // fees for challenging address resolver; // resolver that will rule the disputes bytes rules; // rules of how DAO should be managed uint256 maxCalldataSize; // max calldatasize for the schedule } struct Collateral { address token; uint256 amount; } function containerHash(bytes32 payloadHash, bytes32 configHash) internal view returns (bytes32) { uint chainId; assembly { chainId := chainid() } return keccak256(abi.encodePacked("erc3k-v1", address(this), chainId, payloadHash, configHash)); } function hash(Container memory container) internal view returns (bytes32) { return containerHash(hash(container.payload), hash(container.config)); } function hash(Payload memory payload) internal pure returns (bytes32) { return keccak256( abi.encode( payload.nonce, payload.executionTime, payload.submitter, payload.executor, keccak256(abi.encode(payload.actions)), payload.allowFailuresMap, keccak256(payload.proof) ) ); } function hash(Config memory config) internal pure returns (bytes32) { return keccak256(abi.encode(config)); } }
/* * SPDX-License-Identifier: MIT */ pragma solidity ^0.6.8; pragma experimental ABIEncoderV2; import "./ERC3000Data.sol"; abstract contract IERC3000Executor { bytes4 internal constant ERC3000_EXEC_INTERFACE_ID = this.exec.selector; /** * @notice Executes all given actions * @param actions A array of ERC3000Data.Action for later executing those * @param allowFailuresMap A map with the allowed failures * @param memo The hash of the ERC3000Data.Container * @return failureMap * @return execResults */ function exec(ERC3000Data.Action[] memory actions, bytes32 allowFailuresMap, bytes32 memo) virtual public returns (bytes32 failureMap, bytes[] memory execResults); event Executed(address indexed actor, ERC3000Data.Action[] actions, bytes32 memo, bytes32 failureMap, bytes[] execResults); }
/* * SPDX-License-Identifier: MIT */ pragma solidity ^0.6.8; pragma experimental ABIEncoderV2; import "../initializable/Initializable.sol"; import "./IACLOracle.sol"; library ACLData { enum BulkOp { Grant, Revoke, Freeze } struct BulkItem { BulkOp op; bytes4 role; address who; } } contract ACL is Initializable { bytes4 public constant ROOT_ROLE = this.grant.selector ^ this.revoke.selector ^ this.freeze.selector ^ this.bulk.selector ; // "Who" constants address internal constant ANY_ADDR = address(-1); // "Access" flags address internal constant UNSET_ROLE = address(0); address internal constant FREEZE_FLAG = address(1); // Also used as "who" address internal constant ALLOW_FLAG = address(2); // Role -> Who -> Access flag (unset or allow) or ACLOracle (any other address denominates auth via ACLOracle) mapping (bytes4 => mapping (address => address)) public roles; event Granted(bytes4 indexed role, address indexed actor, address indexed who, IACLOracle oracle); event Revoked(bytes4 indexed role, address indexed actor, address indexed who); event Frozen(bytes4 indexed role, address indexed actor); modifier auth(bytes4 _role) { require(willPerform(_role, msg.sender, msg.data), "acl: auth"); _; } modifier initACL(address _initialRoot) { // ACL might have been already initialized by constructors if (initBlocks["acl"] == 0) { _initializeACL(_initialRoot); } else { require(roles[ROOT_ROLE][_initialRoot] == ALLOW_FLAG, "acl: initial root misaligned"); } _; } constructor(address _initialRoot) public initACL(_initialRoot) { } function grant(bytes4 _role, address _who) external auth(ROOT_ROLE) { _grant(_role, _who); } function grantWithOracle(bytes4 _role, address _who, IACLOracle _oracle) external auth(ROOT_ROLE) { _grantWithOracle(_role, _who, _oracle); } function revoke(bytes4 _role, address _who) external auth(ROOT_ROLE) { _revoke(_role, _who); } function freeze(bytes4 _role) external auth(ROOT_ROLE) { _freeze(_role); } function bulk(ACLData.BulkItem[] calldata items) external auth(ROOT_ROLE) { for (uint256 i = 0; i < items.length; i++) { ACLData.BulkItem memory item = items[i]; if (item.op == ACLData.BulkOp.Grant) _grant(item.role, item.who); else if (item.op == ACLData.BulkOp.Revoke) _revoke(item.role, item.who); else if (item.op == ACLData.BulkOp.Freeze) _freeze(item.role); } } function willPerform(bytes4 _role, address _who, bytes memory _data) internal returns (bool) { // First check if the given who is auth'd, then if any address is auth'd return _checkRole(_role, _who, _data) || _checkRole(_role, ANY_ADDR, _data); } function isFrozen(bytes4 _role) public view returns (bool) { return roles[_role][FREEZE_FLAG] == FREEZE_FLAG; } function _initializeACL(address _initialRoot) internal onlyInit("acl") { _grant(ROOT_ROLE, _initialRoot); } function _grant(bytes4 _role, address _who) internal { _grantWithOracle(_role, _who, IACLOracle(ALLOW_FLAG)); } function _grantWithOracle(bytes4 _role, address _who, IACLOracle _oracle) internal { require(!isFrozen(_role), "acl: frozen"); require(_who != FREEZE_FLAG, "acl: bad freeze"); roles[_role][_who] = address(_oracle); emit Granted(_role, msg.sender, _who, _oracle); } function _revoke(bytes4 _role, address _who) internal { require(!isFrozen(_role), "acl: frozen"); roles[_role][_who] = UNSET_ROLE; emit Revoked(_role, msg.sender, _who); } function _freeze(bytes4 _role) internal { require(!isFrozen(_role), "acl: frozen"); roles[_role][FREEZE_FLAG] = FREEZE_FLAG; emit Frozen(_role, msg.sender); } function _checkRole(bytes4 _role, address _who, bytes memory _data) internal returns (bool) { address accessFlagOrAclOracle = roles[_role][_who]; if (accessFlagOrAclOracle != UNSET_ROLE) { if (accessFlagOrAclOracle == ALLOW_FLAG) return true; // Since it's not a flag, assume it's an ACLOracle and try-catch to skip failures try IACLOracle(accessFlagOrAclOracle).willPerform(_role, _who, _data) returns (bool allowed) { if (allowed) return true; } catch { } } return false; } }
/* * SPDX-License-Identifier: MIT */ pragma solidity ^0.6.8; import "../erc165/ERC165.sol"; contract AdaptiveERC165 is ERC165 { // ERC165 interface ID -> whether it is supported mapping (bytes4 => bool) internal standardSupported; // Callback function signature -> magic number to return mapping (bytes4 => bytes32) internal callbackMagicNumbers; bytes32 internal constant UNREGISTERED_CALLBACK = bytes32(0); event RegisteredStandard(bytes4 interfaceId); event RegisteredCallback(bytes4 sig, bytes4 magicNumber); event ReceivedCallback(bytes4 indexed sig, bytes data); function supportsInterface(bytes4 _interfaceId) override virtual public view returns (bool) { return standardSupported[_interfaceId] || super.supportsInterface(_interfaceId); } function _handleCallback(bytes4 _sig, bytes memory _data) internal { bytes32 magicNumber = callbackMagicNumbers[_sig]; require(magicNumber != UNREGISTERED_CALLBACK, "adap-erc165: unknown callback"); emit ReceivedCallback(_sig, _data); // low-level return magic number assembly { mstore(0x00, magicNumber) return(0x00, 0x20) } } function _registerStandardAndCallback(bytes4 _interfaceId, bytes4 _callbackSig, bytes4 _magicNumber) internal { _registerStandard(_interfaceId); _registerCallback(_callbackSig, _magicNumber); } function _registerStandard(bytes4 _interfaceId) internal { standardSupported[_interfaceId] = true; emit RegisteredStandard(_interfaceId); } function _registerCallback(bytes4 _callbackSig, bytes4 _magicNumber) internal { callbackMagicNumbers[_callbackSig] = _magicNumber; emit RegisteredCallback(_callbackSig, _magicNumber); } }
/* * SPDX-License-Identifier: MIT */ pragma solidity ^0.6.8; library BitmapLib { bytes32 constant internal empty = bytes32(0); function flip(bytes32 map, uint8 index) internal pure returns (bytes32) { return bytes32(uint256(map) ^ uint256(1) << index); } function get(bytes32 map, uint8 index) internal pure returns (bool) { return (uint256(map) >> index & 1) == 1; } }
/* * SPDX-License-Identifier: MIT */ pragma solidity ^0.6.8; /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ interface ERC20 { // Optional fields function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); function totalSupply() external view returns (uint256); function balanceOf(address _who) external view returns (uint256); function allowance(address _owner, address _spender) external view returns (uint256); function transfer(address _to, uint256 _value) external returns (bool); function approve(address _spender, uint256 _value) external returns (bool); function transferFrom(address _from, address _to, uint256 _value) external returns (bool); event Transfer( address indexed from, address indexed to, uint256 value ); event Approval( address indexed owner, address indexed spender, uint256 value ); }
/* * SPDX-License-Identifier: MIT */ // From https://github.com/aragon/aragonOS/blob/next/contracts/common/SafeERC20.sol // Inspired by AdEx (https://github.com/AdExNetwork/adex-protocol-eth/blob/b9df617829661a7518ee10f4cb6c4108659dd6d5/contracts/libs/SafeERC20.sol) // and 0x (https://github.com/0xProject/0x-monorepo/blob/737d1dc54d72872e24abce5a1dbe1b66d35fa21a/contracts/protocol/contracts/protocol/AssetProxy/ERC20Proxy.sol#L143) pragma solidity ^0.6.8; import "../address-utils/AddressUtils.sol"; import "./ERC20.sol"; library SafeERC20 { using AddressUtils for address; function invokeAndCheckSuccess(address _addr, bytes memory _calldata) private returns (bool ret) { if (!_addr.isContract()) { return false; } assembly { let ptr := mload(0x40) // free memory pointer let success := call( gas(), // forward all _addr, // address 0, // no value add(_calldata, 0x20), // calldata start mload(_calldata), // calldata length ptr, // write output over free memory 0x20 // uint256 return ) if gt(success, 0) { // Check number of bytes returned from last function call switch returndatasize() // No bytes returned: assume success case 0 { ret := 1 } // 32 bytes returned: check if non-zero case 0x20 { // Only return success if returned data was true // Already have output in ptr ret := iszero(iszero(mload(ptr))) } // Not sure what was returned: don't mark as success default { } } } } /** * @dev Same as a standards-compliant ERC20.transfer() that never reverts (returns false). * Note that this makes an external call to the token. */ function safeTransfer(ERC20 _token, address _to, uint256 _amount) internal returns (bool) { bytes memory transferCallData = abi.encodeWithSelector( _token.transfer.selector, _to, _amount ); return invokeAndCheckSuccess(address(_token), transferCallData); } /** * @dev Same as a standards-compliant ERC20.transferFrom() that never reverts (returns false). * Note that this makes an external call to the token. */ function safeTransferFrom(ERC20 _token, address _from, address _to, uint256 _amount) internal returns (bool) { bytes memory transferFromCallData = abi.encodeWithSelector( _token.transferFrom.selector, _from, _to, _amount ); return invokeAndCheckSuccess(address(_token), transferFromCallData); } /** * @dev Same as a standards-compliant ERC20.approve() that never reverts (returns false). * Note that this makes an external call to the token. */ function safeApprove(ERC20 _token, address _spender, uint256 _amount) internal returns (bool) { bytes memory approveCallData = abi.encodeWithSelector( _token.approve.selector, _spender, _amount ); return invokeAndCheckSuccess(address(_token), approveCallData); } }
/* * SPDX-License-Identifier: MIT */ pragma solidity ^0.6.8; /** * @title ERC1271 interface * @dev see https://eips.ethereum.org/EIPS/eip-1271 */ abstract contract ERC1271 { // bytes4(keccak256("isValidSignature(bytes32,bytes)") bytes4 constant internal MAGICVALUE = 0x1626ba7e; /** * @dev Should return whether the signature provided is valid for the provided data * @param _hash Keccak256 hash of arbitrary length data signed on the behalf of address(this) * @param _signature Signature byte array associated with _data * * MUST return the bytes4 magic value 0x1626ba7e when function passes. * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5) * MUST allow external calls */ function isValidSignature(bytes32 _hash, bytes memory _signature) virtual public view returns (bytes4 magicValue); }
/* * SPDX-License-Identifier: MIT */ pragma solidity 0.6.8; contract Initializable { mapping (string => uint256) public initBlocks; event Initialized(string indexed key); modifier onlyInit(string memory key) { require(initBlocks[key] == 0, "initializable: already initialized"); initBlocks[key] = block.number; _; emit Initialized(key); } }
/* * SPDX-License-Identifier: MIT */ pragma solidity ^0.6.8; interface IACLOracle { function willPerform(bytes4 role, address who, bytes calldata data) external returns (bool allowed); }
/* * SPDX-License-Identifier: MIT */ pragma solidity ^0.6.8; abstract contract ERC165 { // Includes supportsInterface method: bytes4 internal constant ERC165_INTERFACE_ID = bytes4(0x01ffc9a7); /** * @dev Query if a contract implements a certain interface * @param _interfaceId The interface identifier being queried, as specified in ERC-165 * @return True if the contract implements the requested interface and if its not 0xffffffff, false otherwise */ function supportsInterface(bytes4 _interfaceId) virtual public view returns (bool) { return _interfaceId == ERC165_INTERFACE_ID; } }
/* * SPDX-License-Identifier: GPL-3.0 */ pragma solidity 0.6.8; pragma experimental ABIEncoderV2; import "@aragon/govern-core/contracts/GovernRegistry.sol"; import "@aragon/govern-token/contracts/GovernTokenFactory.sol"; import "@aragon/govern-token/contracts/interfaces/IERC20.sol"; import "@aragon/govern-token/contracts/GovernMinter.sol"; import "@aragon/govern-token/contracts/libraries/TokenLib.sol"; import "./core-factories/GovernFactory.sol"; import "./core-factories/GovernQueueFactory.sol"; contract GovernBaseFactory { address internal constant ANY_ADDR = address(-1); uint256 internal constant MAX_SCHEDULE_ACCESS_LIST_ALLOWED = 10; string private constant ERROR_SCHEDULE_LIST_EXCEEDED = "basefactory: schedule list exceeded"; GovernFactory public governFactory; GovernQueueFactory public queueFactory; GovernTokenFactory public tokenFactory; GovernRegistry public registry; constructor( GovernRegistry _registry, GovernFactory _governFactory, GovernQueueFactory _queueFactory, GovernTokenFactory _tokenFactory ) public { governFactory = _governFactory; queueFactory = _queueFactory; tokenFactory = _tokenFactory; registry = _registry; } function newGovern( TokenLib.TokenConfig calldata _token, address[] calldata _scheduleAccessList, bool _useProxies, ERC3000Data.Config calldata _config, string calldata _name ) external returns (Govern govern, GovernQueue queue) { require(_scheduleAccessList.length <= MAX_SCHEDULE_ACCESS_LIST_ALLOWED, ERROR_SCHEDULE_LIST_EXCEEDED); bytes32 salt = _useProxies ? keccak256(abi.encodePacked(_name)) : bytes32(0); queue = queueFactory.newQueue(address(this), _config, salt); govern = governFactory.newGovern(queue, salt); IERC20 token = _token.tokenAddress; GovernMinter minter; if (address(token) == address(0)) { (token, minter) = tokenFactory.newToken( govern, _token, _useProxies ); // if both(scheduleDeposit and challengeDeposit) are non-zero, // they have already been set and no need for a config change. if (_config.scheduleDeposit.token == address(0) || _config.challengeDeposit.token == address(0)) { // give base factory the permission so that it can change // the config with new token in the same transaction queue.grant(queue.configure.selector, address(this)); ERC3000Data.Config memory newConfig = ERC3000Data.Config({ executionDelay: _config.executionDelay, scheduleDeposit: ERC3000Data.Collateral({ token: _config.scheduleDeposit.token != address(0) ? _config.scheduleDeposit.token : address(token), amount: _config.scheduleDeposit.amount }), challengeDeposit: ERC3000Data.Collateral({ token: _config.challengeDeposit.token != address(0) ? _config.challengeDeposit.token : address(token), amount: _config.challengeDeposit.amount }), resolver: _config.resolver, rules: _config.rules, maxCalldataSize: _config.maxCalldataSize }); queue.configure(newConfig); queue.revoke(queue.configure.selector, address(this)); } } registry.register(govern, queue, token, address(minter), _name, ""); uint256 bulkSize = _scheduleAccessList.length == 0 ? 7 : 6 + _scheduleAccessList.length; ACLData.BulkItem[] memory items = new ACLData.BulkItem[](bulkSize); items[0] = ACLData.BulkItem(ACLData.BulkOp.Grant, queue.execute.selector, ANY_ADDR); items[1] = ACLData.BulkItem(ACLData.BulkOp.Grant, queue.challenge.selector, ANY_ADDR); items[2] = ACLData.BulkItem(ACLData.BulkOp.Grant, queue.configure.selector, address(govern)); items[3] = ACLData.BulkItem(ACLData.BulkOp.Revoke, queue.ROOT_ROLE(), address(this)); items[4] = ACLData.BulkItem(ACLData.BulkOp.Grant, queue.ROOT_ROLE(), address(govern)); items[5] = ACLData.BulkItem(ACLData.BulkOp.Freeze, queue.ROOT_ROLE(), address(0)); // If the schedule access list is empty, anyone can schedule // otherwise, only the addresses specified are allowed. if (_scheduleAccessList.length == 0) { items[6] = ACLData.BulkItem(ACLData.BulkOp.Grant, queue.schedule.selector, ANY_ADDR); } else { for (uint256 i = 0; i < _scheduleAccessList.length; i++) { items[6 + i] = ACLData.BulkItem( ACLData.BulkOp.Grant, queue.schedule.selector, _scheduleAccessList[i] ); } } queue.bulk(items); } }
/* * SPDX-License-Identifier: GPL-3.0 */ pragma solidity 0.6.8; import "erc3k/contracts/IERC3000.sol"; import "erc3k/contracts/IERC3000Executor.sol"; import "erc3k/contracts/IERC3000Registry.sol"; import "@aragon/govern-contract-utils/contracts/erc165/ERC165.sol"; contract GovernRegistry is IERC3000Registry { mapping(string => bool) public nameUsed; function register( IERC3000Executor _executor, IERC3000 _queue, IERC20 _token, address minter, string calldata _name, bytes calldata _initialMetadata ) override external { require(!nameUsed[_name], "registry: name used"); nameUsed[_name] = true; emit Registered(_executor, _queue, _token, minter, msg.sender, _name); _setMetadata(_executor, _initialMetadata); } function setMetadata(bytes memory _metadata) override public { _setMetadata(IERC3000Executor(msg.sender), _metadata); } function _setMetadata(IERC3000Executor _executor, bytes memory _metadata) internal { emit SetMetadata(_executor, _metadata); } }
/* * SPDX-License-Identifier: GPL-3.0 */ pragma solidity 0.6.8; pragma experimental ABIEncoderV2; import "@aragon/govern-contract-utils/contracts/minimal-proxies/ERC1167ProxyFactory.sol"; import "./libraries/TokenLib.sol"; import "erc3k/contracts/IERC3000Executor.sol"; import "./GovernToken.sol"; import "./GovernMinter.sol"; import "./MerkleDistributor.sol"; contract GovernTokenFactory { using ERC1167ProxyFactory for address; address public tokenBase; address public minterBase; address public distributorBase; event CreatedToken(GovernToken token, GovernMinter minter); constructor() public { setupBases(); } function newToken( IERC3000Executor _governExecutor, TokenLib.TokenConfig calldata _token, bool _useProxies ) external returns ( GovernToken token, GovernMinter minter ) { if (!_useProxies) { (token, minter) = _deployContracts(_token.tokenName, _token.tokenSymbol, _token.tokenDecimals); } else { token = GovernToken(tokenBase.clone(abi.encodeWithSelector( token.initialize.selector, address(this), _token.tokenName, _token.tokenSymbol, _token.tokenDecimals ))); minter = GovernMinter(minterBase.clone(abi.encodeWithSelector( minter.initialize.selector, token, address(this), MerkleDistributor(distributorBase) ))); } token.changeMinter(address(minter)); if (_token.mintAmount > 0) { minter.mint(_token.mintAddress, _token.mintAmount, "initial mint"); } if (_token.merkleRoot != bytes32(0)) { minter.merkleMint(_token.merkleRoot, _token.merkleMintAmount, _token.merkleTree, _token.merkleContext); } bytes4 mintRole = minter.mint.selector ^ minter.merkleMint.selector; bytes4 rootRole = minter.ROOT_ROLE(); ACLData.BulkItem[] memory items = new ACLData.BulkItem[](4); items[0] = ACLData.BulkItem(ACLData.BulkOp.Grant, mintRole, address(_governExecutor)); items[1] = ACLData.BulkItem(ACLData.BulkOp.Grant, rootRole, address(_governExecutor)); items[2] = ACLData.BulkItem(ACLData.BulkOp.Revoke, mintRole, address(this)); items[3] = ACLData.BulkItem(ACLData.BulkOp.Revoke, rootRole, address(this)); minter.bulk(items); emit CreatedToken(token, minter); } function setupBases() private { distributorBase = address(new MerkleDistributor(ERC20(tokenBase), bytes32(0))); (GovernToken token, GovernMinter minter) = _deployContracts( "GovernToken base", "GTB", 0 ); token.changeMinter(address(minter)); // test the bases minter.mint(msg.sender, 1, "test mint"); minter.merkleMint(bytes32(0), 1, "no tree", "test merkle mint"); // store bases tokenBase = address(token); minterBase = address(minter); } function _deployContracts( string memory _tokenName, string memory _tokenSymbol, uint8 _tokenDecimals ) internal returns ( GovernToken token, GovernMinter minter ) { token = new GovernToken(address(this), _tokenName, _tokenSymbol, _tokenDecimals); minter = new GovernMinter(GovernToken(token), address(this), MerkleDistributor(distributorBase)); } }
/* * SPDX-License-Identifier: GPL-3.0 */ pragma solidity ^0.6.8; interface IERC20 { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transfer(address recipient, uint256 amount) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); }
/* * SPDX-License-Identifier: GPL-3.0 */ pragma solidity ^0.6.8; pragma experimental ABIEncoderV2; import "@aragon/govern-contract-utils/contracts/acl/ACL.sol"; import "@aragon/govern-contract-utils/contracts/minimal-proxies/ERC1167ProxyFactory.sol"; import "./GovernToken.sol"; import "./MerkleDistributor.sol"; contract GovernMinter is ACL { using ERC1167ProxyFactory for address; bytes4 constant internal MINT_ROLE = this.mint.selector ^ this.merkleMint.selector ; GovernToken public token; address public distributorBase; event MintedSingle(address indexed to, uint256 amount, bytes context); event MintedMerkle(address indexed distributor, bytes32 indexed merkleRoot, uint256 totalAmount, bytes tree, bytes context); constructor(GovernToken _token, address _initialMinter, MerkleDistributor _distributorBase) ACL(_initialMinter) public { initialize(_token, _initialMinter, _distributorBase); } function initialize(GovernToken _token, address _initialMinter, MerkleDistributor _distributorBase) public initACL(_initialMinter) onlyInit("minter") { token = _token; distributorBase = address(_distributorBase); _grant(MINT_ROLE, _initialMinter); } function mint(address _to, uint256 _amount, bytes calldata _context) external auth(MINT_ROLE) { token.mint(_to, _amount); emit MintedSingle(_to, _amount, _context); } function merkleMint(bytes32 _merkleRoot, uint256 _totalAmount, bytes calldata _tree, bytes calldata _context) external auth(MINT_ROLE) returns (MerkleDistributor distributor) { address distributorAddr = distributorBase.clone(abi.encodeWithSelector(distributor.initialize.selector, token, _merkleRoot)); token.mint(distributorAddr, _totalAmount); emit MintedMerkle(distributorAddr, _merkleRoot, _totalAmount, _tree, _context); return MerkleDistributor(distributorAddr); } function eject(address _newMinter) external auth(this.eject.selector) { token.changeMinter(_newMinter); } }
/* * SPDX-License-Identifier: MIT */ pragma solidity ^0.6.8; import "../interfaces/IERC20.sol"; library TokenLib { struct TokenConfig { IERC20 tokenAddress; uint8 tokenDecimals; string tokenName; string tokenSymbol; address mintAddress; // initial minter address uint256 mintAmount; // how much to mint to initial minter address // merkle settings bytes32 merkleRoot; // merkle distribution root. uint256 merkleMintAmount; // how much to mint for the distributor. bytes merkleTree; // merkle tree object bytes merkleContext; // context/string what's the actual reason is... } }
/* * SPDX-License-Identifier: MIT */ pragma solidity 0.6.8; import "./IERC3000.sol"; import "./IERC3000Executor.sol"; import "@aragon/govern-token/contracts/interfaces/IERC20.sol"; abstract contract IERC3000Registry { /** * @notice Registers a IERC3000Executor and IERC3000 contract by a name and with his metadata * @param executor IERC3000Executor contract * @param queue IERC3000 contract * @param name The name of this DAO * @param token Governance token of the DAO * @param initialMetadata Additional data to store for this DAO */ function register(IERC3000Executor executor, IERC3000 queue, IERC20 token, address minter, string calldata name, bytes calldata initialMetadata) virtual external; event Registered(IERC3000Executor indexed executor, IERC3000 queue, IERC20 indexed token, address minter, address indexed registrant, string name); /** * @notice Sets or updates the metadata of a DAO * @param metadata Additional data to store for this DAO */ function setMetadata(bytes memory metadata) virtual public; event SetMetadata(IERC3000Executor indexed executor, bytes metadata); }
/* * SPDX-License-Identifier: GPL-3.0 */ pragma solidity ^0.6.8; import '@aragon/govern-contract-utils/contracts/initializable/Initializable.sol'; import '@aragon/govern-contract-utils/contracts/safe-math/SafeMath.sol'; import './interfaces/IERC20.sol'; // Copied and slightly modified from https://github.com/aragon/aragon-network-token/blob/v2-v1.0.0/packages/v2/contracts/token.sol // Lightweight token modelled after UNI-LP: https://github.com/Uniswap/uniswap-v2-core/blob/v1.0.1/contracts/UniswapV2ERC20.sol // Adds: // - An exposed `mint()` with minting role // - An exposed `burn()` // - ERC-3009 (`transferWithAuthorization()`) contract GovernToken is IERC20, Initializable { using SafeMath for uint256; // bytes32 private constant EIP712DOMAIN_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)") bytes32 private constant EIP712DOMAIN_HASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; // bytes32 private constant VERSION_HASH = keccak256("1") bytes32 private constant VERSION_HASH = 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6; // bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; // bytes32 public constant TRANSFER_WITH_AUTHORIZATION_TYPEHASH = // keccak256("TransferWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)"); bytes32 public constant TRANSFER_WITH_AUTHORIZATION_TYPEHASH = 0x7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a2267; string public name; string public symbol; uint8 public decimals; address public minter; uint256 override public totalSupply; mapping (address => uint256) override public balanceOf; mapping (address => mapping (address => uint256)) override public allowance; // ERC-2612, ERC-3009 state mapping (address => uint256) public nonces; mapping (address => mapping (bytes32 => bool)) public authorizationState; event Approval(address indexed owner, address indexed spender, uint256 value); event Transfer(address indexed from, address indexed to, uint256 value); event AuthorizationUsed(address indexed authorizer, bytes32 indexed nonce); event ChangeMinter(address indexed minter); modifier onlyMinter { require(msg.sender == minter, "token: not minter"); _; } constructor(address _initialMinter, string memory _name, string memory _symbol, uint8 _decimals) public { initialize(_initialMinter, _name, _symbol, _decimals); } function initialize(address _initialMinter, string memory _name, string memory _symbol, uint8 _decimals) public onlyInit("token") { _changeMinter(_initialMinter); name = _name; symbol = _symbol; decimals = _decimals; } function _validateSignedData(address signer, bytes32 encodeData, uint8 v, bytes32 r, bytes32 s) internal view { bytes32 digest = keccak256( abi.encodePacked( "\x19\x01", getDomainSeparator(), encodeData ) ); address recoveredAddress = ecrecover(digest, v, r, s); // Explicitly disallow authorizations for address(0) as ecrecover returns address(0) on malformed messages require(recoveredAddress != address(0) && recoveredAddress == signer, "token: bad sig"); } function _changeMinter(address newMinter) internal { minter = newMinter; emit ChangeMinter(newMinter); } function _mint(address to, uint256 value) internal { totalSupply = totalSupply.add(value); balanceOf[to] = balanceOf[to].add(value); emit Transfer(address(0), to, value); } function _burn(address from, uint value) internal { // Balance is implicitly checked with SafeMath's underflow protection balanceOf[from] = balanceOf[from].sub(value); totalSupply = totalSupply.sub(value); emit Transfer(from, address(0), value); } function _approve(address owner, address spender, uint256 value) private { allowance[owner][spender] = value; emit Approval(owner, spender, value); } function _transfer(address from, address to, uint256 value) private { require(to != address(this) && to != address(0), "token: bad to"); // Balance is implicitly checked with SafeMath's underflow protection balanceOf[from] = balanceOf[from].sub(value); balanceOf[to] = balanceOf[to].add(value); emit Transfer(from, to, value); } function getChainId() public pure returns (uint256 chainId) { assembly { chainId := chainid() } } function getDomainSeparator() public view returns (bytes32) { return keccak256( abi.encode( EIP712DOMAIN_HASH, keccak256(abi.encodePacked(name)), VERSION_HASH, getChainId(), address(this) ) ); } function mint(address to, uint256 value) external onlyMinter returns (bool) { _mint(to, value); return true; } function changeMinter(address newMinter) external onlyMinter { _changeMinter(newMinter); } function burn(uint256 value) external returns (bool) { _burn(msg.sender, value); return true; } function approve(address spender, uint256 value) override external returns (bool) { _approve(msg.sender, spender, value); return true; } function transfer(address to, uint256 value) override external returns (bool) { _transfer(msg.sender, to, value); return true; } function transferFrom(address from, address to, uint256 value) override external returns (bool) { uint256 fromAllowance = allowance[from][msg.sender]; if (fromAllowance != uint256(-1)) { // Allowance is implicitly checked with SafeMath's underflow protection allowance[from][msg.sender] = fromAllowance.sub(value); } _transfer(from, to, value); return true; } function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external { require(deadline >= block.timestamp, "token: auth expired"); bytes32 encodeData = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)); _validateSignedData(owner, encodeData, v, r, s); _approve(owner, spender, value); } function transferWithAuthorization( address from, address to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, uint8 v, bytes32 r, bytes32 s ) external { require(block.timestamp > validAfter, "token: auth wait"); require(block.timestamp < validBefore, "token: auth expired"); require(!authorizationState[from][nonce], "token: auth used"); bytes32 encodeData = keccak256(abi.encode(TRANSFER_WITH_AUTHORIZATION_TYPEHASH, from, to, value, validAfter, validBefore, nonce)); _validateSignedData(from, encodeData, v, r, s); authorizationState[from][nonce] = true; emit AuthorizationUsed(from, nonce); _transfer(from, to, value); } }
/* * SPDX-License-Identifier: GPL-3.0 */ // Copied and modified from: https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol pragma solidity ^0.6.8; import "@openzeppelin/contracts/cryptography/MerkleProof.sol"; import "@aragon/govern-contract-utils/contracts/erc20/SafeERC20.sol"; import "@aragon/govern-contract-utils/contracts/initializable/Initializable.sol"; contract MerkleDistributor is Initializable { using SafeERC20 for ERC20; ERC20 public token; bytes32 public merkleRoot; // This is a packed array of booleans. mapping (uint256 => uint256) private claimedBitMap; event Claimed(uint256 indexed index, address indexed to, uint256 amount); constructor(ERC20 _token, bytes32 _merkleRoot) public { initialize(_token, _merkleRoot); } function initialize(ERC20 _token, bytes32 _merkleRoot) public onlyInit("distributor") { token = _token; merkleRoot = _merkleRoot; } function claim(uint256 _index, address _to, uint256 _amount, bytes32[] calldata _merkleProof) external { require(!isClaimed(_index), "dist: already claimed"); require(_verifyBalanceOnTree(_index, _to, _amount, _merkleProof), "dist: proof failed"); _setClaimed(_index); token.safeTransfer(_to, _amount); emit Claimed(_index, _to, _amount); } function unclaimedBalance(uint256 _index, address _to, uint256 _amount, bytes32[] memory _proof) public view returns (uint256) { if (isClaimed(_index)) return 0; return _verifyBalanceOnTree(_index, _to, _amount, _proof) ? _amount : 0; } function _verifyBalanceOnTree(uint256 _index, address _to, uint256 _amount, bytes32[] memory _proof) internal view returns (bool) { bytes32 node = keccak256(abi.encodePacked(_index, _to, _amount)); return MerkleProof.verify(_proof, merkleRoot, node); } function isClaimed(uint256 _index) public view returns (bool) { uint256 claimedWord_index = _index / 256; uint256 claimedBit_index = _index % 256; uint256 claimedWord = claimedBitMap[claimedWord_index]; uint256 mask = (1 << claimedBit_index); return claimedWord & mask == mask; } function _setClaimed(uint256 _index) private { uint256 claimedWord_index = _index / 256; uint256 claimedBit_index = _index % 256; claimedBitMap[claimedWord_index] = claimedBitMap[claimedWord_index] | (1 << claimedBit_index); } }
/* * SPDX-License-Identifier: GPL-3.0 */ pragma solidity ^0.6.8; // A library for performing overflow-safe math, courtesy of DappHub: https://github.com/dapphub/ds-math/blob/d0ef6d6a5f/src/math.sol // Modified to include only the essentials library SafeMath { function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x, "math: overflow"); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x, "math: underflow"); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev These functions deal with verification of Merkle trees (hash trees), */ library MerkleProof { /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { bytes32 proofElement = proof[i]; if (computedHash <= proofElement) { // Hash(current computed hash + current element of the proof) computedHash = keccak256(abi.encodePacked(computedHash, proofElement)); } else { // Hash(current element of the proof + current computed hash) computedHash = keccak256(abi.encodePacked(proofElement, computedHash)); } } // Check if the computed hash (root) is equal to the provided root return computedHash == root; } }
/* * SPDX-License-Identifier: GPL-3.0 */ pragma solidity 0.6.8; pragma experimental ABIEncoderV2; // required for passing structs in calldata (fairly secure at this point) import "erc3k/contracts/IERC3000.sol"; import "@aragon/govern-contract-utils/contracts/acl/ACL.sol"; import "@aragon/govern-contract-utils/contracts/adaptive-erc165/AdaptiveERC165.sol"; import "@aragon/govern-contract-utils/contracts/deposits/DepositLib.sol"; import "@aragon/govern-contract-utils/contracts/erc20/SafeERC20.sol"; import '@aragon/govern-contract-utils/contracts/safe-math/SafeMath.sol'; import "../protocol/IArbitrable.sol"; import "../protocol/IArbitrator.sol"; library GovernQueueStateLib { enum State { None, Scheduled, Challenged, Approved, Rejected, Cancelled, Executed } struct Item { State state; } function checkState(Item storage _item, State _requiredState) internal view { require(_item.state == _requiredState, "queue: bad state"); } function setState(Item storage _item, State _state) internal { _item.state = _state; } function checkAndSetState(Item storage _item, State _fromState, State _toState) internal { checkState(_item, _fromState); setState(_item, _toState); } } contract GovernQueue is IERC3000, IArbitrable, AdaptiveERC165, ACL { // Syntax sugar to enable method-calling syntax on types using ERC3000Data for *; using DepositLib for ERC3000Data.Collateral; using GovernQueueStateLib for GovernQueueStateLib.Item; using SafeERC20 for ERC20; using SafeMath for uint256; // Map '4' as the 'allow' ruling; this implicitly maps '3' as the 'reject' ruling uint256 internal constant ALLOW_RULING = 4; // Permanent state bytes32 public configHash; // keccak256 hash of the current ERC3000Data.Config uint256 public nonce; // number of scheduled payloads so far mapping (bytes32 => GovernQueueStateLib.Item) public queue; // container hash -> execution state // Temporary state mapping (bytes32 => address) public challengerCache; // container hash -> challenger addr (used after challenging and before dispute resolution) mapping (bytes32 => mapping (IArbitrator => uint256)) public disputeItemCache; // container hash -> arbitrator addr -> dispute id (used between dispute creation and ruling) /** * @param _aclRoot account that will be given root permissions on ACL (commonly given to factory) * @param _initialConfig initial configuration parameters */ constructor(address _aclRoot, ERC3000Data.Config memory _initialConfig) public ACL(_aclRoot) // note that this contract directly derives from ACL (ACL is local to contract and not global to system in Govern) { initialize(_aclRoot, _initialConfig); } function initialize(address _aclRoot, ERC3000Data.Config memory _initialConfig) public initACL(_aclRoot) onlyInit("queue") { _setConfig(_initialConfig); _registerStandard(type(IERC3000).interfaceId); } /** * @notice Schedules an action for execution, allowing for challenges and vetos on a defined time window. Pulls collateral from submitter into contract. * @param _container A ERC3000Data.Container struct holding both the payload being scheduled for execution and * the current configuration of the system */ function schedule(ERC3000Data.Container memory _container) // TO FIX: Container is in memory and function has to be public to avoid an unestrutable solidity crash public override auth(this.schedule.selector) // note that all functions in this contract are ACL protected (commonly some of them will be open for any addr to perform) returns (bytes32 containerHash) { // prevent griefing by front-running (the same container is sent by two different people and one must be challenged) // and ensure container hashes are unique require(_container.payload.nonce == ++nonce, "queue: bad nonce"); // hash using ERC3000Data.hash(ERC3000Data.Config) bytes32 _configHash = _container.config.hash(); // ensure that the hash of the config passed in the container matches the current config (implicit agreement approval by scheduler) require(_configHash == configHash, "queue: bad config"); // ensure that the time delta to the execution timestamp provided in the payload is at least after the config's execution delay require(_container.payload.executionTime >= _container.config.executionDelay.add(block.timestamp), "queue: bad delay"); // ensure that the submitter of the payload is also the sender of this call require(_container.payload.submitter == msg.sender, "queue: bad submitter"); // Restrict the size of calldata to _container.config.maxCalldataSize to make sure challenge function stays callable uint calldataSize; assembly { calldataSize := calldatasize() } require(calldataSize <= _container.config.maxCalldataSize, "calldatasize: limit exceeded"); // store and set container's hash containerHash = ERC3000Data.containerHash(_container.payload.hash(), _configHash); queue[containerHash].checkAndSetState( GovernQueueStateLib.State.None, // ensure that the state for this container is None GovernQueueStateLib.State.Scheduled // and if so perform a state transition to Scheduled ); // we don't need to save any more state about the container in storage // we just authenticate the hash and assign it a state, since all future // actions regarding the container will need to provide it as a witness // all witnesses are logged from this contract at least once, so the // trust assumption should be the same as storing all on-chain (move complexity to clients) ERC3000Data.Collateral memory collateral = _container.config.scheduleDeposit; collateral.collectFrom(_container.payload.submitter); // pull collateral from submitter (requires previous approval) // the configured resolver may specify additional out-of-band payments for scheduling actions // schedule() leaves these requirements up to the callers of `schedule()` or other users to fulfill // emit an event to ensure data availability of all state that cannot be otherwise fetched (see how config isn't emitted since an observer should already have it) emit Scheduled(containerHash, _container.payload); } /** * @notice Executes an action after its execution delay has passed and its state hasn't been altered by a challenge or veto * @param _container A ERC3000Data.Container struct holding both the payload being scheduled for execution and * the current configuration of the system */ function execute(ERC3000Data.Container memory _container) public override auth(this.execute.selector) // in most instances this will be open for any addr, but leaving configurable for flexibility returns (bytes32 failureMap, bytes[] memory) { // ensure enough time has passed require(block.timestamp >= _container.payload.executionTime, "queue: wait more"); bytes32 containerHash = _container.hash(); queue[containerHash].checkAndSetState( GovernQueueStateLib.State.Scheduled, // note that we will revert here if the container wasn't previously scheduled GovernQueueStateLib.State.Executed ); _container.config.scheduleDeposit.releaseTo(_container.payload.submitter); // release collateral to original submitter return _execute(_container.payload, containerHash); } /** * @notice Challenge a container in case its scheduling is illegal as per Config.rules. Pulls collateral and dispute fees from sender into contract * @param _container A ERC3000Data.Container struct holding both the payload being scheduled for execution and * the current configuration of the system * @param _reason Hint for case reviewers as to why the scheduled container is illegal */ function challenge(ERC3000Data.Container memory _container, bytes memory _reason) auth(this.challenge.selector) override public returns (uint256 disputeId) { bytes32 containerHash = _container.hash(); challengerCache[containerHash] = msg.sender; // cache challenger address while it is needed queue[containerHash].checkAndSetState( GovernQueueStateLib.State.Scheduled, GovernQueueStateLib.State.Challenged ); ERC3000Data.Collateral memory collateral = _container.config.challengeDeposit; collateral.collectFrom(msg.sender); // pull challenge collateral from sender // create dispute on arbitrator IArbitrator arbitrator = IArbitrator(_container.config.resolver); (address recipient, ERC20 feeToken, uint256 feeAmount) = arbitrator.getDisputeFees(); require(feeToken.safeTransferFrom(msg.sender, address(this), feeAmount), "queue: bad fee pull"); require(feeToken.safeApprove(recipient, feeAmount), "queue: bad approve"); disputeId = arbitrator.createDispute(2, abi.encode(_container)); // create dispute sending full container ABI encoded (could prob just send payload to save gas) require(feeToken.safeApprove(recipient, 0), "queue: bad reset"); // reset just in case non-compliant tokens (that fail on non-zero to non-zero approvals) are used // submit both arguments as evidence and close evidence period. no more evidence can be submitted and a settlement can't happen (could happen off-protocol) arbitrator.submitEvidence(disputeId, _container.payload.submitter, _container.payload.proof); arbitrator.submitEvidence(disputeId, msg.sender, _reason); arbitrator.closeEvidencePeriod(disputeId); disputeItemCache[containerHash][arbitrator] = disputeId + 1; // cache a relation between disputeId and containerHash while needed emit Challenged(containerHash, msg.sender, _reason, disputeId, collateral); } /** * @notice Apply arbitrator's ruling over a challenge once it has come to a final ruling * @param _container A ERC3000Data.Container struct holding both the payload being scheduled for execution and * the current configuration of the system * @param _disputeId disputeId in the arbitrator in which the dispute over the container was created */ function resolve(ERC3000Data.Container memory _container, uint256 _disputeId) override public returns (bytes32 failureMap, bytes[] memory) { bytes32 containerHash = _container.hash(); IArbitrator arbitrator = IArbitrator(_container.config.resolver); require(disputeItemCache[containerHash][arbitrator] == _disputeId + 1, "queue: bad dispute id"); delete disputeItemCache[containerHash][arbitrator]; // release state to refund gas; no longer needed in state queue[containerHash].checkState(GovernQueueStateLib.State.Challenged); (address subject, uint256 ruling) = arbitrator.rule(_disputeId); require(subject == address(this), "queue: not subject"); bool arbitratorApproved = ruling == ALLOW_RULING; queue[containerHash].setState( arbitratorApproved ? GovernQueueStateLib.State.Approved : GovernQueueStateLib.State.Rejected ); emit Resolved(containerHash, msg.sender, arbitratorApproved); emit Ruled(arbitrator, _disputeId, ruling); if (arbitratorApproved) { return _executeApproved(_container); } else { return _settleRejection(_container); } } function veto(ERC3000Data.Container memory _container, bytes memory _reason) auth(this.veto.selector) override public { bytes32 containerHash = _container.hash(); GovernQueueStateLib.Item storage item = queue[containerHash]; if (item.state == GovernQueueStateLib.State.Challenged) { item.checkAndSetState( GovernQueueStateLib.State.Challenged, GovernQueueStateLib.State.Cancelled ); address challenger = challengerCache[containerHash]; // release state to refund gas; no longer needed in state delete challengerCache[containerHash]; delete disputeItemCache[containerHash][IArbitrator(_container.config.resolver)]; // release collateral to challenger and scheduler _container.config.scheduleDeposit.releaseTo(_container.payload.submitter); _container.config.challengeDeposit.releaseTo(challenger); } else { // If the given container doesn't have the state Challenged // has it to be the Scheduled state and otherwise should it throw as expected item.checkAndSetState( GovernQueueStateLib.State.Scheduled, GovernQueueStateLib.State.Cancelled ); _container.config.scheduleDeposit.releaseTo(_container.payload.submitter); } emit Vetoed(containerHash, msg.sender, _reason); } /** * @notice Apply a new configuration for all *new* containers to be scheduled * @param _config A ERC3000Data.Config struct holding all the new params that will control the queue */ function configure(ERC3000Data.Config memory _config) public override auth(this.configure.selector) returns (bytes32) { return _setConfig(_config); } // Internal function _executeApproved(ERC3000Data.Container memory _container) internal returns (bytes32 failureMap, bytes[] memory) { bytes32 containerHash = _container.hash(); queue[containerHash].checkAndSetState( GovernQueueStateLib.State.Approved, GovernQueueStateLib.State.Executed ); delete challengerCache[containerHash]; // release state to refund gas; no longer needed in state // release all collateral to submitter _container.config.scheduleDeposit.releaseTo(_container.payload.submitter); _container.config.challengeDeposit.releaseTo(_container.payload.submitter); return _execute(_container.payload, containerHash); } function _settleRejection(ERC3000Data.Container memory _container) internal returns (bytes32, bytes[] memory) { bytes32 containerHash = _container.hash(); queue[containerHash].checkAndSetState( GovernQueueStateLib.State.Rejected, GovernQueueStateLib.State.Cancelled ); address challenger = challengerCache[containerHash]; delete challengerCache[containerHash]; // release state to refund gas; no longer needed in state // release all collateral to challenger _container.config.scheduleDeposit.releaseTo(challenger); _container.config.challengeDeposit.releaseTo(challenger); // return zero values as nothing is executed on rejection } function _execute(ERC3000Data.Payload memory _payload, bytes32 _containerHash) internal returns (bytes32, bytes[] memory) { emit Executed(_containerHash, msg.sender); return _payload.executor.exec(_payload.actions, _payload.allowFailuresMap, _containerHash); } function _setConfig(ERC3000Data.Config memory _config) internal returns (bytes32) { // validate collaterals by calling balanceOf on their interface if(_config.challengeDeposit.amount != 0 && _config.challengeDeposit.token != address(0)) { (bool ok, bytes memory value) = _config.challengeDeposit.token.call( abi.encodeWithSelector(ERC20.balanceOf.selector, address(this)) ); require(ok && value.length > 0, "queue: bad config"); } if(_config.scheduleDeposit.amount != 0 && _config.scheduleDeposit.token != address(0)) { (bool ok, bytes memory value) = _config.scheduleDeposit.token.call( abi.encodeWithSelector(ERC20.balanceOf.selector, address(this)) ); require(ok && value.length > 0, "queue: bad config"); } configHash = _config.hash(); emit Configured(configHash, msg.sender, _config); return configHash; } }
/* * SPDX-License-Identifier: MIT */ pragma solidity ^0.6.8; import "erc3k/contracts/ERC3000Data.sol"; import "../erc20/ERC20.sol"; import "../erc20/SafeERC20.sol"; library DepositLib { using SafeERC20 for ERC20; event Locked(address indexed token, address indexed from, uint256 amount); event Unlocked(address indexed token, address indexed to, uint256 amount); function collectFrom(ERC3000Data.Collateral memory _collateral, address _from) internal { if (_collateral.amount > 0) { ERC20 token = ERC20(_collateral.token); require(token.safeTransferFrom(_from, address(this), _collateral.amount), "deposit: bad token lock"); emit Locked(_collateral.token, _from, _collateral.amount); } } function releaseTo(ERC3000Data.Collateral memory _collateral, address _to) internal { if (_collateral.amount > 0) { ERC20 token = ERC20(_collateral.token); require(token.safeTransfer(_to, _collateral.amount), "deposit: bad token release"); emit Unlocked(_collateral.token, _to, _collateral.amount); } } }
/* * SPDX-License-Identifier: MIT */ // From https://github.com/aragon/protocol/blob/f1b3361a160da92b9bb449c0a05dee0c30e41594/packages/evm/contracts/arbitration/IArbitrable.sol pragma solidity ^0.6.8; import "./IArbitrator.sol"; /** * @dev The Arbitrable instances actually don't require to follow any specific interface. * Note that this is actually optional, although it does allow the Protocol to at least have a way to identify a specific set of instances. */ abstract contract IArbitrable { /** * @dev Emitted when an IArbitrable instance's dispute is ruled by an IArbitrator * @param arbitrator IArbitrator instance ruling the dispute * @param disputeId Identification number of the dispute being ruled by the arbitrator * @param ruling Ruling given by the arbitrator */ event Ruled(IArbitrator indexed arbitrator, uint256 indexed disputeId, uint256 ruling); }
/* * SPDX-License-Identifier: MIT */ // From https://github.com/aragon/protocol/blob/f1b3361a160da92b9bb449c0a05dee0c30e41594/packages/evm/contracts/arbitration/IArbitrator.sol pragma solidity ^0.6.8; import "@aragon/govern-contract-utils/contracts/erc20/ERC20.sol"; interface IArbitrator { /** * @dev Create a dispute over the Arbitrable sender with a number of possible rulings * @param _possibleRulings Number of possible rulings allowed for the dispute * @param _metadata Optional metadata that can be used to provide additional information on the dispute to be created * @return Dispute identification number */ function createDispute(uint256 _possibleRulings, bytes calldata _metadata) external returns (uint256); /** * @dev Submit evidence for a dispute * @param _disputeId Id of the dispute in the Protocol * @param _submitter Address of the account submitting the evidence * @param _evidence Data submitted for the evidence related to the dispute */ function submitEvidence(uint256 _disputeId, address _submitter, bytes calldata _evidence) external; /** * @dev Close the evidence period of a dispute * @param _disputeId Identification number of the dispute to close its evidence submitting period */ function closeEvidencePeriod(uint256 _disputeId) external; /** * @notice Rule dispute #`_disputeId` if ready * @param _disputeId Identification number of the dispute to be ruled * @return subject Subject associated to the dispute * @return ruling Ruling number computed for the given dispute */ function rule(uint256 _disputeId) external returns (address subject, uint256 ruling); /** * @dev Tell the dispute fees information to create a dispute * @return recipient Address where the corresponding dispute fees must be transferred to * @return feeToken ERC20 token used for the fees * @return feeAmount Total amount of fees that must be allowed to the recipient */ function getDisputeFees() external view returns (address recipient, ERC20 feeToken, uint256 feeAmount); /** * @dev Tell the payments recipient address * @return Address of the payments recipient module */ function getPaymentsRecipient() external view returns (address); }
/* * SPDX-License-Identifier: GPL-3.0 */ pragma solidity 0.6.8; pragma experimental ABIEncoderV2; import "@aragon/govern-token/contracts/GovernMinter.sol"; import "@aragon/govern-token/contracts/GovernToken.sol"; import "@aragon/govern-token/contracts/libraries/TokenLib.sol"; contract GovernTokenFactoryMock { event NewTokenCalledWith(address initialMinter, string _tokenName, string _tokenSymbol, uint8 tokenDecimals, address mintAddr, uint256 mintAmount, bool useProxies); function newToken( address _initialMinter, TokenLib.TokenConfig calldata _token, bool _useProxies ) external returns ( GovernToken token, GovernMinter minter ) { emit NewTokenCalledWith( _initialMinter, _token.tokenName, _token.tokenSymbol, _token.tokenDecimals, _token.mintAddress, _token.mintAmount, _useProxies ); token = GovernToken(address(this)); minter = GovernMinter(address(this)); } }
/* * SPDX-License-Identifier: GPL-3.0 */ pragma solidity 0.6.8; pragma experimental ABIEncoderV2; import "@aragon/govern-core/contracts/pipelines/GovernQueue.sol"; import "@aragon/govern-contract-utils/contracts/acl/ACL.sol"; contract GovernQueueFactoryMock { event NewQueueCalledWith(address aclRoot, bytes32 salt); event BulkCalled(ACLData.BulkItem[] items); bytes4 public constant ROOT_ROLE = "0x"; function schedule() public pure {} function execute() public pure {} function challenge() public pure {} function configure(ERC3000Data.Config memory /*_config*/) public pure returns(bool) { // TODO: emit events and catch it in the govern-base-factory-unit.test.ts return true; } // probably ACL inheritance can be used instead of implementing ACL functions again. function grant(bytes4 _role, address _who) public pure { // TODO: emit events and catch it in the govern-base-factory-unit.test.ts } function revoke(bytes4 _role, address _who) public pure { // TODO: emit events and catch it in the govern-base-factory-unit.test.ts } function bulk(ACLData.BulkItem[] memory items) public { emit BulkCalled(items); } function newQueue(address _aclRoot, ERC3000Data.Config memory /*_config*/, bytes32 _salt) public returns (GovernQueue queue) { /* TODO:There seems to be a bug with waffle. After it's been fixed, emit the _config too and in the test, assert it. https://github.com/EthWorks/Waffle/issues/454 */ emit NewQueueCalledWith(_aclRoot, _salt); return GovernQueue(address(this)); } }
/* * SPDX-License-Identifier: GPL-3.0 */ pragma solidity 0.6.8; import "erc3k/contracts/IERC3000.sol"; import "@aragon/govern-core/contracts/Govern.sol"; import "@aragon/govern-contract-utils/contracts/address-utils/AddressUtils.sol"; contract GovernFactoryMock { using AddressUtils for address; event NewGovernCalledWith(IERC3000 executor, bytes32 salt); function newGovern(IERC3000 _initialExecutor, bytes32 _salt) public returns (Govern govern) { emit NewGovernCalledWith(_initialExecutor, _salt); return Govern(address(this).toPayable()); } }
{ "optimizer": { "enabled": true, "runs": 20000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "metadata": { "useLiteralContent": true } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"base","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_aclRoot","type":"address"},{"components":[{"internalType":"uint256","name":"executionDelay","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ERC3000Data.Collateral","name":"scheduleDeposit","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ERC3000Data.Collateral","name":"challengeDeposit","type":"tuple"},{"internalType":"address","name":"resolver","type":"address"},{"internalType":"bytes","name":"rules","type":"bytes"},{"internalType":"uint256","name":"maxCalldataSize","type":"uint256"}],"internalType":"struct ERC3000Data.Config","name":"_config","type":"tuple"},{"internalType":"bytes32","name":"_salt","type":"bytes32"}],"name":"newQueue","outputs":[{"internalType":"contract GovernQueue","name":"queue","type":"address"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50620000256001600160e01b036200002b16565b62000254565b62000035620000ec565b6200003f62000103565b6040518060c00160405280610e10815260200183815260200183815260200160006001600160a01b03168152602001604051806020016040528060008152508152602001620186a081525090506002816040516200009d9062000152565b620000aa92919062000178565b604051809103906000f080158015620000c7573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b03929092169190911790555050565b604080518082019091526000808252602082015290565b6040518060c00160405280600081526020016200011f620000ec565b81526020016200012e620000ec565b815260200160006001600160a01b0316815260200160608152602001600081525090565b61473a80620052af83390190565b80516001600160a01b03168252602090810151910152565b600060018060a01b03808516835260406020840152835160408401526020840151620001a8606085018262000160565b506040840151620001bd60a085018262000160565b5060608401511660e08301526080830151610100808401528051620001e781610140860162000218565b620001f782826020860162000221565b60a0959095015161012094909401939093525050601f01601f191601919050565b90815260200190565b60005b838110156200023e57818101518382015260200162000224565b838111156200024e576000848401525b50505050565b61504b80620002646000396000f3fe60806040523480156200001157600080fd5b50600436106200003a5760003560e01c80635001f3b5146200003f578063a691fc671462000061575b600080fd5b6200004962000078565b6040516200005891906200073e565b60405180910390f35b6200004962000072366004620004c6565b62000094565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b600081156200016b576200016382638f8b35b260e01b8686604051602401620000bf9291906200075f565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915260005473ffffffffffffffffffffffffffffffffffffffff16919063ffffffff620001b016565b9050620001a9565b83836040516200017b90620003db565b620001889291906200075f565b604051809103906000f080158015620001a5573d6000803e3d6000fd5b5090505b9392505050565b6000620001be84846200028e565b9050600060608273ffffffffffffffffffffffffffffffffffffffff1684604051620001eb919062000720565b6000604051808303816000865af19150503d80600081146200022a576040519150601f19603f3d011682016040523d82523d6000602084013e6200022f565b606091505b509150915081620002408262000302565b9062000284576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200027b9190620007f1565b60405180910390fd5b5050509392505050565b600060606200029d8462000349565b9050826037602083016000f5915073ffffffffffffffffffffffffffffffffffffffff8216620002fb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200027b9062000806565b5092915050565b606060448251101562000325575060408051602081019091526000815262000344565b60048201915081806020019051810190620003419190620005a7565b90505b919050565b604051606090620003c5907f3d602d80600a3d3981f300000000000000000000000000000000000000000000907f363d3d373d3d3d363d73000000000000000000000000000000000000000000009085907f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000009060200162000697565b6040516020818303038152906040529050919050565b61473a80620008dc83390190565b803573ffffffffffffffffffffffffffffffffffffffff811681146200040e57600080fd5b92915050565b600082601f83011262000425578081fd5b81356200043c620004368262000865565b6200083d565b91508082528360208285010111156200045457600080fd5b8060208401602084013760009082016020015292915050565b6000604082840312156200047f578081fd5b6200048b60406200083d565b9050813573ffffffffffffffffffffffffffffffffffffffff81168114620004b257600080fd5b808252506020820135602082015292915050565b600080600060608486031215620004db578283fd5b620004e78585620003e9565b9250602084013567ffffffffffffffff8082111562000504578384fd5b818601610100818903121562000518578485fd5b6200052460c06200083d565b9250803583526200053988602083016200046d565b60208401526200054d88606083016200046d565b6040840152620005618860a08301620003e9565b606084015260c08101358281111562000578578586fd5b620005868982840162000414565b60808501525060e0013560a083015250929592945050506040919091013590565b600060208284031215620005b9578081fd5b815167ffffffffffffffff811115620005d0578182fd5b80830184601f820112620005e2578283fd5b80519150620005f5620004368362000865565b8281528560208484010111156200060a578384fd5b6200061d836020830160208501620008a8565b95945050505050565b6000815180845262000640816020860160208601620008a8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b7fffffffffffffffffffff00000000000000000000000000000000000000000000948516815292909316600a83015260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660148201527fffffffffffffffffffffffffffffff000000000000000000000000000000000091909116602882015260370190565b6000825162000734818460208701620008a8565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600073ffffffffffffffffffffffffffffffffffffffff8085168352604060208401528351604084015260208401516200079d606085018262000672565b506040840151620007b260a085018262000672565b5060608401511660e0830152608083015161010080840152620007da61014084018262000626565b60a085015161012085015280925050509392505050565b600060208252620001a9602083018462000626565b6020808252601a908201527f70726f78792d666163746f72793a206261642063726561746532000000000000604082015260600190565b60405181810167ffffffffffffffff811182821017156200085d57600080fd5b604052919050565b600067ffffffffffffffff8211156200087c578081fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015620008c5578181015183820152602001620008ab565b83811115620008d5576000848401525b5050505056fe60806040523480156200001157600080fd5b506040516200473a3803806200473a833981016040819052620000349162000858565b81806002604051620000469062000967565b90815260200160405180910390205460001415620000785762000072816001600160e01b03620000ec16565b620000cc565b6001600160a01b038181166000908152600080516020620046fa833981519152602052604090205416600214620000cc5760405162461bcd60e51b8152600401620000c39062000a31565b60405180910390fd5b50620000e4905082826001600160e01b03620001bd16565b505062000b84565b604051806040016040528060038152602001621858db60ea1b8152506002816040516200011a919062000949565b9081526020016040518091039020546000146200014b5760405162461bcd60e51b8152600401620000c390620009ef565b436002826040516200015e919062000949565b908152604051908190036020019020556200018a63161b7d8160e21b836001600160e01b036200033416565b806040516200019a919062000949565b604051908190038120906000805160206200471a83398151915290600090a25050565b816002604051620001ce9062000967565b908152602001604051809103902054600014156200020057620001fa816001600160e01b03620000ec16565b6200024b565b6001600160a01b038181166000908152600080516020620046fa8339815191526020526040902054166002146200024b5760405162461bcd60e51b8152600401620000c39062000a31565b60405180604001604052806005815260200164717565756560d81b8152506002816040516200027b919062000949565b908152602001604051809103902054600014620002ac5760405162461bcd60e51b8152600401620000c390620009ef565b43600282604051620002bf919062000949565b90815260405190819003602001902055620002e3836001600160e01b036200034f16565b50620002ff63d311828160e01b6001600160e01b03620005de16565b806040516200030f919062000949565b604051908190038120906000805160206200471a83398151915290600090a250505050565b6200034b828260026001600160e01b036200063f16565b5050565b60008160400151602001516000141580156200037857506040820151516001600160a01b031615155b156200046957600060608360400151600001516001600160a01b03166370a0823160e01b30604051602401620003af919062000976565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051620003ef919062000949565b6000604051808303816000865af19150503d80600081146200042e576040519150601f19603f3d011682016040523d82523d6000602084013e62000433565b606091505b509150915081801562000447575060008151115b620004665760405162461bcd60e51b8152600401620000c3906200099f565b50505b6020808301510151158015906200048d57506020820151516001600160a01b031615155b156200057e57600060608360200151600001516001600160a01b03166370a0823160e01b30604051602401620004c4919062000976565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905162000504919062000949565b6000604051808303816000865af19150503d806000811462000543576040519150601f19603f3d011682016040523d82523d6000602084013e62000548565b606091505b50915091508180156200055c575060008151115b6200057b5760405162461bcd60e51b8152600401620000c3906200099f565b50505b62000594826200072960201b620016e11760201c565b60048190556040513391907f844435c59f7ccdf12de134e8f9b3b7d664fe9f06e3263680779599ba4097bc3f90620005ce90869062000a91565b60405180910390a3505060045490565b6001600160e01b0319811660009081526020819052604090819020805460ff19166001179055517fbf5e1f87f5ab65b58074cd29244d7c487a948983cda4b932e0f966b62bd34aca90620006349083906200098a565b60405180910390a150565b62000653836001600160e01b036200075b16565b15620006735760405162461bcd60e51b8152600401620000c390620009ca565b6001600160a01b03821660011415620006a05760405162461bcd60e51b8152600401620000c39062000a68565b6001600160e01b0319831660008181526003602090815260408083206001600160a01b03878116808652919093529281902080546001600160a01b0319169286169290921790915551909133917fc62063b81f7036fd97a0dc546516e99f11004d2d76ca0fddd3866346c86e7091906200071c90869062000976565b60405180910390a4505050565b6000816040516020016200073e919062000a91565b604051602081830303815290604052805190602001209050919050565b6001600160e01b031916600090815260036020908152604080832060018085529252909120546001600160a01b03161490565b80516001600160a01b0381168114620007a657600080fd5b92915050565b600082601f830112620007bd578081fd5b81516001600160401b03811115620007d3578182fd5b620007e8601f8201601f191660200162000b2a565b91508082528360208285010111156200080057600080fd5b6200081381602084016020860162000b51565b5092915050565b6000604082840312156200082c578081fd5b62000838604062000b2a565b90506200084683836200078e565b81526020820151602082015292915050565b600080604083850312156200086b578182fd5b6200087784846200078e565b60208401519092506001600160401b038082111562000894578283fd5b8185016101008188031215620008a8578384fd5b620008b460c062000b2a565b925080518352620008c987602083016200081a565b6020840152620008dd87606083016200081a565b6040840152620008f18760a083016200078e565b606084015260c08101518281111562000908578485fd5b6200091688828401620007ac565b60808501525060e0015160a083015250919491935090915050565b80516001600160a01b03168252602090810151910152565b600082516200095d81846020870162000b51565b9190910192915050565b621858db60ea1b815260030190565b6001600160a01b0391909116815260200190565b6001600160e01b031991909116815260200190565b60208082526011908201527071756575653a2062616420636f6e66696760781b604082015260600190565b6020808252600b908201526a30b1b61d10333937bd32b760a91b604082015260600190565b60208082526022908201527f696e697469616c697a61626c653a20616c726561647920696e697469616c697a604082015261195960f21b606082015260800190565b6020808252601c908201527f61636c3a20696e697469616c20726f6f74206d6973616c69676e656400000000604082015260600190565b6020808252600f908201526e61636c3a2062616420667265657a6560881b604082015260600190565b60006020825282516020830152602083015162000ab2604084018262000931565b50604083015162000ac7608084018262000931565b5060608301516001600160a01b031660c0830152608083015161010060e084018190528151610120850181905261014062000b09828288016020870162000b51565b60a0969096015191850191909152601f01601f191690920190920192915050565b6040518181016001600160401b038111828210171562000b4957600080fd5b604052919050565b60005b8381101562000b6e57818101518382015260200162000b54565b8381111562000b7e576000848401525b50505050565b613b668062000b946000396000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c80637e8c7f08116100d8578063affed0e01161008c578063c832048011610066578063c832048014610334578063cc1d4cab14610347578063e1f1176d1461035a57610182565b8063affed0e014610306578063bdf9a7261461030e578063c8182af01461032157610182565b806396fc8abd116100bd57806396fc8abd146102c0578063a157a10d146102e0578063a2157227146102f357610182565b80637e8c7f08146102985780638f8b35b2146102ad57610182565b80633e2da6a91161013a5780635a08160b116101145780635a08160b146102525780637744efda146102655780637c10dea61461027857610182565b80633e2da6a914610219578063495a98251461022c578063588497341461023f57610182565b80631c47671b1161016b5780631c47671b146101d15780631f13405b146101e65780633da956aa1461020657610182565b806301ffc9a71461018757806314d56921146101b0575b600080fd5b61019a610195366004612db5565b610362565b6040516101a79190613335565b60405180910390f35b6101c36101be366004612f90565b6103ac565b6040516101a7929190613349565b6101e46101df366004612c4b565b610631565b005b6101f96101f4366004612f39565b61076b565b6040516101a79190613340565b6101c3610214366004612f06565b610c88565b6101f9610227366004612d86565b610d7d565b61019a61023a366004612db5565b610d9a565b6101e461024d366004612dd1565b610df2565b6101e4610260366004612f39565b610e80565b6101f9610273366004612ed3565b61105e565b61028b610286366004612cd8565b6110d6565b6040516101a7919061348e565b6102a06110eb565b6040516101a791906133cf565b6101e46102bb366004612bd0565b61110f565b6102d36102ce366004612dd1565b6112b5565b6040516101a79190613285565b6101e46102ee366004612dd1565b6112e8565b6101e4610301366004612dfe565b611371565b6101f96113fb565b6101e461031c366004612db5565b611401565b6102d361032f366004612cd8565b61148d565b6101f9610342366004612f06565b6114b5565b6101f9610355366004612e48565b6116be565b6101f96116db565b7fffffffff00000000000000000000000000000000000000000000000000000000811660009081526020819052604081205460ff16806103a657506103a682611711565b92915050565b6000606060006103bb8561175b565b60208087015160600151600083815260088352604080822073ffffffffffffffffffffffffffffffffffffffff8416835290935291909120549192509060018601146104225760405162461bcd60e51b815260040161041990613597565b60405180910390fd5b600082815260086020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845282528083208390558483526006909152902061046f90600263ffffffff61177f16565b6000808273ffffffffffffffffffffffffffffffffffffffff1663db18af6c886040518263ffffffff1660e01b81526004016104ab9190613340565b6040805180830381600087803b1580156104c457600080fd5b505af11580156104d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104fc9190612c1e565b909250905073ffffffffffffffffffffffffffffffffffffffff821630146105365760405162461bcd60e51b81526004016104199061381a565b600481146105668161054957600461054c565b60035b60008781526006602052604090209063ffffffff6117b816565b3373ffffffffffffffffffffffffffffffffffffffff16857f027d8a5d945eb361475964ed2c71b8332b27af2d630ab5daf829d67afd2584e6836040516105ad9190613335565b60405180910390a3878473ffffffffffffffffffffffffffffffffffffffff167f56c8631a8915c0d362dbe57a61215fdde954f73f81c8a3a1f55572fb015207b1846040516105fc9190613340565b60405180910390a3801561062157610613896117f7565b96509650505050505061062a565b610613896118b8565b9250929050565b60408051602036601f81018290048202830182019093528282527f586df604000000000000000000000000000000000000000000000000000000009261069492849233926000918190840183828082843760009201919091525061197592505050565b6106b05760405162461bcd60e51b815260040161041990613560565b60005b82811015610765576106c36127f3565b8484838181106106cf57fe5b9050606002018036038101906106e59190612e7b565b90506000815160028111156106f657fe5b14156107135761070e816020015182604001516119bb565b61075c565b60018151600281111561072257fe5b141561073a5761070e816020015182604001516119c7565b60028151600281111561074957fe5b141561075c5761075c8160200151611a95565b506001016106b3565b50505050565b6000631f13405b60e01b6107b781336000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061197592505050565b6107d35760405162461bcd60e51b815260040161041990613560565b60006107de8561175b565b600081815260076020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317905560069091529020909150610834906001600263ffffffff611b4d16565b61083c612815565b50602085015160400151610856813363ffffffff611b6116565b6000866020015160600151905060008060008373ffffffffffffffffffffffffffffffffffffffff16637b751b9e6040518163ffffffff1660e01b815260040160606040518083038186803b1580156108ae57600080fd5b505afa1580156108c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e69190612b8e565b9194509250905061091573ffffffffffffffffffffffffffffffffffffffff831633308463ffffffff611c2b16565b6109315760405162461bcd60e51b815260040161041990613673565b61095873ffffffffffffffffffffffffffffffffffffffff8316848363ffffffff611cdf16565b6109745760405162461bcd60e51b815260040161041990613718565b8373ffffffffffffffffffffffffffffffffffffffff1663c13517e160028c6040516020016109a39190613940565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016109cf9291906134a2565b602060405180830381600087803b1580156109e957600080fd5b505af11580156109fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a219190612fd3565b9750610a4b73ffffffffffffffffffffffffffffffffffffffff831684600063ffffffff611cdf16565b610a675760405162461bcd60e51b81526004016104199061363c565b895160408082015160c09092015190517f7cb57c6400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871692637cb57c6492610ac8928d9291906004016139aa565b600060405180830381600087803b158015610ae257600080fd5b505af1158015610af6573d6000803e3d6000fd5b50506040517f7cb57c6400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87169250637cb57c649150610b50908b9033908e906004016139aa565b600060405180830381600087803b158015610b6a57600080fd5b505af1158015610b7e573d6000803e3d6000fd5b50506040517f7e9adccf00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87169250637e9adccf9150610bd4908b90600401613340565b600060405180830381600087803b158015610bee57600080fd5b505af1158015610c02573d6000803e3d6000fd5b505050600087815260086020908152604080832073ffffffffffffffffffffffffffffffffffffffff891684529091529081902060018b0190555133915087907f429df837eb45b6713f725a0d3e57db939fd7dd7d58bb3cd967fa37091572db9f90610c73908d908d908b90613466565b60405180910390a35050505050505092915050565b60006060633da956aa60e01b610cd681336000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061197592505050565b610cf25760405162461bcd60e51b815260040161041990613560565b835160200151421015610d175760405162461bcd60e51b8152600401610419906137ac565b6000610d228561175b565b6000818152600660208190526040909120919250610d49919060019063ffffffff611b4d16565b8451604001516020808701510151610d669163ffffffff611d9016565b8451610d729082611e4b565b935093505050915091565b600860209081526000928352604080842090915290825290205481565b7fffffffff00000000000000000000000000000000000000000000000000000000166000908152600360209081526040808320600180855292529091205473ffffffffffffffffffffffffffffffffffffffff161490565b60408051602036601f81018290048202830182019093528282527f586df6040000000000000000000000000000000000000000000000000000000092610e5592849233926000918190840183828082843760009201919091525061197592505050565b610e715760405162461bcd60e51b815260040161041990613560565b610e7b83836119c7565b505050565b635a08160b60e01b610eca81336000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061197592505050565b610ee65760405162461bcd60e51b815260040161041990613560565b6000610ef18461175b565b60008181526006602052604090209091506002815460ff166006811115610f1457fe5b1415610fd857610f2d816002600563ffffffff611b4d16565b600082815260076020908152604080832080547fffffffffffffffffffffffff000000000000000000000000000000000000000081169091556008835281842089840180516060015173ffffffffffffffffffffffffffffffffffffffff908116875291855283862095909555895190920151935190920151911691610fb9919063ffffffff611d9016565b602086015160400151610fd2908263ffffffff611d9016565b50611008565b610feb816001600563ffffffff611b4d16565b84516040015160208087015101516110089163ffffffff611d9016565b3373ffffffffffffffffffffffffffffffffffffffff16827fe2530b9681f9726904f9ca7fe725c0c53ea1b72370981ac6a5beaa9758c8c3568660405161104f9190613453565b60405180910390a35050505050565b6000637744efda60e01b6110aa81336000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061197592505050565b6110c65760405162461bcd60e51b815260040161041990613560565b6110cf83611f45565b9392505050565b60066020526000908152604090205460ff1681565b7f586df6040000000000000000000000000000000000000000000000000000000081565b81600260405161111e906131f4565b908152602001604051809103902054600014156111435761113e81612277565b6111a9565b73ffffffffffffffffffffffffffffffffffffffff81811660009081527fd87da3e1f08043464b74e6b0861ccd8d8a5174e228287ac9b9f6efc1673da4ec6020526040902054166002146111a95760405162461bcd60e51b815260040161041990613888565b6040518060400160405280600581526020017f71756575650000000000000000000000000000000000000000000000000000008152506002816040516111ef91906131d8565b90815260200160405180910390205460001461121d5760405162461bcd60e51b81526004016104199061374f565b4360028260405161122e91906131d8565b9081526040519081900360200190205561124783611f45565b506112717fd311828100000000000000000000000000000000000000000000000000000000612378565b8060405161127f91906131d8565b604051908190038120907f7bc2a48a4a566e237a12186f19d985b0f76afc9d5290601edac19876253670c290600090a250505050565b600360209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b60408051602036601f81018290048202830182019093528282527f586df604000000000000000000000000000000000000000000000000000000009261134b92849233926000918190840183828082843760009201919091525061197592505050565b6113675760405162461bcd60e51b815260040161041990613560565b610e7b83836119bb565b60408051602036601f81018290048202830182019093528282527f586df60400000000000000000000000000000000000000000000000000000000926113d492849233926000918190840183828082843760009201919091525061197592505050565b6113f05760405162461bcd60e51b815260040161041990613560565b61076584848461240d565b60055481565b60408051602036601f81018290048202830182019093528282527f586df604000000000000000000000000000000000000000000000000000000009261146492849233926000918190840183828082843760009201919091525061197592505050565b6114805760405162461bcd60e51b815260040161041990613560565b61148982611a95565b5050565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b600063c832048060e01b61150181336000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061197592505050565b61151d5760405162461bcd60e51b815260040161041990613560565b6005805460010190819055835151146115485760405162461bcd60e51b8152600401610419906135ce565b600061155784602001516116e1565b9050600454811461157a5760405162461bcd60e51b815260040161041990613529565b602084015151611590904263ffffffff61252e16565b84516020015110156115b45760405162461bcd60e51b815260040161041990613605565b83516040015173ffffffffffffffffffffffffffffffffffffffff1633146115ee5760405162461bcd60e51b8152600401610419906136aa565b602084015160a0015136908111156116185760405162461bcd60e51b815260040161041990613851565b61162e6116288660000151612551565b836125b9565b60008181526006602052604081209195506116519190600163ffffffff611b4d16565b611659612815565b50602080860151015185516040015161167990829063ffffffff611b6116565b847f67f87ff46443c95843c7bd72a026dd23ba0015528ce9f8f15c5c6917645034ef87600001516040516116ad9190613997565b60405180910390a250505050919050565b805160208183018101805160028252928201919093012091525481565b60045481565b6000816040516020016116f4919061392d565b604051602081830303815290604052805190602001209050919050565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f01ffc9a70000000000000000000000000000000000000000000000000000000014919050565b60006103a661176d8360000151612551565b61177a84602001516116e1565b6125b9565b80600681111561178b57fe5b825460ff16600681111561179b57fe5b146114895760405162461bcd60e51b8152600401610419906134f2565b8154819083907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660018360068111156117ee57fe5b02179055505050565b6000606060006118068461175b565b600081815260066020819052604090912091925061182d919060039063ffffffff611b4d16565b60008181526007602090815260409182902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905585519091015185820151909101516118829163ffffffff611d9016565b83516040908101516020860151909101516118a29163ffffffff611d9016565b83516118ae9082611e4b565b9250925050915091565b6000606060006118c78461175b565b60008181526006602052604090209091506118eb906004600563ffffffff611b4d16565b600081815260076020908152604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000008116909155858201519091015173ffffffffffffffffffffffffffffffffffffffff90911690611955908263ffffffff611d9016565b60208501516040015161196e908263ffffffff611d9016565b5050915091565b60006119828484846125f4565b806119b357506119b3847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff846125f4565b949350505050565b6114898282600261240d565b6119d082610d9a565b156119ed5760405162461bcd60e51b8152600401610419906136e1565b7fffffffff000000000000000000000000000000000000000000000000000000008216600081815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055519092339290917f682f2c466c1e9f6883eb72cbced01373e1cb18b05ae5c8bc04dc73d73e29f8cd9190a45050565b611a9e81610d9a565b15611abb5760405162461bcd60e51b8152600401610419906136e1565b7fffffffff00000000000000000000000000000000000000000000000000000000811660008181526003602090815260408083206001808552925280832080547fffffffffffffffffffffffff000000000000000000000000000000000000000016909217909155513392917f049c6b8b07a879425742523fa80f8ffb25e39ad518c93a5896a0df19518397e591a350565b611b57838361177f565b610e7b83826117b8565b6020820151156114895781516020830151611b9d9073ffffffffffffffffffffffffffffffffffffffff8316908490309063ffffffff611c2b16565b611bb95760405162461bcd60e51b8152600401610419906137e3565b8173ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff167f989eaa915cbb416ea3d6f9a63b1a3de51770c7674b11fe21ecdf76b4e1d139108560200151604051611c1e9190613340565b60405180910390a3505050565b600060606323b872dd60e01b858585604051602401611c4c939291906132a6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050611cd5868261275c565b9695505050505050565b6000606063095ea7b360e01b8484604051602401611cfe9291906132d7565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050611d87858261275c565b95945050505050565b6020820151156114895781516020830151611dca9073ffffffffffffffffffffffffffffffffffffffff831690849063ffffffff6127ce16565b611de65760405162461bcd60e51b8152600401610419906134bb565b8173ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff167fe6e0ef9cd056ca98561ca60e347ada61e1ede2f1142a078951b7a52e1e508e608560200151604051611c1e9190613340565b604051600090606090339084907f59c3746e635078efc737fb3f37dd8188203b8df10bbad35878a7d156f4f51c41908590a3836060015173ffffffffffffffffffffffffffffffffffffffff1663c2d85afc85608001518660a00151866040518463ffffffff1660e01b8152600401611ec693929190613310565b600060405180830381600087803b158015611ee057600080fd5b505af1158015611ef4573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611f3a9190810190612cf0565b915091509250929050565b6000816040015160200151600014158015611f7a575060408201515173ffffffffffffffffffffffffffffffffffffffff1615155b156120b8576000606083604001516000015173ffffffffffffffffffffffffffffffffffffffff166370a0823160e01b30604051602401611fbb9190613285565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161204491906131d8565b6000604051808303816000865af19150503d8060008114612081576040519150601f19603f3d011682016040523d82523d6000602084013e612086565b606091505b5091509150818015612099575060008151115b6120b55760405162461bcd60e51b815260040161041990613529565b50505b6020808301510151158015906120e8575060208201515173ffffffffffffffffffffffffffffffffffffffff1615155b15612226576000606083602001516000015173ffffffffffffffffffffffffffffffffffffffff166370a0823160e01b306040516024016121299190613285565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516121b291906131d8565b6000604051808303816000865af19150503d80600081146121ef576040519150601f19603f3d011682016040523d82523d6000602084013e6121f4565b606091505b5091509150818015612207575060008151115b6122235760405162461bcd60e51b815260040161041990613529565b50505b61222f826116e1565b60048190556040513391907f844435c59f7ccdf12de134e8f9b3b7d664fe9f06e3263680779599ba4097bc3f9061226790869061392d565b60405180910390a3505060045490565b6040518060400160405280600381526020017f61636c00000000000000000000000000000000000000000000000000000000008152506002816040516122bd91906131d8565b9081526020016040518091039020546000146122eb5760405162461bcd60e51b81526004016104199061374f565b436002826040516122fc91906131d8565b908152604051908190036020019020556123367f586df60400000000000000000000000000000000000000000000000000000000836119bb565b8060405161234491906131d8565b604051908190038120907f7bc2a48a4a566e237a12186f19d985b0f76afc9d5290601edac19876253670c290600090a25050565b7fffffffff0000000000000000000000000000000000000000000000000000000081166000908152602081905260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fbf5e1f87f5ab65b58074cd29244d7c487a948983cda4b932e0f966b62bd34aca906124029083906133cf565b60405180910390a150565b61241683610d9a565b156124335760405162461bcd60e51b8152600401610419906136e1565b73ffffffffffffffffffffffffffffffffffffffff82166001141561246a5760405162461bcd60e51b8152600401610419906138bf565b7fffffffff000000000000000000000000000000000000000000000000000000008316600081815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff878116808652919093529281902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169286169290921790915551909133917fc62063b81f7036fd97a0dc546516e99f11004d2d76ca0fddd3866346c86e709190612521908690613285565b60405180910390a4505050565b808201828110156103a65760405162461bcd60e51b8152600401610419906138f6565b60008160000151826020015183604001518460600151856080015160405160200161257c91906132fd565b604051602081830303815290604052805190602001208660a001518760c00151805190602001206040516020016116f497969594939291906139df565b60405160009046906125d590309083908790879060200161321d565b6040516020818303038152906040528051906020012091505092915050565b7fffffffff000000000000000000000000000000000000000000000000000000008316600090815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff808716855292528220541680156127515773ffffffffffffffffffffffffffffffffffffffff8116600214156126775760019150506110cf565b6040517f097c810800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82169063097c8108906126cd908890889088906004016133fc565b602060405180830381600087803b1580156126e757600080fd5b505af1925050508015612735575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261273291810190612cb8565b60015b61273e57612751565b801561274f576001925050506110cf565b505b506000949350505050565b600061277d8373ffffffffffffffffffffffffffffffffffffffff166127ed565b612789575060006103a6565b6040516020818451602086016000885af180156127c6573d80156127b457602081146127bd576127c4565b600193506127c4565b8251151593505b505b505092915050565b6000606063a9059cbb60e01b8484604051602401611cfe9291906132d7565b3b151590565b6040805160608101909152806000815260006020820181905260409091015290565b604080518082019091526000808252602082015290565b80356103a681613add565b600082601f830112612847578081fd5b813561285a61285582613a4f565b613a28565b818152915060208083019084810160005b8481101561290f57813587016060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0838c030112156128aa57600080fd5b6128b381613a28565b858301356128c081613add565b8152604083810135878301528284013567ffffffffffffffff8111156128e557600080fd5b6128f38d898388010161291a565b918301919091525086525050928201929082019060010161286b565b505050505092915050565b600082601f83011261292a578081fd5b813561293861285582613a6f565b915080825283602082850101111561294f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112612978578081fd5b815161298661285582613a6f565b915080825283602082850101111561299d57600080fd5b6129ae816020840160208601613ab1565b5092915050565b6000604082840312156129c6578081fd5b6129d06040613a28565b905081356129dd81613add565b808252506020820135602082015292915050565b60006101008284031215612a03578081fd5b612a0d60c0613a28565b905081358152612a2083602084016129b5565b6020820152612a3283606084016129b5565b604082015260a0820135612a4581613add565b606082015260c082013567ffffffffffffffff811115612a6457600080fd5b612a708482850161291a565b60808301525060e082013560a082015292915050565b600060408284031215612a97578081fd5b612aa16040613a28565b9050813567ffffffffffffffff80821115612abb57600080fd5b81840160e08187031215612ace57600080fd5b612ad860e0613a28565b92508035835260208101356020840152612af5866040830161282c565b6040840152612b07866060830161282c565b6060840152608081013582811115612b1e57600080fd5b612b2a87828401612837565b60808501525060a081013560a084015260c081013582811115612b4c57600080fd5b612b588782840161291a565b60c0850152505090825260208301359080821115612b7557600080fd5b50612b82848285016129f1565b60208301525092915050565b600080600060608486031215612ba2578283fd5b8351612bad81613add565b6020850151909350612bbe81613add565b80925050604084015190509250925092565b60008060408385031215612be2578182fd5b8235612bed81613add565b9150602083013567ffffffffffffffff811115612c08578182fd5b612c14858286016129f1565b9150509250929050565b60008060408385031215612c30578182fd5b8251612c3b81613add565b6020939093015192949293505050565b60008060208385031215612c5d578182fd5b823567ffffffffffffffff80821115612c74578384fd5b81850186601f820112612c85578485fd5b8035925081831115612c95578485fd5b866020606085028301011115612ca9578485fd5b60200196919550909350505050565b600060208284031215612cc9578081fd5b815180151581146110cf578182fd5b600060208284031215612ce9578081fd5b5035919050565b60008060408385031215612d02578182fd5b8251915060208084015167ffffffffffffffff811115612d20578283fd5b80850186601f820112612d31578384fd5b80519150612d4161285583613a4f565b82815283810190828501865b85811015612d7657612d648b888451880101612968565b84529286019290860190600101612d4d565b5096999098509650505050505050565b60008060408385031215612d98578182fd5b823591506020830135612daa81613add565b809150509250929050565b600060208284031215612dc6578081fd5b81356110cf81613b02565b60008060408385031215612de3578182fd5b8235612dee81613b02565b91506020830135612daa81613add565b600080600060608486031215612e12578081fd5b8335612e1d81613b02565b92506020840135612e2d81613add565b91506040840135612e3d81613add565b809150509250925092565b600060208284031215612e59578081fd5b813567ffffffffffffffff811115612e6f578182fd5b6119b38482850161291a565b600060608284031215612e8c578081fd5b612e966060613a28565b823560038110612ea4578283fd5b81526020830135612eb481613b02565b60208201526040830135612ec781613add565b60408201529392505050565b600060208284031215612ee4578081fd5b813567ffffffffffffffff811115612efa578182fd5b6119b3848285016129f1565b600060208284031215612f17578081fd5b813567ffffffffffffffff811115612f2d578182fd5b6119b384828501612a86565b60008060408385031215612f4b578182fd5b823567ffffffffffffffff80821115612f62578384fd5b612f6e86838701612a86565b93506020850135915080821115612f83578283fd5b50612c148582860161291a565b60008060408385031215612fa2578182fd5b823567ffffffffffffffff811115612fb8578283fd5b612fc485828601612a86565b95602094909401359450505050565b600060208284031215612fe4578081fd5b5051919050565b6000815180845260208085019450848183028601828601855b858110156130645783830389528151606073ffffffffffffffffffffffffffffffffffffffff82511685528682015187860152604080830151828288015261304e83880182613071565b9c89019c96505050928601925050600101613004565b5090979650505050505050565b60008151808452613089816020860160208601613ab1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b60006101008251845260208301516130fb60208601826130bb565b50604083015161310e60608601826130bb565b5073ffffffffffffffffffffffffffffffffffffffff60608401511660a085015260808301518160c086015261314682860182613071565b60a085015160e087015280935050505092915050565b60008151835260208201516020840152604082015173ffffffffffffffffffffffffffffffffffffffff80821660408601528060608501511660608601525050608082015160e060808501526131b560e0850182612feb565b60a084015160a086015260c0840151915084810360c0860152611d878183613071565b600082516131ea818460208701613ab1565b9190910192915050565b7f61636c0000000000000000000000000000000000000000000000000000000000815260030190565b7f657263336b2d7631000000000000000000000000000000000000000000000000815260609490941b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166008850152601c840192909252603c830152605c820152607c0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152604081019190915260600190565b73ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b6000602082526110cf6020830184612feb565b6000606082526133236060830186612feb565b60208301949094525060400152919050565b901515815260200190565b90815260200190565b600060408201848352602060408185015281855180845260608601915060608382028701019350828701855b828110156133c1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030184526133af868351613071565b95509284019290840190600101613375565b509398975050505050505050565b7fffffffff0000000000000000000000000000000000000000000000000000000091909116815260200190565b60007fffffffff000000000000000000000000000000000000000000000000000000008516825273ffffffffffffffffffffffffffffffffffffffff8416602083015260606040830152611d876060830184613071565b6000602082526110cf6020830184613071565b6000608082526134796080830186613071565b90508360208301526119b360408301846130bb565b602081016007831061349c57fe5b91905290565b6000838252604060208301526119b36040830184613071565b6020808252601a908201527f6465706f7369743a2062616420746f6b656e2072656c65617365000000000000604082015260600190565b60208082526010908201527f71756575653a2062616420737461746500000000000000000000000000000000604082015260600190565b60208082526011908201527f71756575653a2062616420636f6e666967000000000000000000000000000000604082015260600190565b60208082526009908201527f61636c3a20617574680000000000000000000000000000000000000000000000604082015260600190565b60208082526015908201527f71756575653a2062616420646973707574652069640000000000000000000000604082015260600190565b60208082526010908201527f71756575653a20626164206e6f6e636500000000000000000000000000000000604082015260600190565b60208082526010908201527f71756575653a206261642064656c617900000000000000000000000000000000604082015260600190565b60208082526010908201527f71756575653a2062616420726573657400000000000000000000000000000000604082015260600190565b60208082526013908201527f71756575653a20626164206665652070756c6c00000000000000000000000000604082015260600190565b60208082526014908201527f71756575653a20626164207375626d6974746572000000000000000000000000604082015260600190565b6020808252600b908201527f61636c3a2066726f7a656e000000000000000000000000000000000000000000604082015260600190565b60208082526012908201527f71756575653a2062616420617070726f76650000000000000000000000000000604082015260600190565b60208082526022908201527f696e697469616c697a61626c653a20616c726561647920696e697469616c697a60408201527f6564000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526010908201527f71756575653a2077616974206d6f726500000000000000000000000000000000604082015260600190565b60208082526017908201527f6465706f7369743a2062616420746f6b656e206c6f636b000000000000000000604082015260600190565b60208082526012908201527f71756575653a206e6f74207375626a6563740000000000000000000000000000604082015260600190565b6020808252601c908201527f63616c6c6461746173697a653a206c696d697420657863656564656400000000604082015260600190565b6020808252601c908201527f61636c3a20696e697469616c20726f6f74206d6973616c69676e656400000000604082015260600190565b6020808252600f908201527f61636c3a2062616420667265657a650000000000000000000000000000000000604082015260600190565b6020808252600e908201527f6d6174683a206f766572666c6f77000000000000000000000000000000000000604082015260600190565b6000602082526110cf60208301846130e0565b60006020825282516040602084015261395c606084018261315c565b602085015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848203016040850152611d8781836130e0565b6000602082526110cf602083018461315c565b600084825273ffffffffffffffffffffffffffffffffffffffff8416602083015260606040830152611d876060830184613071565b968752602087019590955273ffffffffffffffffffffffffffffffffffffffff9384166040870152919092166060850152608084019190915260a083015260c082015260e00190565b60405181810167ffffffffffffffff81118282101715613a4757600080fd5b604052919050565b600067ffffffffffffffff821115613a65578081fd5b5060209081020190565b600067ffffffffffffffff821115613a85578081fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015613acc578181015183820152602001613ab4565b838111156107655750506000910152565b73ffffffffffffffffffffffffffffffffffffffff81168114613aff57600080fd5b50565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114613aff57600080fdfea2646970667358221220047f58de53e183d409d81810d17312376c0fd2479adb7e90037508e7eab281fa64736f6c63430006080033d87da3e1f08043464b74e6b0861ccd8d8a5174e228287ac9b9f6efc1673da4ec7bc2a48a4a566e237a12186f19d985b0f76afc9d5290601edac19876253670c2a2646970667358221220b172753c8385a1d34d2071a1ee0f7d825f059cbdd1b587f3a6383726a08b6eb764736f6c6343000608003360806040523480156200001157600080fd5b506040516200473a3803806200473a833981016040819052620000349162000858565b81806002604051620000469062000967565b90815260200160405180910390205460001415620000785762000072816001600160e01b03620000ec16565b620000cc565b6001600160a01b038181166000908152600080516020620046fa833981519152602052604090205416600214620000cc5760405162461bcd60e51b8152600401620000c39062000a31565b60405180910390fd5b50620000e4905082826001600160e01b03620001bd16565b505062000b84565b604051806040016040528060038152602001621858db60ea1b8152506002816040516200011a919062000949565b9081526020016040518091039020546000146200014b5760405162461bcd60e51b8152600401620000c390620009ef565b436002826040516200015e919062000949565b908152604051908190036020019020556200018a63161b7d8160e21b836001600160e01b036200033416565b806040516200019a919062000949565b604051908190038120906000805160206200471a83398151915290600090a25050565b816002604051620001ce9062000967565b908152602001604051809103902054600014156200020057620001fa816001600160e01b03620000ec16565b6200024b565b6001600160a01b038181166000908152600080516020620046fa8339815191526020526040902054166002146200024b5760405162461bcd60e51b8152600401620000c39062000a31565b60405180604001604052806005815260200164717565756560d81b8152506002816040516200027b919062000949565b908152602001604051809103902054600014620002ac5760405162461bcd60e51b8152600401620000c390620009ef565b43600282604051620002bf919062000949565b90815260405190819003602001902055620002e3836001600160e01b036200034f16565b50620002ff63d311828160e01b6001600160e01b03620005de16565b806040516200030f919062000949565b604051908190038120906000805160206200471a83398151915290600090a250505050565b6200034b828260026001600160e01b036200063f16565b5050565b60008160400151602001516000141580156200037857506040820151516001600160a01b031615155b156200046957600060608360400151600001516001600160a01b03166370a0823160e01b30604051602401620003af919062000976565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051620003ef919062000949565b6000604051808303816000865af19150503d80600081146200042e576040519150601f19603f3d011682016040523d82523d6000602084013e62000433565b606091505b509150915081801562000447575060008151115b620004665760405162461bcd60e51b8152600401620000c3906200099f565b50505b6020808301510151158015906200048d57506020820151516001600160a01b031615155b156200057e57600060608360200151600001516001600160a01b03166370a0823160e01b30604051602401620004c4919062000976565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905162000504919062000949565b6000604051808303816000865af19150503d806000811462000543576040519150601f19603f3d011682016040523d82523d6000602084013e62000548565b606091505b50915091508180156200055c575060008151115b6200057b5760405162461bcd60e51b8152600401620000c3906200099f565b50505b62000594826200072960201b620016e11760201c565b60048190556040513391907f844435c59f7ccdf12de134e8f9b3b7d664fe9f06e3263680779599ba4097bc3f90620005ce90869062000a91565b60405180910390a3505060045490565b6001600160e01b0319811660009081526020819052604090819020805460ff19166001179055517fbf5e1f87f5ab65b58074cd29244d7c487a948983cda4b932e0f966b62bd34aca90620006349083906200098a565b60405180910390a150565b62000653836001600160e01b036200075b16565b15620006735760405162461bcd60e51b8152600401620000c390620009ca565b6001600160a01b03821660011415620006a05760405162461bcd60e51b8152600401620000c39062000a68565b6001600160e01b0319831660008181526003602090815260408083206001600160a01b03878116808652919093529281902080546001600160a01b0319169286169290921790915551909133917fc62063b81f7036fd97a0dc546516e99f11004d2d76ca0fddd3866346c86e7091906200071c90869062000976565b60405180910390a4505050565b6000816040516020016200073e919062000a91565b604051602081830303815290604052805190602001209050919050565b6001600160e01b031916600090815260036020908152604080832060018085529252909120546001600160a01b03161490565b80516001600160a01b0381168114620007a657600080fd5b92915050565b600082601f830112620007bd578081fd5b81516001600160401b03811115620007d3578182fd5b620007e8601f8201601f191660200162000b2a565b91508082528360208285010111156200080057600080fd5b6200081381602084016020860162000b51565b5092915050565b6000604082840312156200082c578081fd5b62000838604062000b2a565b90506200084683836200078e565b81526020820151602082015292915050565b600080604083850312156200086b578182fd5b6200087784846200078e565b60208401519092506001600160401b038082111562000894578283fd5b8185016101008188031215620008a8578384fd5b620008b460c062000b2a565b925080518352620008c987602083016200081a565b6020840152620008dd87606083016200081a565b6040840152620008f18760a083016200078e565b606084015260c08101518281111562000908578485fd5b6200091688828401620007ac565b60808501525060e0015160a083015250919491935090915050565b80516001600160a01b03168252602090810151910152565b600082516200095d81846020870162000b51565b9190910192915050565b621858db60ea1b815260030190565b6001600160a01b0391909116815260200190565b6001600160e01b031991909116815260200190565b60208082526011908201527071756575653a2062616420636f6e66696760781b604082015260600190565b6020808252600b908201526a30b1b61d10333937bd32b760a91b604082015260600190565b60208082526022908201527f696e697469616c697a61626c653a20616c726561647920696e697469616c697a604082015261195960f21b606082015260800190565b6020808252601c908201527f61636c3a20696e697469616c20726f6f74206d6973616c69676e656400000000604082015260600190565b6020808252600f908201526e61636c3a2062616420667265657a6560881b604082015260600190565b60006020825282516020830152602083015162000ab2604084018262000931565b50604083015162000ac7608084018262000931565b5060608301516001600160a01b031660c0830152608083015161010060e084018190528151610120850181905261014062000b09828288016020870162000b51565b60a0969096015191850191909152601f01601f191690920190920192915050565b6040518181016001600160401b038111828210171562000b4957600080fd5b604052919050565b60005b8381101562000b6e57818101518382015260200162000b54565b8381111562000b7e576000848401525b50505050565b613b668062000b946000396000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c80637e8c7f08116100d8578063affed0e01161008c578063c832048011610066578063c832048014610334578063cc1d4cab14610347578063e1f1176d1461035a57610182565b8063affed0e014610306578063bdf9a7261461030e578063c8182af01461032157610182565b806396fc8abd116100bd57806396fc8abd146102c0578063a157a10d146102e0578063a2157227146102f357610182565b80637e8c7f08146102985780638f8b35b2146102ad57610182565b80633e2da6a91161013a5780635a08160b116101145780635a08160b146102525780637744efda146102655780637c10dea61461027857610182565b80633e2da6a914610219578063495a98251461022c578063588497341461023f57610182565b80631c47671b1161016b5780631c47671b146101d15780631f13405b146101e65780633da956aa1461020657610182565b806301ffc9a71461018757806314d56921146101b0575b600080fd5b61019a610195366004612db5565b610362565b6040516101a79190613335565b60405180910390f35b6101c36101be366004612f90565b6103ac565b6040516101a7929190613349565b6101e46101df366004612c4b565b610631565b005b6101f96101f4366004612f39565b61076b565b6040516101a79190613340565b6101c3610214366004612f06565b610c88565b6101f9610227366004612d86565b610d7d565b61019a61023a366004612db5565b610d9a565b6101e461024d366004612dd1565b610df2565b6101e4610260366004612f39565b610e80565b6101f9610273366004612ed3565b61105e565b61028b610286366004612cd8565b6110d6565b6040516101a7919061348e565b6102a06110eb565b6040516101a791906133cf565b6101e46102bb366004612bd0565b61110f565b6102d36102ce366004612dd1565b6112b5565b6040516101a79190613285565b6101e46102ee366004612dd1565b6112e8565b6101e4610301366004612dfe565b611371565b6101f96113fb565b6101e461031c366004612db5565b611401565b6102d361032f366004612cd8565b61148d565b6101f9610342366004612f06565b6114b5565b6101f9610355366004612e48565b6116be565b6101f96116db565b7fffffffff00000000000000000000000000000000000000000000000000000000811660009081526020819052604081205460ff16806103a657506103a682611711565b92915050565b6000606060006103bb8561175b565b60208087015160600151600083815260088352604080822073ffffffffffffffffffffffffffffffffffffffff8416835290935291909120549192509060018601146104225760405162461bcd60e51b815260040161041990613597565b60405180910390fd5b600082815260086020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845282528083208390558483526006909152902061046f90600263ffffffff61177f16565b6000808273ffffffffffffffffffffffffffffffffffffffff1663db18af6c886040518263ffffffff1660e01b81526004016104ab9190613340565b6040805180830381600087803b1580156104c457600080fd5b505af11580156104d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104fc9190612c1e565b909250905073ffffffffffffffffffffffffffffffffffffffff821630146105365760405162461bcd60e51b81526004016104199061381a565b600481146105668161054957600461054c565b60035b60008781526006602052604090209063ffffffff6117b816565b3373ffffffffffffffffffffffffffffffffffffffff16857f027d8a5d945eb361475964ed2c71b8332b27af2d630ab5daf829d67afd2584e6836040516105ad9190613335565b60405180910390a3878473ffffffffffffffffffffffffffffffffffffffff167f56c8631a8915c0d362dbe57a61215fdde954f73f81c8a3a1f55572fb015207b1846040516105fc9190613340565b60405180910390a3801561062157610613896117f7565b96509650505050505061062a565b610613896118b8565b9250929050565b60408051602036601f81018290048202830182019093528282527f586df604000000000000000000000000000000000000000000000000000000009261069492849233926000918190840183828082843760009201919091525061197592505050565b6106b05760405162461bcd60e51b815260040161041990613560565b60005b82811015610765576106c36127f3565b8484838181106106cf57fe5b9050606002018036038101906106e59190612e7b565b90506000815160028111156106f657fe5b14156107135761070e816020015182604001516119bb565b61075c565b60018151600281111561072257fe5b141561073a5761070e816020015182604001516119c7565b60028151600281111561074957fe5b141561075c5761075c8160200151611a95565b506001016106b3565b50505050565b6000631f13405b60e01b6107b781336000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061197592505050565b6107d35760405162461bcd60e51b815260040161041990613560565b60006107de8561175b565b600081815260076020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317905560069091529020909150610834906001600263ffffffff611b4d16565b61083c612815565b50602085015160400151610856813363ffffffff611b6116565b6000866020015160600151905060008060008373ffffffffffffffffffffffffffffffffffffffff16637b751b9e6040518163ffffffff1660e01b815260040160606040518083038186803b1580156108ae57600080fd5b505afa1580156108c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e69190612b8e565b9194509250905061091573ffffffffffffffffffffffffffffffffffffffff831633308463ffffffff611c2b16565b6109315760405162461bcd60e51b815260040161041990613673565b61095873ffffffffffffffffffffffffffffffffffffffff8316848363ffffffff611cdf16565b6109745760405162461bcd60e51b815260040161041990613718565b8373ffffffffffffffffffffffffffffffffffffffff1663c13517e160028c6040516020016109a39190613940565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016109cf9291906134a2565b602060405180830381600087803b1580156109e957600080fd5b505af11580156109fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a219190612fd3565b9750610a4b73ffffffffffffffffffffffffffffffffffffffff831684600063ffffffff611cdf16565b610a675760405162461bcd60e51b81526004016104199061363c565b895160408082015160c09092015190517f7cb57c6400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871692637cb57c6492610ac8928d9291906004016139aa565b600060405180830381600087803b158015610ae257600080fd5b505af1158015610af6573d6000803e3d6000fd5b50506040517f7cb57c6400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87169250637cb57c649150610b50908b9033908e906004016139aa565b600060405180830381600087803b158015610b6a57600080fd5b505af1158015610b7e573d6000803e3d6000fd5b50506040517f7e9adccf00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87169250637e9adccf9150610bd4908b90600401613340565b600060405180830381600087803b158015610bee57600080fd5b505af1158015610c02573d6000803e3d6000fd5b505050600087815260086020908152604080832073ffffffffffffffffffffffffffffffffffffffff891684529091529081902060018b0190555133915087907f429df837eb45b6713f725a0d3e57db939fd7dd7d58bb3cd967fa37091572db9f90610c73908d908d908b90613466565b60405180910390a35050505050505092915050565b60006060633da956aa60e01b610cd681336000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061197592505050565b610cf25760405162461bcd60e51b815260040161041990613560565b835160200151421015610d175760405162461bcd60e51b8152600401610419906137ac565b6000610d228561175b565b6000818152600660208190526040909120919250610d49919060019063ffffffff611b4d16565b8451604001516020808701510151610d669163ffffffff611d9016565b8451610d729082611e4b565b935093505050915091565b600860209081526000928352604080842090915290825290205481565b7fffffffff00000000000000000000000000000000000000000000000000000000166000908152600360209081526040808320600180855292529091205473ffffffffffffffffffffffffffffffffffffffff161490565b60408051602036601f81018290048202830182019093528282527f586df6040000000000000000000000000000000000000000000000000000000092610e5592849233926000918190840183828082843760009201919091525061197592505050565b610e715760405162461bcd60e51b815260040161041990613560565b610e7b83836119c7565b505050565b635a08160b60e01b610eca81336000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061197592505050565b610ee65760405162461bcd60e51b815260040161041990613560565b6000610ef18461175b565b60008181526006602052604090209091506002815460ff166006811115610f1457fe5b1415610fd857610f2d816002600563ffffffff611b4d16565b600082815260076020908152604080832080547fffffffffffffffffffffffff000000000000000000000000000000000000000081169091556008835281842089840180516060015173ffffffffffffffffffffffffffffffffffffffff908116875291855283862095909555895190920151935190920151911691610fb9919063ffffffff611d9016565b602086015160400151610fd2908263ffffffff611d9016565b50611008565b610feb816001600563ffffffff611b4d16565b84516040015160208087015101516110089163ffffffff611d9016565b3373ffffffffffffffffffffffffffffffffffffffff16827fe2530b9681f9726904f9ca7fe725c0c53ea1b72370981ac6a5beaa9758c8c3568660405161104f9190613453565b60405180910390a35050505050565b6000637744efda60e01b6110aa81336000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061197592505050565b6110c65760405162461bcd60e51b815260040161041990613560565b6110cf83611f45565b9392505050565b60066020526000908152604090205460ff1681565b7f586df6040000000000000000000000000000000000000000000000000000000081565b81600260405161111e906131f4565b908152602001604051809103902054600014156111435761113e81612277565b6111a9565b73ffffffffffffffffffffffffffffffffffffffff81811660009081527fd87da3e1f08043464b74e6b0861ccd8d8a5174e228287ac9b9f6efc1673da4ec6020526040902054166002146111a95760405162461bcd60e51b815260040161041990613888565b6040518060400160405280600581526020017f71756575650000000000000000000000000000000000000000000000000000008152506002816040516111ef91906131d8565b90815260200160405180910390205460001461121d5760405162461bcd60e51b81526004016104199061374f565b4360028260405161122e91906131d8565b9081526040519081900360200190205561124783611f45565b506112717fd311828100000000000000000000000000000000000000000000000000000000612378565b8060405161127f91906131d8565b604051908190038120907f7bc2a48a4a566e237a12186f19d985b0f76afc9d5290601edac19876253670c290600090a250505050565b600360209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b60408051602036601f81018290048202830182019093528282527f586df604000000000000000000000000000000000000000000000000000000009261134b92849233926000918190840183828082843760009201919091525061197592505050565b6113675760405162461bcd60e51b815260040161041990613560565b610e7b83836119bb565b60408051602036601f81018290048202830182019093528282527f586df60400000000000000000000000000000000000000000000000000000000926113d492849233926000918190840183828082843760009201919091525061197592505050565b6113f05760405162461bcd60e51b815260040161041990613560565b61076584848461240d565b60055481565b60408051602036601f81018290048202830182019093528282527f586df604000000000000000000000000000000000000000000000000000000009261146492849233926000918190840183828082843760009201919091525061197592505050565b6114805760405162461bcd60e51b815260040161041990613560565b61148982611a95565b5050565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b600063c832048060e01b61150181336000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061197592505050565b61151d5760405162461bcd60e51b815260040161041990613560565b6005805460010190819055835151146115485760405162461bcd60e51b8152600401610419906135ce565b600061155784602001516116e1565b9050600454811461157a5760405162461bcd60e51b815260040161041990613529565b602084015151611590904263ffffffff61252e16565b84516020015110156115b45760405162461bcd60e51b815260040161041990613605565b83516040015173ffffffffffffffffffffffffffffffffffffffff1633146115ee5760405162461bcd60e51b8152600401610419906136aa565b602084015160a0015136908111156116185760405162461bcd60e51b815260040161041990613851565b61162e6116288660000151612551565b836125b9565b60008181526006602052604081209195506116519190600163ffffffff611b4d16565b611659612815565b50602080860151015185516040015161167990829063ffffffff611b6116565b847f67f87ff46443c95843c7bd72a026dd23ba0015528ce9f8f15c5c6917645034ef87600001516040516116ad9190613997565b60405180910390a250505050919050565b805160208183018101805160028252928201919093012091525481565b60045481565b6000816040516020016116f4919061392d565b604051602081830303815290604052805190602001209050919050565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f01ffc9a70000000000000000000000000000000000000000000000000000000014919050565b60006103a661176d8360000151612551565b61177a84602001516116e1565b6125b9565b80600681111561178b57fe5b825460ff16600681111561179b57fe5b146114895760405162461bcd60e51b8152600401610419906134f2565b8154819083907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660018360068111156117ee57fe5b02179055505050565b6000606060006118068461175b565b600081815260066020819052604090912091925061182d919060039063ffffffff611b4d16565b60008181526007602090815260409182902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905585519091015185820151909101516118829163ffffffff611d9016565b83516040908101516020860151909101516118a29163ffffffff611d9016565b83516118ae9082611e4b565b9250925050915091565b6000606060006118c78461175b565b60008181526006602052604090209091506118eb906004600563ffffffff611b4d16565b600081815260076020908152604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000008116909155858201519091015173ffffffffffffffffffffffffffffffffffffffff90911690611955908263ffffffff611d9016565b60208501516040015161196e908263ffffffff611d9016565b5050915091565b60006119828484846125f4565b806119b357506119b3847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff846125f4565b949350505050565b6114898282600261240d565b6119d082610d9a565b156119ed5760405162461bcd60e51b8152600401610419906136e1565b7fffffffff000000000000000000000000000000000000000000000000000000008216600081815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055519092339290917f682f2c466c1e9f6883eb72cbced01373e1cb18b05ae5c8bc04dc73d73e29f8cd9190a45050565b611a9e81610d9a565b15611abb5760405162461bcd60e51b8152600401610419906136e1565b7fffffffff00000000000000000000000000000000000000000000000000000000811660008181526003602090815260408083206001808552925280832080547fffffffffffffffffffffffff000000000000000000000000000000000000000016909217909155513392917f049c6b8b07a879425742523fa80f8ffb25e39ad518c93a5896a0df19518397e591a350565b611b57838361177f565b610e7b83826117b8565b6020820151156114895781516020830151611b9d9073ffffffffffffffffffffffffffffffffffffffff8316908490309063ffffffff611c2b16565b611bb95760405162461bcd60e51b8152600401610419906137e3565b8173ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff167f989eaa915cbb416ea3d6f9a63b1a3de51770c7674b11fe21ecdf76b4e1d139108560200151604051611c1e9190613340565b60405180910390a3505050565b600060606323b872dd60e01b858585604051602401611c4c939291906132a6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050611cd5868261275c565b9695505050505050565b6000606063095ea7b360e01b8484604051602401611cfe9291906132d7565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050611d87858261275c565b95945050505050565b6020820151156114895781516020830151611dca9073ffffffffffffffffffffffffffffffffffffffff831690849063ffffffff6127ce16565b611de65760405162461bcd60e51b8152600401610419906134bb565b8173ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff167fe6e0ef9cd056ca98561ca60e347ada61e1ede2f1142a078951b7a52e1e508e608560200151604051611c1e9190613340565b604051600090606090339084907f59c3746e635078efc737fb3f37dd8188203b8df10bbad35878a7d156f4f51c41908590a3836060015173ffffffffffffffffffffffffffffffffffffffff1663c2d85afc85608001518660a00151866040518463ffffffff1660e01b8152600401611ec693929190613310565b600060405180830381600087803b158015611ee057600080fd5b505af1158015611ef4573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611f3a9190810190612cf0565b915091509250929050565b6000816040015160200151600014158015611f7a575060408201515173ffffffffffffffffffffffffffffffffffffffff1615155b156120b8576000606083604001516000015173ffffffffffffffffffffffffffffffffffffffff166370a0823160e01b30604051602401611fbb9190613285565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161204491906131d8565b6000604051808303816000865af19150503d8060008114612081576040519150601f19603f3d011682016040523d82523d6000602084013e612086565b606091505b5091509150818015612099575060008151115b6120b55760405162461bcd60e51b815260040161041990613529565b50505b6020808301510151158015906120e8575060208201515173ffffffffffffffffffffffffffffffffffffffff1615155b15612226576000606083602001516000015173ffffffffffffffffffffffffffffffffffffffff166370a0823160e01b306040516024016121299190613285565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516121b291906131d8565b6000604051808303816000865af19150503d80600081146121ef576040519150601f19603f3d011682016040523d82523d6000602084013e6121f4565b606091505b5091509150818015612207575060008151115b6122235760405162461bcd60e51b815260040161041990613529565b50505b61222f826116e1565b60048190556040513391907f844435c59f7ccdf12de134e8f9b3b7d664fe9f06e3263680779599ba4097bc3f9061226790869061392d565b60405180910390a3505060045490565b6040518060400160405280600381526020017f61636c00000000000000000000000000000000000000000000000000000000008152506002816040516122bd91906131d8565b9081526020016040518091039020546000146122eb5760405162461bcd60e51b81526004016104199061374f565b436002826040516122fc91906131d8565b908152604051908190036020019020556123367f586df60400000000000000000000000000000000000000000000000000000000836119bb565b8060405161234491906131d8565b604051908190038120907f7bc2a48a4a566e237a12186f19d985b0f76afc9d5290601edac19876253670c290600090a25050565b7fffffffff0000000000000000000000000000000000000000000000000000000081166000908152602081905260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fbf5e1f87f5ab65b58074cd29244d7c487a948983cda4b932e0f966b62bd34aca906124029083906133cf565b60405180910390a150565b61241683610d9a565b156124335760405162461bcd60e51b8152600401610419906136e1565b73ffffffffffffffffffffffffffffffffffffffff82166001141561246a5760405162461bcd60e51b8152600401610419906138bf565b7fffffffff000000000000000000000000000000000000000000000000000000008316600081815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff878116808652919093529281902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169286169290921790915551909133917fc62063b81f7036fd97a0dc546516e99f11004d2d76ca0fddd3866346c86e709190612521908690613285565b60405180910390a4505050565b808201828110156103a65760405162461bcd60e51b8152600401610419906138f6565b60008160000151826020015183604001518460600151856080015160405160200161257c91906132fd565b604051602081830303815290604052805190602001208660a001518760c00151805190602001206040516020016116f497969594939291906139df565b60405160009046906125d590309083908790879060200161321d565b6040516020818303038152906040528051906020012091505092915050565b7fffffffff000000000000000000000000000000000000000000000000000000008316600090815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff808716855292528220541680156127515773ffffffffffffffffffffffffffffffffffffffff8116600214156126775760019150506110cf565b6040517f097c810800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82169063097c8108906126cd908890889088906004016133fc565b602060405180830381600087803b1580156126e757600080fd5b505af1925050508015612735575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261273291810190612cb8565b60015b61273e57612751565b801561274f576001925050506110cf565b505b506000949350505050565b600061277d8373ffffffffffffffffffffffffffffffffffffffff166127ed565b612789575060006103a6565b6040516020818451602086016000885af180156127c6573d80156127b457602081146127bd576127c4565b600193506127c4565b8251151593505b505b505092915050565b6000606063a9059cbb60e01b8484604051602401611cfe9291906132d7565b3b151590565b6040805160608101909152806000815260006020820181905260409091015290565b604080518082019091526000808252602082015290565b80356103a681613add565b600082601f830112612847578081fd5b813561285a61285582613a4f565b613a28565b818152915060208083019084810160005b8481101561290f57813587016060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0838c030112156128aa57600080fd5b6128b381613a28565b858301356128c081613add565b8152604083810135878301528284013567ffffffffffffffff8111156128e557600080fd5b6128f38d898388010161291a565b918301919091525086525050928201929082019060010161286b565b505050505092915050565b600082601f83011261292a578081fd5b813561293861285582613a6f565b915080825283602082850101111561294f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112612978578081fd5b815161298661285582613a6f565b915080825283602082850101111561299d57600080fd5b6129ae816020840160208601613ab1565b5092915050565b6000604082840312156129c6578081fd5b6129d06040613a28565b905081356129dd81613add565b808252506020820135602082015292915050565b60006101008284031215612a03578081fd5b612a0d60c0613a28565b905081358152612a2083602084016129b5565b6020820152612a3283606084016129b5565b604082015260a0820135612a4581613add565b606082015260c082013567ffffffffffffffff811115612a6457600080fd5b612a708482850161291a565b60808301525060e082013560a082015292915050565b600060408284031215612a97578081fd5b612aa16040613a28565b9050813567ffffffffffffffff80821115612abb57600080fd5b81840160e08187031215612ace57600080fd5b612ad860e0613a28565b92508035835260208101356020840152612af5866040830161282c565b6040840152612b07866060830161282c565b6060840152608081013582811115612b1e57600080fd5b612b2a87828401612837565b60808501525060a081013560a084015260c081013582811115612b4c57600080fd5b612b588782840161291a565b60c0850152505090825260208301359080821115612b7557600080fd5b50612b82848285016129f1565b60208301525092915050565b600080600060608486031215612ba2578283fd5b8351612bad81613add565b6020850151909350612bbe81613add565b80925050604084015190509250925092565b60008060408385031215612be2578182fd5b8235612bed81613add565b9150602083013567ffffffffffffffff811115612c08578182fd5b612c14858286016129f1565b9150509250929050565b60008060408385031215612c30578182fd5b8251612c3b81613add565b6020939093015192949293505050565b60008060208385031215612c5d578182fd5b823567ffffffffffffffff80821115612c74578384fd5b81850186601f820112612c85578485fd5b8035925081831115612c95578485fd5b866020606085028301011115612ca9578485fd5b60200196919550909350505050565b600060208284031215612cc9578081fd5b815180151581146110cf578182fd5b600060208284031215612ce9578081fd5b5035919050565b60008060408385031215612d02578182fd5b8251915060208084015167ffffffffffffffff811115612d20578283fd5b80850186601f820112612d31578384fd5b80519150612d4161285583613a4f565b82815283810190828501865b85811015612d7657612d648b888451880101612968565b84529286019290860190600101612d4d565b5096999098509650505050505050565b60008060408385031215612d98578182fd5b823591506020830135612daa81613add565b809150509250929050565b600060208284031215612dc6578081fd5b81356110cf81613b02565b60008060408385031215612de3578182fd5b8235612dee81613b02565b91506020830135612daa81613add565b600080600060608486031215612e12578081fd5b8335612e1d81613b02565b92506020840135612e2d81613add565b91506040840135612e3d81613add565b809150509250925092565b600060208284031215612e59578081fd5b813567ffffffffffffffff811115612e6f578182fd5b6119b38482850161291a565b600060608284031215612e8c578081fd5b612e966060613a28565b823560038110612ea4578283fd5b81526020830135612eb481613b02565b60208201526040830135612ec781613add565b60408201529392505050565b600060208284031215612ee4578081fd5b813567ffffffffffffffff811115612efa578182fd5b6119b3848285016129f1565b600060208284031215612f17578081fd5b813567ffffffffffffffff811115612f2d578182fd5b6119b384828501612a86565b60008060408385031215612f4b578182fd5b823567ffffffffffffffff80821115612f62578384fd5b612f6e86838701612a86565b93506020850135915080821115612f83578283fd5b50612c148582860161291a565b60008060408385031215612fa2578182fd5b823567ffffffffffffffff811115612fb8578283fd5b612fc485828601612a86565b95602094909401359450505050565b600060208284031215612fe4578081fd5b5051919050565b6000815180845260208085019450848183028601828601855b858110156130645783830389528151606073ffffffffffffffffffffffffffffffffffffffff82511685528682015187860152604080830151828288015261304e83880182613071565b9c89019c96505050928601925050600101613004565b5090979650505050505050565b60008151808452613089816020860160208601613ab1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b60006101008251845260208301516130fb60208601826130bb565b50604083015161310e60608601826130bb565b5073ffffffffffffffffffffffffffffffffffffffff60608401511660a085015260808301518160c086015261314682860182613071565b60a085015160e087015280935050505092915050565b60008151835260208201516020840152604082015173ffffffffffffffffffffffffffffffffffffffff80821660408601528060608501511660608601525050608082015160e060808501526131b560e0850182612feb565b60a084015160a086015260c0840151915084810360c0860152611d878183613071565b600082516131ea818460208701613ab1565b9190910192915050565b7f61636c0000000000000000000000000000000000000000000000000000000000815260030190565b7f657263336b2d7631000000000000000000000000000000000000000000000000815260609490941b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166008850152601c840192909252603c830152605c820152607c0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152604081019190915260600190565b73ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b6000602082526110cf6020830184612feb565b6000606082526133236060830186612feb565b60208301949094525060400152919050565b901515815260200190565b90815260200190565b600060408201848352602060408185015281855180845260608601915060608382028701019350828701855b828110156133c1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030184526133af868351613071565b95509284019290840190600101613375565b509398975050505050505050565b7fffffffff0000000000000000000000000000000000000000000000000000000091909116815260200190565b60007fffffffff000000000000000000000000000000000000000000000000000000008516825273ffffffffffffffffffffffffffffffffffffffff8416602083015260606040830152611d876060830184613071565b6000602082526110cf6020830184613071565b6000608082526134796080830186613071565b90508360208301526119b360408301846130bb565b602081016007831061349c57fe5b91905290565b6000838252604060208301526119b36040830184613071565b6020808252601a908201527f6465706f7369743a2062616420746f6b656e2072656c65617365000000000000604082015260600190565b60208082526010908201527f71756575653a2062616420737461746500000000000000000000000000000000604082015260600190565b60208082526011908201527f71756575653a2062616420636f6e666967000000000000000000000000000000604082015260600190565b60208082526009908201527f61636c3a20617574680000000000000000000000000000000000000000000000604082015260600190565b60208082526015908201527f71756575653a2062616420646973707574652069640000000000000000000000604082015260600190565b60208082526010908201527f71756575653a20626164206e6f6e636500000000000000000000000000000000604082015260600190565b60208082526010908201527f71756575653a206261642064656c617900000000000000000000000000000000604082015260600190565b60208082526010908201527f71756575653a2062616420726573657400000000000000000000000000000000604082015260600190565b60208082526013908201527f71756575653a20626164206665652070756c6c00000000000000000000000000604082015260600190565b60208082526014908201527f71756575653a20626164207375626d6974746572000000000000000000000000604082015260600190565b6020808252600b908201527f61636c3a2066726f7a656e000000000000000000000000000000000000000000604082015260600190565b60208082526012908201527f71756575653a2062616420617070726f76650000000000000000000000000000604082015260600190565b60208082526022908201527f696e697469616c697a61626c653a20616c726561647920696e697469616c697a60408201527f6564000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526010908201527f71756575653a2077616974206d6f726500000000000000000000000000000000604082015260600190565b60208082526017908201527f6465706f7369743a2062616420746f6b656e206c6f636b000000000000000000604082015260600190565b60208082526012908201527f71756575653a206e6f74207375626a6563740000000000000000000000000000604082015260600190565b6020808252601c908201527f63616c6c6461746173697a653a206c696d697420657863656564656400000000604082015260600190565b6020808252601c908201527f61636c3a20696e697469616c20726f6f74206d6973616c69676e656400000000604082015260600190565b6020808252600f908201527f61636c3a2062616420667265657a650000000000000000000000000000000000604082015260600190565b6020808252600e908201527f6d6174683a206f766572666c6f77000000000000000000000000000000000000604082015260600190565b6000602082526110cf60208301846130e0565b60006020825282516040602084015261395c606084018261315c565b602085015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848203016040850152611d8781836130e0565b6000602082526110cf602083018461315c565b600084825273ffffffffffffffffffffffffffffffffffffffff8416602083015260606040830152611d876060830184613071565b968752602087019590955273ffffffffffffffffffffffffffffffffffffffff9384166040870152919092166060850152608084019190915260a083015260c082015260e00190565b60405181810167ffffffffffffffff81118282101715613a4757600080fd5b604052919050565b600067ffffffffffffffff821115613a65578081fd5b5060209081020190565b600067ffffffffffffffff821115613a85578081fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015613acc578181015183820152602001613ab4565b838111156107655750506000910152565b73ffffffffffffffffffffffffffffffffffffffff81168114613aff57600080fd5b50565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114613aff57600080fdfea2646970667358221220047f58de53e183d409d81810d17312376c0fd2479adb7e90037508e7eab281fa64736f6c63430006080033d87da3e1f08043464b74e6b0861ccd8d8a5174e228287ac9b9f6efc1673da4ec7bc2a48a4a566e237a12186f19d985b0f76afc9d5290601edac19876253670c2
Deployed Bytecode
0x60806040523480156200001157600080fd5b50600436106200003a5760003560e01c80635001f3b5146200003f578063a691fc671462000061575b600080fd5b6200004962000078565b6040516200005891906200073e565b60405180910390f35b6200004962000072366004620004c6565b62000094565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b600081156200016b576200016382638f8b35b260e01b8686604051602401620000bf9291906200075f565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915260005473ffffffffffffffffffffffffffffffffffffffff16919063ffffffff620001b016565b9050620001a9565b83836040516200017b90620003db565b620001889291906200075f565b604051809103906000f080158015620001a5573d6000803e3d6000fd5b5090505b9392505050565b6000620001be84846200028e565b9050600060608273ffffffffffffffffffffffffffffffffffffffff1684604051620001eb919062000720565b6000604051808303816000865af19150503d80600081146200022a576040519150601f19603f3d011682016040523d82523d6000602084013e6200022f565b606091505b509150915081620002408262000302565b9062000284576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200027b9190620007f1565b60405180910390fd5b5050509392505050565b600060606200029d8462000349565b9050826037602083016000f5915073ffffffffffffffffffffffffffffffffffffffff8216620002fb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200027b9062000806565b5092915050565b606060448251101562000325575060408051602081019091526000815262000344565b60048201915081806020019051810190620003419190620005a7565b90505b919050565b604051606090620003c5907f3d602d80600a3d3981f300000000000000000000000000000000000000000000907f363d3d373d3d3d363d73000000000000000000000000000000000000000000009085907f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000009060200162000697565b6040516020818303038152906040529050919050565b61473a80620008dc83390190565b803573ffffffffffffffffffffffffffffffffffffffff811681146200040e57600080fd5b92915050565b600082601f83011262000425578081fd5b81356200043c620004368262000865565b6200083d565b91508082528360208285010111156200045457600080fd5b8060208401602084013760009082016020015292915050565b6000604082840312156200047f578081fd5b6200048b60406200083d565b9050813573ffffffffffffffffffffffffffffffffffffffff81168114620004b257600080fd5b808252506020820135602082015292915050565b600080600060608486031215620004db578283fd5b620004e78585620003e9565b9250602084013567ffffffffffffffff8082111562000504578384fd5b818601610100818903121562000518578485fd5b6200052460c06200083d565b9250803583526200053988602083016200046d565b60208401526200054d88606083016200046d565b6040840152620005618860a08301620003e9565b606084015260c08101358281111562000578578586fd5b620005868982840162000414565b60808501525060e0013560a083015250929592945050506040919091013590565b600060208284031215620005b9578081fd5b815167ffffffffffffffff811115620005d0578182fd5b80830184601f820112620005e2578283fd5b80519150620005f5620004368362000865565b8281528560208484010111156200060a578384fd5b6200061d836020830160208501620008a8565b95945050505050565b6000815180845262000640816020860160208601620008a8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b7fffffffffffffffffffff00000000000000000000000000000000000000000000948516815292909316600a83015260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660148201527fffffffffffffffffffffffffffffff000000000000000000000000000000000091909116602882015260370190565b6000825162000734818460208701620008a8565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600073ffffffffffffffffffffffffffffffffffffffff8085168352604060208401528351604084015260208401516200079d606085018262000672565b506040840151620007b260a085018262000672565b5060608401511660e0830152608083015161010080840152620007da61014084018262000626565b60a085015161012085015280925050509392505050565b600060208252620001a9602083018462000626565b6020808252601a908201527f70726f78792d666163746f72793a206261642063726561746532000000000000604082015260600190565b60405181810167ffffffffffffffff811182821017156200085d57600080fd5b604052919050565b600067ffffffffffffffff8211156200087c578081fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015620008c5578181015183820152602001620008ab565b83811115620008d5576000848401525b5050505056fe60806040523480156200001157600080fd5b506040516200473a3803806200473a833981016040819052620000349162000858565b81806002604051620000469062000967565b90815260200160405180910390205460001415620000785762000072816001600160e01b03620000ec16565b620000cc565b6001600160a01b038181166000908152600080516020620046fa833981519152602052604090205416600214620000cc5760405162461bcd60e51b8152600401620000c39062000a31565b60405180910390fd5b50620000e4905082826001600160e01b03620001bd16565b505062000b84565b604051806040016040528060038152602001621858db60ea1b8152506002816040516200011a919062000949565b9081526020016040518091039020546000146200014b5760405162461bcd60e51b8152600401620000c390620009ef565b436002826040516200015e919062000949565b908152604051908190036020019020556200018a63161b7d8160e21b836001600160e01b036200033416565b806040516200019a919062000949565b604051908190038120906000805160206200471a83398151915290600090a25050565b816002604051620001ce9062000967565b908152602001604051809103902054600014156200020057620001fa816001600160e01b03620000ec16565b6200024b565b6001600160a01b038181166000908152600080516020620046fa8339815191526020526040902054166002146200024b5760405162461bcd60e51b8152600401620000c39062000a31565b60405180604001604052806005815260200164717565756560d81b8152506002816040516200027b919062000949565b908152602001604051809103902054600014620002ac5760405162461bcd60e51b8152600401620000c390620009ef565b43600282604051620002bf919062000949565b90815260405190819003602001902055620002e3836001600160e01b036200034f16565b50620002ff63d311828160e01b6001600160e01b03620005de16565b806040516200030f919062000949565b604051908190038120906000805160206200471a83398151915290600090a250505050565b6200034b828260026001600160e01b036200063f16565b5050565b60008160400151602001516000141580156200037857506040820151516001600160a01b031615155b156200046957600060608360400151600001516001600160a01b03166370a0823160e01b30604051602401620003af919062000976565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051620003ef919062000949565b6000604051808303816000865af19150503d80600081146200042e576040519150601f19603f3d011682016040523d82523d6000602084013e62000433565b606091505b509150915081801562000447575060008151115b620004665760405162461bcd60e51b8152600401620000c3906200099f565b50505b6020808301510151158015906200048d57506020820151516001600160a01b031615155b156200057e57600060608360200151600001516001600160a01b03166370a0823160e01b30604051602401620004c4919062000976565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905162000504919062000949565b6000604051808303816000865af19150503d806000811462000543576040519150601f19603f3d011682016040523d82523d6000602084013e62000548565b606091505b50915091508180156200055c575060008151115b6200057b5760405162461bcd60e51b8152600401620000c3906200099f565b50505b62000594826200072960201b620016e11760201c565b60048190556040513391907f844435c59f7ccdf12de134e8f9b3b7d664fe9f06e3263680779599ba4097bc3f90620005ce90869062000a91565b60405180910390a3505060045490565b6001600160e01b0319811660009081526020819052604090819020805460ff19166001179055517fbf5e1f87f5ab65b58074cd29244d7c487a948983cda4b932e0f966b62bd34aca90620006349083906200098a565b60405180910390a150565b62000653836001600160e01b036200075b16565b15620006735760405162461bcd60e51b8152600401620000c390620009ca565b6001600160a01b03821660011415620006a05760405162461bcd60e51b8152600401620000c39062000a68565b6001600160e01b0319831660008181526003602090815260408083206001600160a01b03878116808652919093529281902080546001600160a01b0319169286169290921790915551909133917fc62063b81f7036fd97a0dc546516e99f11004d2d76ca0fddd3866346c86e7091906200071c90869062000976565b60405180910390a4505050565b6000816040516020016200073e919062000a91565b604051602081830303815290604052805190602001209050919050565b6001600160e01b031916600090815260036020908152604080832060018085529252909120546001600160a01b03161490565b80516001600160a01b0381168114620007a657600080fd5b92915050565b600082601f830112620007bd578081fd5b81516001600160401b03811115620007d3578182fd5b620007e8601f8201601f191660200162000b2a565b91508082528360208285010111156200080057600080fd5b6200081381602084016020860162000b51565b5092915050565b6000604082840312156200082c578081fd5b62000838604062000b2a565b90506200084683836200078e565b81526020820151602082015292915050565b600080604083850312156200086b578182fd5b6200087784846200078e565b60208401519092506001600160401b038082111562000894578283fd5b8185016101008188031215620008a8578384fd5b620008b460c062000b2a565b925080518352620008c987602083016200081a565b6020840152620008dd87606083016200081a565b6040840152620008f18760a083016200078e565b606084015260c08101518281111562000908578485fd5b6200091688828401620007ac565b60808501525060e0015160a083015250919491935090915050565b80516001600160a01b03168252602090810151910152565b600082516200095d81846020870162000b51565b9190910192915050565b621858db60ea1b815260030190565b6001600160a01b0391909116815260200190565b6001600160e01b031991909116815260200190565b60208082526011908201527071756575653a2062616420636f6e66696760781b604082015260600190565b6020808252600b908201526a30b1b61d10333937bd32b760a91b604082015260600190565b60208082526022908201527f696e697469616c697a61626c653a20616c726561647920696e697469616c697a604082015261195960f21b606082015260800190565b6020808252601c908201527f61636c3a20696e697469616c20726f6f74206d6973616c69676e656400000000604082015260600190565b6020808252600f908201526e61636c3a2062616420667265657a6560881b604082015260600190565b60006020825282516020830152602083015162000ab2604084018262000931565b50604083015162000ac7608084018262000931565b5060608301516001600160a01b031660c0830152608083015161010060e084018190528151610120850181905261014062000b09828288016020870162000b51565b60a0969096015191850191909152601f01601f191690920190920192915050565b6040518181016001600160401b038111828210171562000b4957600080fd5b604052919050565b60005b8381101562000b6e57818101518382015260200162000b54565b8381111562000b7e576000848401525b50505050565b613b668062000b946000396000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c80637e8c7f08116100d8578063affed0e01161008c578063c832048011610066578063c832048014610334578063cc1d4cab14610347578063e1f1176d1461035a57610182565b8063affed0e014610306578063bdf9a7261461030e578063c8182af01461032157610182565b806396fc8abd116100bd57806396fc8abd146102c0578063a157a10d146102e0578063a2157227146102f357610182565b80637e8c7f08146102985780638f8b35b2146102ad57610182565b80633e2da6a91161013a5780635a08160b116101145780635a08160b146102525780637744efda146102655780637c10dea61461027857610182565b80633e2da6a914610219578063495a98251461022c578063588497341461023f57610182565b80631c47671b1161016b5780631c47671b146101d15780631f13405b146101e65780633da956aa1461020657610182565b806301ffc9a71461018757806314d56921146101b0575b600080fd5b61019a610195366004612db5565b610362565b6040516101a79190613335565b60405180910390f35b6101c36101be366004612f90565b6103ac565b6040516101a7929190613349565b6101e46101df366004612c4b565b610631565b005b6101f96101f4366004612f39565b61076b565b6040516101a79190613340565b6101c3610214366004612f06565b610c88565b6101f9610227366004612d86565b610d7d565b61019a61023a366004612db5565b610d9a565b6101e461024d366004612dd1565b610df2565b6101e4610260366004612f39565b610e80565b6101f9610273366004612ed3565b61105e565b61028b610286366004612cd8565b6110d6565b6040516101a7919061348e565b6102a06110eb565b6040516101a791906133cf565b6101e46102bb366004612bd0565b61110f565b6102d36102ce366004612dd1565b6112b5565b6040516101a79190613285565b6101e46102ee366004612dd1565b6112e8565b6101e4610301366004612dfe565b611371565b6101f96113fb565b6101e461031c366004612db5565b611401565b6102d361032f366004612cd8565b61148d565b6101f9610342366004612f06565b6114b5565b6101f9610355366004612e48565b6116be565b6101f96116db565b7fffffffff00000000000000000000000000000000000000000000000000000000811660009081526020819052604081205460ff16806103a657506103a682611711565b92915050565b6000606060006103bb8561175b565b60208087015160600151600083815260088352604080822073ffffffffffffffffffffffffffffffffffffffff8416835290935291909120549192509060018601146104225760405162461bcd60e51b815260040161041990613597565b60405180910390fd5b600082815260086020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845282528083208390558483526006909152902061046f90600263ffffffff61177f16565b6000808273ffffffffffffffffffffffffffffffffffffffff1663db18af6c886040518263ffffffff1660e01b81526004016104ab9190613340565b6040805180830381600087803b1580156104c457600080fd5b505af11580156104d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104fc9190612c1e565b909250905073ffffffffffffffffffffffffffffffffffffffff821630146105365760405162461bcd60e51b81526004016104199061381a565b600481146105668161054957600461054c565b60035b60008781526006602052604090209063ffffffff6117b816565b3373ffffffffffffffffffffffffffffffffffffffff16857f027d8a5d945eb361475964ed2c71b8332b27af2d630ab5daf829d67afd2584e6836040516105ad9190613335565b60405180910390a3878473ffffffffffffffffffffffffffffffffffffffff167f56c8631a8915c0d362dbe57a61215fdde954f73f81c8a3a1f55572fb015207b1846040516105fc9190613340565b60405180910390a3801561062157610613896117f7565b96509650505050505061062a565b610613896118b8565b9250929050565b60408051602036601f81018290048202830182019093528282527f586df604000000000000000000000000000000000000000000000000000000009261069492849233926000918190840183828082843760009201919091525061197592505050565b6106b05760405162461bcd60e51b815260040161041990613560565b60005b82811015610765576106c36127f3565b8484838181106106cf57fe5b9050606002018036038101906106e59190612e7b565b90506000815160028111156106f657fe5b14156107135761070e816020015182604001516119bb565b61075c565b60018151600281111561072257fe5b141561073a5761070e816020015182604001516119c7565b60028151600281111561074957fe5b141561075c5761075c8160200151611a95565b506001016106b3565b50505050565b6000631f13405b60e01b6107b781336000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061197592505050565b6107d35760405162461bcd60e51b815260040161041990613560565b60006107de8561175b565b600081815260076020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317905560069091529020909150610834906001600263ffffffff611b4d16565b61083c612815565b50602085015160400151610856813363ffffffff611b6116565b6000866020015160600151905060008060008373ffffffffffffffffffffffffffffffffffffffff16637b751b9e6040518163ffffffff1660e01b815260040160606040518083038186803b1580156108ae57600080fd5b505afa1580156108c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e69190612b8e565b9194509250905061091573ffffffffffffffffffffffffffffffffffffffff831633308463ffffffff611c2b16565b6109315760405162461bcd60e51b815260040161041990613673565b61095873ffffffffffffffffffffffffffffffffffffffff8316848363ffffffff611cdf16565b6109745760405162461bcd60e51b815260040161041990613718565b8373ffffffffffffffffffffffffffffffffffffffff1663c13517e160028c6040516020016109a39190613940565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016109cf9291906134a2565b602060405180830381600087803b1580156109e957600080fd5b505af11580156109fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a219190612fd3565b9750610a4b73ffffffffffffffffffffffffffffffffffffffff831684600063ffffffff611cdf16565b610a675760405162461bcd60e51b81526004016104199061363c565b895160408082015160c09092015190517f7cb57c6400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871692637cb57c6492610ac8928d9291906004016139aa565b600060405180830381600087803b158015610ae257600080fd5b505af1158015610af6573d6000803e3d6000fd5b50506040517f7cb57c6400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87169250637cb57c649150610b50908b9033908e906004016139aa565b600060405180830381600087803b158015610b6a57600080fd5b505af1158015610b7e573d6000803e3d6000fd5b50506040517f7e9adccf00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87169250637e9adccf9150610bd4908b90600401613340565b600060405180830381600087803b158015610bee57600080fd5b505af1158015610c02573d6000803e3d6000fd5b505050600087815260086020908152604080832073ffffffffffffffffffffffffffffffffffffffff891684529091529081902060018b0190555133915087907f429df837eb45b6713f725a0d3e57db939fd7dd7d58bb3cd967fa37091572db9f90610c73908d908d908b90613466565b60405180910390a35050505050505092915050565b60006060633da956aa60e01b610cd681336000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061197592505050565b610cf25760405162461bcd60e51b815260040161041990613560565b835160200151421015610d175760405162461bcd60e51b8152600401610419906137ac565b6000610d228561175b565b6000818152600660208190526040909120919250610d49919060019063ffffffff611b4d16565b8451604001516020808701510151610d669163ffffffff611d9016565b8451610d729082611e4b565b935093505050915091565b600860209081526000928352604080842090915290825290205481565b7fffffffff00000000000000000000000000000000000000000000000000000000166000908152600360209081526040808320600180855292529091205473ffffffffffffffffffffffffffffffffffffffff161490565b60408051602036601f81018290048202830182019093528282527f586df6040000000000000000000000000000000000000000000000000000000092610e5592849233926000918190840183828082843760009201919091525061197592505050565b610e715760405162461bcd60e51b815260040161041990613560565b610e7b83836119c7565b505050565b635a08160b60e01b610eca81336000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061197592505050565b610ee65760405162461bcd60e51b815260040161041990613560565b6000610ef18461175b565b60008181526006602052604090209091506002815460ff166006811115610f1457fe5b1415610fd857610f2d816002600563ffffffff611b4d16565b600082815260076020908152604080832080547fffffffffffffffffffffffff000000000000000000000000000000000000000081169091556008835281842089840180516060015173ffffffffffffffffffffffffffffffffffffffff908116875291855283862095909555895190920151935190920151911691610fb9919063ffffffff611d9016565b602086015160400151610fd2908263ffffffff611d9016565b50611008565b610feb816001600563ffffffff611b4d16565b84516040015160208087015101516110089163ffffffff611d9016565b3373ffffffffffffffffffffffffffffffffffffffff16827fe2530b9681f9726904f9ca7fe725c0c53ea1b72370981ac6a5beaa9758c8c3568660405161104f9190613453565b60405180910390a35050505050565b6000637744efda60e01b6110aa81336000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061197592505050565b6110c65760405162461bcd60e51b815260040161041990613560565b6110cf83611f45565b9392505050565b60066020526000908152604090205460ff1681565b7f586df6040000000000000000000000000000000000000000000000000000000081565b81600260405161111e906131f4565b908152602001604051809103902054600014156111435761113e81612277565b6111a9565b73ffffffffffffffffffffffffffffffffffffffff81811660009081527fd87da3e1f08043464b74e6b0861ccd8d8a5174e228287ac9b9f6efc1673da4ec6020526040902054166002146111a95760405162461bcd60e51b815260040161041990613888565b6040518060400160405280600581526020017f71756575650000000000000000000000000000000000000000000000000000008152506002816040516111ef91906131d8565b90815260200160405180910390205460001461121d5760405162461bcd60e51b81526004016104199061374f565b4360028260405161122e91906131d8565b9081526040519081900360200190205561124783611f45565b506112717fd311828100000000000000000000000000000000000000000000000000000000612378565b8060405161127f91906131d8565b604051908190038120907f7bc2a48a4a566e237a12186f19d985b0f76afc9d5290601edac19876253670c290600090a250505050565b600360209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b60408051602036601f81018290048202830182019093528282527f586df604000000000000000000000000000000000000000000000000000000009261134b92849233926000918190840183828082843760009201919091525061197592505050565b6113675760405162461bcd60e51b815260040161041990613560565b610e7b83836119bb565b60408051602036601f81018290048202830182019093528282527f586df60400000000000000000000000000000000000000000000000000000000926113d492849233926000918190840183828082843760009201919091525061197592505050565b6113f05760405162461bcd60e51b815260040161041990613560565b61076584848461240d565b60055481565b60408051602036601f81018290048202830182019093528282527f586df604000000000000000000000000000000000000000000000000000000009261146492849233926000918190840183828082843760009201919091525061197592505050565b6114805760405162461bcd60e51b815260040161041990613560565b61148982611a95565b5050565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b600063c832048060e01b61150181336000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061197592505050565b61151d5760405162461bcd60e51b815260040161041990613560565b6005805460010190819055835151146115485760405162461bcd60e51b8152600401610419906135ce565b600061155784602001516116e1565b9050600454811461157a5760405162461bcd60e51b815260040161041990613529565b602084015151611590904263ffffffff61252e16565b84516020015110156115b45760405162461bcd60e51b815260040161041990613605565b83516040015173ffffffffffffffffffffffffffffffffffffffff1633146115ee5760405162461bcd60e51b8152600401610419906136aa565b602084015160a0015136908111156116185760405162461bcd60e51b815260040161041990613851565b61162e6116288660000151612551565b836125b9565b60008181526006602052604081209195506116519190600163ffffffff611b4d16565b611659612815565b50602080860151015185516040015161167990829063ffffffff611b6116565b847f67f87ff46443c95843c7bd72a026dd23ba0015528ce9f8f15c5c6917645034ef87600001516040516116ad9190613997565b60405180910390a250505050919050565b805160208183018101805160028252928201919093012091525481565b60045481565b6000816040516020016116f4919061392d565b604051602081830303815290604052805190602001209050919050565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f01ffc9a70000000000000000000000000000000000000000000000000000000014919050565b60006103a661176d8360000151612551565b61177a84602001516116e1565b6125b9565b80600681111561178b57fe5b825460ff16600681111561179b57fe5b146114895760405162461bcd60e51b8152600401610419906134f2565b8154819083907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660018360068111156117ee57fe5b02179055505050565b6000606060006118068461175b565b600081815260066020819052604090912091925061182d919060039063ffffffff611b4d16565b60008181526007602090815260409182902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905585519091015185820151909101516118829163ffffffff611d9016565b83516040908101516020860151909101516118a29163ffffffff611d9016565b83516118ae9082611e4b565b9250925050915091565b6000606060006118c78461175b565b60008181526006602052604090209091506118eb906004600563ffffffff611b4d16565b600081815260076020908152604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000008116909155858201519091015173ffffffffffffffffffffffffffffffffffffffff90911690611955908263ffffffff611d9016565b60208501516040015161196e908263ffffffff611d9016565b5050915091565b60006119828484846125f4565b806119b357506119b3847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff846125f4565b949350505050565b6114898282600261240d565b6119d082610d9a565b156119ed5760405162461bcd60e51b8152600401610419906136e1565b7fffffffff000000000000000000000000000000000000000000000000000000008216600081815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055519092339290917f682f2c466c1e9f6883eb72cbced01373e1cb18b05ae5c8bc04dc73d73e29f8cd9190a45050565b611a9e81610d9a565b15611abb5760405162461bcd60e51b8152600401610419906136e1565b7fffffffff00000000000000000000000000000000000000000000000000000000811660008181526003602090815260408083206001808552925280832080547fffffffffffffffffffffffff000000000000000000000000000000000000000016909217909155513392917f049c6b8b07a879425742523fa80f8ffb25e39ad518c93a5896a0df19518397e591a350565b611b57838361177f565b610e7b83826117b8565b6020820151156114895781516020830151611b9d9073ffffffffffffffffffffffffffffffffffffffff8316908490309063ffffffff611c2b16565b611bb95760405162461bcd60e51b8152600401610419906137e3565b8173ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff167f989eaa915cbb416ea3d6f9a63b1a3de51770c7674b11fe21ecdf76b4e1d139108560200151604051611c1e9190613340565b60405180910390a3505050565b600060606323b872dd60e01b858585604051602401611c4c939291906132a6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050611cd5868261275c565b9695505050505050565b6000606063095ea7b360e01b8484604051602401611cfe9291906132d7565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050611d87858261275c565b95945050505050565b6020820151156114895781516020830151611dca9073ffffffffffffffffffffffffffffffffffffffff831690849063ffffffff6127ce16565b611de65760405162461bcd60e51b8152600401610419906134bb565b8173ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff167fe6e0ef9cd056ca98561ca60e347ada61e1ede2f1142a078951b7a52e1e508e608560200151604051611c1e9190613340565b604051600090606090339084907f59c3746e635078efc737fb3f37dd8188203b8df10bbad35878a7d156f4f51c41908590a3836060015173ffffffffffffffffffffffffffffffffffffffff1663c2d85afc85608001518660a00151866040518463ffffffff1660e01b8152600401611ec693929190613310565b600060405180830381600087803b158015611ee057600080fd5b505af1158015611ef4573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611f3a9190810190612cf0565b915091509250929050565b6000816040015160200151600014158015611f7a575060408201515173ffffffffffffffffffffffffffffffffffffffff1615155b156120b8576000606083604001516000015173ffffffffffffffffffffffffffffffffffffffff166370a0823160e01b30604051602401611fbb9190613285565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161204491906131d8565b6000604051808303816000865af19150503d8060008114612081576040519150601f19603f3d011682016040523d82523d6000602084013e612086565b606091505b5091509150818015612099575060008151115b6120b55760405162461bcd60e51b815260040161041990613529565b50505b6020808301510151158015906120e8575060208201515173ffffffffffffffffffffffffffffffffffffffff1615155b15612226576000606083602001516000015173ffffffffffffffffffffffffffffffffffffffff166370a0823160e01b306040516024016121299190613285565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516121b291906131d8565b6000604051808303816000865af19150503d80600081146121ef576040519150601f19603f3d011682016040523d82523d6000602084013e6121f4565b606091505b5091509150818015612207575060008151115b6122235760405162461bcd60e51b815260040161041990613529565b50505b61222f826116e1565b60048190556040513391907f844435c59f7ccdf12de134e8f9b3b7d664fe9f06e3263680779599ba4097bc3f9061226790869061392d565b60405180910390a3505060045490565b6040518060400160405280600381526020017f61636c00000000000000000000000000000000000000000000000000000000008152506002816040516122bd91906131d8565b9081526020016040518091039020546000146122eb5760405162461bcd60e51b81526004016104199061374f565b436002826040516122fc91906131d8565b908152604051908190036020019020556123367f586df60400000000000000000000000000000000000000000000000000000000836119bb565b8060405161234491906131d8565b604051908190038120907f7bc2a48a4a566e237a12186f19d985b0f76afc9d5290601edac19876253670c290600090a25050565b7fffffffff0000000000000000000000000000000000000000000000000000000081166000908152602081905260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fbf5e1f87f5ab65b58074cd29244d7c487a948983cda4b932e0f966b62bd34aca906124029083906133cf565b60405180910390a150565b61241683610d9a565b156124335760405162461bcd60e51b8152600401610419906136e1565b73ffffffffffffffffffffffffffffffffffffffff82166001141561246a5760405162461bcd60e51b8152600401610419906138bf565b7fffffffff000000000000000000000000000000000000000000000000000000008316600081815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff878116808652919093529281902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169286169290921790915551909133917fc62063b81f7036fd97a0dc546516e99f11004d2d76ca0fddd3866346c86e709190612521908690613285565b60405180910390a4505050565b808201828110156103a65760405162461bcd60e51b8152600401610419906138f6565b60008160000151826020015183604001518460600151856080015160405160200161257c91906132fd565b604051602081830303815290604052805190602001208660a001518760c00151805190602001206040516020016116f497969594939291906139df565b60405160009046906125d590309083908790879060200161321d565b6040516020818303038152906040528051906020012091505092915050565b7fffffffff000000000000000000000000000000000000000000000000000000008316600090815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff808716855292528220541680156127515773ffffffffffffffffffffffffffffffffffffffff8116600214156126775760019150506110cf565b6040517f097c810800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82169063097c8108906126cd908890889088906004016133fc565b602060405180830381600087803b1580156126e757600080fd5b505af1925050508015612735575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261273291810190612cb8565b60015b61273e57612751565b801561274f576001925050506110cf565b505b506000949350505050565b600061277d8373ffffffffffffffffffffffffffffffffffffffff166127ed565b612789575060006103a6565b6040516020818451602086016000885af180156127c6573d80156127b457602081146127bd576127c4565b600193506127c4565b8251151593505b505b505092915050565b6000606063a9059cbb60e01b8484604051602401611cfe9291906132d7565b3b151590565b6040805160608101909152806000815260006020820181905260409091015290565b604080518082019091526000808252602082015290565b80356103a681613add565b600082601f830112612847578081fd5b813561285a61285582613a4f565b613a28565b818152915060208083019084810160005b8481101561290f57813587016060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0838c030112156128aa57600080fd5b6128b381613a28565b858301356128c081613add565b8152604083810135878301528284013567ffffffffffffffff8111156128e557600080fd5b6128f38d898388010161291a565b918301919091525086525050928201929082019060010161286b565b505050505092915050565b600082601f83011261292a578081fd5b813561293861285582613a6f565b915080825283602082850101111561294f57600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112612978578081fd5b815161298661285582613a6f565b915080825283602082850101111561299d57600080fd5b6129ae816020840160208601613ab1565b5092915050565b6000604082840312156129c6578081fd5b6129d06040613a28565b905081356129dd81613add565b808252506020820135602082015292915050565b60006101008284031215612a03578081fd5b612a0d60c0613a28565b905081358152612a2083602084016129b5565b6020820152612a3283606084016129b5565b604082015260a0820135612a4581613add565b606082015260c082013567ffffffffffffffff811115612a6457600080fd5b612a708482850161291a565b60808301525060e082013560a082015292915050565b600060408284031215612a97578081fd5b612aa16040613a28565b9050813567ffffffffffffffff80821115612abb57600080fd5b81840160e08187031215612ace57600080fd5b612ad860e0613a28565b92508035835260208101356020840152612af5866040830161282c565b6040840152612b07866060830161282c565b6060840152608081013582811115612b1e57600080fd5b612b2a87828401612837565b60808501525060a081013560a084015260c081013582811115612b4c57600080fd5b612b588782840161291a565b60c0850152505090825260208301359080821115612b7557600080fd5b50612b82848285016129f1565b60208301525092915050565b600080600060608486031215612ba2578283fd5b8351612bad81613add565b6020850151909350612bbe81613add565b80925050604084015190509250925092565b60008060408385031215612be2578182fd5b8235612bed81613add565b9150602083013567ffffffffffffffff811115612c08578182fd5b612c14858286016129f1565b9150509250929050565b60008060408385031215612c30578182fd5b8251612c3b81613add565b6020939093015192949293505050565b60008060208385031215612c5d578182fd5b823567ffffffffffffffff80821115612c74578384fd5b81850186601f820112612c85578485fd5b8035925081831115612c95578485fd5b866020606085028301011115612ca9578485fd5b60200196919550909350505050565b600060208284031215612cc9578081fd5b815180151581146110cf578182fd5b600060208284031215612ce9578081fd5b5035919050565b60008060408385031215612d02578182fd5b8251915060208084015167ffffffffffffffff811115612d20578283fd5b80850186601f820112612d31578384fd5b80519150612d4161285583613a4f565b82815283810190828501865b85811015612d7657612d648b888451880101612968565b84529286019290860190600101612d4d565b5096999098509650505050505050565b60008060408385031215612d98578182fd5b823591506020830135612daa81613add565b809150509250929050565b600060208284031215612dc6578081fd5b81356110cf81613b02565b60008060408385031215612de3578182fd5b8235612dee81613b02565b91506020830135612daa81613add565b600080600060608486031215612e12578081fd5b8335612e1d81613b02565b92506020840135612e2d81613add565b91506040840135612e3d81613add565b809150509250925092565b600060208284031215612e59578081fd5b813567ffffffffffffffff811115612e6f578182fd5b6119b38482850161291a565b600060608284031215612e8c578081fd5b612e966060613a28565b823560038110612ea4578283fd5b81526020830135612eb481613b02565b60208201526040830135612ec781613add565b60408201529392505050565b600060208284031215612ee4578081fd5b813567ffffffffffffffff811115612efa578182fd5b6119b3848285016129f1565b600060208284031215612f17578081fd5b813567ffffffffffffffff811115612f2d578182fd5b6119b384828501612a86565b60008060408385031215612f4b578182fd5b823567ffffffffffffffff80821115612f62578384fd5b612f6e86838701612a86565b93506020850135915080821115612f83578283fd5b50612c148582860161291a565b60008060408385031215612fa2578182fd5b823567ffffffffffffffff811115612fb8578283fd5b612fc485828601612a86565b95602094909401359450505050565b600060208284031215612fe4578081fd5b5051919050565b6000815180845260208085019450848183028601828601855b858110156130645783830389528151606073ffffffffffffffffffffffffffffffffffffffff82511685528682015187860152604080830151828288015261304e83880182613071565b9c89019c96505050928601925050600101613004565b5090979650505050505050565b60008151808452613089816020860160208601613ab1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b60006101008251845260208301516130fb60208601826130bb565b50604083015161310e60608601826130bb565b5073ffffffffffffffffffffffffffffffffffffffff60608401511660a085015260808301518160c086015261314682860182613071565b60a085015160e087015280935050505092915050565b60008151835260208201516020840152604082015173ffffffffffffffffffffffffffffffffffffffff80821660408601528060608501511660608601525050608082015160e060808501526131b560e0850182612feb565b60a084015160a086015260c0840151915084810360c0860152611d878183613071565b600082516131ea818460208701613ab1565b9190910192915050565b7f61636c0000000000000000000000000000000000000000000000000000000000815260030190565b7f657263336b2d7631000000000000000000000000000000000000000000000000815260609490941b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166008850152601c840192909252603c830152605c820152607c0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152604081019190915260600190565b73ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b6000602082526110cf6020830184612feb565b6000606082526133236060830186612feb565b60208301949094525060400152919050565b901515815260200190565b90815260200190565b600060408201848352602060408185015281855180845260608601915060608382028701019350828701855b828110156133c1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030184526133af868351613071565b95509284019290840190600101613375565b509398975050505050505050565b7fffffffff0000000000000000000000000000000000000000000000000000000091909116815260200190565b60007fffffffff000000000000000000000000000000000000000000000000000000008516825273ffffffffffffffffffffffffffffffffffffffff8416602083015260606040830152611d876060830184613071565b6000602082526110cf6020830184613071565b6000608082526134796080830186613071565b90508360208301526119b360408301846130bb565b602081016007831061349c57fe5b91905290565b6000838252604060208301526119b36040830184613071565b6020808252601a908201527f6465706f7369743a2062616420746f6b656e2072656c65617365000000000000604082015260600190565b60208082526010908201527f71756575653a2062616420737461746500000000000000000000000000000000604082015260600190565b60208082526011908201527f71756575653a2062616420636f6e666967000000000000000000000000000000604082015260600190565b60208082526009908201527f61636c3a20617574680000000000000000000000000000000000000000000000604082015260600190565b60208082526015908201527f71756575653a2062616420646973707574652069640000000000000000000000604082015260600190565b60208082526010908201527f71756575653a20626164206e6f6e636500000000000000000000000000000000604082015260600190565b60208082526010908201527f71756575653a206261642064656c617900000000000000000000000000000000604082015260600190565b60208082526010908201527f71756575653a2062616420726573657400000000000000000000000000000000604082015260600190565b60208082526013908201527f71756575653a20626164206665652070756c6c00000000000000000000000000604082015260600190565b60208082526014908201527f71756575653a20626164207375626d6974746572000000000000000000000000604082015260600190565b6020808252600b908201527f61636c3a2066726f7a656e000000000000000000000000000000000000000000604082015260600190565b60208082526012908201527f71756575653a2062616420617070726f76650000000000000000000000000000604082015260600190565b60208082526022908201527f696e697469616c697a61626c653a20616c726561647920696e697469616c697a60408201527f6564000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526010908201527f71756575653a2077616974206d6f726500000000000000000000000000000000604082015260600190565b60208082526017908201527f6465706f7369743a2062616420746f6b656e206c6f636b000000000000000000604082015260600190565b60208082526012908201527f71756575653a206e6f74207375626a6563740000000000000000000000000000604082015260600190565b6020808252601c908201527f63616c6c6461746173697a653a206c696d697420657863656564656400000000604082015260600190565b6020808252601c908201527f61636c3a20696e697469616c20726f6f74206d6973616c69676e656400000000604082015260600190565b6020808252600f908201527f61636c3a2062616420667265657a650000000000000000000000000000000000604082015260600190565b6020808252600e908201527f6d6174683a206f766572666c6f77000000000000000000000000000000000000604082015260600190565b6000602082526110cf60208301846130e0565b60006020825282516040602084015261395c606084018261315c565b602085015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848203016040850152611d8781836130e0565b6000602082526110cf602083018461315c565b600084825273ffffffffffffffffffffffffffffffffffffffff8416602083015260606040830152611d876060830184613071565b968752602087019590955273ffffffffffffffffffffffffffffffffffffffff9384166040870152919092166060850152608084019190915260a083015260c082015260e00190565b60405181810167ffffffffffffffff81118282101715613a4757600080fd5b604052919050565b600067ffffffffffffffff821115613a65578081fd5b5060209081020190565b600067ffffffffffffffff821115613a85578081fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015613acc578181015183820152602001613ab4565b838111156107655750506000910152565b73ffffffffffffffffffffffffffffffffffffffff81168114613aff57600080fd5b50565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114613aff57600080fdfea2646970667358221220047f58de53e183d409d81810d17312376c0fd2479adb7e90037508e7eab281fa64736f6c63430006080033d87da3e1f08043464b74e6b0861ccd8d8a5174e228287ac9b9f6efc1673da4ec7bc2a48a4a566e237a12186f19d985b0f76afc9d5290601edac19876253670c2a2646970667358221220b172753c8385a1d34d2071a1ee0f7d825f059cbdd1b587f3a6383726a08b6eb764736f6c63430006080033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.