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 | 7586184 | 2046 days ago | IN | 0 ETH | 0.06119812 |
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 2019-04-17 */ // 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 { event RecoverToVault(address indexed vault, address indexed token, uint256 amount); 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; interface IKernelEvents { event SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app); } // This should be an interface, but interfaces can't inherit yet :( contract IKernel is IKernelEvents, IVaultRecoverable { 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/acl/ACLSyntaxSugar.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; contract ACLSyntaxSugar { function arr() internal pure returns (uint256[]) { return new uint256[](0); } 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/common/Uint256Helpers.sol pragma solidity ^0.4.24; 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/common/ConversionHelpers.sol pragma solidity ^0.4.24; library ConversionHelpers { string private constant ERROR_IMPROPER_LENGTH = "CONVERSION_IMPROPER_LENGTH"; function dangerouslyCastUintArrayToBytes(uint256[] memory _input) internal pure returns (bytes memory output) { // 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 the input and a new length. The input becomes invalid from this point forward. uint256 byteLength = _input.length * 32; assembly { output := _input mstore(output, byteLength) } } function dangerouslyCastBytesToUintArray(bytes memory _input) internal pure returns (uint256[] memory output) { // Force cast the bytes array into a uint256[], by overwriting its length // Note that the uint256[] doesn't need to be initialized as we immediately overwrite it // with the input and a new length. The input becomes invalid from this point forward. uint256 intsLength = _input.length / 32; require(_input.length == intsLength * 32, ERROR_IMPROPER_LENGTH); assembly { output := _input mstore(output, intsLength) } } } // File: @aragon/os/contracts/common/ReentrancyGuard.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; contract ReentrancyGuard { using UnstructuredStorage for bytes32; /* Hardcoded constants to save gas bytes32 internal constant REENTRANCY_MUTEX_POSITION = keccak256("aragonOS.reentrancyGuard.mutex"); */ bytes32 private constant REENTRANCY_MUTEX_POSITION = 0xe855346402235fdd185c890e68d2c4ecad599b88587635ee285bce2fda58dacb; string private constant ERROR_REENTRANT = "REENTRANCY_REENTRANT_CALL"; modifier nonReentrant() { // Ensure mutex is unlocked require(!REENTRANCY_MUTEX_POSITION.getStorageBool(), ERROR_REENTRANT); // Lock mutex before function call REENTRANCY_MUTEX_POSITION.setStorageBool(true); // Perform function call _; // Unlock mutex after function call REENTRANCY_MUTEX_POSITION.setStorageBool(false); } } // 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/SafeERC20.sol // Inspired by AdEx (https://github.com/AdExNetwork/adex-protocol-eth/blob/b9df617829661a7518ee10f4cb6c4108659dd6d5/contracts/libs/SafeERC20.sol) // and 0x (https://github.com/0xProject/0x-monorepo/blob/737d1dc54d72872e24abce5a1dbe1b66d35fa21a/contracts/protocol/contracts/protocol/AssetProxy/ERC20Proxy.sol#L143) pragma solidity ^0.4.24; library SafeERC20 { // Before 0.5, solidity has a mismatch between `address.transfer()` and `token.transfer()`: // https://github.com/ethereum/solidity/issues/3544 bytes4 private constant TRANSFER_SELECTOR = 0xa9059cbb; string private constant ERROR_TOKEN_BALANCE_REVERTED = "SAFE_ERC_20_BALANCE_REVERTED"; string private constant ERROR_TOKEN_ALLOWANCE_REVERTED = "SAFE_ERC_20_ALLOWANCE_REVERTED"; function invokeAndCheckSuccess(address _addr, bytes memory _calldata) private returns (bool) { bool ret; assembly { let ptr := mload(0x40) // free memory pointer let success := call( gas, // forward all gas _addr, // address 0, // no value add(_calldata, 0x20), // calldata start mload(_calldata), // calldata length ptr, // write output over free memory 0x20 // uint256 return ) if gt(success, 0) { // Check number of bytes returned from last function call switch returndatasize // No bytes returned: assume success case 0 { ret := 1 } // 32 bytes returned: check if non-zero case 0x20 { // Only return success if returned data was true // Already have output in ptr ret := eq(mload(ptr), 1) } // Not sure what was returned: don't mark as success default { } } } return ret; } function staticInvoke(address _addr, bytes memory _calldata) private view returns (bool, uint256) { bool success; uint256 ret; assembly { let ptr := mload(0x40) // free memory pointer success := staticcall( gas, // forward all gas _addr, // address add(_calldata, 0x20), // calldata start mload(_calldata), // calldata length ptr, // write output over free memory 0x20 // uint256 return ) if gt(success, 0) { ret := mload(ptr) } } return (success, ret); } /** * @dev Same as a standards-compliant ERC20.transfer() that never reverts (returns false). * Note that this makes an external call to the token. */ function safeTransfer(ERC20 _token, address _to, uint256 _amount) internal returns (bool) { bytes memory transferCallData = abi.encodeWithSelector( TRANSFER_SELECTOR, _to, _amount ); return invokeAndCheckSuccess(_token, transferCallData); } /** * @dev Same as a standards-compliant ERC20.transferFrom() that never reverts (returns false). * Note that this makes an external call to the token. */ function safeTransferFrom(ERC20 _token, address _from, address _to, uint256 _amount) internal returns (bool) { bytes memory transferFromCallData = abi.encodeWithSelector( _token.transferFrom.selector, _from, _to, _amount ); return invokeAndCheckSuccess(_token, transferFromCallData); } /** * @dev Same as a standards-compliant ERC20.approve() that never reverts (returns false). * Note that this makes an external call to the token. */ function safeApprove(ERC20 _token, address _spender, uint256 _amount) internal returns (bool) { bytes memory approveCallData = abi.encodeWithSelector( _token.approve.selector, _spender, _amount ); return invokeAndCheckSuccess(_token, approveCallData); } /** * @dev Static call into ERC20.balanceOf(). * Reverts if the call fails for some reason (should never fail). */ function staticBalanceOf(ERC20 _token, address _owner) internal view returns (uint256) { bytes memory balanceOfCallData = abi.encodeWithSelector( _token.balanceOf.selector, _owner ); (bool success, uint256 tokenBalance) = staticInvoke(_token, balanceOfCallData); require(success, ERROR_TOKEN_BALANCE_REVERTED); return tokenBalance; } /** * @dev Static call into ERC20.allowance(). * Reverts if the call fails for some reason (should never fail). */ function staticAllowance(ERC20 _token, address _owner, address _spender) internal view returns (uint256) { bytes memory allowanceCallData = abi.encodeWithSelector( _token.allowance.selector, _owner, _spender ); (bool success, uint256 allowance) = staticInvoke(_token, allowanceCallData); require(success, ERROR_TOKEN_ALLOWANCE_REVERTED); return allowance; } } // File: @aragon/os/contracts/common/VaultRecoverable.sol /* * SPDX-License-Identitifer: MIT */ pragma solidity ^0.4.24; contract VaultRecoverable is IVaultRecoverable, EtherTokenConstant, IsContract { using SafeERC20 for ERC20; string private constant ERROR_DISALLOWED = "RECOVER_DISALLOWED"; string private constant ERROR_VAULT_NOT_CONTRACT = "RECOVER_VAULT_NOT_CONTRACT"; string private constant ERROR_TOKEN_TRANSFER_FAILED = "RECOVER_TOKEN_TRANSFER_FAILED"; /** * @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); uint256 balance; if (_token == ETH) { balance = address(this).balance; vault.transfer(balance); } else { ERC20 token = ERC20(_token); balance = token.staticBalanceOf(this); require(token.safeTransfer(vault, balance), ERROR_TOKEN_TRANSFER_FAILED); } emit RecoverToVault(vault, _token, balance); } /** * @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_PROTECTED_STATE_MODIFIED = "EVMRUN_PROTECTED_STATE_MODIFIED"; /* This is manually crafted in assembly string private constant ERROR_EXECUTOR_INVALID_RETURN = "EVMRUN_EXECUTOR_INVALID_RETURN"; */ 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) { 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); bytes memory output; assembly { let success := delegatecall( gas, // forward all gas executor, // address add(data, 0x20), // calldata start mload(data), // calldata length 0, // don't write output (we'll handle this ourselves) 0 // don't write output ) output := mload(0x40) // free mem ptr get switch success case 0 { // If the call errored, forward its full error data returndatacopy(output, 0, returndatasize) revert(output, returndatasize) } default { switch gt(returndatasize, 0x3f) case 0 { // Need at least 0x40 bytes returned for properly ABI-encoded bytes values, // revert with "EVMRUN_EXECUTOR_INVALID_RETURN" // See remix: doing a `revert("EVMRUN_EXECUTOR_INVALID_RETURN")` always results in // this memory layout mstore(output, 0x08c379a000000000000000000000000000000000000000000000000000000000) // error identifier mstore(add(output, 0x04), 0x0000000000000000000000000000000000000000000000000000000000000020) // starting offset mstore(add(output, 0x24), 0x000000000000000000000000000000000000000000000000000000000000001e) // reason length mstore(add(output, 0x44), 0x45564d52554e5f4558454355544f525f494e56414c49445f52455455524e0000) // reason revert(output, 100) // 100 = 4 + 3 * 32 (error identifier + 3 words for the ABI encoded error) } default { // Copy result // // Needs to perform an ABI decode for the expected `bytes` return type of // `executor.execScript()` as solidity will automatically ABI encode the returned bytes as: // [ position of the first dynamic length return value = 0x20 (32 bytes) ] // [ output length (32 bytes) ] // [ output content (N bytes) ] // // Perform the ABI decode by ignoring the first 32 bytes of the return data let copysize := sub(returndatasize, 0x20) returndatacopy(output, 0x20, copysize) mstore(0x40, add(output, copysize)) // free mem ptr set } } } emit ScriptResult(address(executor), _script, _input, output); return output; } 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/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. // ReentrancyGuard, EVMScriptRunner, and ACLSyntaxSugar 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, ReentrancyGuard, 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; } return linkedKernel.hasPermission( _sender, address(this), _role, ConversionHelpers.dangerouslyCastUintArrayToBytes(_params) ); } /** * @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 pragma solidity 0.4.24; 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 pragma solidity 0.4.24; contract Vault is EtherTokenConstant, AragonApp, DepositableStorage { using SafeERC20 for ERC20; 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 VaultTransfer(address indexed token, address indexed to, uint256 amount); event VaultDeposit(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).safeTransfer(_to, _value), ERROR_TOKEN_TRANSFER_REVERTED); } emit VaultTransfer(_token, _to, _value); } function balance(address _token) public view returns (uint256) { if (_token == ETH) { return address(this).balance; } else { return ERC20(_token).staticBalanceOf(address(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).safeTransferFrom(msg.sender, address(this), _value), ERROR_TOKEN_TRANSFER_FROM_REVERTED ); } emit VaultDeposit(_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; using SafeERC20 for ERC20; 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_SCHEDULED_PAYMENT = 0; uint256 internal constant NO_TRANSACTION = 0; uint256 internal constant MAX_SCHEDULED_PAYMENTS_PER_TX = 20; uint256 internal constant MAX_UINT256 = uint256(-1); uint64 internal constant MAX_UINT64 = uint64(-1); uint64 internal constant MINIMUM_PERIOD = uint64(1 days); string private constant ERROR_COMPLETE_TRANSITION = "FINANCE_COMPLETE_TRANSITION"; string private constant ERROR_NO_SCHEDULED_PAYMENT = "FINANCE_NO_SCHEDULED_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_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_NEW_PAYMENT_INTERVAL_ZERO = "FINANCE_NEW_PAYMENT_INTRVL_ZERO"; string private constant ERROR_NEW_PAYMENT_EXECS_ZERO = "FINANCE_NEW_PAYMENT_EXECS_ZERO"; string private constant ERROR_NEW_PAYMENT_IMMEDIATE = "FINANCE_NEW_PAYMENT_IMMEDIATE"; 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_ETH_VALUE_MISMATCH = "FINANCE_ETH_VALUE_MISMATCH"; string private constant ERROR_BUDGET = "FINANCE_BUDGET"; string private constant ERROR_EXECUTE_PAYMENT_NUM = "FINANCE_EXECUTE_PAYMENT_NUM"; string private constant ERROR_EXECUTE_PAYMENT_TIME = "FINANCE_EXECUTE_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_TOKEN_APPROVE_FAILED = "FINANCE_TKN_APPROVE_FAILED"; string private constant ERROR_PAYMENT_INACTIVE = "FINANCE_PAYMENT_INACTIVE"; string private constant ERROR_REMAINING_BUDGET = "FINANCE_REMAINING_BUDGET"; // Order optimized for storage struct ScheduledPayment { address token; address receiver; address createdBy; bool inactive; uint256 amount; uint64 initialPaymentTime; uint64 interval; uint64 maxExecutions; uint64 executions; } // Order optimized for storage struct Transaction { address token; address entity; bool isIncoming; uint256 amount; uint256 paymentId; uint64 paymentExecutionNumber; 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 => ScheduledPayment) internal scheduledPayments; // Payments start at index 1, to allow us to use scheduledPayments[0] for transactions that are not // linked to a scheduled 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 maxExecutions, string reference); event NewTransaction(uint256 indexed transactionId, bool incoming, address indexed entity, uint256 amount, string reference); event ChangePaymentState(uint256 indexed paymentId, bool active); 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 scheduledPaymentExists(uint256 _paymentId) { require(_paymentId > 0 && _paymentId < paymentsNextIndex, ERROR_NO_SCHEDULED_PAYMENT); _; } modifier transactionExists(uint256 _transactionId) { require(_transactionId > 0 && _transactionId < transactionsNextIndex, ERROR_NO_TRANSACTION); _; } modifier periodExists(uint64 _periodId) { require(_periodId < periodsLength, ERROR_NO_PERIOD); _; } /** * @notice Deposit ETH to the Vault, to avoid locking them in this Finance app forever * @dev Send ETH to Vault. Send all the available balance. */ function () external payable isInitialized transitionsPeriod { require(msg.value > 0, ERROR_DEPOSIT_AMOUNT_ZERO); _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 >= MINIMUM_PERIOD, ERROR_SET_PERIOD_TOO_SHORT); settings.periodDuration = _periodDuration; // Reserve the first scheduled payment index as an unused index for transactions not linked // to a scheduled payment scheduledPayments[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()); } /** * @notice Deposit `@tokenAmount(_token, _amount)` * @dev Deposit for approved ERC20 tokens or ETH * @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 { require(_amount > 0, ERROR_DEPOSIT_AMOUNT_ZERO); if (_token == ETH) { // Ensure that the ETH sent with the transaction equals the amount in the deposit require(msg.value == _amount, ERROR_ETH_VALUE_MISMATCH); } _deposit( _token, _amount, _reference, msg.sender, true ); } /** * @notice Create a new payment of `@tokenAmount(_token, _amount)` to `_receiver` for '`_reference`' * @dev Note that this function is protected by the `CREATE_PAYMENTS_ROLE` but uses `MAX_UINT256` * as its interval auth parameter (as a sentinel value for "never repeating"). * While this protects against most cases (you typically want to set a baseline requirement * for interval time), it does mean users will have to explicitly check for this case when * granting a permission that includes a upperbound requirement on the interval time. * @param _token Address of token for payment * @param _receiver Address that will receive payment * @param _amount Tokens that are paid every time the payment is due * @param _reference String detailing payment reason */ function newImmediatePayment(address _token, address _receiver, uint256 _amount, string _reference) external // Use MAX_UINT256 as the interval parameter, as this payment will never repeat // Payment time parameter is left as the last param as it was added later authP(CREATE_PAYMENTS_ROLE, _arr(_token, _receiver, _amount, MAX_UINT256, uint256(1), getTimestamp())) transitionsPeriod { require(_amount > 0, ERROR_NEW_PAYMENT_AMOUNT_ZERO); _makePaymentTransaction( _token, _receiver, _amount, NO_SCHEDULED_PAYMENT, // unrelated to any payment id; it isn't created 0, // also unrelated to any payment executions _reference ); } /** * @notice Create a new payment of `@tokenAmount(_token, _amount)` to `_receiver` for `_reference`, executing `_maxExecutions` times at intervals of `@transformTime(_interval)` * @dev See `newImmediatePayment()` for limitations on how the interval auth parameter can be used * @param _token Address of token for payment * @param _receiver Address that will receive payment * @param _amount Tokens that are paid 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 _maxExecutions Maximum instances a payment can be executed * @param _reference String detailing payment reason */ function newScheduledPayment( address _token, address _receiver, uint256 _amount, uint64 _initialPaymentTime, uint64 _interval, uint64 _maxExecutions, string _reference ) external // Payment time parameter is left as the last param as it was added later authP(CREATE_PAYMENTS_ROLE, _arr(_token, _receiver, _amount, uint256(_interval), uint256(_maxExecutions), uint256(_initialPaymentTime))) transitionsPeriod returns (uint256 paymentId) { require(_amount > 0, ERROR_NEW_PAYMENT_AMOUNT_ZERO); require(_interval > 0, ERROR_NEW_PAYMENT_INTERVAL_ZERO); require(_maxExecutions > 0, ERROR_NEW_PAYMENT_EXECS_ZERO); // Token budget must not be set at all or allow at least one instance of this payment each period require(!settings.hasBudget[_token] || settings.budgets[_token] >= _amount, ERROR_BUDGET); // Don't allow creating single payments that are immediately executable, use `newImmediatePayment()` instead if (_maxExecutions == 1) { require(_initialPaymentTime > getTimestamp64(), ERROR_NEW_PAYMENT_IMMEDIATE); } paymentId = paymentsNextIndex++; emit NewPayment(paymentId, _receiver, _maxExecutions, _reference); ScheduledPayment storage payment = scheduledPayments[paymentId]; payment.token = _token; payment.receiver = _receiver; payment.amount = _amount; payment.initialPaymentTime = _initialPaymentTime; payment.interval = _interval; payment.maxExecutions = _maxExecutions; payment.createdBy = msg.sender; // We skip checking how many times the new payment was executed to allow creating new // scheduled payments before having enough vault balance _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 >= MINIMUM_PERIOD, 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], uint256(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], uint256(settings.hasBudget[_token] ? 1 : 0))) transitionsPeriod { settings.budgets[_token] = 0; settings.hasBudget[_token] = false; emit SetBudget(_token, 0, false); } /** * @notice Execute pending payment #`_paymentId` * @dev Executes any payment (requires role) * @param _paymentId Identifier for payment */ function executePayment(uint256 _paymentId) external authP(EXECUTE_PAYMENTS_ROLE, arr(_paymentId, scheduledPayments[_paymentId].amount)) scheduledPaymentExists(_paymentId) transitionsPeriod { _executePaymentAtLeastOnce(_paymentId); } /** * @notice Execute pending payment #`_paymentId` * @dev Always allow receiver of a payment to trigger execution * Initialization check is implicitly provided by `scheduledPaymentExists()` as new * scheduled payments can only be created via `newScheduledPayment(),` which requires initialization * @param _paymentId Identifier for payment */ function receiverExecutePayment(uint256 _paymentId) external scheduledPaymentExists(_paymentId) transitionsPeriod { require(scheduledPayments[_paymentId].receiver == msg.sender, ERROR_PAYMENT_RECEIVER); _executePaymentAtLeastOnce(_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))) scheduledPaymentExists(_paymentId) { scheduledPayments[_paymentId].inactive = !_active; emit ChangePaymentState(_paymentId, _active); } /** * @notice Send tokens held in this contract to the Vault * @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. * @param _token Token whose balance is going to be transferred. */ function recoverToVault(address _token) external isInitialized transitionsPeriod { uint256 amount = _token == ETH ? address(this).balance : ERC20(_token).staticBalanceOf(address(this)); require(amount > 0, ERROR_RECOVER_AMOUNT_ZERO); _deposit( _token, amount, "Recover to Vault", address(this), false ); } /** * @notice Transition accounting period if needed * @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. * @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) external isInitialized returns (bool success) { return _tryTransitionAccountingPeriod(_maxTransitions); } // Getter fns /** * @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 scheduledPaymentExists(_paymentId) returns ( address token, address receiver, uint256 amount, uint64 initialPaymentTime, uint64 interval, uint64 maxExecutions, bool inactive, uint64 executions, address createdBy ) { ScheduledPayment storage payment = scheduledPayments[_paymentId]; token = payment.token; receiver = payment.receiver; amount = payment.amount; initialPaymentTime = payment.initialPaymentTime; interval = payment.interval; maxExecutions = payment.maxExecutions; executions = payment.executions; inactive = payment.inactive; createdBy = payment.createdBy; } function getTransaction(uint256 _transactionId) public view transactionExists(_transactionId) returns ( uint64 periodId, uint256 amount, uint256 paymentId, uint64 paymentExecutionNumber, 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; paymentExecutionNumber = transaction.paymentExecutionNumber; } 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; } /** * @dev We have to check for initialization as periods are only valid after initializing */ function currentPeriodId() public view isInitialized returns (uint64) { return _currentPeriodId(); } /** * @dev We have to check for initialization as periods are only valid after initializing */ function getPeriodDuration() public view isInitialized returns (uint64) { return settings.periodDuration; } /** * @dev We have to check for initialization as budgets are only valid after initializing */ function getBudget(address _token) public view isInitialized returns (uint256 budget, bool hasBudget) { budget = settings.budgets[_token]; hasBudget = settings.hasBudget[_token]; } /** * @dev We have to check for initialization as budgets 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 budgets are only valid after initializing */ function canMakePayment(address _token, uint256 _amount) public view isInitialized returns (bool) { return _canMakePayment(_token, _amount); } /** * @dev Initialization check is implicitly provided by `scheduledPaymentExists()` as new * scheduled payments can only be created via `newScheduledPayment(),` which requires initialization */ function nextPaymentTime(uint256 _paymentId) public view scheduledPaymentExists(_paymentId) returns (uint64) { return _nextPaymentTime(_paymentId); } // Internal fns function _deposit(address _token, uint256 _amount, string _reference, address _sender, bool _isExternalDeposit) internal { _recordIncomingTransaction( _token, _sender, _amount, _reference ); if (_token == ETH) { vault.deposit.value(_amount)(ETH, _amount); } else { // First, transfer the tokens to Finance if necessary // 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) { // This assumes the sender has approved the tokens for Finance require( ERC20(_token).safeTransferFrom(msg.sender, address(this), _amount), ERROR_TOKEN_TRANSFER_FROM_REVERTED ); } // Approve the tokens for the Vault (it does the actual transferring) require(ERC20(_token).safeApprove(vault, _amount), ERROR_TOKEN_APPROVE_FAILED); // Finally, initiate the deposit vault.deposit(_token, _amount); } } function _executePayment(uint256 _paymentId) internal returns (uint256) { ScheduledPayment storage payment = scheduledPayments[_paymentId]; require(!payment.inactive, ERROR_PAYMENT_INACTIVE); uint64 paid = 0; while (_nextPaymentTime(_paymentId) <= getTimestamp64() && paid < MAX_SCHEDULED_PAYMENTS_PER_TX) { if (!_canMakePayment(payment.token, payment.amount)) { emit PaymentFailure(_paymentId); break; } // The while() predicate prevents these two from ever overflowing payment.executions += 1; paid += 1; // We've already checked the remaining budget with `_canMakePayment()` _unsafeMakePaymentTransaction( payment.token, payment.receiver, payment.amount, _paymentId, payment.executions, "" ); } return paid; } function _executePaymentAtLeastOnce(uint256 _paymentId) internal { uint256 paid = _executePayment(_paymentId); if (paid == 0) { if (_nextPaymentTime(_paymentId) <= getTimestamp64()) { revert(ERROR_EXECUTE_PAYMENT_NUM); } else { revert(ERROR_EXECUTE_PAYMENT_TIME); } } } function _makePaymentTransaction( address _token, address _receiver, uint256 _amount, uint256 _paymentId, uint64 _paymentExecutionNumber, string _reference ) internal { require(_getRemainingBudget(_token) >= _amount, ERROR_REMAINING_BUDGET); _unsafeMakePaymentTransaction(_token, _receiver, _amount, _paymentId, _paymentExecutionNumber, _reference); } /** * @dev Unsafe version of _makePaymentTransaction that assumes you have already checked the * remaining budget */ function _unsafeMakePaymentTransaction( address _token, address _receiver, uint256 _amount, uint256 _paymentId, uint64 _paymentExecutionNumber, string _reference ) internal { _recordTransaction( false, _token, _receiver, _amount, _paymentId, _paymentExecutionNumber, _reference ); vault.transfer(_token, _receiver, _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 _recordIncomingTransaction( address _token, address _sender, uint256 _amount, string _reference ) internal { _recordTransaction( true, // incoming transaction _token, _sender, _amount, NO_SCHEDULED_PAYMENT, // unrelated to any existing payment 0, // and no payment executions _reference ); } function _recordTransaction( bool _incoming, address _token, address _entity, uint256 _amount, uint256 _paymentId, uint64 _paymentExecutionNumber, 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.paymentExecutionNumber = _paymentExecutionNumber; 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(uint64 _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; } // We're already protected from underflowing above _maxTransitions -= 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 _currentPeriodId() internal view returns (uint64) { // There is no way for this to overflow if protected by an initialization check return periodsLength - 1; } function _getRemainingBudget(address _token) internal view returns (uint256) { if (!settings.hasBudget[_token]) { return MAX_UINT256; } uint256 budget = settings.budgets[_token]; 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 >= budget) { return 0; } // We're already protected from the overflow above return budget - spent; } function _nextPaymentTime(uint256 _paymentId) internal view returns (uint64) { ScheduledPayment storage payment = scheduledPayments[_paymentId]; if (payment.executions >= payment.maxExecutions) { return MAX_UINT64; // re-executes in some billions of years time... should not need to worry } // Split in multiple lines to circumvent linter warning uint64 increase = payment.executions.mul(payment.interval); uint64 nextPayment = payment.initialPaymentTime.add(increase); return nextPayment; } // Syntax sugar function _arr(address _a, address _b, uint256 _c, uint256 _d, uint256 _e, uint256 _f) internal pure returns (uint256[] r) { r = new uint256[](6); r[0] = uint256(_a); r[1] = uint256(_b); r[2] = _c; r[3] = _d; r[4] = _e; r[5] = _f; } // Mocked fns (overrided during testing) // 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":"_token","type":"address"},{"name":"_receiver","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_initialPaymentTime","type":"uint64"},{"name":"_interval","type":"uint64"},{"name":"_maxExecutions","type":"uint64"},{"name":"_reference","type":"string"}],"name":"newScheduledPayment","outputs":[{"name":"paymentId","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","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":"maxExecutions","type":"uint64"},{"name":"inactive","type":"bool"},{"name":"executions","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":"paymentExecutionNumber","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":"_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":"_token","type":"address"},{"name":"_amount","type":"uint256"}],"name":"canMakePayment","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":false,"inputs":[{"name":"_token","type":"address"},{"name":"_receiver","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_reference","type":"string"}],"name":"newImmediatePayment","outputs":[],"payable":false,"stateMutability":"nonpayable","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":"maxExecutions","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":"active","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"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}]
Contract Creation Code
6080604052620000176401000000006200001d810204565b6200023b565b6200003064010000000062000125810204565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a45440000000000000000602082015290156200010c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620000d0578181015183820152602001620000b6565b50505050905090810190601f168015620000fe5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506200012360001964010000000062000154810204565b565b60006200014f60008051602062005d3c83398151915264010000000062004ec16200023382021704565b905090565b6200016764010000000062000125810204565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a454400000000000000006020820152901562000206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252838181518152602001915080519060200190808383600083811015620000d0578181015183820152602001620000b6565b506200023060008051602062005d3c833981519152826401000000006200589b6200023782021704565b50565b5490565b9055565b615af1806200024b6000396000f3006080604052600436106102035763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630803fac0811461047e5780630842ace4146104a757806314920438146104ce578063162a0cf8146105305780631798de811461054a57806318f053da1461058557806319b7d7bd146105b35780632914b9bd146105fa5780632d00cad31461067c5780633280a8361461069957806332f0a3b51461072457806333ea3dc8146107395780635985feec146107ba5780635b14dbc8146107cf5780636436f189146107e457806367047c4a146107fc578063671273f4146108585780636abe602d1461087a57806374bfb426146108ac5780637e7db6e1146108dd57806380afdea81461090b5780638b3dd749146109205780639297d86014610935578063981cc34214610963578063988e6595146109785780639d4941d81461098d578063a1658fad146109bb578063a479e50814610a2f578063a662944114610a44578063b36fec5714610a66578063bfe07da614610a7b578063cb045a9614610aac578063d2d27b4114610ac4578063d4aae0c414610b18578063de048a7b14610b2d578063de4796ed14610b42578063e90a1b6e14610b57578063e94ebac514610b88578063eaa7ec6814610b9d578063eca8181714610bb2578063f636484614610be0578063fbfa77cf14610c26575b61020b610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a454400000000000000000000000060208201529015156102e4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156102a9578181015183820152602001610291565b50505050905090810190601f1680156102d65780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060006102f76102f2610c64565b610c6a565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515610397576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060408051808201909152601b81527f46494e414e43455f4445504f5349545f414d4f554e545f5a45524f0000000000602082015260003411610436576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5061047b6000346040805190810160405280601d81526020017f4574686572207472616e7366657220746f2046696e616e636520617070000000815250336001610d51565b50005b34801561048a57600080fd5b50610493610c3b565b604080519115158252519081900360200190f35b3480156104b357600080fd5b506104bc611043565b60408051918252519081900360200190f35b3480156104da57600080fd5b506104bc73ffffffffffffffffffffffffffffffffffffffff6004803582169160248035909116916044359167ffffffffffffffff60643581169260843582169260a4359092169160c435908101910135611078565b34801561053c57600080fd5b506105486004356117f1565b005b34801561055657600080fd5b5061054873ffffffffffffffffffffffffffffffffffffffff6004351667ffffffffffffffff60243516611a50565b34801561059157600080fd5b5061054873ffffffffffffffffffffffffffffffffffffffff60043516611d45565b3480156105bf57600080fd5b506105e173ffffffffffffffffffffffffffffffffffffffff60043516611fb8565b6040805192835290151560208301528051918290030190f35b34801561060657600080fd5b506040805160206004803580820135601f810184900484028501840190955284845261065394369492936024939284019190819084018382808284375094975061209e9650505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b34801561068857600080fd5b5061054860043560243515156121aa565b3480156106a557600080fd5b506106b16004356123e4565b6040805173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a01528881019790975267ffffffffffffffff9586166060890152938516608088015291841660a0870152151560c086015290911660e08401529092166101008201529051908190036101200190f35b34801561073057600080fd5b50610653612568565b34801561074557600080fd5b50610751600435612606565b6040805167ffffffffffffffff998a168152602081019890985287810196909652938716606087015273ffffffffffffffffffffffffffffffffffffffff9283166080870152911660a0850152151560c084015290921660e08201529051908190036101000190f35b3480156107c657600080fd5b506104bc612767565b3480156107db57600080fd5b506104bc61279c565b3480156107f057600080fd5b506105486004356127d1565b34801561080857600080fd5b5061081e67ffffffffffffffff60043516612a01565b60408051951515865267ffffffffffffffff9485166020870152929093168483015260608401526080830191909152519081900360a00190f35b34801561086457600080fd5b5061054867ffffffffffffffff60043516612b22565b34801561088657600080fd5b5061088f612de1565b6040805167ffffffffffffffff9092168252519081900360200190f35b3480156108b857600080fd5b5061054873ffffffffffffffffffffffffffffffffffffffff60043516602435612df1565b3480156108e957600080fd5b5061049373ffffffffffffffffffffffffffffffffffffffff600435166130a4565b34801561091757600080fd5b506104bc6130b5565b34801561092c57600080fd5b506104bc6130e5565b34801561094157600080fd5b5061054873ffffffffffffffffffffffffffffffffffffffff60043516613110565b34801561096f57600080fd5b506104bc613395565b34801561098457600080fd5b5061088f6133ca565b34801561099957600080fd5b5061054873ffffffffffffffffffffffffffffffffffffffff6004351661347a565b3480156109c757600080fd5b50604080516020600460443581810135838102808601850190965280855261049395833573ffffffffffffffffffffffffffffffffffffffff1695602480359636969560649593949201929182918501908490808284375094975061379c9650505050505050565b348015610a3b57600080fd5b5061065361392c565b348015610a5057600080fd5b5061049367ffffffffffffffff600435166139ee565b348015610a7257600080fd5b5061088f613aa5565b6105486004803573ffffffffffffffffffffffffffffffffffffffff16906024803591604435918201910135613b5e565b348015610ab857600080fd5b5061088f600435613e4d565b348015610ad057600080fd5b50610aff67ffffffffffffffff6004351673ffffffffffffffffffffffffffffffffffffffff60243516613f11565b6040805192835260208301919091528051918290030190f35b348015610b2457600080fd5b5061065361401c565b348015610b3957600080fd5b506104bc614047565b348015610b4e57600080fd5b5061049361404d565b348015610b6357600080fd5b5061049373ffffffffffffffffffffffffffffffffffffffff60043516602435614060565b348015610b9457600080fd5b506104bc614119565b348015610ba957600080fd5b506104bc61414e565b348015610bbe57600080fd5b506104bc73ffffffffffffffffffffffffffffffffffffffff60043516614154565b348015610bec57600080fd5b5061054873ffffffffffffffffffffffffffffffffffffffff60048035821691602480359091169160443591606435908101910135614205565b348015610c3257600080fd5b5061065361448e565b600080610c466130e5565b90508015801590610c5e575080610c5b6144aa565b10155b91505090565b60001990565b600080600060086000610c7b6144ae565b67ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000209150610ca76144c2565b90505b815467ffffffffffffffff6801000000000000000090910481169082161115610d455767ffffffffffffffff84161515610ce75760009250610d4a565b60018201546000199094019315610d1257600754610d0c90600163ffffffff6144d416565b60028301555b8154610d3e90610d399068010000000000000000900467ffffffffffffffff16600161457f565b614631565b9150610caa565b600192505b5050919050565b610d5d8583868661473f565b73ffffffffffffffffffffffffffffffffffffffff85161515610e115760008054604080517f47e7ef240000000000000000000000000000000000000000000000000000000081526004810184905260248101889052905173ffffffffffffffffffffffffffffffffffffffff909216926347e7ef24928892604480820193929182900301818588803b158015610df357600080fd5b505af1158015610e07573d6000803e3d6000fd5b505050505061103c565b8015610ee057610e3f73ffffffffffffffffffffffffffffffffffffffff861633308763ffffffff61475616565b6040805190810160405280602081526020017f46494e414e43455f544b4e5f5452414e534645525f46524f4d5f524556455254815250901515610ede576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b505b600054610f0d9073ffffffffffffffffffffffffffffffffffffffff87811691168663ffffffff6147f716565b60408051808201909152601a81527f46494e414e43455f544b4e5f415050524f56455f4641494c45440000000000006020820152901515610faa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060008054604080517f47e7ef2400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff898116600483015260248201899052915191909216926347e7ef24926044808201939182900301818387803b15801561102357600080fd5b505af1158015611037573d6000803e3d6000fd5b505050505b5050505050565b604080517f4352454154455f5041594d454e54535f524f4c450000000000000000000000008152905190819003601401902081565b60008060405180807f4352454154455f5041594d454e54535f524f4c45000000000000000000000000815250601401905060405180910390206110dd8b8b8b8a67ffffffffffffffff168a67ffffffffffffffff168d67ffffffffffffffff1661488f565b6110e833838361379c565b60408051808201909152600f81527f4150505f415554485f4641494c454400000000000000000000000000000000006020820152901515611185576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060006111936102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515611233576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060408051808201909152601f81527f46494e414e43455f4e45575f5041594d454e545f414d4f554e545f5a45524f00602082015260008c116112d2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060408051808201909152601f81527f46494e414e43455f4e45575f5041594d454e545f494e5452564c5f5a45524f006020820152600067ffffffffffffffff8b161161137b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060408051808201909152601e81527f46494e414e43455f4e45575f5041594d454e545f45584543535f5a45524f00006020820152600067ffffffffffffffff8a1611611424576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5073ffffffffffffffffffffffffffffffffffffffff8d1660009081526003602052604090205460ff16158061147f575073ffffffffffffffffffffffffffffffffffffffff8d166000908152600260205260409020548b11155b60408051808201909152600e81527f46494e414e43455f425544474554000000000000000000000000000000000000602082015290151561151c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b508767ffffffffffffffff16600114156115e5576115386144c2565b60408051808201909152601d81527f46494e414e43455f4e45575f5041594d454e545f494d4d45444941544500000060208201529067ffffffffffffffff908116908c16116115e3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b505b60058054600181019091556040805167ffffffffffffffff8b1681526020810182815291810189905291965073ffffffffffffffffffffffffffffffffffffffff8e169187917f41e8c14bdf2b044354d788d944b364e1de0b64aeddeba755b8ef69ab68bd9083918c918c918c91606082018484808284376040519201829003965090945050505050a36004600086815260200190815260200160002093508c8460000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508b8460010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508a8460030181905550898460040160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550888460040160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550878460040160106101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550338460020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506117e085614989565b505050505098975050505050505050565b604080517f455845435554455f5041594d454e54535f524f4c45000000000000000000000081528151908190036015019020600083815260046020529190912060030154611840908390614bc6565b61184b33838361379c565b60408051808201909152600f81527f4150505f415554485f4641494c4544000000000000000000000000000000000060208201529015156118e8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50826000811180156118fb575060055481105b60408051808201909152601c81527f46494e414e43455f4e4f5f5343484544554c45445f5041594d454e54000000006020820152901515611998576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060006119a66102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515611a46576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5061103c85614c21565b611a586130e5565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015611af4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50611afd614d8b565b611b0682614e6a565b60408051808201909152601a81527f46494e414e43455f5641554c545f4e4f545f434f4e54524143540000000000006020820152901515611ba3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff841617905560408051808201909152601c81527f46494e414e43455f5345545f504552494f445f544f4f5f53484f52540000000060208201526201518067ffffffffffffffff83161015611c8f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506001805467ffffffffffffffff83167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009091161781556000805260046020527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ee80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790556005819055600755611d40610d396144c2565b505050565b604080517f4348414e47455f425544474554535f524f4c45000000000000000000000000008152815190819003601301902073ffffffffffffffffffffffffffffffffffffffff8316600090815260026020908152838220546003909152928120549192611dca928592919060ff16611dbf576000611dc2565b60015b60ff16614e9d565b611dd533838361379c565b60408051808201909152600f81527f4150505f415554485f4641494c454400000000000000000000000000000000006020820152901515611e72576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506000611e806102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515611f20576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5073ffffffffffffffffffffffffffffffffffffffff841660008181526002602090815260408083208390556003825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905580518381529182019290925281517f6e768d8fe4a1460cae6d5af9382c3e9abbc41f66f2ec91fda24b12e3c2796f03929181900390910190a250505050565b600080611fc3610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515612060576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50505073ffffffffffffffffffffffffffffffffffffffff16600090815260026020908152604080832054600390925290912054909160ff90911690565b60006120a861392c565b73ffffffffffffffffffffffffffffffffffffffff166304bf2a7f836040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561212c578181015183820152602001612114565b50505050905090810190601f1680156121595780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b15801561217857600080fd5b505af115801561218c573d6000803e3d6000fd5b505050506040513d60208110156121a257600080fd5b505192915050565b604080517f4d414e4147455f5041594d454e54535f524f4c45000000000000000000000000815290519081900360140190206121f783836121ec5760006121ef565b60015b60ff16614bc6565b61220233838361379c565b60408051808201909152600f81527f4150505f415554485f4641494c45440000000000000000000000000000000000602082015290151561229f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50836000811180156122b2575060055481105b60408051808201909152601c81527f46494e414e43455f4e4f5f5343484544554c45445f5041594d454e5400000000602082015290151561234f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060008581526004602090815260409182902060020180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16871574010000000000000000000000000000000000000000810291909117909155825190158152915187927faca91836ee6e44bf1c422f7ee89afb243a4fb775d9fe87150ff5f8e566dc161292908290030190a25050505050565b6000806000806000806000806000808a600081118015612405575060055481105b60408051808201909152601c81527f46494e414e43455f4e4f5f5343484544554c45445f5041594d454e540000000060208201529015156124a2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5050506000998a5250506004602081905260409098208054600182015460038301549a83015460029093015473ffffffffffffffffffffffffffffffffffffffff9283169c9183169b9a5067ffffffffffffffff8085169a506801000000000000000085048116995070010000000000000000000000000000000085048116985060ff7401000000000000000000000000000000000000000083041697507801000000000000000000000000000000000000000000000000909404909316945091169150565b600061257261401c565b73ffffffffffffffffffffffffffffffffffffffff166332f0a3b56040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156125d557600080fd5b505af11580156125e9573d6000803e3d6000fd5b505050506040513d60208110156125ff57600080fd5b5051905090565b600080600080600080600080600089600081118015612626575060075481105b60408051808201909152601681527f46494e414e43455f4e4f5f5452414e53414354494f4e0000000000000000000060208201529015156126c3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50505060009889525050600660205250506040909420805460018201546004830154600284015460039094015467ffffffffffffffff700100000000000000000000000000000000830481169a959950909750808216965073ffffffffffffffffffffffffffffffffffffffff9384169550928216937401000000000000000000000000000000000000000090920460ff1692680100000000000000009091041690565b604080517f4348414e47455f504552494f445f524f4c4500000000000000000000000000008152905190819003601201902081565b604080517f4348414e47455f425544474554535f524f4c45000000000000000000000000008152905190819003601301902081565b806000811180156127e3575060055481105b60408051808201909152601c81527f46494e414e43455f4e4f5f5343484544554c45445f5041594d454e54000000006020820152901515612880576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50600061288e6102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e0000000000602082015290915081151561292e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50600083815260046020908152604091829020600101548251808401909352601883527f46494e414e43455f5041594d454e545f524543454956455200000000000000009183019190915273ffffffffffffffffffffffffffffffffffffffff1633146129f7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50611d4083614c21565b60095460408051808201909152601181527f46494e414e43455f4e4f5f504552494f44000000000000000000000000000000602082015260009182918291829182918291889167ffffffffffffffff90811690831610612abd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5067ffffffffffffffff881660008181526008602052604090209250612ae16144ae565b8354600185015460029095015467ffffffffffffffff928316939093149b8183169b5068010000000000000000909104909116985092965094509092505050565b604080517f4348414e47455f504552494f445f524f4c45000000000000000000000000000081529051908190036012019020600154612b6e9067ffffffffffffffff8085169116614bc6565b612b7933838361379c565b60408051808201909152600f81527f4150505f415554485f4641494c454400000000000000000000000000000000006020820152901515612c16576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506000612c246102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515612cc4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060408051808201909152601c81527f46494e414e43455f5345545f504552494f445f544f4f5f53484f52540000000060208201526201518067ffffffffffffffff86161015612d70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506001805467ffffffffffffffff86167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909116811790915560408051918252517fa32389dd0d5a3bf7cc635f8c30fee3b70d06a6c547d6dbf31628378ee267bfc99181900360200190a150505050565b60095467ffffffffffffffff1681565b604080517f4348414e47455f425544474554535f524f4c45000000000000000000000000008152815190819003601301902073ffffffffffffffffffffffffffffffffffffffff8416600090815260026020908152838220546003909152929020549091612e6b918591859160ff16611dbf576000611dc2565b612e7633838361379c565b60408051808201909152600f81527f4150505f415554485f4641494c454400000000000000000000000000000000006020820152901515612f13576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506000612f216102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515612fc1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5073ffffffffffffffffffffffffffffffffffffffff85166000908152600260209081526040808320879055600390915290205460ff16151561304d5773ffffffffffffffffffffffffffffffffffffffff8516600090815260036020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b6040805185815260016020820152815173ffffffffffffffffffffffffffffffffffffffff8816927f6e768d8fe4a1460cae6d5af9382c3e9abbc41f66f2ec91fda24b12e3c2796f03928290030190a25050505050565b60006130ae610c3b565b1592915050565b60006130e07fd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b614ec1565b905090565b60006130e07febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e614ec1565b600061311a610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a454400000000000000000000000060208201529015156131b7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060006131c56102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515613265576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5073ffffffffffffffffffffffffffffffffffffffff8316156132ad576132a873ffffffffffffffffffffffffffffffffffffffff84163063ffffffff614ec916565b6132b0565b30315b60408051808201909152601b81527f46494e414e43455f5245434f5645525f414d4f554e545f5a45524f0000000000602082015290925060008311613351576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50611d4083836040805190810160405280601081526020017f5265636f76657220746f205661756c7400000000000000000000000000000000815250306000610d51565b604080517f455845435554455f5041594d454e54535f524f4c4500000000000000000000008152905190819003601501902081565b60006133d4610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515613471576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506130e06144ae565b6000806000613488846130a4565b60408051808201909152601281527f5245434f5645525f444953414c4c4f57454400000000000000000000000000006020820152901515613525576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5061352e612568565b925061353983614e6a565b60408051808201909152601a81527f5245434f5645525f5641554c545f4e4f545f434f4e545241435400000000000060208201529015156135d6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5073ffffffffffffffffffffffffffffffffffffffff84161515613641576040513031925073ffffffffffffffffffffffffffffffffffffffff84169083156108fc029084906000818181858888f1935050505015801561363b573d6000803e3d6000fd5b50613731565b508261366973ffffffffffffffffffffffffffffffffffffffff82163063ffffffff614ec916565b915061369273ffffffffffffffffffffffffffffffffffffffff8216848463ffffffff61500216565b60408051808201909152601d81527f5245434f5645525f544f4b454e5f5452414e534645525f4641494c4544000000602082015290151561372f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b505b8373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f596caf56044b55fb8c4ca640089bbc2b63cae3e978b851f5745cbb7c5b288e02846040518082815260200191505060405180910390a350505050565b6000806137a7610c3b565b15156137b65760009150613924565b6137be61401c565b905073ffffffffffffffffffffffffffffffffffffffff811615156137e65760009150613924565b8073ffffffffffffffffffffffffffffffffffffffff1663fdef910686308761380e88615091565b6040517c010000000000000000000000000000000000000000000000000000000063ffffffff871602815273ffffffffffffffffffffffffffffffffffffffff808616600483019081529085166024830152604482018490526080606483019081528351608484015283519192909160a490910190602085019080838360005b838110156138a657818101518382015260200161388e565b50505050905090810190601f1680156138d35780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b1580156138f557600080fd5b505af1158015613909573d6000803e3d6000fd5b505050506040513d602081101561391f57600080fd5b505191505b509392505050565b60008061393761401c565b604080517fbe00bbd80000000000000000000000000000000000000000000000000000000081527fd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb60048201527fddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd616024820152905173ffffffffffffffffffffffffffffffffffffffff929092169163be00bbd8916044808201926020929091908290030181600087803b15801561217857600080fd5b60006139f8610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515613a95576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50613a9f82610c6a565b92915050565b6000613aaf610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515613b4c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b505060015467ffffffffffffffff1690565b613b66610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515613c03576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506000613c116102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515613cb1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060408051808201909152601b81527f46494e414e43455f4445504f5349545f414d4f554e545f5a45524f0000000000602082015260008511613d50576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5073ffffffffffffffffffffffffffffffffffffffff85161515613e0d5760408051808201909152601a81527f46494e414e43455f4554485f56414c55455f4d49534d415443480000000000006020820152348514613e0b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b505b61103c858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050336001610d51565b600081600081118015613e61575060055481105b60408051808201909152601c81527f46494e414e43455f4e4f5f5343484544554c45445f5041594d454e54000000006020820152901515613efe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50613f088361509b565b91505b50919050565b60095460408051808201909152601181527f46494e414e43455f4e4f5f504552494f4400000000000000000000000000000060208201526000918291829186919067ffffffffffffffff90811690831610613fc8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5050505067ffffffffffffffff92909216600090815260086020908152604080832073ffffffffffffffffffffffffffffffffffffffff949094168352600390930190522080546001909101549092909150565b60006130e07f4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b614ec1565b60055481565b600060001961405a6130e5565b14905090565b600061406a610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515614107576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506141128383615164565b9392505050565b604080517f4d414e4147455f5041594d454e54535f524f4c450000000000000000000000008152905190819003601401902081565b60075481565b600061415e610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a454400000000000000000000000060208201529015156141fb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50613a9f82615228565b604080517f4352454154455f5041594d454e54535f524f4c450000000000000000000000008152905190819003601401902061424f868686600019600161424a6152f3565b61488f565b61425a33838361379c565b60408051808201909152600f81527f4150505f415554485f4641494c4544000000000000000000000000000000000060208201529015156142f7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060006143056102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e000000000060208201529091508115156143a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060408051808201909152601f81527f46494e414e43455f4e45575f5041594d454e545f414d4f554e545f5a45524f00602082015260008711614444576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506144848888886000808a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437506152f7945050505050565b5050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b4390565b60095467ffffffffffffffff166000190190565b60006130e06144cf6152f3565b6153b5565b60408051808201909152601281527f4d4154485f5355425f554e444552464c4f5700000000000000000000000000006020820152600090819084841115614577576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b505050900390565b60408051808201909152601381527f4d41544836345f4144445f4f564552464c4f570000000000000000000000000060208201526000908383019067ffffffffffffffff8086169083161015613924576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b6009805467ffffffffffffffff808216600181810183167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000948516179094556000818152600860205260408120805487851695168517815594549094919391926000199181168701919091019190821610156146ac57506000195b81547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff83811682029290921780855560408051828516815292909104831660208301528051928616927fe183df4530c4b573af76d47f020d4b86e418cef40ed4c9ce924b563e791b832c9281900390910190a28193505b505050919050565b614750600185858560008087615465565b50505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790526000906147ed868261579d565b9695505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052600090614886858261579d565b95945050505050565b60408051600680825260e082019092526060916020820160c0803883390190505090508673ffffffffffffffffffffffffffffffffffffffff168160008151811015156148d857fe5b60209081029091010152805173ffffffffffffffffffffffffffffffffffffffff8716908290600190811061490957fe5b60209081029091010152805185908290600290811061492457fe5b60209081029091010152805184908290600390811061493f57fe5b60209081029091010152805183908290600490811061495a57fe5b60209081029091010152805182908290600590811061497557fe5b602090810290910101529695505050505050565b600081815260046020908152604080832060028101548251808401909352601883527f46494e414e43455f5041594d454e545f494e4143544956450000000000000000938301939093529183919074010000000000000000000000000000000000000000900460ff1615614a59576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50600090505b614a676144c2565b67ffffffffffffffff16614a7a8561509b565b67ffffffffffffffff1611158015614a9c575060148167ffffffffffffffff16105b15614bb55781546003830154614ac89173ffffffffffffffffffffffffffffffffffffffff1690615164565b1515614b06576040805185815290517f5f352e4123f4620cacbb8eb0dd683705aaa3e1f9384adbbd85b665b205097f519181900360200190a1614bb5565b60048201805467ffffffffffffffff7801000000000000000000000000000000000000000000000000808304821660019081018316820277ffffffffffffffffffffffffffffffffffffffffffffffff909416939093179384905585548684015460038801546040805160208101909152600081529790950196614bb09673ffffffffffffffffffffffffffffffffffffffff93841696929093169491938b9304909116906157eb565b614a5f565b67ffffffffffffffff169392505050565b604080516002808252606080830184529260208301908038833901905050905082816000815181101515614bf657fe5b602090810290910101528051829082906001908110614c1157fe5b6020908102909101015292915050565b6000614c2c82614989565b9050801515614d8757614c3d6144c2565b67ffffffffffffffff16614c508361509b565b67ffffffffffffffff1611614cf357604080518082018252601b81527f46494e414e43455f455845435554455f5041594d454e545f4e554d0000000000602080830191825292517f08c379a0000000000000000000000000000000000000000000000000000000008152600481019384528251602482015282519293928392604490920191908083836000838110156102a9578181015183820152602001610291565b604080518082018252601c81527f46494e414e43455f455845435554455f5041594d454e545f54494d4500000000602080830191825292517f08c379a0000000000000000000000000000000000000000000000000000000008152600481019384528251602482015282519293928392604490920191908083836000838110156102a9578181015183820152602001610291565b5050565b614d936130e5565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015614e2f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50614e68614e3b6144aa565b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e9063ffffffff61589b16565b565b60008073ffffffffffffffffffffffffffffffffffffffff83161515614e935760009150613f0b565b50506000903b1190565b60606148868573ffffffffffffffffffffffffffffffffffffffff1685858561589f565b5490565b5490565b6040805173ffffffffffffffffffffffffffffffffffffffff83166024808301919091528251808303909101815260449091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a08231000000000000000000000000000000000000000000000000000000001790526000908180614f568684615935565b60408051808201909152601c81527f534146455f4552435f32305f42414c414e43455f52455645525445440000000060208201529193509150821515614ff8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5095945050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052600090614886858261579d565b8051602002815290565b60008181526004602081905260408220908101548290819067ffffffffffffffff70010000000000000000000000000000000082048116780100000000000000000000000000000000000000000000000090920416106150ff576000199350614737565b60048301546151429067ffffffffffffffff7801000000000000000000000000000000000000000000000000820481169168010000000000000000900416615966565b60048401549092506148869067ffffffffffffffff168363ffffffff61457f16565b60008161517084615228565b10158015614112575060008054604080517fe3d670d700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff878116600483015291518694929093169263e3d670d792602480840193602093929083900390910190829087803b1580156151f357600080fd5b505af1158015615207573d6000803e3d6000fd5b505050506040513d602081101561521d57600080fd5b505110159392505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600360205260408120548190819060ff161515615265576000199250610d4a565b73ffffffffffffffffffffffffffffffffffffffff841660009081526002602052604081205492506008906152986144ae565b67ffffffffffffffff1681526020808201929092526040908101600090812073ffffffffffffffffffffffffffffffffffffffff8816825260030190925290205490508181106152eb5760009250610d4a565b900392915050565b4290565b8361530187615228565b60408051808201909152601881527f46494e414e43455f52454d41494e494e475f4255444745540000000000000000602082015291111561539e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506153ad8686868686866157eb565b505050505050565b60408051808201909152601581527f55494e5436345f4e554d4245525f544f4f5f4249470000000000000000000000602082015260009067ffffffffffffffff83111561545e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5090919050565b60008060008060006154756144ae565b9450600860008667ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060030160008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002093508b156155055760018401546154fb908a63ffffffff615a2016565b600185015561551a565b8354615517908a63ffffffff615a2016565b84555b600760008154809291906001019190505592506006600084815260200190815260200160002091508a8260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550898260010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508b8260010160146101000a81548160ff021916908315150217905550888260020181905550878260030181905550868260040160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506156296144c2565b6004830180547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff93841602177fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000009288169283021790556000908152600860205260409020600181015490915015156156ca57600181018390555b8973ffffffffffffffffffffffffffffffffffffffff16837f5b2c6f4cb53711ae51d600df17fa68f8239b4a704f766c99642f667d1d7bd40e8e8c8a604051808415151515815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561575357818101518382015260200161573b565b50505050905090810190601f1680156157805780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a3505050505050505050505050565b6000806040516020818551602087016000895af160008111156157e1573d80156157ce57602081146157d7576157df565b600193506157df565b600183511493505b505b5090949350505050565b6157fb6000878787878787615465565b60008054604080517fbeabacc800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a811660048301528981166024830152604482018990529151919092169263beabacc8926064808201939182900301818387803b15801561587b57600080fd5b505af115801561588f573d6000803e3d6000fd5b50505050505050505050565b9055565b60408051600480825260a0820190925260609160208201608080388339019050509050848160008151811015156158d257fe5b6020908102909101015280518490829060019081106158ed57fe5b60209081029091010152805183908290600290811061590857fe5b60209081029091010152805182908290600390811061592357fe5b60209081029091010152949350505050565b6000806000806040516020818751602089018a5afa9250600083111561595a57805191505b50909590945092505050565b60408051808201909152601381527f4d41544836345f4d554c5f4f564552464c4f5700000000000000000000000000602082015260009067ffffffffffffffff8481169084160290680100000000000000008210613924576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f5700000000000000000000000000000060208201526000908383019084821015613924576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a95781810151838201526020016102915600a165627a7a723058204fed94733de008d6b4964e029b08cddd21d45e3912ff9e0afb755ee567a5c5200029ebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e
Deployed Bytecode
0x6080604052600436106102035763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630803fac0811461047e5780630842ace4146104a757806314920438146104ce578063162a0cf8146105305780631798de811461054a57806318f053da1461058557806319b7d7bd146105b35780632914b9bd146105fa5780632d00cad31461067c5780633280a8361461069957806332f0a3b51461072457806333ea3dc8146107395780635985feec146107ba5780635b14dbc8146107cf5780636436f189146107e457806367047c4a146107fc578063671273f4146108585780636abe602d1461087a57806374bfb426146108ac5780637e7db6e1146108dd57806380afdea81461090b5780638b3dd749146109205780639297d86014610935578063981cc34214610963578063988e6595146109785780639d4941d81461098d578063a1658fad146109bb578063a479e50814610a2f578063a662944114610a44578063b36fec5714610a66578063bfe07da614610a7b578063cb045a9614610aac578063d2d27b4114610ac4578063d4aae0c414610b18578063de048a7b14610b2d578063de4796ed14610b42578063e90a1b6e14610b57578063e94ebac514610b88578063eaa7ec6814610b9d578063eca8181714610bb2578063f636484614610be0578063fbfa77cf14610c26575b61020b610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a454400000000000000000000000060208201529015156102e4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156102a9578181015183820152602001610291565b50505050905090810190601f1680156102d65780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060006102f76102f2610c64565b610c6a565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515610397576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060408051808201909152601b81527f46494e414e43455f4445504f5349545f414d4f554e545f5a45524f0000000000602082015260003411610436576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5061047b6000346040805190810160405280601d81526020017f4574686572207472616e7366657220746f2046696e616e636520617070000000815250336001610d51565b50005b34801561048a57600080fd5b50610493610c3b565b604080519115158252519081900360200190f35b3480156104b357600080fd5b506104bc611043565b60408051918252519081900360200190f35b3480156104da57600080fd5b506104bc73ffffffffffffffffffffffffffffffffffffffff6004803582169160248035909116916044359167ffffffffffffffff60643581169260843582169260a4359092169160c435908101910135611078565b34801561053c57600080fd5b506105486004356117f1565b005b34801561055657600080fd5b5061054873ffffffffffffffffffffffffffffffffffffffff6004351667ffffffffffffffff60243516611a50565b34801561059157600080fd5b5061054873ffffffffffffffffffffffffffffffffffffffff60043516611d45565b3480156105bf57600080fd5b506105e173ffffffffffffffffffffffffffffffffffffffff60043516611fb8565b6040805192835290151560208301528051918290030190f35b34801561060657600080fd5b506040805160206004803580820135601f810184900484028501840190955284845261065394369492936024939284019190819084018382808284375094975061209e9650505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b34801561068857600080fd5b5061054860043560243515156121aa565b3480156106a557600080fd5b506106b16004356123e4565b6040805173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a01528881019790975267ffffffffffffffff9586166060890152938516608088015291841660a0870152151560c086015290911660e08401529092166101008201529051908190036101200190f35b34801561073057600080fd5b50610653612568565b34801561074557600080fd5b50610751600435612606565b6040805167ffffffffffffffff998a168152602081019890985287810196909652938716606087015273ffffffffffffffffffffffffffffffffffffffff9283166080870152911660a0850152151560c084015290921660e08201529051908190036101000190f35b3480156107c657600080fd5b506104bc612767565b3480156107db57600080fd5b506104bc61279c565b3480156107f057600080fd5b506105486004356127d1565b34801561080857600080fd5b5061081e67ffffffffffffffff60043516612a01565b60408051951515865267ffffffffffffffff9485166020870152929093168483015260608401526080830191909152519081900360a00190f35b34801561086457600080fd5b5061054867ffffffffffffffff60043516612b22565b34801561088657600080fd5b5061088f612de1565b6040805167ffffffffffffffff9092168252519081900360200190f35b3480156108b857600080fd5b5061054873ffffffffffffffffffffffffffffffffffffffff60043516602435612df1565b3480156108e957600080fd5b5061049373ffffffffffffffffffffffffffffffffffffffff600435166130a4565b34801561091757600080fd5b506104bc6130b5565b34801561092c57600080fd5b506104bc6130e5565b34801561094157600080fd5b5061054873ffffffffffffffffffffffffffffffffffffffff60043516613110565b34801561096f57600080fd5b506104bc613395565b34801561098457600080fd5b5061088f6133ca565b34801561099957600080fd5b5061054873ffffffffffffffffffffffffffffffffffffffff6004351661347a565b3480156109c757600080fd5b50604080516020600460443581810135838102808601850190965280855261049395833573ffffffffffffffffffffffffffffffffffffffff1695602480359636969560649593949201929182918501908490808284375094975061379c9650505050505050565b348015610a3b57600080fd5b5061065361392c565b348015610a5057600080fd5b5061049367ffffffffffffffff600435166139ee565b348015610a7257600080fd5b5061088f613aa5565b6105486004803573ffffffffffffffffffffffffffffffffffffffff16906024803591604435918201910135613b5e565b348015610ab857600080fd5b5061088f600435613e4d565b348015610ad057600080fd5b50610aff67ffffffffffffffff6004351673ffffffffffffffffffffffffffffffffffffffff60243516613f11565b6040805192835260208301919091528051918290030190f35b348015610b2457600080fd5b5061065361401c565b348015610b3957600080fd5b506104bc614047565b348015610b4e57600080fd5b5061049361404d565b348015610b6357600080fd5b5061049373ffffffffffffffffffffffffffffffffffffffff60043516602435614060565b348015610b9457600080fd5b506104bc614119565b348015610ba957600080fd5b506104bc61414e565b348015610bbe57600080fd5b506104bc73ffffffffffffffffffffffffffffffffffffffff60043516614154565b348015610bec57600080fd5b5061054873ffffffffffffffffffffffffffffffffffffffff60048035821691602480359091169160443591606435908101910135614205565b348015610c3257600080fd5b5061065361448e565b600080610c466130e5565b90508015801590610c5e575080610c5b6144aa565b10155b91505090565b60001990565b600080600060086000610c7b6144ae565b67ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000209150610ca76144c2565b90505b815467ffffffffffffffff6801000000000000000090910481169082161115610d455767ffffffffffffffff84161515610ce75760009250610d4a565b60018201546000199094019315610d1257600754610d0c90600163ffffffff6144d416565b60028301555b8154610d3e90610d399068010000000000000000900467ffffffffffffffff16600161457f565b614631565b9150610caa565b600192505b5050919050565b610d5d8583868661473f565b73ffffffffffffffffffffffffffffffffffffffff85161515610e115760008054604080517f47e7ef240000000000000000000000000000000000000000000000000000000081526004810184905260248101889052905173ffffffffffffffffffffffffffffffffffffffff909216926347e7ef24928892604480820193929182900301818588803b158015610df357600080fd5b505af1158015610e07573d6000803e3d6000fd5b505050505061103c565b8015610ee057610e3f73ffffffffffffffffffffffffffffffffffffffff861633308763ffffffff61475616565b6040805190810160405280602081526020017f46494e414e43455f544b4e5f5452414e534645525f46524f4d5f524556455254815250901515610ede576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b505b600054610f0d9073ffffffffffffffffffffffffffffffffffffffff87811691168663ffffffff6147f716565b60408051808201909152601a81527f46494e414e43455f544b4e5f415050524f56455f4641494c45440000000000006020820152901515610faa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060008054604080517f47e7ef2400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff898116600483015260248201899052915191909216926347e7ef24926044808201939182900301818387803b15801561102357600080fd5b505af1158015611037573d6000803e3d6000fd5b505050505b5050505050565b604080517f4352454154455f5041594d454e54535f524f4c450000000000000000000000008152905190819003601401902081565b60008060405180807f4352454154455f5041594d454e54535f524f4c45000000000000000000000000815250601401905060405180910390206110dd8b8b8b8a67ffffffffffffffff168a67ffffffffffffffff168d67ffffffffffffffff1661488f565b6110e833838361379c565b60408051808201909152600f81527f4150505f415554485f4641494c454400000000000000000000000000000000006020820152901515611185576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060006111936102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515611233576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060408051808201909152601f81527f46494e414e43455f4e45575f5041594d454e545f414d4f554e545f5a45524f00602082015260008c116112d2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060408051808201909152601f81527f46494e414e43455f4e45575f5041594d454e545f494e5452564c5f5a45524f006020820152600067ffffffffffffffff8b161161137b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060408051808201909152601e81527f46494e414e43455f4e45575f5041594d454e545f45584543535f5a45524f00006020820152600067ffffffffffffffff8a1611611424576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5073ffffffffffffffffffffffffffffffffffffffff8d1660009081526003602052604090205460ff16158061147f575073ffffffffffffffffffffffffffffffffffffffff8d166000908152600260205260409020548b11155b60408051808201909152600e81527f46494e414e43455f425544474554000000000000000000000000000000000000602082015290151561151c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b508767ffffffffffffffff16600114156115e5576115386144c2565b60408051808201909152601d81527f46494e414e43455f4e45575f5041594d454e545f494d4d45444941544500000060208201529067ffffffffffffffff908116908c16116115e3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b505b60058054600181019091556040805167ffffffffffffffff8b1681526020810182815291810189905291965073ffffffffffffffffffffffffffffffffffffffff8e169187917f41e8c14bdf2b044354d788d944b364e1de0b64aeddeba755b8ef69ab68bd9083918c918c918c91606082018484808284376040519201829003965090945050505050a36004600086815260200190815260200160002093508c8460000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508b8460010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508a8460030181905550898460040160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550888460040160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550878460040160106101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550338460020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506117e085614989565b505050505098975050505050505050565b604080517f455845435554455f5041594d454e54535f524f4c45000000000000000000000081528151908190036015019020600083815260046020529190912060030154611840908390614bc6565b61184b33838361379c565b60408051808201909152600f81527f4150505f415554485f4641494c4544000000000000000000000000000000000060208201529015156118e8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50826000811180156118fb575060055481105b60408051808201909152601c81527f46494e414e43455f4e4f5f5343484544554c45445f5041594d454e54000000006020820152901515611998576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060006119a66102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515611a46576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5061103c85614c21565b611a586130e5565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015611af4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50611afd614d8b565b611b0682614e6a565b60408051808201909152601a81527f46494e414e43455f5641554c545f4e4f545f434f4e54524143540000000000006020820152901515611ba3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff841617905560408051808201909152601c81527f46494e414e43455f5345545f504552494f445f544f4f5f53484f52540000000060208201526201518067ffffffffffffffff83161015611c8f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506001805467ffffffffffffffff83167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009091161781556000805260046020527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ee80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790556005819055600755611d40610d396144c2565b505050565b604080517f4348414e47455f425544474554535f524f4c45000000000000000000000000008152815190819003601301902073ffffffffffffffffffffffffffffffffffffffff8316600090815260026020908152838220546003909152928120549192611dca928592919060ff16611dbf576000611dc2565b60015b60ff16614e9d565b611dd533838361379c565b60408051808201909152600f81527f4150505f415554485f4641494c454400000000000000000000000000000000006020820152901515611e72576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506000611e806102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515611f20576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5073ffffffffffffffffffffffffffffffffffffffff841660008181526002602090815260408083208390556003825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905580518381529182019290925281517f6e768d8fe4a1460cae6d5af9382c3e9abbc41f66f2ec91fda24b12e3c2796f03929181900390910190a250505050565b600080611fc3610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515612060576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50505073ffffffffffffffffffffffffffffffffffffffff16600090815260026020908152604080832054600390925290912054909160ff90911690565b60006120a861392c565b73ffffffffffffffffffffffffffffffffffffffff166304bf2a7f836040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561212c578181015183820152602001612114565b50505050905090810190601f1680156121595780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b15801561217857600080fd5b505af115801561218c573d6000803e3d6000fd5b505050506040513d60208110156121a257600080fd5b505192915050565b604080517f4d414e4147455f5041594d454e54535f524f4c45000000000000000000000000815290519081900360140190206121f783836121ec5760006121ef565b60015b60ff16614bc6565b61220233838361379c565b60408051808201909152600f81527f4150505f415554485f4641494c45440000000000000000000000000000000000602082015290151561229f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50836000811180156122b2575060055481105b60408051808201909152601c81527f46494e414e43455f4e4f5f5343484544554c45445f5041594d454e5400000000602082015290151561234f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060008581526004602090815260409182902060020180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16871574010000000000000000000000000000000000000000810291909117909155825190158152915187927faca91836ee6e44bf1c422f7ee89afb243a4fb775d9fe87150ff5f8e566dc161292908290030190a25050505050565b6000806000806000806000806000808a600081118015612405575060055481105b60408051808201909152601c81527f46494e414e43455f4e4f5f5343484544554c45445f5041594d454e540000000060208201529015156124a2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5050506000998a5250506004602081905260409098208054600182015460038301549a83015460029093015473ffffffffffffffffffffffffffffffffffffffff9283169c9183169b9a5067ffffffffffffffff8085169a506801000000000000000085048116995070010000000000000000000000000000000085048116985060ff7401000000000000000000000000000000000000000083041697507801000000000000000000000000000000000000000000000000909404909316945091169150565b600061257261401c565b73ffffffffffffffffffffffffffffffffffffffff166332f0a3b56040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156125d557600080fd5b505af11580156125e9573d6000803e3d6000fd5b505050506040513d60208110156125ff57600080fd5b5051905090565b600080600080600080600080600089600081118015612626575060075481105b60408051808201909152601681527f46494e414e43455f4e4f5f5452414e53414354494f4e0000000000000000000060208201529015156126c3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50505060009889525050600660205250506040909420805460018201546004830154600284015460039094015467ffffffffffffffff700100000000000000000000000000000000830481169a959950909750808216965073ffffffffffffffffffffffffffffffffffffffff9384169550928216937401000000000000000000000000000000000000000090920460ff1692680100000000000000009091041690565b604080517f4348414e47455f504552494f445f524f4c4500000000000000000000000000008152905190819003601201902081565b604080517f4348414e47455f425544474554535f524f4c45000000000000000000000000008152905190819003601301902081565b806000811180156127e3575060055481105b60408051808201909152601c81527f46494e414e43455f4e4f5f5343484544554c45445f5041594d454e54000000006020820152901515612880576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50600061288e6102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e0000000000602082015290915081151561292e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50600083815260046020908152604091829020600101548251808401909352601883527f46494e414e43455f5041594d454e545f524543454956455200000000000000009183019190915273ffffffffffffffffffffffffffffffffffffffff1633146129f7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50611d4083614c21565b60095460408051808201909152601181527f46494e414e43455f4e4f5f504552494f44000000000000000000000000000000602082015260009182918291829182918291889167ffffffffffffffff90811690831610612abd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5067ffffffffffffffff881660008181526008602052604090209250612ae16144ae565b8354600185015460029095015467ffffffffffffffff928316939093149b8183169b5068010000000000000000909104909116985092965094509092505050565b604080517f4348414e47455f504552494f445f524f4c45000000000000000000000000000081529051908190036012019020600154612b6e9067ffffffffffffffff8085169116614bc6565b612b7933838361379c565b60408051808201909152600f81527f4150505f415554485f4641494c454400000000000000000000000000000000006020820152901515612c16576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506000612c246102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515612cc4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060408051808201909152601c81527f46494e414e43455f5345545f504552494f445f544f4f5f53484f52540000000060208201526201518067ffffffffffffffff86161015612d70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506001805467ffffffffffffffff86167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909116811790915560408051918252517fa32389dd0d5a3bf7cc635f8c30fee3b70d06a6c547d6dbf31628378ee267bfc99181900360200190a150505050565b60095467ffffffffffffffff1681565b604080517f4348414e47455f425544474554535f524f4c45000000000000000000000000008152815190819003601301902073ffffffffffffffffffffffffffffffffffffffff8416600090815260026020908152838220546003909152929020549091612e6b918591859160ff16611dbf576000611dc2565b612e7633838361379c565b60408051808201909152600f81527f4150505f415554485f4641494c454400000000000000000000000000000000006020820152901515612f13576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506000612f216102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515612fc1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5073ffffffffffffffffffffffffffffffffffffffff85166000908152600260209081526040808320879055600390915290205460ff16151561304d5773ffffffffffffffffffffffffffffffffffffffff8516600090815260036020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b6040805185815260016020820152815173ffffffffffffffffffffffffffffffffffffffff8816927f6e768d8fe4a1460cae6d5af9382c3e9abbc41f66f2ec91fda24b12e3c2796f03928290030190a25050505050565b60006130ae610c3b565b1592915050565b60006130e07fd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b614ec1565b905090565b60006130e07febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e614ec1565b600061311a610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a454400000000000000000000000060208201529015156131b7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060006131c56102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515613265576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5073ffffffffffffffffffffffffffffffffffffffff8316156132ad576132a873ffffffffffffffffffffffffffffffffffffffff84163063ffffffff614ec916565b6132b0565b30315b60408051808201909152601b81527f46494e414e43455f5245434f5645525f414d4f554e545f5a45524f0000000000602082015290925060008311613351576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50611d4083836040805190810160405280601081526020017f5265636f76657220746f205661756c7400000000000000000000000000000000815250306000610d51565b604080517f455845435554455f5041594d454e54535f524f4c4500000000000000000000008152905190819003601501902081565b60006133d4610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515613471576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506130e06144ae565b6000806000613488846130a4565b60408051808201909152601281527f5245434f5645525f444953414c4c4f57454400000000000000000000000000006020820152901515613525576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5061352e612568565b925061353983614e6a565b60408051808201909152601a81527f5245434f5645525f5641554c545f4e4f545f434f4e545241435400000000000060208201529015156135d6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5073ffffffffffffffffffffffffffffffffffffffff84161515613641576040513031925073ffffffffffffffffffffffffffffffffffffffff84169083156108fc029084906000818181858888f1935050505015801561363b573d6000803e3d6000fd5b50613731565b508261366973ffffffffffffffffffffffffffffffffffffffff82163063ffffffff614ec916565b915061369273ffffffffffffffffffffffffffffffffffffffff8216848463ffffffff61500216565b60408051808201909152601d81527f5245434f5645525f544f4b454e5f5452414e534645525f4641494c4544000000602082015290151561372f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b505b8373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f596caf56044b55fb8c4ca640089bbc2b63cae3e978b851f5745cbb7c5b288e02846040518082815260200191505060405180910390a350505050565b6000806137a7610c3b565b15156137b65760009150613924565b6137be61401c565b905073ffffffffffffffffffffffffffffffffffffffff811615156137e65760009150613924565b8073ffffffffffffffffffffffffffffffffffffffff1663fdef910686308761380e88615091565b6040517c010000000000000000000000000000000000000000000000000000000063ffffffff871602815273ffffffffffffffffffffffffffffffffffffffff808616600483019081529085166024830152604482018490526080606483019081528351608484015283519192909160a490910190602085019080838360005b838110156138a657818101518382015260200161388e565b50505050905090810190601f1680156138d35780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b1580156138f557600080fd5b505af1158015613909573d6000803e3d6000fd5b505050506040513d602081101561391f57600080fd5b505191505b509392505050565b60008061393761401c565b604080517fbe00bbd80000000000000000000000000000000000000000000000000000000081527fd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb60048201527fddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd616024820152905173ffffffffffffffffffffffffffffffffffffffff929092169163be00bbd8916044808201926020929091908290030181600087803b15801561217857600080fd5b60006139f8610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515613a95576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50613a9f82610c6a565b92915050565b6000613aaf610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515613b4c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b505060015467ffffffffffffffff1690565b613b66610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515613c03576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506000613c116102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e00000000006020820152909150811515613cb1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060408051808201909152601b81527f46494e414e43455f4445504f5349545f414d4f554e545f5a45524f0000000000602082015260008511613d50576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5073ffffffffffffffffffffffffffffffffffffffff85161515613e0d5760408051808201909152601a81527f46494e414e43455f4554485f56414c55455f4d49534d415443480000000000006020820152348514613e0b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b505b61103c858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050336001610d51565b600081600081118015613e61575060055481105b60408051808201909152601c81527f46494e414e43455f4e4f5f5343484544554c45445f5041594d454e54000000006020820152901515613efe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50613f088361509b565b91505b50919050565b60095460408051808201909152601181527f46494e414e43455f4e4f5f504552494f4400000000000000000000000000000060208201526000918291829186919067ffffffffffffffff90811690831610613fc8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5050505067ffffffffffffffff92909216600090815260086020908152604080832073ffffffffffffffffffffffffffffffffffffffff949094168352600390930190522080546001909101549092909150565b60006130e07f4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b614ec1565b60055481565b600060001961405a6130e5565b14905090565b600061406a610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a45440000000000000000000000006020820152901515614107576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506141128383615164565b9392505050565b604080517f4d414e4147455f5041594d454e54535f524f4c450000000000000000000000008152905190819003601401902081565b60075481565b600061415e610c3b565b60408051808201909152601481527f494e49545f4e4f545f494e495449414c495a454400000000000000000000000060208201529015156141fb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50613a9f82615228565b604080517f4352454154455f5041594d454e54535f524f4c450000000000000000000000008152905190819003601401902061424f868686600019600161424a6152f3565b61488f565b61425a33838361379c565b60408051808201909152600f81527f4150505f415554485f4641494c4544000000000000000000000000000000000060208201529015156142f7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060006143056102f2610c64565b60408051808201909152601b81527f46494e414e43455f434f4d504c4554455f5452414e534954494f4e000000000060208201529091508115156143a5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5060408051808201909152601f81527f46494e414e43455f4e45575f5041594d454e545f414d4f554e545f5a45524f00602082015260008711614444576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506144848888886000808a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437506152f7945050505050565b5050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b4390565b60095467ffffffffffffffff166000190190565b60006130e06144cf6152f3565b6153b5565b60408051808201909152601281527f4d4154485f5355425f554e444552464c4f5700000000000000000000000000006020820152600090819084841115614577576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b505050900390565b60408051808201909152601381527f4d41544836345f4144445f4f564552464c4f570000000000000000000000000060208201526000908383019067ffffffffffffffff8086169083161015613924576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b6009805467ffffffffffffffff808216600181810183167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000948516179094556000818152600860205260408120805487851695168517815594549094919391926000199181168701919091019190821610156146ac57506000195b81547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff83811682029290921780855560408051828516815292909104831660208301528051928616927fe183df4530c4b573af76d47f020d4b86e418cef40ed4c9ce924b563e791b832c9281900390910190a28193505b505050919050565b614750600185858560008087615465565b50505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790526000906147ed868261579d565b9695505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052600090614886858261579d565b95945050505050565b60408051600680825260e082019092526060916020820160c0803883390190505090508673ffffffffffffffffffffffffffffffffffffffff168160008151811015156148d857fe5b60209081029091010152805173ffffffffffffffffffffffffffffffffffffffff8716908290600190811061490957fe5b60209081029091010152805185908290600290811061492457fe5b60209081029091010152805184908290600390811061493f57fe5b60209081029091010152805183908290600490811061495a57fe5b60209081029091010152805182908290600590811061497557fe5b602090810290910101529695505050505050565b600081815260046020908152604080832060028101548251808401909352601883527f46494e414e43455f5041594d454e545f494e4143544956450000000000000000938301939093529183919074010000000000000000000000000000000000000000900460ff1615614a59576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50600090505b614a676144c2565b67ffffffffffffffff16614a7a8561509b565b67ffffffffffffffff1611158015614a9c575060148167ffffffffffffffff16105b15614bb55781546003830154614ac89173ffffffffffffffffffffffffffffffffffffffff1690615164565b1515614b06576040805185815290517f5f352e4123f4620cacbb8eb0dd683705aaa3e1f9384adbbd85b665b205097f519181900360200190a1614bb5565b60048201805467ffffffffffffffff7801000000000000000000000000000000000000000000000000808304821660019081018316820277ffffffffffffffffffffffffffffffffffffffffffffffff909416939093179384905585548684015460038801546040805160208101909152600081529790950196614bb09673ffffffffffffffffffffffffffffffffffffffff93841696929093169491938b9304909116906157eb565b614a5f565b67ffffffffffffffff169392505050565b604080516002808252606080830184529260208301908038833901905050905082816000815181101515614bf657fe5b602090810290910101528051829082906001908110614c1157fe5b6020908102909101015292915050565b6000614c2c82614989565b9050801515614d8757614c3d6144c2565b67ffffffffffffffff16614c508361509b565b67ffffffffffffffff1611614cf357604080518082018252601b81527f46494e414e43455f455845435554455f5041594d454e545f4e554d0000000000602080830191825292517f08c379a0000000000000000000000000000000000000000000000000000000008152600481019384528251602482015282519293928392604490920191908083836000838110156102a9578181015183820152602001610291565b604080518082018252601c81527f46494e414e43455f455845435554455f5041594d454e545f54494d4500000000602080830191825292517f08c379a0000000000000000000000000000000000000000000000000000000008152600481019384528251602482015282519293928392604490920191908083836000838110156102a9578181015183820152602001610291565b5050565b614d936130e5565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015614e2f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b50614e68614e3b6144aa565b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e9063ffffffff61589b16565b565b60008073ffffffffffffffffffffffffffffffffffffffff83161515614e935760009150613f0b565b50506000903b1190565b60606148868573ffffffffffffffffffffffffffffffffffffffff1685858561589f565b5490565b5490565b6040805173ffffffffffffffffffffffffffffffffffffffff83166024808301919091528251808303909101815260449091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a08231000000000000000000000000000000000000000000000000000000001790526000908180614f568684615935565b60408051808201909152601c81527f534146455f4552435f32305f42414c414e43455f52455645525445440000000060208201529193509150821515614ff8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5095945050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052600090614886858261579d565b8051602002815290565b60008181526004602081905260408220908101548290819067ffffffffffffffff70010000000000000000000000000000000082048116780100000000000000000000000000000000000000000000000090920416106150ff576000199350614737565b60048301546151429067ffffffffffffffff7801000000000000000000000000000000000000000000000000820481169168010000000000000000900416615966565b60048401549092506148869067ffffffffffffffff168363ffffffff61457f16565b60008161517084615228565b10158015614112575060008054604080517fe3d670d700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff878116600483015291518694929093169263e3d670d792602480840193602093929083900390910190829087803b1580156151f357600080fd5b505af1158015615207573d6000803e3d6000fd5b505050506040513d602081101561521d57600080fd5b505110159392505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600360205260408120548190819060ff161515615265576000199250610d4a565b73ffffffffffffffffffffffffffffffffffffffff841660009081526002602052604081205492506008906152986144ae565b67ffffffffffffffff1681526020808201929092526040908101600090812073ffffffffffffffffffffffffffffffffffffffff8816825260030190925290205490508181106152eb5760009250610d4a565b900392915050565b4290565b8361530187615228565b60408051808201909152601881527f46494e414e43455f52454d41494e494e475f4255444745540000000000000000602082015291111561539e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b506153ad8686868686866157eb565b505050505050565b60408051808201909152601581527f55494e5436345f4e554d4245525f544f4f5f4249470000000000000000000000602082015260009067ffffffffffffffff83111561545e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b5090919050565b60008060008060006154756144ae565b9450600860008667ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060030160008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002093508b156155055760018401546154fb908a63ffffffff615a2016565b600185015561551a565b8354615517908a63ffffffff615a2016565b84555b600760008154809291906001019190505592506006600084815260200190815260200160002091508a8260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550898260010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508b8260010160146101000a81548160ff021916908315150217905550888260020181905550878260030181905550868260040160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506156296144c2565b6004830180547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff93841602177fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000009288169283021790556000908152600860205260409020600181015490915015156156ca57600181018390555b8973ffffffffffffffffffffffffffffffffffffffff16837f5b2c6f4cb53711ae51d600df17fa68f8239b4a704f766c99642f667d1d7bd40e8e8c8a604051808415151515815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561575357818101518382015260200161573b565b50505050905090810190601f1680156157805780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a3505050505050505050505050565b6000806040516020818551602087016000895af160008111156157e1573d80156157ce57602081146157d7576157df565b600193506157df565b600183511493505b505b5090949350505050565b6157fb6000878787878787615465565b60008054604080517fbeabacc800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a811660048301528981166024830152604482018990529151919092169263beabacc8926064808201939182900301818387803b15801561587b57600080fd5b505af115801561588f573d6000803e3d6000fd5b50505050505050505050565b9055565b60408051600480825260a0820190925260609160208201608080388339019050509050848160008151811015156158d257fe5b6020908102909101015280518490829060019081106158ed57fe5b60209081029091010152805183908290600290811061590857fe5b60209081029091010152805182908290600390811061592357fe5b60209081029091010152949350505050565b6000806000806040516020818751602089018a5afa9250600083111561595a57805191505b50909590945092505050565b60408051808201909152601381527f4d41544836345f4d554c5f4f564552464c4f5700000000000000000000000000602082015260009067ffffffffffffffff8481169084160290680100000000000000008210613924576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a9578181015183820152602001610291565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f5700000000000000000000000000000060208201526000908383019084821015613924576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382528381815181526020019150805190602001908083836000838110156102a95781810151838201526020016102915600a165627a7a723058204fed94733de008d6b4964e029b08cddd21d45e3912ff9e0afb755ee567a5c5200029
Swarm Source
bzzr://4fed94733de008d6b4964e029b08cddd21d45e3912ff9e0afb755ee567a5c520
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.