Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 6593119 | 2215 days ago | IN | 0 ETH | 0.05560403 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
Finance
Compiler Version
v0.4.24+commit.e67f0147
Optimization Enabled:
Yes with 10000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2018-10-28 */ pragma solidity 0.4.24; // File: @aragon/os/contracts/common/UnstructuredStorage.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; library UnstructuredStorage { function getStorageBool(bytes32 position) internal view returns (bool data) { assembly { data := sload(position) } } function getStorageAddress(bytes32 position) internal view returns (address data) { assembly { data := sload(position) } } function getStorageBytes32(bytes32 position) internal view returns (bytes32 data) { assembly { data := sload(position) } } function getStorageUint256(bytes32 position) internal view returns (uint256 data) { assembly { data := sload(position) } } function setStorageBool(bytes32 position, bool data) internal { assembly { sstore(position, data) } } function setStorageAddress(bytes32 position, address data) internal { assembly { sstore(position, data) } } function setStorageBytes32(bytes32 position, bytes32 data) internal { assembly { sstore(position, data) } } function setStorageUint256(bytes32 position, uint256 data) internal { assembly { sstore(position, data) } } } // File: @aragon/os/contracts/acl/IACL.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; interface IACL { function initialize(address permissionsCreator) external; // TODO: this should be external // See https://github.com/ethereum/solidity/issues/4832 function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool); } // File: @aragon/os/contracts/common/IVaultRecoverable.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; interface IVaultRecoverable { function transferToVault(address token) external; function allowRecoverability(address token) external view returns (bool); function getRecoveryVault() external view returns (address); } // File: @aragon/os/contracts/kernel/IKernel.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; // This should be an interface, but interfaces can't inherit yet :( contract IKernel is IVaultRecoverable { event SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app); function acl() public view returns (IACL); function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool); function setApp(bytes32 namespace, bytes32 appId, address app) public; function getApp(bytes32 namespace, bytes32 appId) public view returns (address); } // File: @aragon/os/contracts/apps/AppStorage.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; contract AppStorage { using UnstructuredStorage for bytes32; /* Hardcoded constants to save gas bytes32 internal constant KERNEL_POSITION = keccak256("aragonOS.appStorage.kernel"); bytes32 internal constant APP_ID_POSITION = keccak256("aragonOS.appStorage.appId"); */ bytes32 internal constant KERNEL_POSITION = 0x4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b; bytes32 internal constant APP_ID_POSITION = 0xd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b; function kernel() public view returns (IKernel) { return IKernel(KERNEL_POSITION.getStorageAddress()); } function appId() public view returns (bytes32) { return APP_ID_POSITION.getStorageBytes32(); } function setKernel(IKernel _kernel) internal { KERNEL_POSITION.setStorageAddress(address(_kernel)); } function setAppId(bytes32 _appId) internal { APP_ID_POSITION.setStorageBytes32(_appId); } } // File: @aragon/os/contracts/common/Uint256Helpers.sol library Uint256Helpers { uint256 private constant MAX_UINT64 = uint64(-1); string private constant ERROR_NUMBER_TOO_BIG = "UINT64_NUMBER_TOO_BIG"; function toUint64(uint256 a) internal pure returns (uint64) { require(a <= MAX_UINT64, ERROR_NUMBER_TOO_BIG); return uint64(a); } } // File: @aragon/os/contracts/common/TimeHelpers.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; contract TimeHelpers { using Uint256Helpers for uint256; /** * @dev Returns the current block number. * Using a function rather than `block.number` allows us to easily mock the block number in * tests. */ function getBlockNumber() internal view returns (uint256) { return block.number; } /** * @dev Returns the current block number, converted to uint64. * Using a function rather than `block.number` allows us to easily mock the block number in * tests. */ function getBlockNumber64() internal view returns (uint64) { return getBlockNumber().toUint64(); } /** * @dev Returns the current timestamp. * Using a function rather than `block.timestamp` allows us to easily mock it in * tests. */ function getTimestamp() internal view returns (uint256) { return block.timestamp; // solium-disable-line security/no-block-members } /** * @dev Returns the current timestamp, converted to uint64. * Using a function rather than `block.timestamp` allows us to easily mock it in * tests. */ function getTimestamp64() internal view returns (uint64) { return getTimestamp().toUint64(); } } // File: @aragon/os/contracts/common/Initializable.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; contract Initializable is TimeHelpers { using UnstructuredStorage for bytes32; // keccak256("aragonOS.initializable.initializationBlock") bytes32 internal constant INITIALIZATION_BLOCK_POSITION = 0xebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e; string private constant ERROR_ALREADY_INITIALIZED = "INIT_ALREADY_INITIALIZED"; string private constant ERROR_NOT_INITIALIZED = "INIT_NOT_INITIALIZED"; modifier onlyInit { require(getInitializationBlock() == 0, ERROR_ALREADY_INITIALIZED); _; } modifier isInitialized { require(hasInitialized(), ERROR_NOT_INITIALIZED); _; } /** * @return Block number in which the contract was initialized */ function getInitializationBlock() public view returns (uint256) { return INITIALIZATION_BLOCK_POSITION.getStorageUint256(); } /** * @return Whether the contract has been initialized by the time of the current block */ function hasInitialized() public view returns (bool) { uint256 initializationBlock = getInitializationBlock(); return initializationBlock != 0 && getBlockNumber() >= initializationBlock; } /** * @dev Function to be called by top level contract after initialization has finished. */ function initialized() internal onlyInit { INITIALIZATION_BLOCK_POSITION.setStorageUint256(getBlockNumber()); } /** * @dev Function to be called by top level contract after initialization to enable the contract * at a future block number rather than immediately. */ function initializedAt(uint256 _blockNumber) internal onlyInit { INITIALIZATION_BLOCK_POSITION.setStorageUint256(_blockNumber); } } // File: @aragon/os/contracts/common/Petrifiable.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; contract Petrifiable is Initializable { // Use block UINT256_MAX (which should be never) as the initializable date uint256 internal constant PETRIFIED_BLOCK = uint256(-1); function isPetrified() public view returns (bool) { return getInitializationBlock() == PETRIFIED_BLOCK; } /** * @dev Function to be called by top level contract to prevent being initialized. * Useful for freezing base contracts when they're used behind proxies. */ function petrify() internal onlyInit { initializedAt(PETRIFIED_BLOCK); } } // File: @aragon/os/contracts/common/Autopetrified.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; contract Autopetrified is Petrifiable { constructor() public { // Immediately petrify base (non-proxy) instances of inherited contracts on deploy. // This renders them uninitializable (and unusable without a proxy). petrify(); } } // File: @aragon/os/contracts/lib/token/ERC20.sol // See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/a9f910d34f0ab33a1ae5e714f69f9596a02b4d91/contracts/token/ERC20/ERC20.sol pragma solidity ^0.4.24; /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ contract ERC20 { function totalSupply() public view returns (uint256); function balanceOf(address _who) public view returns (uint256); function allowance(address _owner, address _spender) public view returns (uint256); function transfer(address _to, uint256 _value) public returns (bool); function approve(address _spender, uint256 _value) public returns (bool); function transferFrom(address _from, address _to, uint256 _value) public returns (bool); event Transfer( address indexed from, address indexed to, uint256 value ); event Approval( address indexed owner, address indexed spender, uint256 value ); } // File: @aragon/os/contracts/common/EtherTokenConstant.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; // aragonOS and aragon-apps rely on address(0) to denote native ETH, in // contracts where both tokens and ETH are accepted contract EtherTokenConstant { address internal constant ETH = address(0); } // File: @aragon/os/contracts/common/IsContract.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; contract IsContract { /* * NOTE: this should NEVER be used for authentication * (see pitfalls: https://github.com/fergarrui/ethereum-security/tree/master/contracts/extcodesize). * * This is only intended to be used as a sanity check that an address is actually a contract, * RATHER THAN an address not being a contract. */ function isContract(address _target) internal view returns (bool) { if (_target == address(0)) { return false; } uint256 size; assembly { size := extcodesize(_target) } return size > 0; } } // File: @aragon/os/contracts/common/VaultRecoverable.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; contract VaultRecoverable is IVaultRecoverable, EtherTokenConstant, IsContract { string private constant ERROR_DISALLOWED = "RECOVER_DISALLOWED"; string private constant ERROR_VAULT_NOT_CONTRACT = "RECOVER_VAULT_NOT_CONTRACT"; /** * @notice Send funds to recovery Vault. This contract should never receive funds, * but in case it does, this function allows one to recover them. * @param _token Token balance to be sent to recovery vault. */ function transferToVault(address _token) external { require(allowRecoverability(_token), ERROR_DISALLOWED); address vault = getRecoveryVault(); require(isContract(vault), ERROR_VAULT_NOT_CONTRACT); if (_token == ETH) { vault.transfer(address(this).balance); } else { uint256 amount = ERC20(_token).balanceOf(this); ERC20(_token).transfer(vault, amount); } } /** * @dev By default deriving from AragonApp makes it recoverable * @param token Token address that would be recovered * @return bool whether the app allows the recovery */ function allowRecoverability(address token) public view returns (bool) { return true; } // Cast non-implemented interface to be public so we can use it internally function getRecoveryVault() public view returns (address); } // File: @aragon/os/contracts/evmscript/IEVMScriptExecutor.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; interface IEVMScriptExecutor { function execScript(bytes script, bytes input, address[] blacklist) external returns (bytes); function executorType() external pure returns (bytes32); } // File: @aragon/os/contracts/evmscript/IEVMScriptRegistry.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; contract EVMScriptRegistryConstants { /* Hardcoded constants to save gas bytes32 internal constant EVMSCRIPT_REGISTRY_APP_ID = apmNamehash("evmreg"); */ bytes32 internal constant EVMSCRIPT_REGISTRY_APP_ID = 0xddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd61; } interface IEVMScriptRegistry { function addScriptExecutor(IEVMScriptExecutor executor) external returns (uint id); function disableScriptExecutor(uint256 executorId) external; // TODO: this should be external // See https://github.com/ethereum/solidity/issues/4832 function getScriptExecutor(bytes script) public view returns (IEVMScriptExecutor); } // File: @aragon/os/contracts/kernel/KernelConstants.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; contract KernelAppIds { /* Hardcoded constants to save gas bytes32 internal constant KERNEL_CORE_APP_ID = apmNamehash("kernel"); bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = apmNamehash("acl"); bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = apmNamehash("vault"); */ bytes32 internal constant KERNEL_CORE_APP_ID = 0x3b4bf6bf3ad5000ecf0f989d5befde585c6860fea3e574a4fab4c49d1c177d9c; bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = 0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a; bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = 0x7e852e0fcfce6551c13800f1e7476f982525c2b5277ba14b24339c68416336d1; } contract KernelNamespaceConstants { /* Hardcoded constants to save gas bytes32 internal constant KERNEL_CORE_NAMESPACE = keccak256("core"); bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = keccak256("base"); bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = keccak256("app"); */ bytes32 internal constant KERNEL_CORE_NAMESPACE = 0xc681a85306374a5ab27f0bbc385296a54bcd314a1948b6cf61c4ea1bc44bb9f8; bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = 0xf1f3eb40f5bc1ad1344716ced8b8a0431d840b5783aea1fd01786bc26f35ac0f; bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb; } // File: @aragon/os/contracts/evmscript/EVMScriptRunner.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; contract EVMScriptRunner is AppStorage, Initializable, EVMScriptRegistryConstants, KernelNamespaceConstants { string private constant ERROR_EXECUTOR_UNAVAILABLE = "EVMRUN_EXECUTOR_UNAVAILABLE"; string private constant ERROR_EXECUTION_REVERTED = "EVMRUN_EXECUTION_REVERTED"; string private constant ERROR_PROTECTED_STATE_MODIFIED = "EVMRUN_PROTECTED_STATE_MODIFIED"; event ScriptResult(address indexed executor, bytes script, bytes input, bytes returnData); function getEVMScriptExecutor(bytes _script) public view returns (IEVMScriptExecutor) { return IEVMScriptExecutor(getEVMScriptRegistry().getScriptExecutor(_script)); } function getEVMScriptRegistry() public view returns (IEVMScriptRegistry) { address registryAddr = kernel().getApp(KERNEL_APP_ADDR_NAMESPACE, EVMSCRIPT_REGISTRY_APP_ID); return IEVMScriptRegistry(registryAddr); } function runScript(bytes _script, bytes _input, address[] _blacklist) internal isInitialized protectState returns (bytes) { // TODO: Too much data flying around, maybe extracting spec id here is cheaper IEVMScriptExecutor executor = getEVMScriptExecutor(_script); require(address(executor) != address(0), ERROR_EXECUTOR_UNAVAILABLE); bytes4 sig = executor.execScript.selector; bytes memory data = abi.encodeWithSelector(sig, _script, _input, _blacklist); require(address(executor).delegatecall(data), ERROR_EXECUTION_REVERTED); bytes memory output = returnedDataDecoded(); emit ScriptResult(address(executor), _script, _input, output); return output; } /** * @dev copies and returns last's call data. Needs to ABI decode first */ function returnedDataDecoded() internal pure returns (bytes ret) { assembly { let size := returndatasize switch size case 0 {} default { ret := mload(0x40) // free mem ptr get mstore(0x40, add(ret, add(size, 0x20))) // free mem ptr set returndatacopy(ret, 0x20, sub(size, 0x20)) // copy return data } } return ret; } modifier protectState { address preKernel = address(kernel()); bytes32 preAppId = appId(); _; // exec require(address(kernel()) == preKernel, ERROR_PROTECTED_STATE_MODIFIED); require(appId() == preAppId, ERROR_PROTECTED_STATE_MODIFIED); } } // File: @aragon/os/contracts/acl/ACLSyntaxSugar.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; contract ACLSyntaxSugar { function arr() internal pure returns (uint256[]) {} function arr(bytes32 _a) internal pure returns (uint256[] r) { return arr(uint256(_a)); } function arr(bytes32 _a, bytes32 _b) internal pure returns (uint256[] r) { return arr(uint256(_a), uint256(_b)); } function arr(address _a) internal pure returns (uint256[] r) { return arr(uint256(_a)); } function arr(address _a, address _b) internal pure returns (uint256[] r) { return arr(uint256(_a), uint256(_b)); } function arr(address _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) { return arr(uint256(_a), _b, _c); } function arr(address _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) { return arr(uint256(_a), _b, _c, _d); } function arr(address _a, uint256 _b) internal pure returns (uint256[] r) { return arr(uint256(_a), uint256(_b)); } function arr(address _a, address _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) { return arr(uint256(_a), uint256(_b), _c, _d, _e); } function arr(address _a, address _b, address _c) internal pure returns (uint256[] r) { return arr(uint256(_a), uint256(_b), uint256(_c)); } function arr(address _a, address _b, uint256 _c) internal pure returns (uint256[] r) { return arr(uint256(_a), uint256(_b), uint256(_c)); } function arr(uint256 _a) internal pure returns (uint256[] r) { r = new uint256[](1); r[0] = _a; } function arr(uint256 _a, uint256 _b) internal pure returns (uint256[] r) { r = new uint256[](2); r[0] = _a; r[1] = _b; } function arr(uint256 _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) { r = new uint256[](3); r[0] = _a; r[1] = _b; r[2] = _c; } function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) { r = new uint256[](4); r[0] = _a; r[1] = _b; r[2] = _c; r[3] = _d; } function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) { r = new uint256[](5); r[0] = _a; r[1] = _b; r[2] = _c; r[3] = _d; r[4] = _e; } } contract ACLHelpers { function decodeParamOp(uint256 _x) internal pure returns (uint8 b) { return uint8(_x >> (8 * 30)); } function decodeParamId(uint256 _x) internal pure returns (uint8 b) { return uint8(_x >> (8 * 31)); } function decodeParamsList(uint256 _x) internal pure returns (uint32 a, uint32 b, uint32 c) { a = uint32(_x); b = uint32(_x >> (8 * 4)); c = uint32(_x >> (8 * 8)); } } // File: @aragon/os/contracts/apps/AragonApp.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; // Contracts inheriting from AragonApp are, by default, immediately petrified upon deployment so // that they can never be initialized. // Unless overriden, this behaviour enforces those contracts to be usable only behind an AppProxy. // ACLSyntaxSugar and EVMScriptRunner are not directly used by this contract, but are included so // that they are automatically usable by subclassing contracts contract AragonApp is AppStorage, Autopetrified, VaultRecoverable, EVMScriptRunner, ACLSyntaxSugar { string private constant ERROR_AUTH_FAILED = "APP_AUTH_FAILED"; modifier auth(bytes32 _role) { require(canPerform(msg.sender, _role, new uint256[](0)), ERROR_AUTH_FAILED); _; } modifier authP(bytes32 _role, uint256[] _params) { require(canPerform(msg.sender, _role, _params), ERROR_AUTH_FAILED); _; } /** * @dev Check whether an action can be performed by a sender for a particular role on this app * @param _sender Sender of the call * @param _role Role on this app * @param _params Permission params for the role * @return Boolean indicating whether the sender has the permissions to perform the action. * Always returns false if the app hasn't been initialized yet. */ function canPerform(address _sender, bytes32 _role, uint256[] _params) public view returns (bool) { if (!hasInitialized()) { return false; } IKernel linkedKernel = kernel(); if (address(linkedKernel) == address(0)) { return false; } // Force cast the uint256[] into a bytes array, by overwriting its length // Note that the bytes array doesn't need to be initialized as we immediately overwrite it // with _params and a new length, and _params becomes invalid from this point forward bytes memory how; uint256 byteLength = _params.length * 32; assembly { how := _params mstore(how, byteLength) } return linkedKernel.hasPermission(_sender, address(this), _role, how); } /** * @dev Get the recovery vault for the app * @return Recovery vault address for the app */ function getRecoveryVault() public view returns (address) { // Funds recovery via a vault is only available when used with a kernel return kernel().getRecoveryVault(); // if kernel is not set, it will revert } } // File: @aragon/os/contracts/lib/math/SafeMath.sol // See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/d51e38758e1d985661534534d5c61e27bece5042/contracts/math/SafeMath.sol // Adapted to use pragma ^0.4.24 and satisfy our linter rules pragma solidity ^0.4.24; /** * @title SafeMath * @dev Math operations with safety checks that revert on error */ library SafeMath { string private constant ERROR_ADD_OVERFLOW = "MATH_ADD_OVERFLOW"; string private constant ERROR_SUB_UNDERFLOW = "MATH_SUB_UNDERFLOW"; string private constant ERROR_MUL_OVERFLOW = "MATH_MUL_OVERFLOW"; string private constant ERROR_DIV_ZERO = "MATH_DIV_ZERO"; /** * @dev Multiplies two numbers, reverts on overflow. */ function mul(uint256 _a, uint256 _b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (_a == 0) { return 0; } uint256 c = _a * _b; require(c / _a == _b, ERROR_MUL_OVERFLOW); return c; } /** * @dev Integer division of two numbers truncating the quotient, reverts on division by zero. */ function div(uint256 _a, uint256 _b) internal pure returns (uint256) { require(_b > 0, ERROR_DIV_ZERO); // Solidity only automatically asserts when dividing by 0 uint256 c = _a / _b; // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold return c; } /** * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 _a, uint256 _b) internal pure returns (uint256) { require(_b <= _a, ERROR_SUB_UNDERFLOW); uint256 c = _a - _b; return c; } /** * @dev Adds two numbers, reverts on overflow. */ function add(uint256 _a, uint256 _b) internal pure returns (uint256) { uint256 c = _a + _b; require(c >= _a, ERROR_ADD_OVERFLOW); return c; } /** * @dev Divides two numbers and returns the remainder (unsigned integer modulo), * reverts when dividing by zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, ERROR_DIV_ZERO); return a % b; } } // File: @aragon/os/contracts/lib/math/SafeMath64.sol // See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/d51e38758e1d985661534534d5c61e27bece5042/contracts/math/SafeMath.sol // Adapted for uint64, pragma ^0.4.24, and satisfying our linter rules // Also optimized the mul() implementation, see https://github.com/aragon/aragonOS/pull/417 pragma solidity ^0.4.24; /** * @title SafeMath64 * @dev Math operations for uint64 with safety checks that revert on error */ library SafeMath64 { string private constant ERROR_ADD_OVERFLOW = "MATH64_ADD_OVERFLOW"; string private constant ERROR_SUB_UNDERFLOW = "MATH64_SUB_UNDERFLOW"; string private constant ERROR_MUL_OVERFLOW = "MATH64_MUL_OVERFLOW"; string private constant ERROR_DIV_ZERO = "MATH64_DIV_ZERO"; /** * @dev Multiplies two numbers, reverts on overflow. */ function mul(uint64 _a, uint64 _b) internal pure returns (uint64) { uint256 c = uint256(_a) * uint256(_b); require(c < 0x010000000000000000, ERROR_MUL_OVERFLOW); // 2**64 (less gas this way) return uint64(c); } /** * @dev Integer division of two numbers truncating the quotient, reverts on division by zero. */ function div(uint64 _a, uint64 _b) internal pure returns (uint64) { require(_b > 0, ERROR_DIV_ZERO); // Solidity only automatically asserts when dividing by 0 uint64 c = _a / _b; // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold return c; } /** * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint64 _a, uint64 _b) internal pure returns (uint64) { require(_b <= _a, ERROR_SUB_UNDERFLOW); uint64 c = _a - _b; return c; } /** * @dev Adds two numbers, reverts on overflow. */ function add(uint64 _a, uint64 _b) internal pure returns (uint64) { uint64 c = _a + _b; require(c >= _a, ERROR_ADD_OVERFLOW); return c; } /** * @dev Divides two numbers and returns the remainder (unsigned integer modulo), * reverts when dividing by zero. */ function mod(uint64 a, uint64 b) internal pure returns (uint64) { require(b != 0, ERROR_DIV_ZERO); return a % b; } } // File: @aragon/os/contracts/common/DepositableStorage.sol contract DepositableStorage { using UnstructuredStorage for bytes32; // keccak256("aragonOS.depositableStorage.depositable") bytes32 internal constant DEPOSITABLE_POSITION = 0x665fd576fbbe6f247aff98f5c94a561e3f71ec2d3c988d56f12d342396c50cea; function isDepositable() public view returns (bool) { return DEPOSITABLE_POSITION.getStorageBool(); } function setDepositable(bool _depositable) internal { DEPOSITABLE_POSITION.setStorageBool(_depositable); } } // File: @aragon/apps-vault/contracts/Vault.sol contract Vault is EtherTokenConstant, AragonApp, DepositableStorage { bytes32 public constant TRANSFER_ROLE = keccak256("TRANSFER_ROLE"); string private constant ERROR_DATA_NON_ZERO = "VAULT_DATA_NON_ZERO"; string private constant ERROR_NOT_DEPOSITABLE = "VAULT_NOT_DEPOSITABLE"; string private constant ERROR_DEPOSIT_VALUE_ZERO = "VAULT_DEPOSIT_VALUE_ZERO"; string private constant ERROR_TRANSFER_VALUE_ZERO = "VAULT_TRANSFER_VALUE_ZERO"; string private constant ERROR_SEND_REVERTED = "VAULT_SEND_REVERTED"; string private constant ERROR_VALUE_MISMATCH = "VAULT_VALUE_MISMATCH"; string private constant ERROR_TOKEN_TRANSFER_FROM_REVERTED = "VAULT_TOKEN_TRANSFER_FROM_REVERT"; string private constant ERROR_TOKEN_TRANSFER_REVERTED = "VAULT_TOKEN_TRANSFER_REVERTED"; event Transfer(address indexed token, address indexed to, uint256 amount); event Deposit(address indexed token, address indexed sender, uint256 amount); /** * @dev On a normal send() or transfer() this fallback is never executed as it will be * intercepted by the Proxy (see aragonOS#281) */ function () external payable isInitialized { require(msg.data.length == 0, ERROR_DATA_NON_ZERO); _deposit(ETH, msg.value); } /** * @notice Initialize Vault app * @dev As an AragonApp it needs to be initialized in order for roles (`auth` and `authP`) to work */ function initialize() external onlyInit { initialized(); setDepositable(true); } /** * @notice Deposit `_value` `_token` to the vault * @param _token Address of the token being transferred * @param _value Amount of tokens being transferred */ function deposit(address _token, uint256 _value) external payable isInitialized { _deposit(_token, _value); } /** * @notice Transfer `_value` `_token` from the Vault to `_to` * @param _token Address of the token being transferred * @param _to Address of the recipient of tokens * @param _value Amount of tokens being transferred */ /* solium-disable-next-line function-order */ function transfer(address _token, address _to, uint256 _value) external authP(TRANSFER_ROLE, arr(_token, _to, _value)) { require(_value > 0, ERROR_TRANSFER_VALUE_ZERO); if (_token == ETH) { require(_to.send(_value), ERROR_SEND_REVERTED); } else { require(ERC20(_token).transfer(_to, _value), ERROR_TOKEN_TRANSFER_REVERTED); } emit Transfer(_token, _to, _value); } function balance(address _token) public view returns (uint256) { if (_token == ETH) { return address(this).balance; } else { return ERC20(_token).balanceOf(this); } } /** * @dev Disable recovery escape hatch, as it could be used * maliciously to transfer funds away from the vault */ function allowRecoverability(address) public view returns (bool) { return false; } function _deposit(address _token, uint256 _value) internal { require(isDepositable(), ERROR_NOT_DEPOSITABLE); require(_value > 0, ERROR_DEPOSIT_VALUE_ZERO); if (_token == ETH) { // Deposit is implicit in this case require(msg.value == _value, ERROR_VALUE_MISMATCH); } else { require(ERC20(_token).transferFrom(msg.sender, this, _value), ERROR_TOKEN_TRANSFER_FROM_REVERTED); } emit Deposit(_token, msg.sender, _value); } } // File: contracts/Finance.sol /* * SPDX-License-Identitifer: GPL-3.0-or-later */ pragma solidity 0.4.24; contract Finance is EtherTokenConstant, IsContract, AragonApp { using SafeMath for uint256; using SafeMath64 for uint64; bytes32 public constant CREATE_PAYMENTS_ROLE = keccak256("CREATE_PAYMENTS_ROLE"); bytes32 public constant CHANGE_PERIOD_ROLE = keccak256("CHANGE_PERIOD_ROLE"); bytes32 public constant CHANGE_BUDGETS_ROLE = keccak256("CHANGE_BUDGETS_ROLE"); bytes32 public constant EXECUTE_PAYMENTS_ROLE = keccak256("EXECUTE_PAYMENTS_ROLE"); bytes32 public constant MANAGE_PAYMENTS_ROLE = keccak256("MANAGE_PAYMENTS_ROLE"); uint256 internal constant NO_PAYMENT = 0; uint256 internal constant NO_TRANSACTION = 0; uint256 internal constant MAX_PAYMENTS_PER_TX = 20; uint256 internal constant MAX_UINT = uint256(-1); uint64 internal constant MAX_UINT64 = uint64(-1); string private constant ERROR_COMPLETE_TRANSITION = "FINANCE_COMPLETE_TRANSITION"; string private constant ERROR_NO_PAYMENT = "FINANCE_NO_PAYMENT"; string private constant ERROR_NO_TRANSACTION = "FINANCE_NO_TRANSACTION"; string private constant ERROR_NO_PERIOD = "FINANCE_NO_PERIOD"; string private constant ERROR_VAULT_NOT_CONTRACT = "FINANCE_VAULT_NOT_CONTRACT"; string private constant ERROR_INIT_PERIOD_TOO_SHORT = "FINANCE_INIT_PERIOD_TOO_SHORT"; string private constant ERROR_SET_PERIOD_TOO_SHORT = "FINANCE_SET_PERIOD_TOO_SHORT"; string private constant ERROR_NEW_PAYMENT_AMOUNT_ZERO = "FINANCE_NEW_PAYMENT_AMOUNT_ZERO"; string private constant ERROR_RECOVER_AMOUNT_ZERO = "FINANCE_RECOVER_AMOUNT_ZERO"; string private constant ERROR_DEPOSIT_AMOUNT_ZERO = "FINANCE_DEPOSIT_AMOUNT_ZERO"; string private constant ERROR_BUDGET = "FINANCE_BUDGET"; string private constant ERROR_EXECUTE_PAYMENT_TIME = "FINANCE_EXECUTE_PAYMENT_TIME"; string private constant ERROR_RECEIVER_EXECUTE_PAYMENT_TIME = "FINANCE_RCVR_EXEC_PAYMENT_TIME"; string private constant ERROR_PAYMENT_RECEIVER = "FINANCE_PAYMENT_RECEIVER"; string private constant ERROR_TOKEN_TRANSFER_FROM_REVERTED = "FINANCE_TKN_TRANSFER_FROM_REVERT"; string private constant ERROR_VALUE_MISMATCH = "FINANCE_VALUE_MISMATCH"; string private constant ERROR_PAYMENT_INACTIVE = "FINANCE_PAYMENT_INACTIVE"; string private constant ERROR_REMAINING_BUDGET = "FINANCE_REMAINING_BUDGET"; // Order optimized for storage struct Payment { address token; address receiver; address createdBy; bool inactive; uint256 amount; uint64 initialPaymentTime; uint64 interval; uint64 maxRepeats; uint64 repeats; } // Order optimized for storage struct Transaction { address token; address entity; bool isIncoming; uint256 amount; uint256 paymentId; uint64 paymentRepeatNumber; uint64 date; uint64 periodId; } struct TokenStatement { uint256 expenses; uint256 income; } struct Period { uint64 startTime; uint64 endTime; uint256 firstTransactionId; uint256 lastTransactionId; mapping (address => TokenStatement) tokenStatement; } struct Settings { uint64 periodDuration; mapping (address => uint256) budgets; mapping (address => bool) hasBudget; } Vault public vault; Settings internal settings; // We are mimicing arrays, we use mappings instead to make app upgrade more graceful mapping (uint256 => Payment) internal payments; // Payments start at index 1, to allow us to use payments[0] for transactions that are not // linked to a recurring payment uint256 public paymentsNextIndex; mapping (uint256 => Transaction) internal transactions; uint256 public transactionsNextIndex; mapping (uint64 => Period) internal periods; uint64 public periodsLength; event NewPeriod(uint64 indexed periodId, uint64 periodStarts, uint64 periodEnds); event SetBudget(address indexed token, uint256 amount, bool hasBudget); event NewPayment(uint256 indexed paymentId, address indexed recipient, uint64 maxRepeats, string reference); event NewTransaction(uint256 indexed transactionId, bool incoming, address indexed entity, uint256 amount, string reference); event ChangePaymentState(uint256 indexed paymentId, bool inactive); event ChangePeriodDuration(uint64 newDuration); event PaymentFailure(uint256 paymentId); // Modifier used by all methods that impact accounting to make sure accounting period // is changed before the operation if needed // NOTE: its use **MUST** be accompanied by an initialization check modifier transitionsPeriod { bool completeTransition = _tryTransitionAccountingPeriod(getMaxPeriodTransitions()); require(completeTransition, ERROR_COMPLETE_TRANSITION); _; } modifier paymentExists(uint256 _paymentId) { require(_paymentId > 0 && _paymentId < paymentsNextIndex, ERROR_NO_PAYMENT); _; } modifier transactionExists(uint256 _transactionId) { require(_transactionId > 0 && _transactionId < transactionsNextIndex, ERROR_NO_TRANSACTION); _; } modifier periodExists(uint64 _periodId) { require(_periodId < periodsLength, ERROR_NO_PERIOD); _; } /** * @dev Sends ETH to Vault. Sends all the available balance. * @notice Deposit ETH to the Vault, to avoid locking them in this Finance app forever */ function () external payable isInitialized transitionsPeriod { _deposit( ETH, msg.value, "Ether transfer to Finance app", msg.sender, true ); } /** * @notice Initialize Finance app for Vault at `_vault` with period length of `@transformTime(_periodDuration)` * @param _vault Address of the vault Finance will rely on (non changeable) * @param _periodDuration Duration in seconds of each period */ function initialize(Vault _vault, uint64 _periodDuration) external onlyInit { initialized(); require(isContract(_vault), ERROR_VAULT_NOT_CONTRACT); vault = _vault; require(_periodDuration >= 1 days, ERROR_INIT_PERIOD_TOO_SHORT); settings.periodDuration = _periodDuration; // Reserve the first recurring payment index as an unused index for transactions not linked to a payment payments[0].inactive = true; paymentsNextIndex = 1; // Reserve the first transaction index as an unused index for periods with no transactions transactionsNextIndex = 1; // Start the first period _newPeriod(getTimestamp64()); } /** * @dev Deposit for approved ERC20 tokens or ETH * @notice Deposit `@tokenAmount(_token, _amount)` * @param _token Address of deposited token * @param _amount Amount of tokens sent * @param _reference Reason for payment */ function deposit(address _token, uint256 _amount, string _reference) external payable isInitialized transitionsPeriod { _deposit( _token, _amount, _reference, msg.sender, true ); } /** * @notice Create a new payment of `@tokenAmount(_token, _amount)` to `_receiver``_maxRepeats > 0 ? ', executing ' + _maxRepeats + ' times at intervals of ' + @transformTime(_interval) : ''` * @param _token Address of token for payment * @param _receiver Address that will receive payment * @param _amount Tokens that are payed every time the payment is due * @param _initialPaymentTime Timestamp for when the first payment is done * @param _interval Number of seconds that need to pass between payment transactions * @param _maxRepeats Maximum instances a payment can be executed * @param _reference String detailing payment reason */ function newPayment( address _token, address _receiver, uint256 _amount, uint64 _initialPaymentTime, uint64 _interval, uint64 _maxRepeats, string _reference ) external authP(CREATE_PAYMENTS_ROLE, arr(_token, _receiver, _amount, _interval, _maxRepeats)) transitionsPeriod returns (uint256 paymentId) { require(_amount > 0, ERROR_NEW_PAYMENT_AMOUNT_ZERO); // Avoid saving payment data for 1 time immediate payments if (_initialPaymentTime <= getTimestamp64() && _maxRepeats == 1) { _makePaymentTransaction( _token, _receiver, _amount, NO_PAYMENT, // unrelated to any payment id; it isn't created 0, // also unrelated to any payment repeats _reference ); return; } // Budget must allow at least one instance of this payment each period, or not be set at all require(settings.budgets[_token] >= _amount || !settings.hasBudget[_token], ERROR_BUDGET); paymentId = paymentsNextIndex++; emit NewPayment(paymentId, _receiver, _maxRepeats, _reference); Payment storage payment = payments[paymentId]; payment.token = _token; payment.receiver = _receiver; payment.amount = _amount; payment.initialPaymentTime = _initialPaymentTime; payment.interval = _interval; payment.maxRepeats = _maxRepeats; payment.createdBy = msg.sender; if (nextPaymentTime(paymentId) <= getTimestamp64()) { _executePayment(paymentId); } } /** * @notice Change period duration to `@transformTime(_periodDuration)`, effective for next accounting period * @param _periodDuration Duration in seconds for accounting periods */ function setPeriodDuration(uint64 _periodDuration) external authP(CHANGE_PERIOD_ROLE, arr(uint256(_periodDuration), uint256(settings.periodDuration))) transitionsPeriod { require(_periodDuration >= 1 days, ERROR_SET_PERIOD_TOO_SHORT); settings.periodDuration = _periodDuration; emit ChangePeriodDuration(_periodDuration); } /** * @notice Set budget for `_token.symbol(): string` to `@tokenAmount(_token, _amount, false)`, effective immediately * @param _token Address for token * @param _amount New budget amount */ function setBudget( address _token, uint256 _amount ) external authP(CHANGE_BUDGETS_ROLE, arr(_token, _amount, settings.budgets[_token], settings.hasBudget[_token] ? 1 : 0)) transitionsPeriod { settings.budgets[_token] = _amount; if (!settings.hasBudget[_token]) { settings.hasBudget[_token] = true; } emit SetBudget(_token, _amount, true); } /** * @notice Remove spending limit for `_token.symbol(): string`, effective immediately * @param _token Address for token */ function removeBudget(address _token) external authP(CHANGE_BUDGETS_ROLE, arr(_token, uint256(0), settings.budgets[_token], settings.hasBudget[_token] ? 1 : 0)) transitionsPeriod { settings.budgets[_token] = 0; settings.hasBudget[_token] = false; emit SetBudget(_token, 0, false); } /** * @dev Executes any payment (requires role) * @notice Execute pending payment #`_paymentId` * @param _paymentId Identifier for payment */ function executePayment(uint256 _paymentId) external authP(EXECUTE_PAYMENTS_ROLE, arr(_paymentId, payments[_paymentId].amount)) paymentExists(_paymentId) transitionsPeriod { require(nextPaymentTime(_paymentId) <= getTimestamp64(), ERROR_EXECUTE_PAYMENT_TIME); _executePayment(_paymentId); } /** * @dev Always allows receiver of a payment to trigger execution * @notice Execute pending payment #`_paymentId` * @param _paymentId Identifier for payment */ function receiverExecutePayment(uint256 _paymentId) external isInitialized paymentExists(_paymentId) transitionsPeriod { require(nextPaymentTime(_paymentId) <= getTimestamp64(), ERROR_RECEIVER_EXECUTE_PAYMENT_TIME); require(payments[_paymentId].receiver == msg.sender, ERROR_PAYMENT_RECEIVER); _executePayment(_paymentId); } /** * @notice `_active ? 'Activate' : 'Disable'` payment #`_paymentId` * @dev Note that we do not require this action to transition periods, as it doesn't directly * impact any accounting periods. * Not having to transition periods also makes disabling payments easier to prevent funds * from being pulled out in the event of a breach. * @param _paymentId Identifier for payment * @param _active Whether it will be active or inactive */ function setPaymentStatus(uint256 _paymentId, bool _active) external authP(MANAGE_PAYMENTS_ROLE, arr(_paymentId, uint256(_active ? 1 : 0))) paymentExists(_paymentId) { payments[_paymentId].inactive = !_active; emit ChangePaymentState(_paymentId, _active); } /** * @dev Allows making a simple payment from this contract to the Vault, to avoid locked tokens. * This contract should never receive tokens with a simple transfer call, but in case it * happens, this function allows for their recovery. * @notice Send tokens held in this contract to the Vault * @param _token Token whose balance is going to be transferred. */ function recoverToVault(address _token) public isInitialized transitionsPeriod { uint256 amount = _token == ETH ? address(this).balance : ERC20(_token).balanceOf(this); require(amount > 0, ERROR_RECOVER_AMOUNT_ZERO); _deposit( _token, amount, "Recover to Vault", this, false ); } /** * @dev Transitions accounting periods if needed. For preventing OOG attacks, a maxTransitions * param is provided. If more than the specified number of periods need to be transitioned, * it will return false. * @notice Transition accounting period if needed * @param _maxTransitions Maximum periods that can be transitioned * @return success Boolean indicating whether the accounting period is the correct one (if false, * maxTransitions was surpased and another call is needed) */ function tryTransitionAccountingPeriod(uint64 _maxTransitions) public isInitialized returns (bool success) { return _tryTransitionAccountingPeriod(_maxTransitions); } // consts /** * @dev Disable recovery escape hatch if the app has been initialized, as it could be used * maliciously to transfer funds in the Finance app to another Vault * finance#recoverToVault() should be used to recover funds to the Finance's vault */ function allowRecoverability(address) public view returns (bool) { return !hasInitialized(); } function getPayment(uint256 _paymentId) public view paymentExists(_paymentId) returns ( address token, address receiver, uint256 amount, uint64 initialPaymentTime, uint64 interval, uint64 maxRepeats, bool inactive, uint64 repeats, address createdBy ) { Payment storage payment = payments[_paymentId]; token = payment.token; receiver = payment.receiver; amount = payment.amount; initialPaymentTime = payment.initialPaymentTime; interval = payment.interval; maxRepeats = payment.maxRepeats; repeats = payment.repeats; inactive = payment.inactive; createdBy = payment.createdBy; } function getTransaction(uint256 _transactionId) public view transactionExists(_transactionId) returns ( uint64 periodId, uint256 amount, uint256 paymentId, uint64 paymentRepeatNumber, address token, address entity, bool isIncoming, uint64 date ) { Transaction storage transaction = transactions[_transactionId]; token = transaction.token; entity = transaction.entity; isIncoming = transaction.isIncoming; date = transaction.date; periodId = transaction.periodId; amount = transaction.amount; paymentId = transaction.paymentId; paymentRepeatNumber = transaction.paymentRepeatNumber; } function getPeriod(uint64 _periodId) public view periodExists(_periodId) returns ( bool isCurrent, uint64 startTime, uint64 endTime, uint256 firstTransactionId, uint256 lastTransactionId ) { Period storage period = periods[_periodId]; isCurrent = _currentPeriodId() == _periodId; startTime = period.startTime; endTime = period.endTime; firstTransactionId = period.firstTransactionId; lastTransactionId = period.lastTransactionId; } function getPeriodTokenStatement(uint64 _periodId, address _token) public view periodExists(_periodId) returns (uint256 expenses, uint256 income) { TokenStatement storage tokenStatement = periods[_periodId].tokenStatement[_token]; expenses = tokenStatement.expenses; income = tokenStatement.income; } function nextPaymentTime(uint256 _paymentId) public view paymentExists(_paymentId) returns (uint64) { Payment memory payment = payments[_paymentId]; if (payment.repeats >= payment.maxRepeats) { return MAX_UINT64; // re-executes in some billions of years time... should not need to worry } // Split in multiple lines to circunvent linter warning uint64 increase = payment.repeats.mul(payment.interval); uint64 nextPayment = payment.initialPaymentTime.add(increase); return nextPayment; } function getPeriodDuration() public view returns (uint64) { return settings.periodDuration; } function getBudget(address _token) public view returns (uint256 budget, bool hasBudget) { budget = settings.budgets[_token]; hasBudget = settings.hasBudget[_token]; } /** * @dev We have to check for initialization as periods are only valid after initializing */ function getRemainingBudget(address _token) public view isInitialized returns (uint256) { return _getRemainingBudget(_token); } /** * @dev We have to check for initialization as periods are only valid after initializing */ function currentPeriodId() public view isInitialized returns (uint64) { return _currentPeriodId(); } // internal fns function _deposit(address _token, uint256 _amount, string _reference, address _sender, bool _isExternalDeposit) internal { require(_amount > 0, ERROR_DEPOSIT_AMOUNT_ZERO); _recordIncomingTransaction( _token, _sender, _amount, _reference ); // If it is an external deposit, check that the assets are actually transferred // External deposit will be false when the assets were already in the Finance app // and just need to be transferred to the vault if (_isExternalDeposit) { if (_token != ETH) { // Get the tokens to Finance require(ERC20(_token).transferFrom(msg.sender, this, _amount), ERROR_TOKEN_TRANSFER_FROM_REVERTED); } else { // Ensure that the ETH sent with the transaction equals the amount in the deposit require(msg.value == _amount, ERROR_VALUE_MISMATCH); } } if (_token == ETH) { vault.deposit.value(_amount)(ETH, _amount); } else { ERC20(_token).approve(vault, _amount); // finally we can deposit them vault.deposit(_token, _amount); } } function _newPeriod(uint64 _startTime) internal returns (Period storage) { // There should be no way for this to overflow since each period is at least one day uint64 newPeriodId = periodsLength++; Period storage period = periods[newPeriodId]; period.startTime = _startTime; // Be careful here to not overflow; if startTime + periodDuration overflows, we set endTime // to MAX_UINT64 (let's assume that's the end of time for now). uint64 endTime = _startTime + settings.periodDuration - 1; if (endTime < _startTime) { // overflowed endTime = MAX_UINT64; } period.endTime = endTime; emit NewPeriod(newPeriodId, period.startTime, period.endTime); return period; } function _executePayment(uint256 _paymentId) internal { Payment storage payment = payments[_paymentId]; require(!payment.inactive, ERROR_PAYMENT_INACTIVE); uint64 payed = 0; while (nextPaymentTime(_paymentId) <= getTimestamp64() && payed < MAX_PAYMENTS_PER_TX) { if (!_canMakePayment(payment.token, payment.amount)) { emit PaymentFailure(_paymentId); return; } // The while() predicate prevents these two from ever overflowing payment.repeats += 1; payed += 1; _makePaymentTransaction( payment.token, payment.receiver, payment.amount, _paymentId, payment.repeats, "" ); } } function _makePaymentTransaction( address _token, address _receiver, uint256 _amount, uint256 _paymentId, uint64 _paymentRepeatNumber, string _reference ) internal { require(_getRemainingBudget(_token) >= _amount, ERROR_REMAINING_BUDGET); _recordTransaction( false, _token, _receiver, _amount, _paymentId, _paymentRepeatNumber, _reference ); vault.transfer(_token, _receiver, _amount); } function _recordIncomingTransaction( address _token, address _sender, uint256 _amount, string _reference ) internal { _recordTransaction( true, // incoming transaction _token, _sender, _amount, NO_PAYMENT, // unrelated to any existing payment 0, // and no payment repeats _reference ); } function _recordTransaction( bool _incoming, address _token, address _entity, uint256 _amount, uint256 _paymentId, uint64 _paymentRepeatNumber, string _reference ) internal { uint64 periodId = _currentPeriodId(); TokenStatement storage tokenStatement = periods[periodId].tokenStatement[_token]; if (_incoming) { tokenStatement.income = tokenStatement.income.add(_amount); } else { tokenStatement.expenses = tokenStatement.expenses.add(_amount); } uint256 transactionId = transactionsNextIndex++; Transaction storage transaction = transactions[transactionId]; transaction.token = _token; transaction.entity = _entity; transaction.isIncoming = _incoming; transaction.amount = _amount; transaction.paymentId = _paymentId; transaction.paymentRepeatNumber = _paymentRepeatNumber; transaction.date = getTimestamp64(); transaction.periodId = periodId; Period storage period = periods[periodId]; if (period.firstTransactionId == NO_TRANSACTION) { period.firstTransactionId = transactionId; } emit NewTransaction(transactionId, _incoming, _entity, _amount, _reference); } function _tryTransitionAccountingPeriod(uint256 _maxTransitions) internal returns (bool success) { Period storage currentPeriod = periods[_currentPeriodId()]; uint64 timestamp = getTimestamp64(); // Transition periods if necessary while (timestamp > currentPeriod.endTime) { if (_maxTransitions == 0) { // Required number of transitions is over allowed number, return false indicating // it didn't fully transition return false; } _maxTransitions = _maxTransitions.sub(1); // If there were any transactions in period, record which was the last // In case 0 transactions occured, first and last tx id will be 0 if (currentPeriod.firstTransactionId != NO_TRANSACTION) { currentPeriod.lastTransactionId = transactionsNextIndex.sub(1); } // New period starts at end time + 1 currentPeriod = _newPeriod(currentPeriod.endTime.add(1)); } return true; } function _canMakePayment(address _token, uint256 _amount) internal view returns (bool) { return _getRemainingBudget(_token) >= _amount && vault.balance(_token) >= _amount; } function _getRemainingBudget(address _token) internal view returns (uint256) { if (!settings.hasBudget[_token]) { return MAX_UINT; } uint256 spent = periods[_currentPeriodId()].tokenStatement[_token].expenses; // A budget decrease can cause the spent amount to be greater than period budget // If so, return 0 to not allow more spending during period if (spent >= settings.budgets[_token]) { return 0; } return settings.budgets[_token].sub(spent); } function _currentPeriodId() internal view returns (uint64) { // There is no way for this to overflow if protected by an initialization check return periodsLength - 1; } // Must be view for mocking purposes function getMaxPeriodTransitions() internal view returns (uint64) { return MAX_UINT64; } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"CREATE_PAYMENTS_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_paymentId","type":"uint256"}],"name":"executePayment","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_vault","type":"address"},{"name":"_periodDuration","type":"uint64"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"removeBudget","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_token","type":"address"}],"name":"getBudget","outputs":[{"name":"budget","type":"uint256"},{"name":"hasBudget","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_paymentId","type":"uint256"},{"name":"_active","type":"bool"}],"name":"setPaymentStatus","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_paymentId","type":"uint256"}],"name":"getPayment","outputs":[{"name":"token","type":"address"},{"name":"receiver","type":"address"},{"name":"amount","type":"uint256"},{"name":"initialPaymentTime","type":"uint64"},{"name":"interval","type":"uint64"},{"name":"maxRepeats","type":"uint64"},{"name":"inactive","type":"bool"},{"name":"repeats","type":"uint64"},{"name":"createdBy","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_transactionId","type":"uint256"}],"name":"getTransaction","outputs":[{"name":"periodId","type":"uint64"},{"name":"amount","type":"uint256"},{"name":"paymentId","type":"uint256"},{"name":"paymentRepeatNumber","type":"uint64"},{"name":"token","type":"address"},{"name":"entity","type":"address"},{"name":"isIncoming","type":"bool"},{"name":"date","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"CHANGE_PERIOD_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"CHANGE_BUDGETS_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_paymentId","type":"uint256"}],"name":"receiverExecutePayment","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_periodId","type":"uint64"}],"name":"getPeriod","outputs":[{"name":"isCurrent","type":"bool"},{"name":"startTime","type":"uint64"},{"name":"endTime","type":"uint64"},{"name":"firstTransactionId","type":"uint256"},{"name":"lastTransactionId","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_periodDuration","type":"uint64"}],"name":"setPeriodDuration","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"periodsLength","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_receiver","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_initialPaymentTime","type":"uint64"},{"name":"_interval","type":"uint64"},{"name":"_maxRepeats","type":"uint64"},{"name":"_reference","type":"string"}],"name":"newPayment","outputs":[{"name":"paymentId","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_amount","type":"uint256"}],"name":"setBudget","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"recoverToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"EXECUTE_PAYMENTS_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentPeriodId","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_maxTransitions","type":"uint64"}],"name":"tryTransitionAccountingPeriod","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getPeriodDuration","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_reference","type":"string"}],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_paymentId","type":"uint256"}],"name":"nextPaymentTime","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_periodId","type":"uint64"},{"name":"_token","type":"address"}],"name":"getPeriodTokenStatement","outputs":[{"name":"expenses","type":"uint256"},{"name":"income","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paymentsNextIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_PAYMENTS_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"transactionsNextIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_token","type":"address"}],"name":"getRemainingBudget","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"vault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"periodId","type":"uint64"},{"indexed":false,"name":"periodStarts","type":"uint64"},{"indexed":false,"name":"periodEnds","type":"uint64"}],"name":"NewPeriod","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"hasBudget","type":"bool"}],"name":"SetBudget","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"paymentId","type":"uint256"},{"indexed":true,"name":"recipient","type":"address"},{"indexed":false,"name":"maxRepeats","type":"uint64"},{"indexed":false,"name":"reference","type":"string"}],"name":"NewPayment","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"transactionId","type":"uint256"},{"indexed":false,"name":"incoming","type":"bool"},{"indexed":true,"name":"entity","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"reference","type":"string"}],"name":"NewTransaction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"paymentId","type":"uint256"},{"indexed":false,"name":"inactive","type":"bool"}],"name":"ChangePaymentState","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newDuration","type":"uint64"}],"name":"ChangePeriodDuration","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"paymentId","type":"uint256"}],"name":"PaymentFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"}]
Contract Creation Code
6080604052620000176401000000006200001d810204565b6200023b565b6200003064010000000062000125810204565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a45440000000000000000602082015290156200010c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620000d0578181015183820152602001620000b6565b50505050905090810190601f168015620000fe5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506200012360001964010000000062000154810204565b565b60006200014f600080516020620054c4833981519152640100000000620049c06200023382021704565b905090565b6200016764010000000062000125810204565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a454400000000000000006020820152901562000206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252838181518152602001915080519060200190808383600083811015620000d0578181015183820152602001620000b6565b5062000230600080516020620054c483398151915282640100000000620050106200023782021704565b50565b5490565b9055565b615279806200024b6000396000f3006080604052600436106101ed5763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630803fac081146103d35780630842ace4146103fc578063162a0cf8146104235780631798de811461043d57806318f053da1461047857806319b7d7bd146104a65780632914b9bd146104ed5780632d00cad31461056f5780633280a8361461058c57806332f0a3b51461061757806333ea3dc81461062c5780635985feec146106ad5780635b14dbc8146106c25780636436f189146106d757806367047c4a146106ef578063671273f41461074b5780636abe602d1461076d5780636f0558b11461079f57806374bfb426146108015780637e7db6e11461083257806380afdea8146108605780638b3dd749146108755780639297d8601461088a578063981cc342146108b8578063988e6595146108cd5780639d4941d8146108e2578063a1658fad14610910578063a479e50814610984578063a662944114610999578063b36fec57146109bb578063bfe07da6146109d0578063cb045a9614610a01578063d2d27b4114610a19578063d4aae0c414610a6d578063de048a7b14610a82578063de4796ed14610a97578063e94ebac514610aac578063eaa7ec6814610ac1578063eca8181714610ad6578063fbfa77cf14610b04575b6101f5610b19565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a454400000000000000000000000060208201529015156102ce576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561029357818101518382015260200161027b565b50505050905090810190601f1680156102c05780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060006102eb6102dc610b42565b67ffffffffffffffff16610b48565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e0000000000602082015290915081151561038b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506103d06000346040805190810160405280601d81526020017f4574686572207472616e7366657220746f2046696e616e636520617070000000815250336001610c32565b50005b3480156103df57600080fd5b506103e8610b19565b604080519115158252519081900360200190f35b34801561040857600080fd5b506104116110dd565b60408051918252519081900360200190f35b34801561042f57600080fd5b5061043b600435611112565b005b34801561044957600080fd5b5061043b73ffffffffffffffffffffffffffffffffffffffff6004351667ffffffffffffffff60243516611438565b34801561048457600080fd5b5061043b73ffffffffffffffffffffffffffffffffffffffff6004351661172d565b3480156104b257600080fd5b506104d473ffffffffffffffffffffffffffffffffffffffff600435166119a0565b6040805192835290151560208301528051918290030190f35b3480156104f957600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526105469436949293602493928401919081908401838280828437509497506119db9650505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b34801561057b57600080fd5b5061043b6004356024351515611ae7565b34801561059857600080fd5b506105a4600435611d21565b6040805173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a01528881019790975267ffffffffffffffff9586166060890152938516608088015291841660a0870152151560c086015290911660e08401529092166101008201529051908190036101200190f35b34801561062357600080fd5b50610546611ea5565b34801561063857600080fd5b50610644600435611f43565b6040805167ffffffffffffffff998a168152602081019890985287810196909652938716606087015273ffffffffffffffffffffffffffffffffffffffff9283166080870152911660a0850152151560c084015290921660e08201529051908190036101000190f35b3480156106b957600080fd5b506104116120a4565b3480156106ce57600080fd5b506104116120d9565b3480156106e357600080fd5b5061043b60043561210e565b3480156106fb57600080fd5b5061071167ffffffffffffffff600435166124ab565b60408051951515865267ffffffffffffffff9485166020870152929093168483015260608401526080830191909152519081900360a00190f35b34801561075757600080fd5b5061043b67ffffffffffffffff600435166125cc565b34801561077957600080fd5b5061078261288b565b6040805167ffffffffffffffff9092168252519081900360200190f35b3480156107ab57600080fd5b5061041173ffffffffffffffffffffffffffffffffffffffff6004803582169160248035909116916044359167ffffffffffffffff60643581169260843582169260a4359092169160c43590810191013561289b565b34801561080d57600080fd5b5061043b73ffffffffffffffffffffffffffffffffffffffff60043516602435612e96565b34801561083e57600080fd5b506103e873ffffffffffffffffffffffffffffffffffffffff60043516613149565b34801561086c57600080fd5b5061041161315a565b34801561088157600080fd5b5061041161318a565b34801561089657600080fd5b5061043b73ffffffffffffffffffffffffffffffffffffffff600435166131b5565b3480156108c457600080fd5b506104116134ae565b3480156108d957600080fd5b506107826134e3565b3480156108ee57600080fd5b5061043b73ffffffffffffffffffffffffffffffffffffffff60043516613593565b34801561091c57600080fd5b5060408051602060046044358181013583810280860185019096528085526103e895833573ffffffffffffffffffffffffffffffffffffffff169560248035963696956064959394920192918291850190849080828437509497506138949650505050505050565b34801561099057600080fd5b50610546613a1a565b3480156109a557600080fd5b506103e867ffffffffffffffff60043516613adc565b3480156109c757600080fd5b50610782613b9d565b61043b6004803573ffffffffffffffffffffffffffffffffffffffff16906024803591604435918201910135613bad565b348015610a0d57600080fd5b50610782600435613d41565b348015610a2557600080fd5b50610a5467ffffffffffffffff6004351673ffffffffffffffffffffffffffffffffffffffff60243516613f51565b6040805192835260208301919091528051918290030190f35b348015610a7957600080fd5b5061054661405c565b348015610a8e57600080fd5b50610411614087565b348015610aa357600080fd5b506103e861408d565b348015610ab857600080fd5b506104116140a0565b348015610acd57600080fd5b506104116140d5565b348015610ae257600080fd5b5061041173ffffffffffffffffffffffffffffffffffffffff600435166140db565b348015610b1057600080fd5b5061054661418c565b600080610b2461318a565b90508015801590610b3c575080610b396141a8565b10155b91505090565b60001990565b600080600060086000610b596141ac565b67ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000209150610b856141c0565b90505b815467ffffffffffffffff6801000000000000000090910481169082161115610c2657831515610bbb5760009250610c2b565b610bcc84600163ffffffff6141d216565b600183015490945015610bf357600754610bed90600163ffffffff6141d216565b60028301555b8154610c1f90610c1a9068010000000000000000900467ffffffffffffffff16600161427d565b614337565b9150610b88565b600192505b5050919050565b60408051808201909152601b81527f46494e414e43455f4445504f5349545f414d4f554e545f5a45524f0000000000602082015260008511610cd0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50610cdd85838686614441565b8015610ee85773ffffffffffffffffffffffffffffffffffffffff851615610e4957604080517f23b872dd00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101869052905173ffffffffffffffffffffffffffffffffffffffff8716916323b872dd9160648083019260209291908290030181600087803b158015610d7a57600080fd5b505af1158015610d8e573d6000803e3d6000fd5b505050506040513d6020811015610da457600080fd5b50516040805180820190915260208082527f46494e414e43455f544b4e5f5452414e534645525f46524f4d5f52455645525490820152901515610e43576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50610ee8565b60408051808201909152601681527f46494e414e43455f56414c55455f4d49534d41544348000000000000000000006020820152348514610ee6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b505b73ffffffffffffffffffffffffffffffffffffffff85161515610f9c5760008054604080517f47e7ef240000000000000000000000000000000000000000000000000000000081526004810184905260248101889052905173ffffffffffffffffffffffffffffffffffffffff909216926347e7ef24928892604480820193929182900301818588803b158015610f7e57600080fd5b505af1158015610f92573d6000803e3d6000fd5b50505050506110d6565b60008054604080517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92831660048201526024810188905290519188169263095ea7b3926044808401936020939083900390910190829087803b15801561101957600080fd5b505af115801561102d573d6000803e3d6000fd5b505050506040513d602081101561104357600080fd5b505060008054604080517f47e7ef2400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff898116600483015260248201899052915191909216926347e7ef24926044808201939182900301818387803b1580156110bd57600080fd5b505af11580156110d1573d6000803e3d6000fd5b505050505b5050505050565b604080517f4352454154455f5041594d454e54535f524f4c450000000000000000000000008152905190819003601401902081565b604080517f455845435554455f5041594d454e54535f524f4c45000000000000000000000081528151908190036015019020600083815260046020529190912060030154611161908390614458565b61116c338383613894565b60408051808201909152600f81527f4150505f415554485f4641494c454400000000000000000000000000000000006020820152901515611209576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b508260008111801561121c575060055481105b60408051808201909152601281527f46494e414e43455f4e4f5f5041594d454e54000000000000000000000000000060208201529015156112b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060006112c76102dc610b42565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515611367576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506113706141c0565b67ffffffffffffffff1661138386613d41565b67ffffffffffffffff1611156040805190810160405280601c81526020017f46494e414e43455f455845435554455f5041594d454e545f54494d450000000081525090151561142e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506110d6856144b3565b61144061318a565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a45440000000000000000602082015290156114dc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506114e56146dd565b6114ee826147bc565b60408051808201909152601a81527f46494e414e43455f5641554c545f4e4f545f434f4e5452414354000000000000602082015290151561158b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff841617905560408051808201909152601d81527f46494e414e43455f494e49545f504552494f445f544f4f5f53484f525400000060208201526201518067ffffffffffffffff83161015611677576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506001805467ffffffffffffffff83167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009091161781556000805260046020527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ee80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790556005819055600755611728610c1a6141c0565b505050565b604080517f4348414e47455f425544474554535f524f4c45000000000000000000000000008152815190819003601301902073ffffffffffffffffffffffffffffffffffffffff83166000908152600260209081528382205460039091529281205491926117b2928592919060ff166117a75760006117aa565b60015b60ff166147f6565b6117bd338383613894565b60408051808201909152600f81527f4150505f415554485f4641494c45440000000000000000000000000000000000602082015290151561185a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060006118686102dc610b42565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515611908576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5073ffffffffffffffffffffffffffffffffffffffff841660008181526002602090815260408083208390556003825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905580518381529182019290925281517f6e768d8fe4a1460cae6d5af9382c3e9abbc41f66f2ec91fda24b12e3c2796f03929181900390910190a250505050565b73ffffffffffffffffffffffffffffffffffffffff16600090815260026020908152604080832054600390925290912054909160ff90911690565b60006119e5613a1a565b73ffffffffffffffffffffffffffffffffffffffff166304bf2a7f836040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611a69578181015183820152602001611a51565b50505050905090810190601f168015611a965780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b158015611ab557600080fd5b505af1158015611ac9573d6000803e3d6000fd5b505050506040513d6020811015611adf57600080fd5b505192915050565b604080517f4d414e4147455f5041594d454e54535f524f4c4500000000000000000000000081529051908190036014019020611b348383611b29576000611b2c565b60015b60ff16614458565b611b3f338383613894565b60408051808201909152600f81527f4150505f415554485f4641494c454400000000000000000000000000000000006020820152901515611bdc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5083600081118015611bef575060055481105b60408051808201909152601281527f46494e414e43455f4e4f5f5041594d454e5400000000000000000000000000006020820152901515611c8c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060008581526004602090815260409182902060020180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16871574010000000000000000000000000000000000000000810291909117909155825190158152915187927faca91836ee6e44bf1c422f7ee89afb243a4fb775d9fe87150ff5f8e566dc161292908290030190a25050505050565b6000806000806000806000806000808a600081118015611d42575060055481105b60408051808201909152601281527f46494e414e43455f4e4f5f5041594d454e5400000000000000000000000000006020820152901515611ddf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5050506000998a5250506004602081905260409098208054600182015460038301549a83015460029093015473ffffffffffffffffffffffffffffffffffffffff9283169c9183169b9a5067ffffffffffffffff8085169a506801000000000000000085048116995070010000000000000000000000000000000085048116985060ff7401000000000000000000000000000000000000000083041697507801000000000000000000000000000000000000000000000000909404909316945091169150565b6000611eaf61405c565b73ffffffffffffffffffffffffffffffffffffffff166332f0a3b56040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015611f1257600080fd5b505af1158015611f26573d6000803e3d6000fd5b505050506040513d6020811015611f3c57600080fd5b5051905090565b600080600080600080600080600089600081118015611f63575060075481105b60408051808201909152601681527f46494e414e43455f4e4f5f5452414e53414354494f4e000000000000000000006020820152901515612000576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50505060009889525050600660205250506040909420805460018201546004830154600284015460039094015467ffffffffffffffff700100000000000000000000000000000000830481169a959950909750808216965073ffffffffffffffffffffffffffffffffffffffff9384169550928216937401000000000000000000000000000000000000000090920460ff1692680100000000000000009091041690565b604080517f4348414e47455f504552494f445f524f4c4500000000000000000000000000008152905190819003601201902081565b604080517f4348414e47455f425544474554535f524f4c45000000000000000000000000008152905190819003601301902081565b612116610b19565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a454400000000000000000000000060208201529015156121b3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50806000811180156121c6575060055481105b60408051808201909152601281527f46494e414e43455f4e4f5f5041594d454e5400000000000000000000000000006020820152901515612263576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060006122716102dc610b42565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515612311576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5061231a6141c0565b67ffffffffffffffff1661232d84613d41565b67ffffffffffffffff1611156040805190810160405280601e81526020017f46494e414e43455f524356525f455845435f5041594d454e545f54494d4500008152509015156123d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50600083815260046020908152604091829020600101548251808401909352601883527f46494e414e43455f5041594d454e545f524543454956455200000000000000009183019190915273ffffffffffffffffffffffffffffffffffffffff1633146124a1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50611728836144b3565b60095460408051808201909152601181527f46494e414e43455f4e4f5f504552494f44000000000000000000000000000000602082015260009182918291829182918291889167ffffffffffffffff90811690831610612567576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5067ffffffffffffffff88166000818152600860205260409020925061258b6141ac565b8354600185015460029095015467ffffffffffffffff928316939093149b8183169b5068010000000000000000909104909116985092965094509092505050565b604080517f4348414e47455f504552494f445f524f4c450000000000000000000000000000815290519081900360120190206001546126189067ffffffffffffffff8085169116614458565b612623338383613894565b60408051808201909152600f81527f4150505f415554485f4641494c4544000000000000000000000000000000000060208201529015156126c0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060006126ce6102dc610b42565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e0000000000602082015290915081151561276e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060408051808201909152601c81527f46494e414e43455f5345545f504552494f445f544f4f5f53484f52540000000060208201526201518067ffffffffffffffff8616101561281a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506001805467ffffffffffffffff86167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909116811790915560408051918252517fa32389dd0d5a3bf7cc635f8c30fee3b70d06a6c547d6dbf31628378ee267bfc99181900360200190a150505050565b60095467ffffffffffffffff1681565b60008060405180807f4352454154455f5041594d454e54535f524f4c45000000000000000000000000815250601401905060405180910390206128f58b8b8b8a67ffffffffffffffff168a67ffffffffffffffff16614823565b612900338383613894565b60408051808201909152600f81527f4150505f415554485f4641494c45440000000000000000000000000000000000602082015290151561299d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060006129ab6102dc610b42565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515612a4b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060408051808201909152601f81527f46494e414e43455f4e45575f5041594d454e545f414d4f554e545f5a45524f00602082015260008c11612aea576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50612af36141c0565b67ffffffffffffffff168a67ffffffffffffffff1611158015612b2057508767ffffffffffffffff166001145b15612b6957612b648d8d8d6000808c8c8080601f01602080910402602001604051908101604052809392919081815260200183838082843750614868945050505050565b612e86565b73ffffffffffffffffffffffffffffffffffffffff8d166000908152600260205260409020548b111580612bc3575073ffffffffffffffffffffffffffffffffffffffff8d1660009081526003602052604090205460ff16155b60408051808201909152600e81527f46494e414e43455f4255444745540000000000000000000000000000000000006020820152901515612c60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060058054600181019091556040805167ffffffffffffffff8b1681526020810182815291810189905291965073ffffffffffffffffffffffffffffffffffffffff8e169187917f41e8c14bdf2b044354d788d944b364e1de0b64aeddeba755b8ef69ab68bd9083918c918c918c91606082018484808284376040519201829003965090945050505050a36004600086815260200190815260200160002093508c8460000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508b8460010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508a8460030181905550898460040160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550888460040160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550878460040160106101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550338460020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550612e5b6141c0565b67ffffffffffffffff16612e6e86613d41565b67ffffffffffffffff1611612e8657612e86856144b3565b5050505098975050505050505050565b604080517f4348414e47455f425544474554535f524f4c45000000000000000000000000008152815190819003601301902073ffffffffffffffffffffffffffffffffffffffff8416600090815260026020908152838220546003909152929020549091612f10918591859160ff166117a75760006117aa565b612f1b338383613894565b60408051808201909152600f81527f4150505f415554485f4641494c454400000000000000000000000000000000006020820152901515612fb8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506000612fc66102dc610b42565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515613066576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5073ffffffffffffffffffffffffffffffffffffffff85166000908152600260209081526040808320879055600390915290205460ff1615156130f25773ffffffffffffffffffffffffffffffffffffffff8516600090815260036020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b6040805185815260016020820152815173ffffffffffffffffffffffffffffffffffffffff8816927f6e768d8fe4a1460cae6d5af9382c3e9abbc41f66f2ec91fda24b12e3c2796f03928290030190a25050505050565b6000613153610b19565b1592915050565b60006131857fd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b6149c0565b905090565b60006131857febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e6149c0565b60006131bf610b19565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a4544000000000000000000000000602082015290151561325c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50600061326a6102dc610b42565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e0000000000602082015290915081151561330a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5073ffffffffffffffffffffffffffffffffffffffff8316156133c657604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8516916370a082319160248083019260209291908290030181600087803b15801561339557600080fd5b505af11580156133a9573d6000803e3d6000fd5b505050506040513d60208110156133bf57600080fd5b50516133c9565b30315b60408051808201909152601b81527f46494e414e43455f5245434f5645525f414d4f554e545f5a45524f000000000060208201529092506000831161346a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5061172883836040805190810160405280601081526020017f5265636f76657220746f205661756c7400000000000000000000000000000000815250306000610c32565b604080517f455845435554455f5041594d454e54535f524f4c4500000000000000000000008152905190819003601501902081565b60006134ed610b19565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a4544000000000000000000000000602082015290151561358a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506131856141ac565b60008061359f83613149565b60408051808201909152601281527f5245434f5645525f444953414c4c4f5745440000000000000000000000000000602082015290151561363c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50613645611ea5565b9150613650826147bc565b60408051808201909152601a81527f5245434f5645525f5641554c545f4e4f545f434f4e545241435400000000000060208201529015156136ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5073ffffffffffffffffffffffffffffffffffffffff831615156137545760405173ffffffffffffffffffffffffffffffffffffffff831690303180156108fc02916000818181858888f1935050505015801561374e573d6000803e3d6000fd5b50611728565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8516916370a082319160248083019260209291908290030181600087803b1580156137c257600080fd5b505af11580156137d6573d6000803e3d6000fd5b505050506040513d60208110156137ec57600080fd5b5051604080517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526024820184905291519293509085169163a9059cbb916044808201926020929091908290030181600087803b15801561386a57600080fd5b505af115801561387e573d6000803e3d6000fd5b505050506040513d60208110156110d657600080fd5b600080606060006138a3610b19565b15156138b25760009350613a10565b6138ba61405c565b925073ffffffffffffffffffffffffffffffffffffffff831615156138e25760009350613a10565b5050825160209081028085526040517ffdef910600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483019081523060248401819052604484018a90526080606485019081528951608486015289518a979489169563fdef9106958e958e948b949193909260a4909101919085019080838360005b8381101561399257818101518382015260200161397a565b50505050905090810190601f1680156139bf5780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b1580156139e157600080fd5b505af11580156139f5573d6000803e3d6000fd5b505050506040513d6020811015613a0b57600080fd5b505193505b5050509392505050565b600080613a2561405c565b604080517fbe00bbd80000000000000000000000000000000000000000000000000000000081527fd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb60048201527fddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd616024820152905173ffffffffffffffffffffffffffffffffffffffff929092169163be00bbd8916044808201926020929091908290030181600087803b158015611ab557600080fd5b6000613ae6610b19565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515613b83576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50613b978267ffffffffffffffff16610b48565b92915050565b60015467ffffffffffffffff1690565b613bb5610b19565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515613c52576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506000613c606102dc610b42565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515613d00576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506110d6858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050336001610c32565b6000613d4b615201565b60008084600081118015613d60575060055481105b60408051808201909152601281527f46494e414e43455f4e4f5f5041594d454e5400000000000000000000000000006020820152901515613dfd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50600086815260046020818152604092839020835161012081018552815473ffffffffffffffffffffffffffffffffffffffff908116825260018301548116938201939093526002820154928316948101949094527401000000000000000000000000000000000000000090910460ff161515606084015260038101546080840152015467ffffffffffffffff80821660a0840152680100000000000000008204811660c08401527001000000000000000000000000000000008204811660e08401819052780100000000000000000000000000000000000000000000000090920416610100830181905291955011613efa576000199450613f48565b613f208460c0015185610100015167ffffffffffffffff166149c890919063ffffffff16565b60a0850151909350613f429067ffffffffffffffff168463ffffffff61427d16565b91508194505b50505050919050565b60095460408051808201909152601181527f46494e414e43455f4e4f5f504552494f4400000000000000000000000000000060208201526000918291829186919067ffffffffffffffff90811690831610614008576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5050505067ffffffffffffffff92909216600090815260086020908152604080832073ffffffffffffffffffffffffffffffffffffffff949094168352600390930190522080546001909101549092909150565b60006131857f4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b6149c0565b60055481565b600060001961409a61318a565b14905090565b604080517f4d414e4147455f5041594d454e54535f524f4c450000000000000000000000008152905190819003601401902081565b60075481565b60006140e5610b19565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515614182576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50613b9782614a82565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b4390565b60095467ffffffffffffffff166000190190565b60006131856141cd614b60565b614b64565b60408051808201909152601281527f4d4154485f5355425f554e444552464c4f5700000000000000000000000000006020820152600090819084841115614275576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b505050900390565b60408051808201909152601381527f4d41544836345f4144445f4f564552464c4f570000000000000000000000000060208201526000908383019067ffffffffffffffff808616908316101561432f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b509392505050565b6009805467ffffffffffffffff808216600181810183167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000948516179094556000818152600860205260408120805487851695168517815594549094919391926000199181168701919091019190821610156143b257506000195b81547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff83811682029290921780855560408051828516815292909104831660208301528051928616927fe183df4530c4b573af76d47f020d4b86e418cef40ed4c9ce924b563e791b832c9281900390910190a2509392505050565b614452600185858560008087614c14565b50505050565b60408051600280825260608083018452926020830190803883390190505090508281600081518110151561448857fe5b6020908102909101015280518290829060019081106144a357fe5b6020908102909101015292915050565b600081815260046020908152604080832060028101548251808401909352601883527f46494e414e43455f5041594d454e545f494e414354495645000000000000000093830193909352929174010000000000000000000000000000000000000000900460ff1615614581576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50600090505b61458f6141c0565b67ffffffffffffffff166145a284613d41565b67ffffffffffffffff16111580156145c4575060148167ffffffffffffffff16105b1561172857815460038301546145f09173ffffffffffffffffffffffffffffffffffffffff1690614f4c565b151561462e576040805184815290517f5f352e4123f4620cacbb8eb0dd683705aaa3e1f9384adbbd85b665b205097f519181900360200190a1611728565b60048201805467ffffffffffffffff7801000000000000000000000000000000000000000000000000808304821660019081018316820277ffffffffffffffffffffffffffffffffffffffffffffffff9094169390931793849055855486840154600388015460408051602081019091526000815297909501966146d89673ffffffffffffffffffffffffffffffffffffffff93841696929093169491938a930490911690614868565b614587565b6146e561318a565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015614781576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506147ba61478d6141a8565b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e9063ffffffff61501016565b565b60008073ffffffffffffffffffffffffffffffffffffffff831615156147e557600091506147f0565b823b90506000811191505b50919050565b606061481a8573ffffffffffffffffffffffffffffffffffffffff16858585615014565b95945050505050565b606061485e8673ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff168686866150aa565b9695505050505050565b8361487287614a82565b60408051808201909152601881527f46494e414e43455f52454d41494e494e475f4255444745540000000000000000602082015291111561490f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506149206000878787878787614c14565b60008054604080517fbeabacc800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a811660048301528981166024830152604482018990529151919092169263beabacc8926064808201939182900301818387803b1580156149a057600080fd5b505af11580156149b4573d6000803e3d6000fd5b50505050505050505050565b5490565b5490565b60408051808201909152601381527f4d41544836345f4d554c5f4f564552464c4f5700000000000000000000000000602082015260009067ffffffffffffffff848116908416029068010000000000000000821061432f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260036020526040812054819060ff161515614abd5760001991506147f0565b60086000614ac96141ac565b67ffffffffffffffff1681526020808201929092526040908101600090812073ffffffffffffffffffffffffffffffffffffffff87168252600301835281812054600290935220549091508110614b2357600091506147f0565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260026020526040902054614b59908263ffffffff6141d216565b9392505050565b4290565b60408051808201909152601581527f55494e5436345f4e554d4245525f544f4f5f4249470000000000000000000000602082015260009067ffffffffffffffff831115614c0d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5090919050565b6000806000806000614c246141ac565b9450600860008667ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060030160008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002093508b15614cb4576001840154614caa908a63ffffffff61515c16565b6001850155614cc9565b8354614cc6908a63ffffffff61515c16565b84555b600760008154809291906001019190505592506006600084815260200190815260200160002091508a8260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550898260010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508b8260010160146101000a81548160ff021916908315150217905550888260020181905550878260030181905550868260040160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550614dd86141c0565b6004830180547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff93841602177fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff16700100000000000000000000000000000000928816928302179055600090815260086020526040902060018101549091501515614e7957600181018390555b8973ffffffffffffffffffffffffffffffffffffffff16837f5b2c6f4cb53711ae51d600df17fa68f8239b4a704f766c99642f667d1d7bd40e8e8c8a604051808415151515815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614f02578181015183820152602001614eea565b50505050905090810190601f168015614f2f5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a3505050505050505050505050565b600081614f5884614a82565b10158015614b59575060008054604080517fe3d670d700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff878116600483015291518694929093169263e3d670d792602480840193602093929083900390910190829087803b158015614fdb57600080fd5b505af1158015614fef573d6000803e3d6000fd5b505050506040513d602081101561500557600080fd5b505110159392505050565b9055565b60408051600480825260a08201909252606091602082016080803883390190505090508481600081518110151561504757fe5b60209081029091010152805184908290600190811061506257fe5b60209081029091010152805183908290600290811061507d57fe5b60209081029091010152805182908290600390811061509857fe5b60209081029091010152949350505050565b60408051600580825260c082019092526060916020820160a080388339019050509050858160008151811015156150dd57fe5b6020908102909101015280518590829060019081106150f857fe5b60209081029091010152805184908290600290811061511357fe5b60209081029091010152805183908290600390811061512e57fe5b60209081029091010152805182908290600490811061514957fe5b6020908102909101015295945050505050565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f570000000000000000000000000000006020820152600090838301908482101561432f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810191909152905600a165627a7a7230582007157d0bfabbea9a414481b35373344068dfd13166595f736bc3973b46ccbc090029ebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e
Deployed Bytecode
0x6080604052600436106101ed5763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630803fac081146103d35780630842ace4146103fc578063162a0cf8146104235780631798de811461043d57806318f053da1461047857806319b7d7bd146104a65780632914b9bd146104ed5780632d00cad31461056f5780633280a8361461058c57806332f0a3b51461061757806333ea3dc81461062c5780635985feec146106ad5780635b14dbc8146106c25780636436f189146106d757806367047c4a146106ef578063671273f41461074b5780636abe602d1461076d5780636f0558b11461079f57806374bfb426146108015780637e7db6e11461083257806380afdea8146108605780638b3dd749146108755780639297d8601461088a578063981cc342146108b8578063988e6595146108cd5780639d4941d8146108e2578063a1658fad14610910578063a479e50814610984578063a662944114610999578063b36fec57146109bb578063bfe07da6146109d0578063cb045a9614610a01578063d2d27b4114610a19578063d4aae0c414610a6d578063de048a7b14610a82578063de4796ed14610a97578063e94ebac514610aac578063eaa7ec6814610ac1578063eca8181714610ad6578063fbfa77cf14610b04575b6101f5610b19565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a454400000000000000000000000060208201529015156102ce576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561029357818101518382015260200161027b565b50505050905090810190601f1680156102c05780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060006102eb6102dc610b42565b67ffffffffffffffff16610b48565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e0000000000602082015290915081151561038b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506103d06000346040805190810160405280601d81526020017f4574686572207472616e7366657220746f2046696e616e636520617070000000815250336001610c32565b50005b3480156103df57600080fd5b506103e8610b19565b604080519115158252519081900360200190f35b34801561040857600080fd5b506104116110dd565b60408051918252519081900360200190f35b34801561042f57600080fd5b5061043b600435611112565b005b34801561044957600080fd5b5061043b73ffffffffffffffffffffffffffffffffffffffff6004351667ffffffffffffffff60243516611438565b34801561048457600080fd5b5061043b73ffffffffffffffffffffffffffffffffffffffff6004351661172d565b3480156104b257600080fd5b506104d473ffffffffffffffffffffffffffffffffffffffff600435166119a0565b6040805192835290151560208301528051918290030190f35b3480156104f957600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526105469436949293602493928401919081908401838280828437509497506119db9650505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b34801561057b57600080fd5b5061043b6004356024351515611ae7565b34801561059857600080fd5b506105a4600435611d21565b6040805173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a01528881019790975267ffffffffffffffff9586166060890152938516608088015291841660a0870152151560c086015290911660e08401529092166101008201529051908190036101200190f35b34801561062357600080fd5b50610546611ea5565b34801561063857600080fd5b50610644600435611f43565b6040805167ffffffffffffffff998a168152602081019890985287810196909652938716606087015273ffffffffffffffffffffffffffffffffffffffff9283166080870152911660a0850152151560c084015290921660e08201529051908190036101000190f35b3480156106b957600080fd5b506104116120a4565b3480156106ce57600080fd5b506104116120d9565b3480156106e357600080fd5b5061043b60043561210e565b3480156106fb57600080fd5b5061071167ffffffffffffffff600435166124ab565b60408051951515865267ffffffffffffffff9485166020870152929093168483015260608401526080830191909152519081900360a00190f35b34801561075757600080fd5b5061043b67ffffffffffffffff600435166125cc565b34801561077957600080fd5b5061078261288b565b6040805167ffffffffffffffff9092168252519081900360200190f35b3480156107ab57600080fd5b5061041173ffffffffffffffffffffffffffffffffffffffff6004803582169160248035909116916044359167ffffffffffffffff60643581169260843582169260a4359092169160c43590810191013561289b565b34801561080d57600080fd5b5061043b73ffffffffffffffffffffffffffffffffffffffff60043516602435612e96565b34801561083e57600080fd5b506103e873ffffffffffffffffffffffffffffffffffffffff60043516613149565b34801561086c57600080fd5b5061041161315a565b34801561088157600080fd5b5061041161318a565b34801561089657600080fd5b5061043b73ffffffffffffffffffffffffffffffffffffffff600435166131b5565b3480156108c457600080fd5b506104116134ae565b3480156108d957600080fd5b506107826134e3565b3480156108ee57600080fd5b5061043b73ffffffffffffffffffffffffffffffffffffffff60043516613593565b34801561091c57600080fd5b5060408051602060046044358181013583810280860185019096528085526103e895833573ffffffffffffffffffffffffffffffffffffffff169560248035963696956064959394920192918291850190849080828437509497506138949650505050505050565b34801561099057600080fd5b50610546613a1a565b3480156109a557600080fd5b506103e867ffffffffffffffff60043516613adc565b3480156109c757600080fd5b50610782613b9d565b61043b6004803573ffffffffffffffffffffffffffffffffffffffff16906024803591604435918201910135613bad565b348015610a0d57600080fd5b50610782600435613d41565b348015610a2557600080fd5b50610a5467ffffffffffffffff6004351673ffffffffffffffffffffffffffffffffffffffff60243516613f51565b6040805192835260208301919091528051918290030190f35b348015610a7957600080fd5b5061054661405c565b348015610a8e57600080fd5b50610411614087565b348015610aa357600080fd5b506103e861408d565b348015610ab857600080fd5b506104116140a0565b348015610acd57600080fd5b506104116140d5565b348015610ae257600080fd5b5061041173ffffffffffffffffffffffffffffffffffffffff600435166140db565b348015610b1057600080fd5b5061054661418c565b600080610b2461318a565b90508015801590610b3c575080610b396141a8565b10155b91505090565b60001990565b600080600060086000610b596141ac565b67ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000209150610b856141c0565b90505b815467ffffffffffffffff6801000000000000000090910481169082161115610c2657831515610bbb5760009250610c2b565b610bcc84600163ffffffff6141d216565b600183015490945015610bf357600754610bed90600163ffffffff6141d216565b60028301555b8154610c1f90610c1a9068010000000000000000900467ffffffffffffffff16600161427d565b614337565b9150610b88565b600192505b5050919050565b60408051808201909152601b81527f46494e414e43455f4445504f5349545f414d4f554e545f5a45524f0000000000602082015260008511610cd0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50610cdd85838686614441565b8015610ee85773ffffffffffffffffffffffffffffffffffffffff851615610e4957604080517f23b872dd00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101869052905173ffffffffffffffffffffffffffffffffffffffff8716916323b872dd9160648083019260209291908290030181600087803b158015610d7a57600080fd5b505af1158015610d8e573d6000803e3d6000fd5b505050506040513d6020811015610da457600080fd5b50516040805180820190915260208082527f46494e414e43455f544b4e5f5452414e534645525f46524f4d5f52455645525490820152901515610e43576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50610ee8565b60408051808201909152601681527f46494e414e43455f56414c55455f4d49534d41544348000000000000000000006020820152348514610ee6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b505b73ffffffffffffffffffffffffffffffffffffffff85161515610f9c5760008054604080517f47e7ef240000000000000000000000000000000000000000000000000000000081526004810184905260248101889052905173ffffffffffffffffffffffffffffffffffffffff909216926347e7ef24928892604480820193929182900301818588803b158015610f7e57600080fd5b505af1158015610f92573d6000803e3d6000fd5b50505050506110d6565b60008054604080517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92831660048201526024810188905290519188169263095ea7b3926044808401936020939083900390910190829087803b15801561101957600080fd5b505af115801561102d573d6000803e3d6000fd5b505050506040513d602081101561104357600080fd5b505060008054604080517f47e7ef2400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff898116600483015260248201899052915191909216926347e7ef24926044808201939182900301818387803b1580156110bd57600080fd5b505af11580156110d1573d6000803e3d6000fd5b505050505b5050505050565b604080517f4352454154455f5041594d454e54535f524f4c450000000000000000000000008152905190819003601401902081565b604080517f455845435554455f5041594d454e54535f524f4c45000000000000000000000081528151908190036015019020600083815260046020529190912060030154611161908390614458565b61116c338383613894565b60408051808201909152600f81527f4150505f415554485f4641494c454400000000000000000000000000000000006020820152901515611209576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b508260008111801561121c575060055481105b60408051808201909152601281527f46494e414e43455f4e4f5f5041594d454e54000000000000000000000000000060208201529015156112b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060006112c76102dc610b42565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515611367576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506113706141c0565b67ffffffffffffffff1661138386613d41565b67ffffffffffffffff1611156040805190810160405280601c81526020017f46494e414e43455f455845435554455f5041594d454e545f54494d450000000081525090151561142e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506110d6856144b3565b61144061318a565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a45440000000000000000602082015290156114dc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506114e56146dd565b6114ee826147bc565b60408051808201909152601a81527f46494e414e43455f5641554c545f4e4f545f434f4e5452414354000000000000602082015290151561158b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff841617905560408051808201909152601d81527f46494e414e43455f494e49545f504552494f445f544f4f5f53484f525400000060208201526201518067ffffffffffffffff83161015611677576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506001805467ffffffffffffffff83167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009091161781556000805260046020527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ee80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790556005819055600755611728610c1a6141c0565b505050565b604080517f4348414e47455f425544474554535f524f4c45000000000000000000000000008152815190819003601301902073ffffffffffffffffffffffffffffffffffffffff83166000908152600260209081528382205460039091529281205491926117b2928592919060ff166117a75760006117aa565b60015b60ff166147f6565b6117bd338383613894565b60408051808201909152600f81527f4150505f415554485f4641494c45440000000000000000000000000000000000602082015290151561185a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060006118686102dc610b42565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515611908576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5073ffffffffffffffffffffffffffffffffffffffff841660008181526002602090815260408083208390556003825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905580518381529182019290925281517f6e768d8fe4a1460cae6d5af9382c3e9abbc41f66f2ec91fda24b12e3c2796f03929181900390910190a250505050565b73ffffffffffffffffffffffffffffffffffffffff16600090815260026020908152604080832054600390925290912054909160ff90911690565b60006119e5613a1a565b73ffffffffffffffffffffffffffffffffffffffff166304bf2a7f836040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611a69578181015183820152602001611a51565b50505050905090810190601f168015611a965780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b158015611ab557600080fd5b505af1158015611ac9573d6000803e3d6000fd5b505050506040513d6020811015611adf57600080fd5b505192915050565b604080517f4d414e4147455f5041594d454e54535f524f4c4500000000000000000000000081529051908190036014019020611b348383611b29576000611b2c565b60015b60ff16614458565b611b3f338383613894565b60408051808201909152600f81527f4150505f415554485f4641494c454400000000000000000000000000000000006020820152901515611bdc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5083600081118015611bef575060055481105b60408051808201909152601281527f46494e414e43455f4e4f5f5041594d454e5400000000000000000000000000006020820152901515611c8c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060008581526004602090815260409182902060020180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16871574010000000000000000000000000000000000000000810291909117909155825190158152915187927faca91836ee6e44bf1c422f7ee89afb243a4fb775d9fe87150ff5f8e566dc161292908290030190a25050505050565b6000806000806000806000806000808a600081118015611d42575060055481105b60408051808201909152601281527f46494e414e43455f4e4f5f5041594d454e5400000000000000000000000000006020820152901515611ddf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5050506000998a5250506004602081905260409098208054600182015460038301549a83015460029093015473ffffffffffffffffffffffffffffffffffffffff9283169c9183169b9a5067ffffffffffffffff8085169a506801000000000000000085048116995070010000000000000000000000000000000085048116985060ff7401000000000000000000000000000000000000000083041697507801000000000000000000000000000000000000000000000000909404909316945091169150565b6000611eaf61405c565b73ffffffffffffffffffffffffffffffffffffffff166332f0a3b56040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015611f1257600080fd5b505af1158015611f26573d6000803e3d6000fd5b505050506040513d6020811015611f3c57600080fd5b5051905090565b600080600080600080600080600089600081118015611f63575060075481105b60408051808201909152601681527f46494e414e43455f4e4f5f5452414e53414354494f4e000000000000000000006020820152901515612000576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50505060009889525050600660205250506040909420805460018201546004830154600284015460039094015467ffffffffffffffff700100000000000000000000000000000000830481169a959950909750808216965073ffffffffffffffffffffffffffffffffffffffff9384169550928216937401000000000000000000000000000000000000000090920460ff1692680100000000000000009091041690565b604080517f4348414e47455f504552494f445f524f4c4500000000000000000000000000008152905190819003601201902081565b604080517f4348414e47455f425544474554535f524f4c45000000000000000000000000008152905190819003601301902081565b612116610b19565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a454400000000000000000000000060208201529015156121b3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50806000811180156121c6575060055481105b60408051808201909152601281527f46494e414e43455f4e4f5f5041594d454e5400000000000000000000000000006020820152901515612263576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060006122716102dc610b42565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515612311576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5061231a6141c0565b67ffffffffffffffff1661232d84613d41565b67ffffffffffffffff1611156040805190810160405280601e81526020017f46494e414e43455f524356525f455845435f5041594d454e545f54494d4500008152509015156123d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50600083815260046020908152604091829020600101548251808401909352601883527f46494e414e43455f5041594d454e545f524543454956455200000000000000009183019190915273ffffffffffffffffffffffffffffffffffffffff1633146124a1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50611728836144b3565b60095460408051808201909152601181527f46494e414e43455f4e4f5f504552494f44000000000000000000000000000000602082015260009182918291829182918291889167ffffffffffffffff90811690831610612567576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5067ffffffffffffffff88166000818152600860205260409020925061258b6141ac565b8354600185015460029095015467ffffffffffffffff928316939093149b8183169b5068010000000000000000909104909116985092965094509092505050565b604080517f4348414e47455f504552494f445f524f4c450000000000000000000000000000815290519081900360120190206001546126189067ffffffffffffffff8085169116614458565b612623338383613894565b60408051808201909152600f81527f4150505f415554485f4641494c4544000000000000000000000000000000000060208201529015156126c0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060006126ce6102dc610b42565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e0000000000602082015290915081151561276e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060408051808201909152601c81527f46494e414e43455f5345545f504552494f445f544f4f5f53484f52540000000060208201526201518067ffffffffffffffff8616101561281a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506001805467ffffffffffffffff86167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909116811790915560408051918252517fa32389dd0d5a3bf7cc635f8c30fee3b70d06a6c547d6dbf31628378ee267bfc99181900360200190a150505050565b60095467ffffffffffffffff1681565b60008060405180807f4352454154455f5041594d454e54535f524f4c45000000000000000000000000815250601401905060405180910390206128f58b8b8b8a67ffffffffffffffff168a67ffffffffffffffff16614823565b612900338383613894565b60408051808201909152600f81527f4150505f415554485f4641494c45440000000000000000000000000000000000602082015290151561299d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060006129ab6102dc610b42565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515612a4b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060408051808201909152601f81527f46494e414e43455f4e45575f5041594d454e545f414d4f554e545f5a45524f00602082015260008c11612aea576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50612af36141c0565b67ffffffffffffffff168a67ffffffffffffffff1611158015612b2057508767ffffffffffffffff166001145b15612b6957612b648d8d8d6000808c8c8080601f01602080910402602001604051908101604052809392919081815260200183838082843750614868945050505050565b612e86565b73ffffffffffffffffffffffffffffffffffffffff8d166000908152600260205260409020548b111580612bc3575073ffffffffffffffffffffffffffffffffffffffff8d1660009081526003602052604090205460ff16155b60408051808201909152600e81527f46494e414e43455f4255444745540000000000000000000000000000000000006020820152901515612c60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5060058054600181019091556040805167ffffffffffffffff8b1681526020810182815291810189905291965073ffffffffffffffffffffffffffffffffffffffff8e169187917f41e8c14bdf2b044354d788d944b364e1de0b64aeddeba755b8ef69ab68bd9083918c918c918c91606082018484808284376040519201829003965090945050505050a36004600086815260200190815260200160002093508c8460000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508b8460010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508a8460030181905550898460040160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550888460040160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550878460040160106101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550338460020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550612e5b6141c0565b67ffffffffffffffff16612e6e86613d41565b67ffffffffffffffff1611612e8657612e86856144b3565b5050505098975050505050505050565b604080517f4348414e47455f425544474554535f524f4c45000000000000000000000000008152815190819003601301902073ffffffffffffffffffffffffffffffffffffffff8416600090815260026020908152838220546003909152929020549091612f10918591859160ff166117a75760006117aa565b612f1b338383613894565b60408051808201909152600f81527f4150505f415554485f4641494c454400000000000000000000000000000000006020820152901515612fb8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506000612fc66102dc610b42565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515613066576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5073ffffffffffffffffffffffffffffffffffffffff85166000908152600260209081526040808320879055600390915290205460ff1615156130f25773ffffffffffffffffffffffffffffffffffffffff8516600090815260036020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b6040805185815260016020820152815173ffffffffffffffffffffffffffffffffffffffff8816927f6e768d8fe4a1460cae6d5af9382c3e9abbc41f66f2ec91fda24b12e3c2796f03928290030190a25050505050565b6000613153610b19565b1592915050565b60006131857fd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b6149c0565b905090565b60006131857febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e6149c0565b60006131bf610b19565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a4544000000000000000000000000602082015290151561325c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50600061326a6102dc610b42565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e0000000000602082015290915081151561330a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5073ffffffffffffffffffffffffffffffffffffffff8316156133c657604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8516916370a082319160248083019260209291908290030181600087803b15801561339557600080fd5b505af11580156133a9573d6000803e3d6000fd5b505050506040513d60208110156133bf57600080fd5b50516133c9565b30315b60408051808201909152601b81527f46494e414e43455f5245434f5645525f414d4f554e545f5a45524f000000000060208201529092506000831161346a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5061172883836040805190810160405280601081526020017f5265636f76657220746f205661756c7400000000000000000000000000000000815250306000610c32565b604080517f455845435554455f5041594d454e54535f524f4c4500000000000000000000008152905190819003601501902081565b60006134ed610b19565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a4544000000000000000000000000602082015290151561358a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506131856141ac565b60008061359f83613149565b60408051808201909152601281527f5245434f5645525f444953414c4c4f5745440000000000000000000000000000602082015290151561363c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50613645611ea5565b9150613650826147bc565b60408051808201909152601a81527f5245434f5645525f5641554c545f4e4f545f434f4e545241435400000000000060208201529015156136ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5073ffffffffffffffffffffffffffffffffffffffff831615156137545760405173ffffffffffffffffffffffffffffffffffffffff831690303180156108fc02916000818181858888f1935050505015801561374e573d6000803e3d6000fd5b50611728565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8516916370a082319160248083019260209291908290030181600087803b1580156137c257600080fd5b505af11580156137d6573d6000803e3d6000fd5b505050506040513d60208110156137ec57600080fd5b5051604080517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526024820184905291519293509085169163a9059cbb916044808201926020929091908290030181600087803b15801561386a57600080fd5b505af115801561387e573d6000803e3d6000fd5b505050506040513d60208110156110d657600080fd5b600080606060006138a3610b19565b15156138b25760009350613a10565b6138ba61405c565b925073ffffffffffffffffffffffffffffffffffffffff831615156138e25760009350613a10565b5050825160209081028085526040517ffdef910600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483019081523060248401819052604484018a90526080606485019081528951608486015289518a979489169563fdef9106958e958e948b949193909260a4909101919085019080838360005b8381101561399257818101518382015260200161397a565b50505050905090810190601f1680156139bf5780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b1580156139e157600080fd5b505af11580156139f5573d6000803e3d6000fd5b505050506040513d6020811015613a0b57600080fd5b505193505b5050509392505050565b600080613a2561405c565b604080517fbe00bbd80000000000000000000000000000000000000000000000000000000081527fd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb60048201527fddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd616024820152905173ffffffffffffffffffffffffffffffffffffffff929092169163be00bbd8916044808201926020929091908290030181600087803b158015611ab557600080fd5b6000613ae6610b19565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515613b83576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50613b978267ffffffffffffffff16610b48565b92915050565b60015467ffffffffffffffff1690565b613bb5610b19565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515613c52576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506000613c606102dc610b42565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515613d00576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506110d6858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050336001610c32565b6000613d4b615201565b60008084600081118015613d60575060055481105b60408051808201909152601281527f46494e414e43455f4e4f5f5041594d454e5400000000000000000000000000006020820152901515613dfd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50600086815260046020818152604092839020835161012081018552815473ffffffffffffffffffffffffffffffffffffffff908116825260018301548116938201939093526002820154928316948101949094527401000000000000000000000000000000000000000090910460ff161515606084015260038101546080840152015467ffffffffffffffff80821660a0840152680100000000000000008204811660c08401527001000000000000000000000000000000008204811660e08401819052780100000000000000000000000000000000000000000000000090920416610100830181905291955011613efa576000199450613f48565b613f208460c0015185610100015167ffffffffffffffff166149c890919063ffffffff16565b60a0850151909350613f429067ffffffffffffffff168463ffffffff61427d16565b91508194505b50505050919050565b60095460408051808201909152601181527f46494e414e43455f4e4f5f504552494f4400000000000000000000000000000060208201526000918291829186919067ffffffffffffffff90811690831610614008576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5050505067ffffffffffffffff92909216600090815260086020908152604080832073ffffffffffffffffffffffffffffffffffffffff949094168352600390930190522080546001909101549092909150565b60006131857f4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b6149c0565b60055481565b600060001961409a61318a565b14905090565b604080517f4d414e4147455f5041594d454e54535f524f4c450000000000000000000000008152905190819003601401902081565b60075481565b60006140e5610b19565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515614182576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50613b9782614a82565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b4390565b60095467ffffffffffffffff166000190190565b60006131856141cd614b60565b614b64565b60408051808201909152601281527f4d4154485f5355425f554e444552464c4f5700000000000000000000000000006020820152600090819084841115614275576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b505050900390565b60408051808201909152601381527f4d41544836345f4144445f4f564552464c4f570000000000000000000000000060208201526000908383019067ffffffffffffffff808616908316101561432f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b509392505050565b6009805467ffffffffffffffff808216600181810183167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000948516179094556000818152600860205260408120805487851695168517815594549094919391926000199181168701919091019190821610156143b257506000195b81547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff83811682029290921780855560408051828516815292909104831660208301528051928616927fe183df4530c4b573af76d47f020d4b86e418cef40ed4c9ce924b563e791b832c9281900390910190a2509392505050565b614452600185858560008087614c14565b50505050565b60408051600280825260608083018452926020830190803883390190505090508281600081518110151561448857fe5b6020908102909101015280518290829060019081106144a357fe5b6020908102909101015292915050565b600081815260046020908152604080832060028101548251808401909352601883527f46494e414e43455f5041594d454e545f494e414354495645000000000000000093830193909352929174010000000000000000000000000000000000000000900460ff1615614581576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b50600090505b61458f6141c0565b67ffffffffffffffff166145a284613d41565b67ffffffffffffffff16111580156145c4575060148167ffffffffffffffff16105b1561172857815460038301546145f09173ffffffffffffffffffffffffffffffffffffffff1690614f4c565b151561462e576040805184815290517f5f352e4123f4620cacbb8eb0dd683705aaa3e1f9384adbbd85b665b205097f519181900360200190a1611728565b60048201805467ffffffffffffffff7801000000000000000000000000000000000000000000000000808304821660019081018316820277ffffffffffffffffffffffffffffffffffffffffffffffff9094169390931793849055855486840154600388015460408051602081019091526000815297909501966146d89673ffffffffffffffffffffffffffffffffffffffff93841696929093169491938a930490911690614868565b614587565b6146e561318a565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015614781576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506147ba61478d6141a8565b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e9063ffffffff61501016565b565b60008073ffffffffffffffffffffffffffffffffffffffff831615156147e557600091506147f0565b823b90506000811191505b50919050565b606061481a8573ffffffffffffffffffffffffffffffffffffffff16858585615014565b95945050505050565b606061485e8673ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff168686866150aa565b9695505050505050565b8361487287614a82565b60408051808201909152601881527f46494e414e43455f52454d41494e494e475f4255444745540000000000000000602082015291111561490f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b506149206000878787878787614c14565b60008054604080517fbeabacc800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a811660048301528981166024830152604482018990529151919092169263beabacc8926064808201939182900301818387803b1580156149a057600080fd5b505af11580156149b4573d6000803e3d6000fd5b50505050505050505050565b5490565b5490565b60408051808201909152601381527f4d41544836345f4d554c5f4f564552464c4f5700000000000000000000000000602082015260009067ffffffffffffffff848116908416029068010000000000000000821061432f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260036020526040812054819060ff161515614abd5760001991506147f0565b60086000614ac96141ac565b67ffffffffffffffff1681526020808201929092526040908101600090812073ffffffffffffffffffffffffffffffffffffffff87168252600301835281812054600290935220549091508110614b2357600091506147f0565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260026020526040902054614b59908263ffffffff6141d216565b9392505050565b4290565b60408051808201909152601581527f55494e5436345f4e554d4245525f544f4f5f4249470000000000000000000000602082015260009067ffffffffffffffff831115614c0d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b5090919050565b6000806000806000614c246141ac565b9450600860008667ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060030160008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002093508b15614cb4576001840154614caa908a63ffffffff61515c16565b6001850155614cc9565b8354614cc6908a63ffffffff61515c16565b84555b600760008154809291906001019190505592506006600084815260200190815260200160002091508a8260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550898260010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508b8260010160146101000a81548160ff021916908315150217905550888260020181905550878260030181905550868260040160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550614dd86141c0565b6004830180547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff93841602177fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff16700100000000000000000000000000000000928816928302179055600090815260086020526040902060018101549091501515614e7957600181018390555b8973ffffffffffffffffffffffffffffffffffffffff16837f5b2c6f4cb53711ae51d600df17fa68f8239b4a704f766c99642f667d1d7bd40e8e8c8a604051808415151515815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614f02578181015183820152602001614eea565b50505050905090810190601f168015614f2f5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a3505050505050505050505050565b600081614f5884614a82565b10158015614b59575060008054604080517fe3d670d700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff878116600483015291518694929093169263e3d670d792602480840193602093929083900390910190829087803b158015614fdb57600080fd5b505af1158015614fef573d6000803e3d6000fd5b505050506040513d602081101561500557600080fd5b505110159392505050565b9055565b60408051600480825260a08201909252606091602082016080803883390190505090508481600081518110151561504757fe5b60209081029091010152805184908290600190811061506257fe5b60209081029091010152805183908290600290811061507d57fe5b60209081029091010152805182908290600390811061509857fe5b60209081029091010152949350505050565b60408051600580825260c082019092526060916020820160a080388339019050509050858160008151811015156150dd57fe5b6020908102909101015280518590829060019081106150f857fe5b60209081029091010152805184908290600290811061511357fe5b60209081029091010152805183908290600390811061512e57fe5b60209081029091010152805182908290600490811061514957fe5b6020908102909101015295945050505050565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f570000000000000000000000000000006020820152600090838301908482101561432f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101561029357818101518382015260200161027b565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810191909152905600a165627a7a7230582007157d0bfabbea9a414481b35373344068dfd13166595f736bc3973b46ccbc090029
Swarm Source
bzzr://07157d0bfabbea9a414481b35373344068dfd13166595f736bc3973b46ccbc09
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.