Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 144 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Execute | 11762862 | 1484 days ago | IN | 0 ETH | 0.00861703 | ||||
Execute | 11668319 | 1499 days ago | IN | 0 ETH | 0.02069808 | ||||
Execute | 11667895 | 1499 days ago | IN | 0 ETH | 0.0066204 | ||||
Cancel | 11667885 | 1499 days ago | IN | 0 ETH | 0.0115135 | ||||
Cancel | 11667883 | 1499 days ago | IN | 0 ETH | 0.00604929 | ||||
Cancel | 11667880 | 1499 days ago | IN | 0 ETH | 0.01385393 | ||||
Cancel | 11667878 | 1499 days ago | IN | 0 ETH | 0.00791183 | ||||
Cancel | 11667868 | 1499 days ago | IN | 0 ETH | 0.01108204 | ||||
Cancel | 11667860 | 1499 days ago | IN | 0 ETH | 0.01102147 | ||||
Execute | 11667849 | 1499 days ago | IN | 0 ETH | 0.0339066 | ||||
Cancel | 11667843 | 1499 days ago | IN | 0 ETH | 0.00650193 | ||||
Cancel | 11667834 | 1499 days ago | IN | 0 ETH | 0.01468843 | ||||
Cancel | 11667830 | 1499 days ago | IN | 0 ETH | 0.01228171 | ||||
Cancel | 11667823 | 1499 days ago | IN | 0 ETH | 0.01457529 | ||||
Execute | 11667811 | 1499 days ago | IN | 0 ETH | 0.04275 | ||||
Cancel | 11667810 | 1499 days ago | IN | 0 ETH | 0.0147627 | ||||
Execute | 11657284 | 1500 days ago | IN | 0 ETH | 0.00448696 | ||||
Execute | 11579363 | 1512 days ago | IN | 0 ETH | 0.00663472 | ||||
Execute | 11579346 | 1512 days ago | IN | 0 ETH | 0.00576138 | ||||
Execute | 11576659 | 1513 days ago | IN | 0 ETH | 0.00629736 | ||||
Execute | 11259983 | 1561 days ago | IN | 0 ETH | 0.00280201 | ||||
Execute | 11259976 | 1561 days ago | IN | 0 ETH | 0.00343635 | ||||
Execute | 11225757 | 1566 days ago | IN | 0 ETH | 0.00224882 | ||||
Execute | 11040382 | 1595 days ago | IN | 0 ETH | 0.01176546 | ||||
Execute | 11040382 | 1595 days ago | IN | 0 ETH | 0.00953333 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
Core
Compiler Version
v0.5.16+commit.9c3226ce
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-03-24 */ /** Source code of Opium Protocol Web https://opium.network Telegram https://t.me/opium_network Twitter https://twitter.com/opium_network */ // File: LICENSE /** The software and documentation available in this repository (the "Software") is protected by copyright law and accessible pursuant to the license set forth below. Copyright © 2020 Blockeys BV. All rights reserved. Permission is hereby granted, free of charge, to any person or organization obtaining the Software (the “Licensee”) to privately study, review, and analyze the Software. Licensee shall not use the Software for any other purpose. Licensee shall not modify, transfer, assign, share, or sub-license the Software or any derivative works of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: openzeppelin-solidity/contracts/math/SafeMath.sol pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot 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-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File: openzeppelin-solidity/contracts/utils/Address.sol pragma solidity ^0.5.5; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * This test is non-exhaustive, and there may be false-negatives: during the * execution of a contract's constructor, its address will be reported as * not containing a contract. * * IMPORTANT: It is unsafe to assume that an address for which this * function returns false is an externally-owned account (EOA) and not a * contract. */ function isContract(address account) internal view returns (bool) { // This method relies in extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != 0x0 && codehash != accountHash); } /** * @dev Converts an `address` into `address payable`. Note that this is * simply a type cast: the actual underlying value is not changed. * * _Available since v2.4.0._ */ function toPayable(address account) internal pure returns (address payable) { return address(uint160(account)); } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. * * _Available since v2.4.0._ */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-call-value (bool success, ) = recipient.call.value(amount)(""); require(success, "Address: unable to send value, recipient may have reverted"); } } // File: openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol pragma solidity ^0.5.0; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. // A Solidity high level call has three parts: // 1. The target address is checked to verify it contains contract code // 2. The call itself is made, and success asserted // 3. The return value is decoded, which in turn checks the size of the returned data. // solhint-disable-next-line max-line-length require(address(token).isContract(), "SafeERC20: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } // File: openzeppelin-solidity/contracts/utils/ReentrancyGuard.sol pragma solidity ^0.5.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. */ contract ReentrancyGuard { // counter to allow mutex lock with only one SSTORE operation uint256 private _guardCounter; constructor () internal { // The counter starts at one to prevent changing it from zero to a non-zero // value, which is a more expensive operation. _guardCounter = 1; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { _guardCounter += 1; uint256 localCounter = _guardCounter; _; require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call"); } } // File: erc721o/contracts/Libs/LibPosition.sol pragma solidity ^0.5.4; library LibPosition { function getLongTokenId(bytes32 _hash) public pure returns (uint256 tokenId) { tokenId = uint256(keccak256(abi.encodePacked(_hash, "LONG"))); } function getShortTokenId(bytes32 _hash) public pure returns (uint256 tokenId) { tokenId = uint256(keccak256(abi.encodePacked(_hash, "SHORT"))); } } // File: contracts/Lib/LibDerivative.sol pragma solidity 0.5.16; pragma experimental ABIEncoderV2; /// @title Opium.Lib.LibDerivative contract should be inherited by contracts that use Derivative structure and calculate derivativeHash contract LibDerivative { // Opium derivative structure (ticker) definition struct Derivative { // Margin parameter for syntheticId uint256 margin; // Maturity of derivative uint256 endTime; // Additional parameters for syntheticId uint256[] params; // oracleId of derivative address oracleId; // Margin token address of derivative address token; // syntheticId of derivative address syntheticId; } /// @notice Calculates hash of provided Derivative /// @param _derivative Derivative Instance of derivative to hash /// @return derivativeHash bytes32 Derivative hash function getDerivativeHash(Derivative memory _derivative) public pure returns (bytes32 derivativeHash) { derivativeHash = keccak256(abi.encodePacked( _derivative.margin, _derivative.endTime, _derivative.params, _derivative.oracleId, _derivative.token, _derivative.syntheticId )); } } // File: contracts/Interface/IDerivativeLogic.sol pragma solidity 0.5.16; /// @title Opium.Interface.IDerivativeLogic contract is an interface that every syntheticId should implement contract IDerivativeLogic is LibDerivative { /// @notice Validates ticker /// @param _derivative Derivative Instance of derivative to validate /// @return Returns boolean whether ticker is valid function validateInput(Derivative memory _derivative) public view returns (bool); /// @notice Calculates margin required for derivative creation /// @param _derivative Derivative Instance of derivative /// @return buyerMargin uint256 Margin needed from buyer (LONG position) /// @return sellerMargin uint256 Margin needed from seller (SHORT position) function getMargin(Derivative memory _derivative) public view returns (uint256 buyerMargin, uint256 sellerMargin); /// @notice Calculates payout for derivative execution /// @param _derivative Derivative Instance of derivative /// @param _result uint256 Data retrieved from oracleId on the maturity /// @return buyerPayout uint256 Payout in ratio for buyer (LONG position holder) /// @return sellerPayout uint256 Payout in ratio for seller (SHORT position holder) function getExecutionPayout(Derivative memory _derivative, uint256 _result) public view returns (uint256 buyerPayout, uint256 sellerPayout); /// @notice Returns syntheticId author address for Opium commissions /// @return authorAddress address The address of syntheticId address function getAuthorAddress() public view returns (address authorAddress); /// @notice Returns syntheticId author commission in base of COMMISSION_BASE /// @return commission uint256 Author commission function getAuthorCommission() public view returns (uint256 commission); /// @notice Returns whether thirdparty could execute on derivative's owner's behalf /// @param _derivativeOwner address Derivative owner address /// @return Returns boolean whether _derivativeOwner allowed third party execution function thirdpartyExecutionAllowed(address _derivativeOwner) public view returns (bool); /// @notice Returns whether syntheticId implements pool logic /// @return Returns whether syntheticId implements pool logic function isPool() public view returns (bool); /// @notice Sets whether thirds parties are allowed or not to execute derivative's on msg.sender's behalf /// @param _allow bool Flag for execution allowance function allowThirdpartyExecution(bool _allow) public; // Event with syntheticId metadata JSON string (for DIB.ONE derivative explorer) event MetadataSet(string metadata); } // File: contracts/Errors/CoreErrors.sol pragma solidity 0.5.16; contract CoreErrors { string constant internal ERROR_CORE_NOT_POOL = "CORE:NOT_POOL"; string constant internal ERROR_CORE_CANT_BE_POOL = "CORE:CANT_BE_POOL"; string constant internal ERROR_CORE_TICKER_WAS_CANCELLED = "CORE:TICKER_WAS_CANCELLED"; string constant internal ERROR_CORE_SYNTHETIC_VALIDATION_ERROR = "CORE:SYNTHETIC_VALIDATION_ERROR"; string constant internal ERROR_CORE_NOT_ENOUGH_TOKEN_ALLOWANCE = "CORE:NOT_ENOUGH_TOKEN_ALLOWANCE"; string constant internal ERROR_CORE_TOKEN_IDS_AND_QUANTITIES_LENGTH_DOES_NOT_MATCH = "CORE:TOKEN_IDS_AND_QUANTITIES_LENGTH_DOES_NOT_MATCH"; string constant internal ERROR_CORE_TOKEN_IDS_AND_DERIVATIVES_LENGTH_DOES_NOT_MATCH = "CORE:TOKEN_IDS_AND_DERIVATIVES_LENGTH_DOES_NOT_MATCH"; string constant internal ERROR_CORE_EXECUTION_BEFORE_MATURITY_NOT_ALLOWED = "CORE:EXECUTION_BEFORE_MATURITY_NOT_ALLOWED"; string constant internal ERROR_CORE_SYNTHETIC_EXECUTION_WAS_NOT_ALLOWED = "CORE:SYNTHETIC_EXECUTION_WAS_NOT_ALLOWED"; string constant internal ERROR_CORE_INSUFFICIENT_POOL_BALANCE = "CORE:INSUFFICIENT_POOL_BALANCE"; string constant internal ERROR_CORE_CANT_CANCEL_DUMMY_ORACLE_ID = "CORE:CANT_CANCEL_DUMMY_ORACLE_ID"; string constant internal ERROR_CORE_CANCELLATION_IS_NOT_ALLOWED = "CORE:CANCELLATION_IS_NOT_ALLOWED"; string constant internal ERROR_CORE_UNKNOWN_POSITION_TYPE = "CORE:UNKNOWN_POSITION_TYPE"; } // File: contracts/Errors/RegistryErrors.sol pragma solidity 0.5.16; contract RegistryErrors { string constant internal ERROR_REGISTRY_ONLY_INITIALIZER = "REGISTRY:ONLY_INITIALIZER"; string constant internal ERROR_REGISTRY_ONLY_OPIUM_ADDRESS_ALLOWED = "REGISTRY:ONLY_OPIUM_ADDRESS_ALLOWED"; string constant internal ERROR_REGISTRY_CANT_BE_ZERO_ADDRESS = "REGISTRY:CANT_BE_ZERO_ADDRESS"; string constant internal ERROR_REGISTRY_ALREADY_SET = "REGISTRY:ALREADY_SET"; } // File: contracts/Registry.sol pragma solidity 0.5.16; /// @title Opium.Registry contract keeps addresses of deployed Opium contracts set to allow them route and communicate to each other contract Registry is RegistryErrors { // Address of Opium.TokenMinter contract address private minter; // Address of Opium.Core contract address private core; // Address of Opium.OracleAggregator contract address private oracleAggregator; // Address of Opium.SyntheticAggregator contract address private syntheticAggregator; // Address of Opium.TokenSpender contract address private tokenSpender; // Address of Opium commission receiver address private opiumAddress; // Address of Opium contract set deployer address public initializer; /// @notice This modifier restricts access to functions, which could be called only by initializer modifier onlyInitializer() { require(msg.sender == initializer, ERROR_REGISTRY_ONLY_INITIALIZER); _; } /// @notice Sets initializer constructor() public { initializer = msg.sender; } // SETTERS /// @notice Sets Opium.TokenMinter, Opium.Core, Opium.OracleAggregator, Opium.SyntheticAggregator, Opium.TokenSpender, Opium commission receiver addresses and allows to do it only once /// @param _minter address Address of Opium.TokenMinter /// @param _core address Address of Opium.Core /// @param _oracleAggregator address Address of Opium.OracleAggregator /// @param _syntheticAggregator address Address of Opium.SyntheticAggregator /// @param _tokenSpender address Address of Opium.TokenSpender /// @param _opiumAddress address Address of Opium commission receiver function init( address _minter, address _core, address _oracleAggregator, address _syntheticAggregator, address _tokenSpender, address _opiumAddress ) external onlyInitializer { require( minter == address(0) && core == address(0) && oracleAggregator == address(0) && syntheticAggregator == address(0) && tokenSpender == address(0) && opiumAddress == address(0), ERROR_REGISTRY_ALREADY_SET ); require( _minter != address(0) && _core != address(0) && _oracleAggregator != address(0) && _syntheticAggregator != address(0) && _tokenSpender != address(0) && _opiumAddress != address(0), ERROR_REGISTRY_CANT_BE_ZERO_ADDRESS ); minter = _minter; core = _core; oracleAggregator = _oracleAggregator; syntheticAggregator = _syntheticAggregator; tokenSpender = _tokenSpender; opiumAddress = _opiumAddress; } /// @notice Allows opium commission receiver address to change itself /// @param _opiumAddress address New opium commission receiver address function changeOpiumAddress(address _opiumAddress) external { require(opiumAddress == msg.sender, ERROR_REGISTRY_ONLY_OPIUM_ADDRESS_ALLOWED); require(_opiumAddress != address(0), ERROR_REGISTRY_CANT_BE_ZERO_ADDRESS); opiumAddress = _opiumAddress; } // GETTERS /// @notice Returns address of Opium.TokenMinter /// @param result address Address of Opium.TokenMinter function getMinter() external view returns (address result) { return minter; } /// @notice Returns address of Opium.Core /// @param result address Address of Opium.Core function getCore() external view returns (address result) { return core; } /// @notice Returns address of Opium.OracleAggregator /// @param result address Address of Opium.OracleAggregator function getOracleAggregator() external view returns (address result) { return oracleAggregator; } /// @notice Returns address of Opium.SyntheticAggregator /// @param result address Address of Opium.SyntheticAggregator function getSyntheticAggregator() external view returns (address result) { return syntheticAggregator; } /// @notice Returns address of Opium.TokenSpender /// @param result address Address of Opium.TokenSpender function getTokenSpender() external view returns (address result) { return tokenSpender; } /// @notice Returns address of Opium commission receiver /// @param result address Address of Opium commission receiver function getOpiumAddress() external view returns (address result) { return opiumAddress; } } // File: contracts/Errors/UsingRegistryErrors.sol pragma solidity 0.5.16; contract UsingRegistryErrors { string constant internal ERROR_USING_REGISTRY_ONLY_CORE_ALLOWED = "USING_REGISTRY:ONLY_CORE_ALLOWED"; } // File: contracts/Lib/UsingRegistry.sol pragma solidity 0.5.16; /// @title Opium.Lib.UsingRegistry contract should be inherited by contracts, that are going to use Opium.Registry contract UsingRegistry is UsingRegistryErrors { // Emitted when registry instance is set event RegistrySet(address registry); // Instance of Opium.Registry contract Registry internal registry; /// @notice This modifier restricts access to functions, which could be called only by Opium.Core modifier onlyCore() { require(msg.sender == registry.getCore(), ERROR_USING_REGISTRY_ONLY_CORE_ALLOWED); _; } /// @notice Defines registry instance and emits appropriate event constructor(address _registry) public { registry = Registry(_registry); emit RegistrySet(_registry); } /// @notice Getter for registry variable /// @return address Address of registry set in current contract function getRegistry() external view returns (address) { return address(registry); } } // File: contracts/Lib/LibCommission.sol pragma solidity 0.5.16; /// @title Opium.Lib.LibCommission contract defines constants for Opium commissions contract LibCommission { // Represents 100% base for commissions calculation uint256 constant public COMMISSION_BASE = 10000; // Represents 100% base for Opium commission uint256 constant public OPIUM_COMMISSION_BASE = 10; // Represents which part of `syntheticId` author commissions goes to opium uint256 constant public OPIUM_COMMISSION_PART = 1; } // File: openzeppelin-solidity/contracts/token/ERC721/IERC721Receiver.sol pragma solidity ^0.5.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ contract IERC721Receiver { /** * @notice Handle the receipt of an NFT * @dev The ERC721 smart contract calls this function on the recipient * after a {IERC721-safeTransferFrom}. This function MUST return the function selector, * otherwise the caller will revert the transaction. The selector to be * returned can be obtained as `this.onERC721Received.selector`. This * function MAY throw to revert and reject the transfer. * Note: the ERC721 contract address is always the message sender. * @param operator The address which called `safeTransferFrom` function * @param from The address which previously owned the token * @param tokenId The NFT identifier which is being transferred * @param data Additional data with no specified format * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` */ function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) public returns (bytes4); } // File: erc721o/contracts/Libs/UintArray.sol pragma solidity ^0.5.4; library UintArray { function indexOf(uint256[] memory A, uint256 a) internal pure returns (uint256, bool) { uint256 length = A.length; for (uint256 i = 0; i < length; i++) { if (A[i] == a) { return (i, true); } } return (0, false); } function contains(uint256[] memory A, uint256 a) internal pure returns (bool) { (, bool isIn) = indexOf(A, a); return isIn; } function difference(uint256[] memory A, uint256[] memory B) internal pure returns (uint256[] memory, uint256[] memory) { uint256 length = A.length; bool[] memory includeMap = new bool[](length); uint256 count = 0; // First count the new length because can't push for in-memory arrays for (uint256 i = 0; i < length; i++) { uint256 e = A[i]; if (!contains(B, e)) { includeMap[i] = true; count++; } } uint256[] memory newUints = new uint256[](count); uint256[] memory newUintsIdxs = new uint256[](count); uint256 j = 0; for (uint256 i = 0; i < length; i++) { if (includeMap[i]) { newUints[j] = A[i]; newUintsIdxs[j] = i; j++; } } return (newUints, newUintsIdxs); } function intersect(uint256[] memory A, uint256[] memory B) internal pure returns (uint256[] memory, uint256[] memory, uint256[] memory) { uint256 length = A.length; bool[] memory includeMap = new bool[](length); uint256 newLength = 0; for (uint256 i = 0; i < length; i++) { if (contains(B, A[i])) { includeMap[i] = true; newLength++; } } uint256[] memory newUints = new uint256[](newLength); uint256[] memory newUintsAIdxs = new uint256[](newLength); uint256[] memory newUintsBIdxs = new uint256[](newLength); uint256 j = 0; for (uint256 i = 0; i < length; i++) { if (includeMap[i]) { newUints[j] = A[i]; newUintsAIdxs[j] = i; (newUintsBIdxs[j], ) = indexOf(B, A[i]); j++; } } return (newUints, newUintsAIdxs, newUintsBIdxs); } function isUnique(uint256[] memory A) internal pure returns (bool) { uint256 length = A.length; for (uint256 i = 0; i < length; i++) { (uint256 idx, bool isIn) = indexOf(A, A[i]); if (isIn && idx < i) { return false; } } return true; } } // File: openzeppelin-solidity/contracts/introspection/IERC165.sol pragma solidity ^0.5.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } // File: openzeppelin-solidity/contracts/introspection/ERC165.sol pragma solidity ^0.5.0; /** * @dev Implementation of the {IERC165} interface. * * Contracts may inherit from this and call {_registerInterface} to declare * their support of an interface. */ contract ERC165 is IERC165 { /* * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 */ bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; /** * @dev Mapping of interface ids to whether or not it's supported. */ mapping(bytes4 => bool) private _supportedInterfaces; constructor () internal { // Derived contracts need only register support for their own interfaces, // we register support for ERC165 itself here _registerInterface(_INTERFACE_ID_ERC165); } /** * @dev See {IERC165-supportsInterface}. * * Time complexity O(1), guaranteed to always use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool) { return _supportedInterfaces[interfaceId]; } /** * @dev Registers the contract as an implementer of the interface defined by * `interfaceId`. Support of the actual ERC165 interface is automatic and * registering its interface id is not required. * * See {IERC165-supportsInterface}. * * Requirements: * * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). */ function _registerInterface(bytes4 interfaceId) internal { require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } } // File: openzeppelin-solidity/contracts/token/ERC721/IERC721.sol pragma solidity ^0.5.0; /** * @dev Required interface of an ERC721 compliant contract. */ contract IERC721 is IERC165 { event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of NFTs in `owner`'s account. */ function balanceOf(address owner) public view returns (uint256 balance); /** * @dev Returns the owner of the NFT specified by `tokenId`. */ function ownerOf(uint256 tokenId) public view returns (address owner); /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). * * * * Requirements: * - `from`, `to` cannot be zero. * - `tokenId` must be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this * NFT by either {approve} or {setApprovalForAll}. */ function safeTransferFrom(address from, address to, uint256 tokenId) public; /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). * * Requirements: * - If the caller is not `from`, it must be approved to move this NFT by * either {approve} or {setApprovalForAll}. */ function transferFrom(address from, address to, uint256 tokenId) public; function approve(address to, uint256 tokenId) public; function getApproved(uint256 tokenId) public view returns (address operator); function setApprovalForAll(address operator, bool _approved) public; function isApprovedForAll(address owner, address operator) public view returns (bool); function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public; } // File: erc721o/contracts/Interfaces/IERC721O.sol pragma solidity ^0.5.4; contract IERC721O { function name() external view returns (string memory); function symbol() external view returns (string memory); function implementsERC721O() public pure returns (bool); function ownerOf(uint256 _tokenId) public view returns (address _owner); function balanceOf(address owner) public view returns (uint256); function balanceOf(address owner, uint256 tokenId) public view returns (uint256); function tokensOwned(address owner) public view returns (uint256[] memory, uint256[] memory); function transfer(address to, uint256 tokenId, uint256 quantity) public; function transferFrom(address from, address to, uint256 tokenId, uint256 quantity) public; // Fungible Safe Transfer From function safeTransferFrom(address from, address to, uint256 tokenId, uint256 _amount) public; function safeTransferFrom(address from, address to, uint256 tokenId, uint256 _amount, bytes memory data) public; // Batch Safe Transfer From function safeBatchTransferFrom(address _from, address _to, uint256[] memory tokenIds, uint256[] memory _amounts, bytes memory _data) public; // Required Events event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event TransferWithQuantity(address indexed from, address indexed to, uint256 indexed tokenId, uint256 quantity); event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); event BatchTransfer(address indexed from, address indexed to, uint256[] tokenTypes, uint256[] amounts); event Composition(uint256 portfolioId, uint256[] tokenIds, uint256[] tokenRatio); } // File: erc721o/contracts/Interfaces/IERC721OReceiver.sol pragma solidity ^0.5.4; /** * @title ERC721O token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721O contracts. */ contract IERC721OReceiver { /** * @dev Magic value to be returned upon successful reception of an amount of ERC721O tokens * ERC721O_RECEIVED = `bytes4(keccak256("onERC721OReceived(address,address,uint256,uint256,bytes)"))` = 0xf891ffe0 * ERC721O_BATCH_RECEIVED = `bytes4(keccak256("onERC721OBatchReceived(address,address,uint256[],uint256[],bytes)"))` = 0xd0e17c0b */ bytes4 constant internal ERC721O_RECEIVED = 0xf891ffe0; bytes4 constant internal ERC721O_BATCH_RECEIVED = 0xd0e17c0b; function onERC721OReceived( address _operator, address _from, uint256 tokenId, uint256 amount, bytes memory data ) public returns(bytes4); function onERC721OBatchReceived( address _operator, address _from, uint256[] memory _types, uint256[] memory _amounts, bytes memory _data ) public returns (bytes4); } // File: erc721o/contracts/Libs/ObjectsLib.sol pragma solidity ^0.5.4; library ObjectLib { // Libraries using SafeMath for uint256; enum Operations { ADD, SUB, REPLACE } // Constants regarding bin or chunk sizes for balance packing uint256 constant TYPES_BITS_SIZE = 32; // Max size of each object uint256 constant TYPES_PER_UINT256 = 256 / TYPES_BITS_SIZE; // Number of types per uint256 // // Objects and Tokens Functions // /** * @dev Return the bin number and index within that bin where ID is * @param _tokenId Object type * @return (Bin number, ID's index within that bin) */ function getTokenBinIndex(uint256 _tokenId) internal pure returns (uint256 bin, uint256 index) { bin = _tokenId * TYPES_BITS_SIZE / 256; index = _tokenId % TYPES_PER_UINT256; return (bin, index); } /** * @dev update the balance of a type provided in _binBalances * @param _binBalances Uint256 containing the balances of objects * @param _index Index of the object in the provided bin * @param _amount Value to update the type balance * @param _operation Which operation to conduct : * Operations.REPLACE : Replace type balance with _amount * Operations.ADD : ADD _amount to type balance * Operations.SUB : Substract _amount from type balance */ function updateTokenBalance( uint256 _binBalances, uint256 _index, uint256 _amount, Operations _operation) internal pure returns (uint256 newBinBalance) { uint256 objectBalance; if (_operation == Operations.ADD) { objectBalance = getValueInBin(_binBalances, _index); newBinBalance = writeValueInBin(_binBalances, _index, objectBalance.add(_amount)); } else if (_operation == Operations.SUB) { objectBalance = getValueInBin(_binBalances, _index); newBinBalance = writeValueInBin(_binBalances, _index, objectBalance.sub(_amount)); } else if (_operation == Operations.REPLACE) { newBinBalance = writeValueInBin(_binBalances, _index, _amount); } else { revert("Invalid operation"); // Bad operation } return newBinBalance; } /* * @dev return value in _binValue at position _index * @param _binValue uint256 containing the balances of TYPES_PER_UINT256 types * @param _index index at which to retrieve value * @return Value at given _index in _bin */ function getValueInBin(uint256 _binValue, uint256 _index) internal pure returns (uint256) { // Mask to retrieve data for a given binData uint256 mask = (uint256(1) << TYPES_BITS_SIZE) - 1; // Shift amount uint256 rightShift = 256 - TYPES_BITS_SIZE * (_index + 1); return (_binValue >> rightShift) & mask; } /** * @dev return the updated _binValue after writing _amount at _index * @param _binValue uint256 containing the balances of TYPES_PER_UINT256 types * @param _index Index at which to retrieve value * @param _amount Value to store at _index in _bin * @return Value at given _index in _bin */ function writeValueInBin(uint256 _binValue, uint256 _index, uint256 _amount) internal pure returns (uint256) { require(_amount < 2**TYPES_BITS_SIZE, "Amount to write in bin is too large"); // Mask to retrieve data for a given binData uint256 mask = (uint256(1) << TYPES_BITS_SIZE) - 1; // Shift amount uint256 leftShift = 256 - TYPES_BITS_SIZE * (_index + 1); return (_binValue & ~(mask << leftShift) ) | (_amount << leftShift); } } // File: erc721o/contracts/ERC721OBase.sol pragma solidity ^0.5.4; contract ERC721OBase is IERC721O, ERC165, IERC721 { // Libraries using ObjectLib for ObjectLib.Operations; using ObjectLib for uint256; // Array with all tokenIds uint256[] internal allTokens; // Packed balances mapping(address => mapping(uint256 => uint256)) internal packedTokenBalance; // Operators mapping(address => mapping(address => bool)) internal operators; // Keeps aprovals for tokens from owner to approved address // tokenApprovals[tokenId][owner] = approved mapping (uint256 => mapping (address => address)) internal tokenApprovals; // Token Id state mapping(uint256 => uint256) internal tokenTypes; uint256 constant internal INVALID = 0; uint256 constant internal POSITION = 1; uint256 constant internal PORTFOLIO = 2; // Interface constants bytes4 internal constant INTERFACE_ID_ERC721O = 0x12345678; // EIP712 constants bytes32 public DOMAIN_SEPARATOR; bytes32 public PERMIT_TYPEHASH; // mapping holds nonces for approval permissions // nonces[holder] => nonce mapping (address => uint) public nonces; modifier isOperatorOrOwner(address _from) { require((msg.sender == _from) || operators[_from][msg.sender], "msg.sender is neither _from nor operator"); _; } constructor() public { _registerInterface(INTERFACE_ID_ERC721O); // Calculate EIP712 constants DOMAIN_SEPARATOR = keccak256(abi.encode( keccak256("EIP712Domain(string name,string version,address verifyingContract)"), keccak256(bytes("ERC721o")), keccak256(bytes("1")), address(this) )); PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)"); } function implementsERC721O() public pure returns (bool) { return true; } /** * @dev Returns whether the specified token exists * @param _tokenId uint256 ID of the token to query the existence of * @return whether the token exists */ function exists(uint256 _tokenId) public view returns (bool) { return tokenTypes[_tokenId] != INVALID; } /** * @dev return the _tokenId type' balance of _address * @param _address Address to query balance of * @param _tokenId type to query balance of * @return Amount of objects of a given type ID */ function balanceOf(address _address, uint256 _tokenId) public view returns (uint256) { (uint256 bin, uint256 index) = _tokenId.getTokenBinIndex(); return packedTokenBalance[_address][bin].getValueInBin(index); } /** * @dev Gets the total amount of tokens stored by the contract * @return uint256 representing the total amount of tokens */ function totalSupply() public view returns (uint256) { return allTokens.length; } /** * @dev Gets Iterate through the list of existing tokens and return the indexes * and balances of the tokens owner by the user * @param _owner The adddress we are checking * @return indexes The tokenIds * @return balances The balances of each token */ function tokensOwned(address _owner) public view returns (uint256[] memory indexes, uint256[] memory balances) { uint256 numTokens = totalSupply(); uint256[] memory tokenIndexes = new uint256[](numTokens); uint256[] memory tempTokens = new uint256[](numTokens); uint256 count; for (uint256 i = 0; i < numTokens; i++) { uint256 tokenId = allTokens[i]; if (balanceOf(_owner, tokenId) > 0) { tempTokens[count] = balanceOf(_owner, tokenId); tokenIndexes[count] = tokenId; count++; } } // copy over the data to a correct size array uint256[] memory _ownedTokens = new uint256[](count); uint256[] memory _ownedTokensIndexes = new uint256[](count); for (uint256 i = 0; i < count; i++) { _ownedTokens[i] = tempTokens[i]; _ownedTokensIndexes[i] = tokenIndexes[i]; } return (_ownedTokensIndexes, _ownedTokens); } /** * @dev Will set _operator operator status to true or false * @param _operator Address to changes operator status. * @param _approved _operator's new operator status (true or false) */ function setApprovalForAll(address _operator, bool _approved) public { // Update operator status operators[msg.sender][_operator] = _approved; emit ApprovalForAll(msg.sender, _operator, _approved); } /// @notice Approve for all by signature function permit(address _holder, address _spender, uint256 _nonce, uint256 _expiry, bool _allowed, bytes calldata _signature) external { // Calculate hash bytes32 digest = keccak256(abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR, keccak256(abi.encode( PERMIT_TYPEHASH, _holder, _spender, _nonce, _expiry, _allowed )) )); // Divide the signature in r, s and v variables // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solium-disable-next-line security/no-inline-assembly bytes32 r; bytes32 s; uint8 v; bytes memory signature = _signature; assembly { r := mload(add(signature, 32)) s := mload(add(signature, 64)) v := byte(0, mload(add(signature, 96))) } // Version of signature should be 27 or 28, but 0 and 1 are also possible versions if (v < 27) { v += 27; } address recoveredAddress; // If the version is correct return the signer address if (v != 27 && v != 28) { recoveredAddress = address(0); } else { // solium-disable-next-line arg-overflow recoveredAddress = ecrecover(digest, v, r, s); } require(_holder != address(0), "Holder can't be zero address"); require(_holder == recoveredAddress, "Signer address is invalid"); require(_expiry == 0 || now <= _expiry, "Permission expired"); require(_nonce == nonces[_holder]++, "Nonce is invalid"); // Update operator status operators[_holder][_spender] = _allowed; emit ApprovalForAll(_holder, _spender, _allowed); } /** * @dev Approves another address to transfer the given token ID * The zero address indicates there is no approved address. * There can only be one approved address per token at a given time. * Can only be called by the token owner or an approved operator. * @param _to address to be approved for the given token ID * @param _tokenId uint256 ID of the token to be approved */ function approve(address _to, uint256 _tokenId) public { require(_to != msg.sender, "Can't approve to yourself"); tokenApprovals[_tokenId][msg.sender] = _to; emit Approval(msg.sender, _to, _tokenId); } /** * @dev Gets the approved address for a token ID, or zero if no address set * @param _tokenId uint256 ID of the token to query the approval of * @return address currently approved for the given token ID */ function getApproved(uint256 _tokenId, address _tokenOwner) public view returns (address) { return tokenApprovals[_tokenId][_tokenOwner]; } /** * @dev Function that verifies whether _operator is an authorized operator of _tokenHolder. * @param _operator The address of the operator to query status of * @param _owner Address of the tokenHolder * @return A uint256 specifying the amount of tokens still available for the spender. */ function isApprovedForAll(address _owner, address _operator) public view returns (bool isOperator) { return operators[_owner][_operator]; } function isApprovedOrOwner( address _spender, address _owner, uint256 _tokenId ) public view returns (bool) { return ( _spender == _owner || getApproved(_tokenId, _owner) == _spender || isApprovedForAll(_owner, _spender) ); } function _updateTokenBalance( address _from, uint256 _tokenId, uint256 _amount, ObjectLib.Operations op ) internal { (uint256 bin, uint256 index) = _tokenId.getTokenBinIndex(); packedTokenBalance[_from][bin] = packedTokenBalance[_from][bin].updateTokenBalance( index, _amount, op ); } } // File: erc721o/contracts/ERC721OTransferable.sol pragma solidity ^0.5.4; contract ERC721OTransferable is ERC721OBase, ReentrancyGuard { // Libraries using Address for address; // safeTransfer constants bytes4 internal constant ERC721O_RECEIVED = 0xf891ffe0; bytes4 internal constant ERC721O_BATCH_RECEIVED = 0xd0e17c0b; function batchTransferFrom(address _from, address _to, uint256[] memory _tokenIds, uint256[] memory _amounts) public { // Batch Transfering _batchTransferFrom(_from, _to, _tokenIds, _amounts); } /** * @dev transfer objects from different tokenIds to specified address * @param _from The address to BatchTransfer objects from. * @param _to The address to batchTransfer objects to. * @param _tokenIds Array of tokenIds to update balance of * @param _amounts Array of amount of object per type to be transferred. * @param _data Data to pass to onERC721OReceived() function if recipient is contract * Note: Arrays should be sorted so that all tokenIds in a same bin are adjacent (more efficient). */ function safeBatchTransferFrom( address _from, address _to, uint256[] memory _tokenIds, uint256[] memory _amounts, bytes memory _data ) public nonReentrant { // Batch Transfering _batchTransferFrom(_from, _to, _tokenIds, _amounts); // Pass data if recipient is contract if (_to.isContract()) { bytes4 retval = IERC721OReceiver(_to).onERC721OBatchReceived( msg.sender, _from, _tokenIds, _amounts, _data ); require(retval == ERC721O_BATCH_RECEIVED); } } function safeBatchTransferFrom( address _from, address _to, uint256[] memory _tokenIds, uint256[] memory _amounts ) public { safeBatchTransferFrom(_from, _to, _tokenIds, _amounts, ""); } function transfer(address _to, uint256 _tokenId, uint256 _amount) public { _transferFrom(msg.sender, _to, _tokenId, _amount); } function transferFrom(address _from, address _to, uint256 _tokenId, uint256 _amount) public { _transferFrom(_from, _to, _tokenId, _amount); } function safeTransferFrom(address _from, address _to, uint256 _tokenId, uint256 _amount) public { safeTransferFrom(_from, _to, _tokenId, _amount, ""); } function safeTransferFrom(address _from, address _to, uint256 _tokenId, uint256 _amount, bytes memory _data) public nonReentrant { _transferFrom(_from, _to, _tokenId, _amount); require( _checkAndCallSafeTransfer(_from, _to, _tokenId, _amount, _data), "Sent to a contract which is not an ERC721O receiver" ); } /** * @dev transfer objects from different tokenIds to specified address * @param _from The address to BatchTransfer objects from. * @param _to The address to batchTransfer objects to. * @param _tokenIds Array of tokenIds to update balance of * @param _amounts Array of amount of object per type to be transferred. * Note: Arrays should be sorted so that all tokenIds in a same bin are adjacent (more efficient). */ function _batchTransferFrom( address _from, address _to, uint256[] memory _tokenIds, uint256[] memory _amounts ) internal isOperatorOrOwner(_from) { // Requirements require(_tokenIds.length == _amounts.length, "Inconsistent array length between args"); require(_to != address(0), "Invalid recipient"); // Load first bin and index where the object balance exists (uint256 bin, uint256 index) = ObjectLib.getTokenBinIndex(_tokenIds[0]); // Balance for current bin in memory (initialized with first transfer) // Written with bad library syntax instead of as below to bypass stack limit error uint256 balFrom = ObjectLib.updateTokenBalance( packedTokenBalance[_from][bin], index, _amounts[0], ObjectLib.Operations.SUB ); uint256 balTo = ObjectLib.updateTokenBalance( packedTokenBalance[_to][bin], index, _amounts[0], ObjectLib.Operations.ADD ); emit Transfer(_from, _to, _tokenIds[0]); emit TransferWithQuantity(_from, _to, _tokenIds[0], _amounts[0]); // Number of transfers to execute uint256 nTransfer = _tokenIds.length; // Last bin updated uint256 lastBin = bin; for (uint256 i = 1; i < nTransfer; i++) { (bin, index) = _tokenIds[i].getTokenBinIndex(); // If new bin if (bin != lastBin) { // Update storage balance of previous bin packedTokenBalance[_from][lastBin] = balFrom; packedTokenBalance[_to][lastBin] = balTo; // Load current bin balance in memory balFrom = packedTokenBalance[_from][bin]; balTo = packedTokenBalance[_to][bin]; // Bin will be the most recent bin lastBin = bin; } // Update memory balance balFrom = balFrom.updateTokenBalance(index, _amounts[i], ObjectLib.Operations.SUB); balTo = balTo.updateTokenBalance(index, _amounts[i], ObjectLib.Operations.ADD); emit Transfer(_from, _to, _tokenIds[i]); emit TransferWithQuantity(_from, _to, _tokenIds[i], _amounts[i]); } // Update storage of the last bin visited packedTokenBalance[_from][bin] = balFrom; packedTokenBalance[_to][bin] = balTo; // Emit batchTransfer event emit BatchTransfer(_from, _to, _tokenIds, _amounts); } function _transferFrom(address _from, address _to, uint256 _tokenId, uint256 _amount) internal { require(isApprovedOrOwner(msg.sender, _from, _tokenId), "Not approved"); require(_amount <= balanceOf(_from, _tokenId), "Quantity greater than from balance"); require(_to != address(0), "Invalid to address"); _updateTokenBalance(_from, _tokenId, _amount, ObjectLib.Operations.SUB); _updateTokenBalance(_to, _tokenId, _amount, ObjectLib.Operations.ADD); emit Transfer(_from, _to, _tokenId); emit TransferWithQuantity(_from, _to, _tokenId, _amount); } function _checkAndCallSafeTransfer( address _from, address _to, uint256 _tokenId, uint256 _amount, bytes memory _data ) internal returns (bool) { if (!_to.isContract()) { return true; } bytes4 retval = IERC721OReceiver(_to).onERC721OReceived(msg.sender, _from, _tokenId, _amount, _data); return(retval == ERC721O_RECEIVED); } } // File: erc721o/contracts/ERC721OMintable.sol pragma solidity ^0.5.4; contract ERC721OMintable is ERC721OTransferable { // Libraries using LibPosition for bytes32; // Internal functions function _mint(uint256 _tokenId, address _to, uint256 _supply) internal { // If the token doesn't exist, add it to the tokens array if (!exists(_tokenId)) { tokenTypes[_tokenId] = POSITION; allTokens.push(_tokenId); } _updateTokenBalance(_to, _tokenId, _supply, ObjectLib.Operations.ADD); emit Transfer(address(0), _to, _tokenId); emit TransferWithQuantity(address(0), _to, _tokenId, _supply); } function _burn(address _tokenOwner, uint256 _tokenId, uint256 _quantity) internal { uint256 ownerBalance = balanceOf(_tokenOwner, _tokenId); require(ownerBalance >= _quantity, "TOKEN_MINTER:NOT_ENOUGH_POSITIONS"); _updateTokenBalance(_tokenOwner, _tokenId, _quantity, ObjectLib.Operations.SUB); emit Transfer(_tokenOwner, address(0), _tokenId); emit TransferWithQuantity(_tokenOwner, address(0), _tokenId, _quantity); } function _mint(address _buyer, address _seller, bytes32 _derivativeHash, uint256 _quantity) internal { _mintLong(_buyer, _derivativeHash, _quantity); _mintShort(_seller, _derivativeHash, _quantity); } function _mintLong(address _buyer, bytes32 _derivativeHash, uint256 _quantity) internal { uint256 longTokenId = _derivativeHash.getLongTokenId(); _mint(longTokenId, _buyer, _quantity); } function _mintShort(address _seller, bytes32 _derivativeHash, uint256 _quantity) internal { uint256 shortTokenId = _derivativeHash.getShortTokenId(); _mint(shortTokenId, _seller, _quantity); } function _registerPortfolio(uint256 _portfolioId, uint256[] memory _tokenIds, uint256[] memory _tokenRatio) internal { if (!exists(_portfolioId)) { tokenTypes[_portfolioId] = PORTFOLIO; emit Composition(_portfolioId, _tokenIds, _tokenRatio); } } } // File: erc721o/contracts/ERC721OComposable.sol pragma solidity ^0.5.4; contract ERC721OComposable is ERC721OMintable { // Libraries using UintArray for uint256[]; function compose(uint256[] memory _tokenIds, uint256[] memory _tokenRatio, uint256 _quantity) public { require(_tokenIds.length == _tokenRatio.length, "TOKEN_MINTER:TOKEN_IDS_AND_RATIO_LENGTH_DOES_NOT_MATCH"); require(_quantity > 0, "TOKEN_MINTER:WRONG_QUANTITY"); require(_tokenIds.length > 0, "TOKEN_MINTER:WRONG_QUANTITY"); require(_tokenIds.isUnique(), "TOKEN_MINTER:TOKEN_IDS_NOT_UNIQUE"); for (uint256 i = 0; i < _tokenIds.length; i++) { _burn(msg.sender, _tokenIds[i], _tokenRatio[i] * _quantity); } uint256 portfolioId = uint256(keccak256(abi.encodePacked( _tokenIds, _tokenRatio ))); _registerPortfolio(portfolioId, _tokenIds, _tokenRatio); _mint(portfolioId, msg.sender, _quantity); } function decompose(uint256 _portfolioId, uint256[] memory _tokenIds, uint256[] memory _tokenRatio, uint256 _quantity) public { require(_tokenIds.length == _tokenRatio.length, "TOKEN_MINTER:TOKEN_IDS_AND_RATIO_LENGTH_DOES_NOT_MATCH"); require(_quantity > 0, "TOKEN_MINTER:WRONG_QUANTITY"); require(_tokenIds.length > 0, "TOKEN_MINTER:WRONG_QUANTITY"); require(_tokenIds.isUnique(), "TOKEN_MINTER:TOKEN_IDS_NOT_UNIQUE"); uint256 portfolioId = uint256(keccak256(abi.encodePacked( _tokenIds, _tokenRatio ))); require(portfolioId == _portfolioId, "TOKEN_MINTER:WRONG_PORTFOLIO_ID"); _burn(msg.sender, _portfolioId, _quantity); for (uint256 i = 0; i < _tokenIds.length; i++) { _mint(_tokenIds[i], msg.sender, _tokenRatio[i] * _quantity); } } function recompose( uint256 _portfolioId, uint256[] memory _initialTokenIds, uint256[] memory _initialTokenRatio, uint256[] memory _finalTokenIds, uint256[] memory _finalTokenRatio, uint256 _quantity ) public { require(_initialTokenIds.length == _initialTokenRatio.length, "TOKEN_MINTER:INITIAL_TOKEN_IDS_AND_RATIO_LENGTH_DOES_NOT_MATCH"); require(_finalTokenIds.length == _finalTokenRatio.length, "TOKEN_MINTER:FINAL_TOKEN_IDS_AND_RATIO_LENGTH_DOES_NOT_MATCH"); require(_quantity > 0, "TOKEN_MINTER:WRONG_QUANTITY"); require(_initialTokenIds.length > 0, "TOKEN_MINTER:WRONG_QUANTITY"); require(_finalTokenIds.length > 0, "TOKEN_MINTER:WRONG_QUANTITY"); require(_initialTokenIds.isUnique(), "TOKEN_MINTER:TOKEN_IDS_NOT_UNIQUE"); require(_finalTokenIds.isUnique(), "TOKEN_MINTER:TOKEN_IDS_NOT_UNIQUE"); uint256 oldPortfolioId = uint256(keccak256(abi.encodePacked( _initialTokenIds, _initialTokenRatio ))); require(oldPortfolioId == _portfolioId, "TOKEN_MINTER:WRONG_PORTFOLIO_ID"); _burn(msg.sender, _portfolioId, _quantity); _removedIds(_initialTokenIds, _initialTokenRatio, _finalTokenIds, _finalTokenRatio, _quantity); _addedIds(_initialTokenIds, _initialTokenRatio, _finalTokenIds, _finalTokenRatio, _quantity); _keptIds(_initialTokenIds, _initialTokenRatio, _finalTokenIds, _finalTokenRatio, _quantity); uint256 newPortfolioId = uint256(keccak256(abi.encodePacked( _finalTokenIds, _finalTokenRatio ))); _registerPortfolio(newPortfolioId, _finalTokenIds, _finalTokenRatio); _mint(newPortfolioId, msg.sender, _quantity); } function _removedIds( uint256[] memory _initialTokenIds, uint256[] memory _initialTokenRatio, uint256[] memory _finalTokenIds, uint256[] memory _finalTokenRatio, uint256 _quantity ) private { (uint256[] memory removedIds, uint256[] memory removedIdsIdxs) = _initialTokenIds.difference(_finalTokenIds); for (uint256 i = 0; i < removedIds.length; i++) { uint256 index = removedIdsIdxs[i]; _mint(_initialTokenIds[index], msg.sender, _initialTokenRatio[index] * _quantity); } _finalTokenRatio; } function _addedIds( uint256[] memory _initialTokenIds, uint256[] memory _initialTokenRatio, uint256[] memory _finalTokenIds, uint256[] memory _finalTokenRatio, uint256 _quantity ) private { (uint256[] memory addedIds, uint256[] memory addedIdsIdxs) = _finalTokenIds.difference(_initialTokenIds); for (uint256 i = 0; i < addedIds.length; i++) { uint256 index = addedIdsIdxs[i]; _burn(msg.sender, _finalTokenIds[index], _finalTokenRatio[index] * _quantity); } _initialTokenRatio; } function _keptIds( uint256[] memory _initialTokenIds, uint256[] memory _initialTokenRatio, uint256[] memory _finalTokenIds, uint256[] memory _finalTokenRatio, uint256 _quantity ) private { (uint256[] memory keptIds, uint256[] memory keptInitialIdxs, uint256[] memory keptFinalIdxs) = _initialTokenIds.intersect(_finalTokenIds); for (uint256 i = 0; i < keptIds.length; i++) { uint256 initialIndex = keptInitialIdxs[i]; uint256 finalIndex = keptFinalIdxs[i]; if (_initialTokenRatio[initialIndex] > _finalTokenRatio[finalIndex]) { uint256 diff = _initialTokenRatio[initialIndex] - _finalTokenRatio[finalIndex]; _mint(_initialTokenIds[initialIndex], msg.sender, diff * _quantity); } else if (_initialTokenRatio[initialIndex] < _finalTokenRatio[finalIndex]) { uint256 diff = _finalTokenRatio[finalIndex] - _initialTokenRatio[initialIndex]; _burn(msg.sender, _initialTokenIds[initialIndex], diff * _quantity); } } } } // File: erc721o/contracts/Libs/UintsLib.sol pragma solidity ^0.5.4; library UintsLib { function uint2str(uint _i) internal pure returns (string memory _uintAsString) { if (_i == 0) { return "0"; } uint j = _i; uint len; while (j != 0) { len++; j /= 10; } bytes memory bstr = new bytes(len); uint k = len - 1; while (_i != 0) { bstr[k--] = byte(uint8(48 + _i % 10)); _i /= 10; } return string(bstr); } } // File: erc721o/contracts/ERC721OBackwardCompatible.sol pragma solidity ^0.5.4; contract ERC721OBackwardCompatible is ERC721OComposable { using UintsLib for uint256; // Interface constants bytes4 internal constant INTERFACE_ID_ERC721 = 0x80ac58cd; bytes4 internal constant INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63; bytes4 internal constant INTERFACE_ID_ERC721_METADATA = 0x5b5e139f; // Reciever constants bytes4 internal constant ERC721_RECEIVED = 0x150b7a02; // Metadata URI string internal baseTokenURI; constructor(string memory _baseTokenURI) public ERC721OBase() { baseTokenURI = _baseTokenURI; _registerInterface(INTERFACE_ID_ERC721); _registerInterface(INTERFACE_ID_ERC721_ENUMERABLE); _registerInterface(INTERFACE_ID_ERC721_METADATA); } // ERC721 compatibility function implementsERC721() public pure returns (bool) { return true; } /** * @dev Gets the owner of a given NFT * @param _tokenId uint256 representing the unique token identifier * @return address the owner of the token */ function ownerOf(uint256 _tokenId) public view returns (address) { if (exists(_tokenId)) { return address(this); } return address(0); } /** * @dev Gets the number of tokens owned by the address we are checking * @param _owner The adddress we are checking * @return balance The unique amount of tokens owned */ function balanceOf(address _owner) public view returns (uint256 balance) { (, uint256[] memory tokens) = tokensOwned(_owner); return tokens.length; } // ERC721 - Enumerable compatibility /** * @dev Gets the token ID at a given index of all the tokens in this contract * Reverts if the index is greater or equal to the total number of tokens * @param _index uint256 representing the index to be accessed of the tokens list * @return uint256 token ID at the given index of the tokens list */ function tokenByIndex(uint256 _index) public view returns (uint256) { require(_index < totalSupply()); return allTokens[_index]; } function tokenOfOwnerByIndex(address _owner, uint256 _index) public view returns (uint256 _tokenId) { (, uint256[] memory tokens) = tokensOwned(_owner); require(_index < tokens.length); return tokens[_index]; } // ERC721 - Metadata compatibility function tokenURI(uint256 _tokenId) public view returns (string memory tokenUri) { require(exists(_tokenId), "Token doesn't exist"); return string(abi.encodePacked( baseTokenURI, _tokenId.uint2str(), ".json" )); } /** * @dev Gets the approved address for a token ID, or zero if no address set * @param _tokenId uint256 ID of the token to query the approval of * @return address currently approved for the given token ID */ function getApproved(uint256 _tokenId) public view returns (address) { if (exists(_tokenId)) { return address(this); } return address(0); } function safeTransferFrom(address _from, address _to, uint256 _tokenId) public { safeTransferFrom(_from, _to, _tokenId, ""); } function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory _data) public nonReentrant { _transferFrom(_from, _to, _tokenId, 1); require( _checkAndCallSafeTransfer(_from, _to, _tokenId, _data), "Sent to a contract which is not an ERC721 receiver" ); } function transferFrom(address _from, address _to, uint256 _tokenId) public { _transferFrom(_from, _to, _tokenId, 1); } /** * @dev Internal function to invoke `onERC721Received` on a target address * The call is not executed if the target address is not a contract * @param _from address representing the previous owner of the given token ID * @param _to target address that will receive the tokens * @param _tokenId uint256 ID of the token to be transferred * @param _data bytes optional data to send along with the call * @return whether the call correctly returned the expected magic value */ function _checkAndCallSafeTransfer( address _from, address _to, uint256 _tokenId, bytes memory _data ) internal returns (bool) { if (!_to.isContract()) { return true; } bytes4 retval = IERC721Receiver(_to).onERC721Received( msg.sender, _from, _tokenId, _data ); return (retval == ERC721_RECEIVED); } } // File: contracts/TokenMinter.sol pragma solidity 0.5.16; /// @title Opium.TokenMinter contract implements ERC721O token standard for minting, burning and transferring position tokens contract TokenMinter is ERC721OBackwardCompatible, UsingRegistry { /// @notice Calls constructors of super-contracts /// @param _baseTokenURI string URI for token explorers /// @param _registry address Address of Opium.registry constructor(string memory _baseTokenURI, address _registry) public ERC721OBackwardCompatible(_baseTokenURI) UsingRegistry(_registry) {} /// @notice Mints LONG and SHORT position tokens /// @param _buyer address Address of LONG position receiver /// @param _seller address Address of SHORT position receiver /// @param _derivativeHash bytes32 Hash of derivative (ticker) of position /// @param _quantity uint256 Quantity of positions to mint function mint(address _buyer, address _seller, bytes32 _derivativeHash, uint256 _quantity) external onlyCore { _mint(_buyer, _seller, _derivativeHash, _quantity); } /// @notice Mints only LONG position tokens for "pooled" derivatives /// @param _buyer address Address of LONG position receiver /// @param _derivativeHash bytes32 Hash of derivative (ticker) of position /// @param _quantity uint256 Quantity of positions to mint function mint(address _buyer, bytes32 _derivativeHash, uint256 _quantity) external onlyCore { _mintLong(_buyer, _derivativeHash, _quantity); } /// @notice Burns position tokens /// @param _tokenOwner address Address of tokens owner /// @param _tokenId uint256 tokenId of positions to burn /// @param _quantity uint256 Quantity of positions to burn function burn(address _tokenOwner, uint256 _tokenId, uint256 _quantity) external onlyCore { _burn(_tokenOwner, _tokenId, _quantity); } /// @notice ERC721 interface compatible function for position token name retrieving /// @return Returns name of token function name() external view returns (string memory) { return "Opium Network Position Token"; } /// @notice ERC721 interface compatible function for position token symbol retrieving /// @return Returns symbol of token function symbol() external view returns (string memory) { return "ONP"; } /// VIEW FUNCTIONS /// @notice Checks whether _spender is approved to spend tokens on _owners behalf or owner itself /// @param _spender address Address of spender /// @param _owner address Address of owner /// @param _tokenId address tokenId of interest /// @return Returns whether _spender is approved to spend tokens function isApprovedOrOwner( address _spender, address _owner, uint256 _tokenId ) public view returns (bool) { return ( _spender == _owner || getApproved(_tokenId, _owner) == _spender || isApprovedForAll(_owner, _spender) || isOpiumSpender(_spender) ); } /// @notice Checks whether _spender is Opium.TokenSpender /// @return Returns whether _spender is Opium.TokenSpender function isOpiumSpender(address _spender) public view returns (bool) { return _spender == registry.getTokenSpender(); } } // File: contracts/Errors/OracleAggregatorErrors.sol pragma solidity 0.5.16; contract OracleAggregatorErrors { string constant internal ERROR_ORACLE_AGGREGATOR_NOT_ENOUGH_ETHER = "ORACLE_AGGREGATOR:NOT_ENOUGH_ETHER"; string constant internal ERROR_ORACLE_AGGREGATOR_QUERY_WAS_ALREADY_MADE = "ORACLE_AGGREGATOR:QUERY_WAS_ALREADY_MADE"; string constant internal ERROR_ORACLE_AGGREGATOR_DATA_DOESNT_EXIST = "ORACLE_AGGREGATOR:DATA_DOESNT_EXIST"; string constant internal ERROR_ORACLE_AGGREGATOR_DATA_ALREADY_EXIST = "ORACLE_AGGREGATOR:DATA_ALREADY_EXIST"; } // File: contracts/Interface/IOracleId.sol pragma solidity 0.5.16; /// @title Opium.Interface.IOracleId contract is an interface that every oracleId should implement interface IOracleId { /// @notice Requests data from `oracleId` one time /// @param timestamp uint256 Timestamp at which data are needed function fetchData(uint256 timestamp) external payable; /// @notice Requests data from `oracleId` multiple times /// @param timestamp uint256 Timestamp at which data are needed for the first time /// @param period uint256 Period in seconds between multiple timestamps /// @param times uint256 How many timestamps are requested function recursivelyFetchData(uint256 timestamp, uint256 period, uint256 times) external payable; /// @notice Requests and returns price in ETH for one request. This function could be called as `view` function. Oraclize API for price calculations restricts making this function as view. /// @return fetchPrice uint256 Price of one data request in ETH function calculateFetchPrice() external returns (uint256 fetchPrice); // Event with oracleId metadata JSON string (for DIB.ONE derivative explorer) event MetadataSet(string metadata); } // File: contracts/OracleAggregator.sol pragma solidity 0.5.16; /// @title Opium.OracleAggregator contract requests and caches the data from `oracleId`s and provides them to the Core for positions execution contract OracleAggregator is OracleAggregatorErrors, ReentrancyGuard { using SafeMath for uint256; // Storage for the `oracleId` results // dataCache[oracleId][timestamp] => data mapping (address => mapping(uint256 => uint256)) public dataCache; // Flags whether data were provided // dataExist[oracleId][timestamp] => bool mapping (address => mapping(uint256 => bool)) public dataExist; // Flags whether data were requested // dataRequested[oracleId][timestamp] => bool mapping (address => mapping(uint256 => bool)) public dataRequested; // MODIFIERS /// @notice Checks whether enough ETH were provided withing data request to proceed /// @param oracleId address Address of the `oracleId` smart contract /// @param times uint256 How many times the `oracleId` is being requested modifier enoughEtherProvided(address oracleId, uint256 times) { // Calling Opium.IOracleId function to get the data fetch price per one request uint256 oneTimePrice = calculateFetchPrice(oracleId); // Checking if enough ether was provided for `times` amount of requests require(msg.value >= oneTimePrice.mul(times), ERROR_ORACLE_AGGREGATOR_NOT_ENOUGH_ETHER); _; } // PUBLIC FUNCTIONS /// @notice Requests data from `oracleId` one time /// @param oracleId address Address of the `oracleId` smart contract /// @param timestamp uint256 Timestamp at which data are needed function fetchData(address oracleId, uint256 timestamp) public payable nonReentrant enoughEtherProvided(oracleId, 1) { // Check if was not requested before and mark as requested _registerQuery(oracleId, timestamp); // Call the `oracleId` contract and transfer ETH IOracleId(oracleId).fetchData.value(msg.value)(timestamp); } /// @notice Requests data from `oracleId` multiple times /// @param oracleId address Address of the `oracleId` smart contract /// @param timestamp uint256 Timestamp at which data are needed for the first time /// @param period uint256 Period in seconds between multiple timestamps /// @param times uint256 How many timestamps are requested function recursivelyFetchData(address oracleId, uint256 timestamp, uint256 period, uint256 times) public payable nonReentrant enoughEtherProvided(oracleId, times) { // Check if was not requested before and mark as requested in loop for each timestamp for (uint256 i = 0; i < times; i++) { _registerQuery(oracleId, timestamp + period * i); } // Call the `oracleId` contract and transfer ETH IOracleId(oracleId).recursivelyFetchData.value(msg.value)(timestamp, period, times); } /// @notice Receives and caches data from `msg.sender` /// @param timestamp uint256 Timestamp of data /// @param data uint256 Data itself function __callback(uint256 timestamp, uint256 data) public { // Don't allow to push data twice require(!dataExist[msg.sender][timestamp], ERROR_ORACLE_AGGREGATOR_DATA_ALREADY_EXIST); // Saving data dataCache[msg.sender][timestamp] = data; // Flagging that data were received dataExist[msg.sender][timestamp] = true; } /// @notice Requests and returns price in ETH for one request. This function could be called as `view` function. Oraclize API for price calculations restricts making this function as view. /// @param oracleId address Address of the `oracleId` smart contract /// @return fetchPrice uint256 Price of one data request in ETH function calculateFetchPrice(address oracleId) public returns(uint256 fetchPrice) { fetchPrice = IOracleId(oracleId).calculateFetchPrice(); } // PRIVATE FUNCTIONS /// @notice Checks if data was not requested and provided before and marks as requested /// @param oracleId address Address of the `oracleId` smart contract /// @param timestamp uint256 Timestamp at which data are requested function _registerQuery(address oracleId, uint256 timestamp) private { // Check if data was not requested and provided yet require(!dataRequested[oracleId][timestamp] && !dataExist[oracleId][timestamp], ERROR_ORACLE_AGGREGATOR_QUERY_WAS_ALREADY_MADE); // Mark as requested dataRequested[oracleId][timestamp] = true; } // VIEW FUNCTIONS /// @notice Returns cached data if they exist, or reverts with an error /// @param oracleId address Address of the `oracleId` smart contract /// @param timestamp uint256 Timestamp at which data were requested /// @return dataResult uint256 Cached data provided by `oracleId` function getData(address oracleId, uint256 timestamp) public view returns(uint256 dataResult) { // Check if Opium.OracleAggregator has data require(hasData(oracleId, timestamp), ERROR_ORACLE_AGGREGATOR_DATA_DOESNT_EXIST); // Return cached data dataResult = dataCache[oracleId][timestamp]; } /// @notice Getter for dataExist mapping /// @param oracleId address Address of the `oracleId` smart contract /// @param timestamp uint256 Timestamp at which data were requested /// @param result bool Returns whether data were provided already function hasData(address oracleId, uint256 timestamp) public view returns(bool result) { return dataExist[oracleId][timestamp]; } } // File: contracts/Errors/SyntheticAggregatorErrors.sol pragma solidity 0.5.16; contract SyntheticAggregatorErrors { string constant internal ERROR_SYNTHETIC_AGGREGATOR_DERIVATIVE_HASH_NOT_MATCH = "SYNTHETIC_AGGREGATOR:DERIVATIVE_HASH_NOT_MATCH"; string constant internal ERROR_SYNTHETIC_AGGREGATOR_WRONG_MARGIN = "SYNTHETIC_AGGREGATOR:WRONG_MARGIN"; string constant internal ERROR_SYNTHETIC_AGGREGATOR_COMMISSION_TOO_BIG = "SYNTHETIC_AGGREGATOR:COMMISSION_TOO_BIG"; } // File: contracts/SyntheticAggregator.sol pragma solidity 0.5.16; /// @notice Opium.SyntheticAggregator contract initialized, identifies and caches syntheticId sensitive data contract SyntheticAggregator is SyntheticAggregatorErrors, LibDerivative, LibCommission, ReentrancyGuard { // Emitted when new ticker is initialized event Create(Derivative derivative, bytes32 derivativeHash); // Enum for types of syntheticId // Invalid - syntheticId is not initialized yet // NotPool - syntheticId with p2p logic // Pool - syntheticId with pooled logic enum SyntheticTypes { Invalid, NotPool, Pool } // Cache of buyer margin by ticker // buyerMarginByHash[derivativeHash] = buyerMargin mapping (bytes32 => uint256) public buyerMarginByHash; // Cache of seller margin by ticker // sellerMarginByHash[derivativeHash] = sellerMargin mapping (bytes32 => uint256) public sellerMarginByHash; // Cache of type by ticker // typeByHash[derivativeHash] = type mapping (bytes32 => SyntheticTypes) public typeByHash; // Cache of commission by ticker // commissionByHash[derivativeHash] = commission mapping (bytes32 => uint256) public commissionByHash; // Cache of author addresses by ticker // authorAddressByHash[derivativeHash] = authorAddress mapping (bytes32 => address) public authorAddressByHash; // PUBLIC FUNCTIONS /// @notice Initializes ticker, if was not initialized and returns `syntheticId` author commission from cache /// @param _derivativeHash bytes32 Hash of derivative /// @param _derivative Derivative Derivative itself /// @return commission uint256 Synthetic author commission function getAuthorCommission(bytes32 _derivativeHash, Derivative memory _derivative) public nonReentrant returns (uint256 commission) { // Initialize derivative if wasn't initialized before _initDerivative(_derivativeHash, _derivative); commission = commissionByHash[_derivativeHash]; } /// @notice Initializes ticker, if was not initialized and returns `syntheticId` author address from cache /// @param _derivativeHash bytes32 Hash of derivative /// @param _derivative Derivative Derivative itself /// @return authorAddress address Synthetic author address function getAuthorAddress(bytes32 _derivativeHash, Derivative memory _derivative) public nonReentrant returns (address authorAddress) { // Initialize derivative if wasn't initialized before _initDerivative(_derivativeHash, _derivative); authorAddress = authorAddressByHash[_derivativeHash]; } /// @notice Initializes ticker, if was not initialized and returns buyer and seller margin from cache /// @param _derivativeHash bytes32 Hash of derivative /// @param _derivative Derivative Derivative itself /// @return buyerMargin uint256 Margin of buyer /// @return sellerMargin uint256 Margin of seller function getMargin(bytes32 _derivativeHash, Derivative memory _derivative) public nonReentrant returns (uint256 buyerMargin, uint256 sellerMargin) { // If it's a pool, just return margin from syntheticId contract if (_isPool(_derivativeHash, _derivative)) { return IDerivativeLogic(_derivative.syntheticId).getMargin(_derivative); } // Initialize derivative if wasn't initialized before _initDerivative(_derivativeHash, _derivative); // Check if margins for _derivativeHash were already cached buyerMargin = buyerMarginByHash[_derivativeHash]; sellerMargin = sellerMarginByHash[_derivativeHash]; } /// @notice Checks whether `syntheticId` implements pooled logic /// @param _derivativeHash bytes32 Hash of derivative /// @param _derivative Derivative Derivative itself /// @return result bool Returns whether synthetic implements pooled logic function isPool(bytes32 _derivativeHash, Derivative memory _derivative) public nonReentrant returns (bool result) { result = _isPool(_derivativeHash, _derivative); } // PRIVATE FUNCTIONS /// @notice Initializes ticker, if was not initialized and returns whether `syntheticId` implements pooled logic /// @param _derivativeHash bytes32 Hash of derivative /// @param _derivative Derivative Derivative itself /// @return result bool Returns whether synthetic implements pooled logic function _isPool(bytes32 _derivativeHash, Derivative memory _derivative) private returns (bool result) { // Initialize derivative if wasn't initialized before _initDerivative(_derivativeHash, _derivative); result = typeByHash[_derivativeHash] == SyntheticTypes.Pool; } /// @notice Initializes ticker: caches syntheticId type, margin, author address and commission /// @param _derivativeHash bytes32 Hash of derivative /// @param _derivative Derivative Derivative itself function _initDerivative(bytes32 _derivativeHash, Derivative memory _derivative) private { // Check if type for _derivativeHash was already cached SyntheticTypes syntheticType = typeByHash[_derivativeHash]; // Type could not be Invalid, thus this condition says us that type was not cached before if (syntheticType != SyntheticTypes.Invalid) { return; } // For security reasons we calculate hash of provided _derivative bytes32 derivativeHash = getDerivativeHash(_derivative); require(derivativeHash == _derivativeHash, ERROR_SYNTHETIC_AGGREGATOR_DERIVATIVE_HASH_NOT_MATCH); // POOL // Get isPool from SyntheticId bool result = IDerivativeLogic(_derivative.syntheticId).isPool(); // Cache type returned from synthetic typeByHash[derivativeHash] = result ? SyntheticTypes.Pool : SyntheticTypes.NotPool; // MARGIN // Get margin from SyntheticId (uint256 buyerMargin, uint256 sellerMargin) = IDerivativeLogic(_derivative.syntheticId).getMargin(_derivative); // We are not allowing both margins to be equal to 0 require(buyerMargin != 0 || sellerMargin != 0, ERROR_SYNTHETIC_AGGREGATOR_WRONG_MARGIN); // Cache margins returned from synthetic buyerMarginByHash[derivativeHash] = buyerMargin; sellerMarginByHash[derivativeHash] = sellerMargin; // AUTHOR ADDRESS // Cache author address returned from synthetic authorAddressByHash[derivativeHash] = IDerivativeLogic(_derivative.syntheticId).getAuthorAddress(); // AUTHOR COMMISSION // Get commission from syntheticId uint256 commission = IDerivativeLogic(_derivative.syntheticId).getAuthorCommission(); // Check if commission is not set > 100% require(commission <= COMMISSION_BASE, ERROR_SYNTHETIC_AGGREGATOR_COMMISSION_TOO_BIG); // Cache commission commissionByHash[derivativeHash] = commission; // If we are here, this basically means this ticker was not used before, so we emit an event for Dapps developers about new ticker (derivative) and it's hash emit Create(_derivative, derivativeHash); } } // File: contracts/Lib/Whitelisted.sol pragma solidity 0.5.16; /// @title Opium.Lib.Whitelisted contract implements whitelist with modifier to restrict access to only whitelisted addresses contract Whitelisted { // Whitelist array address[] internal whitelist; /// @notice This modifier restricts access to functions, which could be called only by whitelisted addresses modifier onlyWhitelisted() { // Allowance flag bool allowed = false; // Going through whitelisted addresses array uint256 whitelistLength = whitelist.length; for (uint256 i = 0; i < whitelistLength; i++) { // If `msg.sender` is met within whitelisted addresses, raise the flag and exit the loop if (whitelist[i] == msg.sender) { allowed = true; break; } } // Check if flag was raised require(allowed, "Only whitelisted allowed"); _; } /// @notice Getter for whitelisted addresses array /// @return Array of whitelisted addresses function getWhitelist() public view returns (address[] memory) { return whitelist; } } // File: contracts/Lib/WhitelistedWithGovernance.sol pragma solidity 0.5.16; /// @title Opium.Lib.WhitelistedWithGovernance contract implements Opium.Lib.Whitelisted and adds governance for whitelist controlling contract WhitelistedWithGovernance is Whitelisted { // Emitted when new governor is set event GovernorSet(address governor); // Emitted when new whitelist is proposed event Proposed(address[] whitelist); // Emitted when proposed whitelist is committed (set) event Committed(address[] whitelist); // Proposal life timelock interval uint256 public timeLockInterval; // Governor address address public governor; // Timestamp of last proposal uint256 public proposalTime; // Proposed whitelist address[] public proposedWhitelist; /// @notice This modifier restricts access to functions, which could be called only by governor modifier onlyGovernor() { require(msg.sender == governor, "Only governor allowed"); _; } /// @notice Contract constructor /// @param _timeLockInterval uint256 Initial value for timelock interval /// @param _governor address Initial value for governor constructor(uint256 _timeLockInterval, address _governor) public { timeLockInterval = _timeLockInterval; governor = _governor; emit GovernorSet(governor); } /// @notice Calling this function governor could propose new whitelist addresses array. Also it allows to initialize first whitelist if it was not initialized yet. function proposeWhitelist(address[] memory _whitelist) public onlyGovernor { // Restrict empty proposals require(_whitelist.length != 0, "Can't be empty"); // Consider empty whitelist as not initialized, as proposing of empty whitelists is not allowed // If whitelist has never been initialized, we set whitelist right away without proposal if (whitelist.length == 0) { whitelist = _whitelist; emit Committed(_whitelist); // Otherwise save current time as timestamp of proposal, save proposed whitelist and emit event } else { proposalTime = now; proposedWhitelist = _whitelist; emit Proposed(_whitelist); } } /// @notice Calling this function governor commits proposed whitelist if timelock interval of proposal was passed function commitWhitelist() public onlyGovernor { // Check if proposal was made require(proposalTime != 0, "Didn't proposed yet"); // Check if timelock interval was passed require((proposalTime + timeLockInterval) < now, "Can't commit yet"); // Set new whitelist and emit event whitelist = proposedWhitelist; emit Committed(whitelist); // Reset proposal time lock proposalTime = 0; } /// @notice This function allows governor to transfer governance to a new governor and emits event /// @param _governor address Address of new governor function setGovernor(address _governor) public onlyGovernor { require(_governor != address(0), "Can't set zero address"); governor = _governor; emit GovernorSet(governor); } } // File: contracts/Lib/WhitelistedWithGovernanceAndChangableTimelock.sol pragma solidity 0.5.16; /// @notice Opium.Lib.WhitelistedWithGovernanceAndChangableTimelock contract implements Opium.Lib.WhitelistedWithGovernance and adds possibility for governor to change timelock interval within timelock interval contract WhitelistedWithGovernanceAndChangableTimelock is WhitelistedWithGovernance { // Emitted when new timelock is proposed event Proposed(uint256 timelock); // Emitted when new timelock is committed (set) event Committed(uint256 timelock); // Timestamp of last timelock proposal uint256 public timeLockProposalTime; // Proposed timelock uint256 public proposedTimeLock; /// @notice Calling this function governor could propose new timelock /// @param _timelock uint256 New timelock value function proposeTimelock(uint256 _timelock) public onlyGovernor { timeLockProposalTime = now; proposedTimeLock = _timelock; emit Proposed(_timelock); } /// @notice Calling this function governor could commit previously proposed new timelock if timelock interval of proposal was passed function commitTimelock() public onlyGovernor { // Check if proposal was made require(timeLockProposalTime != 0, "Didn't proposed yet"); // Check if timelock interval was passed require((timeLockProposalTime + timeLockInterval) < now, "Can't commit yet"); // Set new timelock and emit event timeLockInterval = proposedTimeLock; emit Committed(proposedTimeLock); // Reset timelock time lock timeLockProposalTime = 0; } } // File: contracts/TokenSpender.sol pragma solidity 0.5.16; /// @title Opium.TokenSpender contract holds users ERC20 approvals and allows whitelisted contracts to use tokens contract TokenSpender is WhitelistedWithGovernanceAndChangableTimelock { using SafeERC20 for IERC20; // Initial timelock period uint256 public constant WHITELIST_TIMELOCK = 1 hours; /// @notice Calls constructors of super-contracts /// @param _governor address Address of governor, who is allowed to adjust whitelist constructor(address _governor) public WhitelistedWithGovernance(WHITELIST_TIMELOCK, _governor) {} /// @notice Using this function whitelisted contracts could call ERC20 transfers /// @param token IERC20 Instance of token /// @param from address Address from which tokens are transferred /// @param to address Address of tokens receiver /// @param amount uint256 Amount of tokens to be transferred function claimTokens(IERC20 token, address from, address to, uint256 amount) external onlyWhitelisted { token.safeTransferFrom(from, to, amount); } /// @notice Using this function whitelisted contracts could call ERC721O transfers /// @param token IERC721O Instance of token /// @param from address Address from which tokens are transferred /// @param to address Address of tokens receiver /// @param tokenId uint256 Token ID to be transferred /// @param amount uint256 Amount of tokens to be transferred function claimPositions(IERC721O token, address from, address to, uint256 tokenId, uint256 amount) external onlyWhitelisted { token.safeTransferFrom(from, to, tokenId, amount); } } // File: contracts/Core.sol pragma solidity 0.5.16; /// @title Opium.Core contract creates positions, holds and distributes margin at the maturity contract Core is LibDerivative, LibCommission, UsingRegistry, CoreErrors, ReentrancyGuard { using SafeMath for uint256; using LibPosition for bytes32; using SafeERC20 for IERC20; // Emitted when Core creates new position event Created(address buyer, address seller, bytes32 derivativeHash, uint256 quantity); // Emitted when Core executes positions event Executed(address tokenOwner, uint256 tokenId, uint256 quantity); // Emitted when Core cancels ticker for the first time event Canceled(bytes32 derivativeHash); // Period of time after which ticker could be canceled if no data was provided to the `oracleId` uint256 public constant NO_DATA_CANCELLATION_PERIOD = 2 weeks; // Vaults for pools // This mapping holds balances of pooled positions // poolVaults[syntheticAddress][tokenAddress] => availableBalance mapping (address => mapping(address => uint256)) public poolVaults; // Vaults for fees // This mapping holds balances of fee recipients // feesVaults[feeRecipientAddress][tokenAddress] => availableBalance mapping (address => mapping(address => uint256)) public feesVaults; // Hashes of cancelled tickers mapping (bytes32 => bool) public cancelled; /// @notice Calls Core.Lib.UsingRegistry constructor constructor(address _registry) public UsingRegistry(_registry) {} // PUBLIC FUNCTIONS /// @notice This function allows fee recipients to withdraw their fees /// @param _tokenAddress address Address of an ERC20 token to withdraw function withdrawFee(address _tokenAddress) public nonReentrant { uint256 balance = feesVaults[msg.sender][_tokenAddress]; feesVaults[msg.sender][_tokenAddress] = 0; IERC20(_tokenAddress).safeTransfer(msg.sender, balance); } /// @notice Creates derivative contracts (positions) /// @param _derivative Derivative Derivative definition /// @param _quantity uint256 Quantity of derivatives to be created /// @param _addresses address[2] Addresses of buyer and seller /// [0] - buyer address /// [1] - seller address - if seller is set to `address(0)`, consider as pooled position function create(Derivative memory _derivative, uint256 _quantity, address[2] memory _addresses) public nonReentrant { if (_addresses[1] == address(0)) { _createPooled(_derivative, _quantity, _addresses[0]); } else { _create(_derivative, _quantity, _addresses); } } /// @notice Executes several positions of `msg.sender` with same `tokenId` /// @param _tokenId uint256 `tokenId` of positions that needs to be executed /// @param _quantity uint256 Quantity of positions to execute /// @param _derivative Derivative Derivative definition function execute(uint256 _tokenId, uint256 _quantity, Derivative memory _derivative) public nonReentrant { uint256[] memory tokenIds = new uint256[](1); uint256[] memory quantities = new uint256[](1); Derivative[] memory derivatives = new Derivative[](1); tokenIds[0] = _tokenId; quantities[0] = _quantity; derivatives[0] = _derivative; _execute(msg.sender, tokenIds, quantities, derivatives); } /// @notice Executes several positions of `_tokenOwner` with same `tokenId` /// @param _tokenOwner address Address of the owner of positions /// @param _tokenId uint256 `tokenId` of positions that needs to be executed /// @param _quantity uint256 Quantity of positions to execute /// @param _derivative Derivative Derivative definition function execute(address _tokenOwner, uint256 _tokenId, uint256 _quantity, Derivative memory _derivative) public nonReentrant { uint256[] memory tokenIds = new uint256[](1); uint256[] memory quantities = new uint256[](1); Derivative[] memory derivatives = new Derivative[](1); tokenIds[0] = _tokenId; quantities[0] = _quantity; derivatives[0] = _derivative; _execute(_tokenOwner, tokenIds, quantities, derivatives); } /// @notice Executes several positions of `msg.sender` with different `tokenId`s /// @param _tokenIds uint256[] `tokenId`s of positions that needs to be executed /// @param _quantities uint256[] Quantity of positions to execute for each `tokenId` /// @param _derivatives Derivative[] Derivative definitions for each `tokenId` function execute(uint256[] memory _tokenIds, uint256[] memory _quantities, Derivative[] memory _derivatives) public nonReentrant { _execute(msg.sender, _tokenIds, _quantities, _derivatives); } /// @notice Executes several positions of `_tokenOwner` with different `tokenId`s /// @param _tokenOwner address Address of the owner of positions /// @param _tokenIds uint256[] `tokenId`s of positions that needs to be executed /// @param _quantities uint256[] Quantity of positions to execute for each `tokenId` /// @param _derivatives Derivative[] Derivative definitions for each `tokenId` function execute(address _tokenOwner, uint256[] memory _tokenIds, uint256[] memory _quantities, Derivative[] memory _derivatives) public nonReentrant { _execute(_tokenOwner, _tokenIds, _quantities, _derivatives); } /// @notice Cancels tickers, burns positions and returns margins to positions owners in case no data were provided within `NO_DATA_CANCELLATION_PERIOD` /// @param _tokenId uint256 `tokenId` of positions that needs to be canceled /// @param _quantity uint256 Quantity of positions to cancel /// @param _derivative Derivative Derivative definition function cancel(uint256 _tokenId, uint256 _quantity, Derivative memory _derivative) public nonReentrant { uint256[] memory tokenIds = new uint256[](1); uint256[] memory quantities = new uint256[](1); Derivative[] memory derivatives = new Derivative[](1); tokenIds[0] = _tokenId; quantities[0] = _quantity; derivatives[0] = _derivative; _cancel(tokenIds, quantities, derivatives); } /// @notice Cancels tickers, burns positions and returns margins to positions owners in case no data were provided within `NO_DATA_CANCELLATION_PERIOD` /// @param _tokenIds uint256[] `tokenId` of positions that needs to be canceled /// @param _quantities uint256[] Quantity of positions to cancel for each `tokenId` /// @param _derivatives Derivative[] Derivative definitions for each `tokenId` function cancel(uint256[] memory _tokenIds, uint256[] memory _quantities, Derivative[] memory _derivatives) public nonReentrant { _cancel(_tokenIds, _quantities, _derivatives); } // PRIVATE FUNCTIONS struct CreatePooledLocalVars { SyntheticAggregator syntheticAggregator; IDerivativeLogic derivativeLogic; IERC20 marginToken; TokenSpender tokenSpender; TokenMinter tokenMinter; } /// @notice This function creates pooled positions /// @param _derivative Derivative Derivative definition /// @param _quantity uint256 Quantity of positions to create /// @param _address address Address of position receiver function _createPooled(Derivative memory _derivative, uint256 _quantity, address _address) private { // Local variables CreatePooledLocalVars memory vars; // Create instance of Opium.SyntheticAggregator // Create instance of Opium.IDerivativeLogic // Create instance of margin token // Create instance of Opium.TokenSpender // Create instance of Opium.TokenMinter vars.syntheticAggregator = SyntheticAggregator(registry.getSyntheticAggregator()); vars.derivativeLogic = IDerivativeLogic(_derivative.syntheticId); vars.marginToken = IERC20(_derivative.token); vars.tokenSpender = TokenSpender(registry.getTokenSpender()); vars.tokenMinter = TokenMinter(registry.getMinter()); // Generate hash for derivative bytes32 derivativeHash = getDerivativeHash(_derivative); // Check with Opium.SyntheticAggregator if syntheticId is a pool require(vars.syntheticAggregator.isPool(derivativeHash, _derivative), ERROR_CORE_NOT_POOL); // Check if ticker was canceled require(!cancelled[derivativeHash], ERROR_CORE_TICKER_WAS_CANCELLED); // Validate input data against Derivative logic (`syntheticId`) require(vars.derivativeLogic.validateInput(_derivative), ERROR_CORE_SYNTHETIC_VALIDATION_ERROR); // Get cached margin required according to logic from Opium.SyntheticAggregator (uint256 margin, ) = vars.syntheticAggregator.getMargin(derivativeHash, _derivative); // Check ERC20 tokens allowance: margin * quantity // `msg.sender` must provide margin for position creation require(vars.marginToken.allowance(msg.sender, address(vars.tokenSpender)) >= margin.mul(_quantity), ERROR_CORE_NOT_ENOUGH_TOKEN_ALLOWANCE); // Take ERC20 tokens from msg.sender, should never revert in correct ERC20 implementation vars.tokenSpender.claimTokens(vars.marginToken, msg.sender, address(this), margin.mul(_quantity)); // Since it's a pooled position, we add transferred margin to pool balance poolVaults[_derivative.syntheticId][_derivative.token] = poolVaults[_derivative.syntheticId][_derivative.token].add(margin.mul(_quantity)); // Mint LONG position tokens vars.tokenMinter.mint(_address, derivativeHash, _quantity); emit Created(_address, address(0), derivativeHash, _quantity); } struct CreateLocalVars { SyntheticAggregator syntheticAggregator; IDerivativeLogic derivativeLogic; IERC20 marginToken; TokenSpender tokenSpender; TokenMinter tokenMinter; } /// @notice This function creates p2p positions /// @param _derivative Derivative Derivative definition /// @param _quantity uint256 Quantity of positions to create /// @param _addresses address[2] Addresses of buyer and seller /// [0] - buyer address /// [1] - seller address function _create(Derivative memory _derivative, uint256 _quantity, address[2] memory _addresses) private { // Local variables CreateLocalVars memory vars; // Create instance of Opium.SyntheticAggregator // Create instance of Opium.IDerivativeLogic // Create instance of margin token // Create instance of Opium.TokenSpender // Create instance of Opium.TokenMinter vars.syntheticAggregator = SyntheticAggregator(registry.getSyntheticAggregator()); vars.derivativeLogic = IDerivativeLogic(_derivative.syntheticId); vars.marginToken = IERC20(_derivative.token); vars.tokenSpender = TokenSpender(registry.getTokenSpender()); vars.tokenMinter = TokenMinter(registry.getMinter()); // Generate hash for derivative bytes32 derivativeHash = getDerivativeHash(_derivative); // Check with Opium.SyntheticAggregator if syntheticId is not a pool require(!vars.syntheticAggregator.isPool(derivativeHash, _derivative), ERROR_CORE_CANT_BE_POOL); // Check if ticker was canceled require(!cancelled[derivativeHash], ERROR_CORE_TICKER_WAS_CANCELLED); // Validate input data against Derivative logic (`syntheticId`) require(vars.derivativeLogic.validateInput(_derivative), ERROR_CORE_SYNTHETIC_VALIDATION_ERROR); uint256[2] memory margins; // Get cached margin required according to logic from Opium.SyntheticAggregator // margins[0] - buyerMargin // margins[1] - sellerMargin (margins[0], margins[1]) = vars.syntheticAggregator.getMargin(derivativeHash, _derivative); // Check ERC20 tokens allowance: (margins[0] + margins[1]) * quantity // `msg.sender` must provide margin for position creation require(vars.marginToken.allowance(msg.sender, address(vars.tokenSpender)) >= margins[0].add(margins[1]).mul(_quantity), ERROR_CORE_NOT_ENOUGH_TOKEN_ALLOWANCE); // Take ERC20 tokens from msg.sender, should never revert in correct ERC20 implementation vars.tokenSpender.claimTokens(vars.marginToken, msg.sender, address(this), margins[0].add(margins[1]).mul(_quantity)); // Mint LONG and SHORT positions tokens vars.tokenMinter.mint(_addresses[0], _addresses[1], derivativeHash, _quantity); emit Created(_addresses[0], _addresses[1], derivativeHash, _quantity); } struct ExecuteAndCancelLocalVars { TokenMinter tokenMinter; OracleAggregator oracleAggregator; SyntheticAggregator syntheticAggregator; } /// @notice Executes several positions of `_tokenOwner` with different `tokenId`s /// @param _tokenOwner address Address of the owner of positions /// @param _tokenIds uint256[] `tokenId`s of positions that needs to be executed /// @param _quantities uint256[] Quantity of positions to execute for each `tokenId` /// @param _derivatives Derivative[] Derivative definitions for each `tokenId` function _execute(address _tokenOwner, uint256[] memory _tokenIds, uint256[] memory _quantities, Derivative[] memory _derivatives) private { require(_tokenIds.length == _quantities.length, ERROR_CORE_TOKEN_IDS_AND_QUANTITIES_LENGTH_DOES_NOT_MATCH); require(_tokenIds.length == _derivatives.length, ERROR_CORE_TOKEN_IDS_AND_DERIVATIVES_LENGTH_DOES_NOT_MATCH); // Local variables ExecuteAndCancelLocalVars memory vars; // Create instance of Opium.TokenMinter // Create instance of Opium.OracleAggregator // Create instance of Opium.SyntheticAggregator vars.tokenMinter = TokenMinter(registry.getMinter()); vars.oracleAggregator = OracleAggregator(registry.getOracleAggregator()); vars.syntheticAggregator = SyntheticAggregator(registry.getSyntheticAggregator()); for (uint256 i; i < _tokenIds.length; i++) { // Check if execution is performed after endTime require(now > _derivatives[i].endTime, ERROR_CORE_EXECUTION_BEFORE_MATURITY_NOT_ALLOWED); // Checking whether execution is performed by `_tokenOwner` or `_tokenOwner` allowed third party executions on it's behalf require( _tokenOwner == msg.sender || IDerivativeLogic(_derivatives[i].syntheticId).thirdpartyExecutionAllowed(_tokenOwner), ERROR_CORE_SYNTHETIC_EXECUTION_WAS_NOT_ALLOWED ); // Returns payout for all positions uint256 payout = _getPayout(_derivatives[i], _tokenIds[i], _quantities[i], vars); // Transfer payout if (payout > 0) { IERC20(_derivatives[i].token).safeTransfer(_tokenOwner, payout); } // Burn executed position tokens vars.tokenMinter.burn(_tokenOwner, _tokenIds[i], _quantities[i]); emit Executed(_tokenOwner, _tokenIds[i], _quantities[i]); } } /// @notice Cancels tickers, burns positions and returns margins to positions owners in case no data were provided within `NO_DATA_CANCELLATION_PERIOD` /// @param _tokenIds uint256[] `tokenId` of positions that needs to be canceled /// @param _quantities uint256[] Quantity of positions to cancel for each `tokenId` /// @param _derivatives Derivative[] Derivative definitions for each `tokenId` function _cancel(uint256[] memory _tokenIds, uint256[] memory _quantities, Derivative[] memory _derivatives) private { require(_tokenIds.length == _quantities.length, ERROR_CORE_TOKEN_IDS_AND_QUANTITIES_LENGTH_DOES_NOT_MATCH); require(_tokenIds.length == _derivatives.length, ERROR_CORE_TOKEN_IDS_AND_DERIVATIVES_LENGTH_DOES_NOT_MATCH); // Local variables ExecuteAndCancelLocalVars memory vars; // Create instance of Opium.TokenMinter // Create instance of Opium.OracleAggregator // Create instance of Opium.SyntheticAggregator vars.tokenMinter = TokenMinter(registry.getMinter()); vars.oracleAggregator = OracleAggregator(registry.getOracleAggregator()); vars.syntheticAggregator = SyntheticAggregator(registry.getSyntheticAggregator()); for (uint256 i; i < _tokenIds.length; i++) { // Don't allow to cancel tickers with "dummy" oracleIds require(_derivatives[i].oracleId != address(0), ERROR_CORE_CANT_CANCEL_DUMMY_ORACLE_ID); // Check if cancellation is called after `NO_DATA_CANCELLATION_PERIOD` and `oracleId` didn't provided data require( _derivatives[i].endTime + NO_DATA_CANCELLATION_PERIOD <= now && !vars.oracleAggregator.hasData(_derivatives[i].oracleId, _derivatives[i].endTime), ERROR_CORE_CANCELLATION_IS_NOT_ALLOWED ); // Generate hash for derivative bytes32 derivativeHash = getDerivativeHash(_derivatives[i]); // Emit `Canceled` event only once and mark ticker as canceled if (!cancelled[derivativeHash]) { cancelled[derivativeHash] = true; emit Canceled(derivativeHash); } uint256[2] memory margins; // Get cached margin required according to logic from Opium.SyntheticAggregator // margins[0] - buyerMargin // margins[1] - sellerMargin (margins[0], margins[1]) = vars.syntheticAggregator.getMargin(derivativeHash, _derivatives[i]); uint256 payout; // Check if `_tokenId` is an ID of LONG position if (derivativeHash.getLongTokenId() == _tokenIds[i]) { // Set payout to buyerPayout payout = margins[0]; // Check if `_tokenId` is an ID of SHORT position } else if (derivativeHash.getShortTokenId() == _tokenIds[i]) { // Set payout to sellerPayout payout = margins[1]; } else { // Either portfolioId, hack or bug revert(ERROR_CORE_UNKNOWN_POSITION_TYPE); } // Transfer payout * _quantities[i] if (payout > 0) { IERC20(_derivatives[i].token).safeTransfer(msg.sender, payout.mul(_quantities[i])); } // Burn canceled position tokens vars.tokenMinter.burn(msg.sender, _tokenIds[i], _quantities[i]); } } /// @notice Calculates payout for position and gets fees /// @param _derivative Derivative Derivative definition /// @param _tokenId uint256 `tokenId` of positions /// @param _quantity uint256 Quantity of positions /// @param _vars ExecuteAndCancelLocalVars Helping local variables /// @return payout uint256 Payout for all tokens function _getPayout(Derivative memory _derivative, uint256 _tokenId, uint256 _quantity, ExecuteAndCancelLocalVars memory _vars) private returns (uint256 payout) { // Trying to getData from Opium.OracleAggregator, could be reverted // Opium allows to use "dummy" oracleIds, in this case data is set to `0` uint256 data; if (_derivative.oracleId != address(0)) { data = _vars.oracleAggregator.getData(_derivative.oracleId, _derivative.endTime); } else { data = 0; } uint256[2] memory payoutRatio; // Get payout ratio from Derivative logic // payoutRatio[0] - buyerPayout // payoutRatio[1] - sellerPayout (payoutRatio[0], payoutRatio[1]) = IDerivativeLogic(_derivative.syntheticId).getExecutionPayout(_derivative, data); // Generate hash for derivative bytes32 derivativeHash = getDerivativeHash(_derivative); // Check if ticker was canceled require(!cancelled[derivativeHash], ERROR_CORE_TICKER_WAS_CANCELLED); uint256[2] memory margins; // Get cached total margin required from Opium.SyntheticAggregator // margins[0] - buyerMargin // margins[1] - sellerMargin (margins[0], margins[1]) = _vars.syntheticAggregator.getMargin(derivativeHash, _derivative); uint256[2] memory payouts; // Calculate payouts from ratio // payouts[0] -> buyerPayout = (buyerMargin + sellerMargin) * buyerPayoutRatio / (buyerPayoutRatio + sellerPayoutRatio) // payouts[1] -> sellerPayout = (buyerMargin + sellerMargin) * sellerPayoutRatio / (buyerPayoutRatio + sellerPayoutRatio) payouts[0] = margins[0].add(margins[1]).mul(payoutRatio[0]).div(payoutRatio[0].add(payoutRatio[1])); payouts[1] = margins[0].add(margins[1]).mul(payoutRatio[1]).div(payoutRatio[0].add(payoutRatio[1])); // Check if `_tokenId` is an ID of LONG position if (derivativeHash.getLongTokenId() == _tokenId) { // Check if it's a pooled position if (_vars.syntheticAggregator.isPool(derivativeHash, _derivative)) { // Pooled position payoutRatio is considered as full payout, not as payoutRatio payout = payoutRatio[0]; // Multiply payout by quantity payout = payout.mul(_quantity); // Check sufficiency of syntheticId balance in poolVaults require( poolVaults[_derivative.syntheticId][_derivative.token] >= payout , ERROR_CORE_INSUFFICIENT_POOL_BALANCE ); // Subtract paid out margin from poolVault poolVaults[_derivative.syntheticId][_derivative.token] = poolVaults[_derivative.syntheticId][_derivative.token].sub(payout); } else { // Set payout to buyerPayout payout = payouts[0]; // Multiply payout by quantity payout = payout.mul(_quantity); } // Take fees only from profit makers // Check: payout > buyerMargin * quantity if (payout > margins[0].mul(_quantity)) { // Get Opium and `syntheticId` author fees and subtract it from payout payout = payout.sub(_getFees(_vars.syntheticAggregator, derivativeHash, _derivative, payout - margins[0].mul(_quantity))); } // Check if `_tokenId` is an ID of SHORT position } else if (derivativeHash.getShortTokenId() == _tokenId) { // Set payout to sellerPayout payout = payouts[1]; // Multiply payout by quantity payout = payout.mul(_quantity); // Take fees only from profit makers // Check: payout > sellerMargin * quantity if (payout > margins[1].mul(_quantity)) { // Get Opium fees and subtract it from payout payout = payout.sub(_getFees(_vars.syntheticAggregator, derivativeHash, _derivative, payout - margins[1].mul(_quantity))); } } else { // Either portfolioId, hack or bug revert(ERROR_CORE_UNKNOWN_POSITION_TYPE); } } /// @notice Calculates `syntheticId` author and opium fees from profit makers /// @param _syntheticAggregator SyntheticAggregator Instance of Opium.SyntheticAggregator /// @param _derivativeHash bytes32 Derivative hash /// @param _derivative Derivative Derivative definition /// @param _profit uint256 payout of one position /// @return fee uint256 Opium and `syntheticId` author fee function _getFees(SyntheticAggregator _syntheticAggregator, bytes32 _derivativeHash, Derivative memory _derivative, uint256 _profit) private returns (uint256 fee) { // Get cached `syntheticId` author address from Opium.SyntheticAggregator address authorAddress = _syntheticAggregator.getAuthorAddress(_derivativeHash, _derivative); // Get cached `syntheticId` fee percentage from Opium.SyntheticAggregator uint256 commission = _syntheticAggregator.getAuthorCommission(_derivativeHash, _derivative); // Calculate fee // fee = profit * commission / COMMISSION_BASE fee = _profit.mul(commission).div(COMMISSION_BASE); // If commission is zero, finish if (fee == 0) { return 0; } // Calculate opium fee // opiumFee = fee * OPIUM_COMMISSION_PART / OPIUM_COMMISSION_BASE uint256 opiumFee = fee.mul(OPIUM_COMMISSION_PART).div(OPIUM_COMMISSION_BASE); // Calculate author fee // authorFee = fee - opiumFee uint256 authorFee = fee.sub(opiumFee); // Get opium address address opiumAddress = registry.getOpiumAddress(); // Update feeVault for Opium team // feesVault[opium][token] += opiumFee feesVaults[opiumAddress][_derivative.token] = feesVaults[opiumAddress][_derivative.token].add(opiumFee); // Update feeVault for `syntheticId` author // feeVault[author][token] += authorFee feesVaults[authorAddress][_derivative.token] = feesVaults[authorAddress][_derivative.token].add(authorFee); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_registry","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"derivativeHash","type":"bytes32"}],"name":"Canceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"bytes32","name":"derivativeHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"Created","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"Executed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"registry","type":"address"}],"name":"RegistrySet","type":"event"},{"constant":true,"inputs":[],"name":"COMMISSION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"NO_DATA_CANCELLATION_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"OPIUM_COMMISSION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"OPIUM_COMMISSION_PART","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_quantities","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256[]","name":"params","type":"uint256[]"},{"internalType":"address","name":"oracleId","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"syntheticId","type":"address"}],"internalType":"struct LibDerivative.Derivative[]","name":"_derivatives","type":"tuple[]"}],"name":"cancel","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_quantity","type":"uint256"},{"components":[{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256[]","name":"params","type":"uint256[]"},{"internalType":"address","name":"oracleId","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"syntheticId","type":"address"}],"internalType":"struct LibDerivative.Derivative","name":"_derivative","type":"tuple"}],"name":"cancel","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"cancelled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256[]","name":"params","type":"uint256[]"},{"internalType":"address","name":"oracleId","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"syntheticId","type":"address"}],"internalType":"struct LibDerivative.Derivative","name":"_derivative","type":"tuple"},{"internalType":"uint256","name":"_quantity","type":"uint256"},{"internalType":"address[2]","name":"_addresses","type":"address[2]"}],"name":"create","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_tokenOwner","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_quantity","type":"uint256"},{"components":[{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256[]","name":"params","type":"uint256[]"},{"internalType":"address","name":"oracleId","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"syntheticId","type":"address"}],"internalType":"struct LibDerivative.Derivative","name":"_derivative","type":"tuple"}],"name":"execute","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_tokenOwner","type":"address"},{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_quantities","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256[]","name":"params","type":"uint256[]"},{"internalType":"address","name":"oracleId","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"syntheticId","type":"address"}],"internalType":"struct LibDerivative.Derivative[]","name":"_derivatives","type":"tuple[]"}],"name":"execute","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_quantity","type":"uint256"},{"components":[{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256[]","name":"params","type":"uint256[]"},{"internalType":"address","name":"oracleId","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"syntheticId","type":"address"}],"internalType":"struct LibDerivative.Derivative","name":"_derivative","type":"tuple"}],"name":"execute","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_quantities","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256[]","name":"params","type":"uint256[]"},{"internalType":"address","name":"oracleId","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"syntheticId","type":"address"}],"internalType":"struct LibDerivative.Derivative[]","name":"_derivatives","type":"tuple[]"}],"name":"execute","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"feesVaults","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"components":[{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256[]","name":"params","type":"uint256[]"},{"internalType":"address","name":"oracleId","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"syntheticId","type":"address"}],"internalType":"struct LibDerivative.Derivative","name":"_derivative","type":"tuple"}],"name":"getDerivativeHash","outputs":[{"internalType":"bytes32","name":"derivativeHash","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"poolVaults","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"withdrawFee","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b5060405162003ce938038062003ce98339810160408190526200003491620000aa565b600080546001600160a01b0319166001600160a01b03831617905560405181907f27fe5f0c1c3b1ed427cc63d0f05759ffdecf9aec9e18d31ef366fc8a6cb5dc3b9062000083908390620000e4565b60405180910390a150506001805562000120565b8051620000a48162000106565b92915050565b600060208284031215620000bd57600080fd5b6000620000cb848462000097565b949350505050565b620000de81620000f4565b82525050565b60208101620000a48284620000d3565b60006001600160a01b038216620000a4565b6200011181620000f4565b81146200011d57600080fd5b50565b613bb980620001306000396000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c806354dc1b22116100a2578063a956fd1211610071578063a956fd1214610210578063ab85d5ec14610218578063d7acb44814610220578063d842b22b14610233578063eb9551221461023b5761010b565b806354dc1b22146101c25780635ab1bd53146101d55780636a990b6e146101ea5780639ecd27aa146101fd5761010b565b80632ac12622116100de5780632ac12622146101695780634b509592146101895780634df6d09d1461019c57806354af742a146101af5761010b565b80630d06dd6b146101105780631ac3ddeb1461012557806328fb2b0314610138578063291092b314610156575b600080fd5b61012361011e3660046131e2565b61024e565b005b61012361013336600461305a565b610293565b6101406102f8565b60405161014d91906138a3565b60405180910390f35b610123610164366004613176565b6102fd565b61017c610177366004613291565b610405565b60405161014d9190613895565b610140610197366004613096565b61041a565b6101236101aa3660046130d0565b610437565b6101236101bd36600461338a565b61046e565b6101236101d036600461338a565b61056e565b6101dd61064b565b60405161014d91906137c2565b6101406101f8366004613096565b61065a565b61012361020b3660046131e2565b610677565b61014061068d565b610140610692565b61012361022e3660046132e3565b610699565b6101406106d4565b6101406102493660046132af565b6106da565b60018054810190819055610263848484610727565b600154811461028d5760405162461bcd60e51b81526004016102849061394a565b60405180910390fd5b50505050565b600180548101908190553360008181526003602090815260408083206001600160a01b03871680855292528220805492905590916102d2919083610ed8565b5060015481146102f45760405162461bcd60e51b81526004016102849061394a565b5050565b600181565b6001805481018082556040805183815280820190915290916060919060208083019080388339505060408051600180825281830190925292935060609291506020808301908038833950506040805160018082528183019092529293506060929150602082015b61036c612d0b565b815260200190600190039081610364579050509050868360008151811061038f57fe5b60200260200101818152505085826000815181106103a957fe5b60200260200101818152505084816000815181106103c357fe5b60200260200101819052506103da88848484610f36565b50505060015481146103fe5760405162461bcd60e51b81526004016102849061394a565b5050505050565b60046020526000908152604090205460ff1681565b600260209081526000928352604080842090915290825290205481565b6001805481019081905561044d85858585610f36565b60015481146103fe5760405162461bcd60e51b81526004016102849061394a565b6001805481018082556040805183815280820190915290916060919060208083019080388339505060408051600180825281830190925292935060609291506020808301908038833950506040805160018082528183019092529293506060929150602082015b6104dd612d0b565b8152602001906001900390816104d5579050509050868360008151811061050057fe5b602002602001018181525050858260008151811061051a57fe5b602002602001018181525050848160008151811061053457fe5b602002602001018190525061054a838383610727565b505050600154811461028d5760405162461bcd60e51b81526004016102849061394a565b6001805481018082556040805183815280820190915290916060919060208083019080388339505060408051600180825281830190925292935060609291506020808301908038833950506040805160018082528183019092529293506060929150602082015b6105dd612d0b565b8152602001906001900390816105d5579050509050868360008151811061060057fe5b602002602001018181525050858260008151811061061a57fe5b602002602001018181525050848160008151811061063457fe5b602002602001018190525061054a33848484610f36565b6000546001600160a01b031690565b600360209081526000928352604080842090915290825290205481565b6001805481019081905561026333858585610f36565b600a81565b6212750081565b6001805481019081905560208201516001600160a01b03166106c95781516106c490859085906113ec565b610263565b610263848484611ad1565b61271081565b80516020808301516040808501516060860151608087015160a0880151935160009761070a97909695910161375c565b604051602081830303815290604052805190602001209050919050565b8151835114604051806060016040528060338152602001613abe60339139906107635760405162461bcd60e51b815260040161028491906138f9565b508051835114604051806060016040528060348152602001613b1960349139906107a05760405162461bcd60e51b815260040161028491906138f9565b506107a9612d5c565b6000809054906101000a90046001600160a01b03166001600160a01b031663f36675176040518163ffffffff1660e01b815260040160206040518083038186803b1580156107f657600080fd5b505afa15801561080a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061082e9190810190613078565b6001600160a01b039081168252600054604080516334d2b0af60e21b81529051919092169163d34ac2bc916004808301926020929190829003018186803b15801561087857600080fd5b505afa15801561088c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108b09190810190613078565b6001600160a01b039081166020808401919091526000546040805163205dd91360e21b815290519190931692638177644c926004808301939192829003018186803b1580156108fe57600080fd5b505afa158015610912573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506109369190810190613078565b6001600160a01b0316604082015260005b84518110156103fe5760006001600160a01b031683828151811061096757fe5b6020026020010151606001516001600160a01b031614156040518060400160405280602081526020017f434f52453a43414e545f43414e43454c5f44554d4d595f4f5241434c455f4944815250906109d25760405162461bcd60e51b815260040161028491906138f9565b5042621275008483815181106109e457fe5b6020026020010151602001510111158015610aac575081602001516001600160a01b031663c8384d2f848381518110610a1957fe5b602002602001015160600151858481518110610a3157fe5b6020026020010151602001516040518363ffffffff1660e01b8152600401610a5a92919061387a565b60206040518083038186803b158015610a7257600080fd5b505afa158015610a86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610aaa9190810190613273565b155b6040518060400160405280602081526020017f434f52453a43414e43454c4c4154494f4e5f49535f4e4f545f414c4c4f57454481525090610b005760405162461bcd60e51b815260040161028491906138f9565b506000610b1f848381518110610b1257fe5b60200260200101516106da565b60008181526004602052604090205490915060ff16610b8a5760008181526004602052604090819020805460ff19166001179055517f134fdd648feeaf30251f0157f9624ef8608ff9a042aad6d13e73f35d21d3f88d90610b819083906138a3565b60405180910390a15b610b92612d7c565b83604001516001600160a01b03166399f685ee83878681518110610bb257fe5b60200260200101516040518363ffffffff1660e01b8152600401610bd79291906138b1565b6040805180830381600087803b158015610bf057600080fd5b505af1158015610c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610c28919081019061335a565b602083015281528651600090889085908110610c4057fe5b6020026020010151837356c54b408c44b12f6c9219c9c73fcda4e783fc2063a085725990916040518263ffffffff1660e01b8152600401610c8191906138a3565b60206040518083038186803b158015610c9957600080fd5b505af4158015610cad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610cd1919081019061333c565b1415610ce7578160005b60200201519050610ddd565b878481518110610cf357fe5b6020026020010151837356c54b408c44b12f6c9219c9c73fcda4e783fc20635b667cf990916040518263ffffffff1660e01b8152600401610d3491906138a3565b60206040518083038186803b158015610d4c57600080fd5b505af4158015610d60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d84919081019061333c565b1415610d9257816001610cdb565b604080518082018252601a81527f434f52453a554e4b4e4f574e5f504f534954494f4e5f545950450000000000006020820152905162461bcd60e51b815261028491906004016138f9565b8015610e3d57610e3d33610e0d898781518110610df657fe5b60200260200101518461218490919063ffffffff16565b888781518110610e1957fe5b6020026020010151608001516001600160a01b0316610ed89092919063ffffffff16565b84600001516001600160a01b031663f5298aca338a8781518110610e5d57fe5b60200260200101518a8881518110610e7157fe5b60200260200101516040518463ffffffff1660e01b8152600401610e97939291906137eb565b600060405180830381600087803b158015610eb157600080fd5b505af1158015610ec5573d6000803e3d6000fd5b5050600190950194506109479350505050565b604051610f3190849063a9059cbb60e01b90610efa908690869060240161387a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526121c7565b505050565b8151835114604051806060016040528060338152602001613abe6033913990610f725760405162461bcd60e51b815260040161028491906138f9565b508051835114604051806060016040528060348152602001613b196034913990610faf5760405162461bcd60e51b815260040161028491906138f9565b50610fb8612d5c565b6000809054906101000a90046001600160a01b03166001600160a01b031663f36675176040518163ffffffff1660e01b815260040160206040518083038186803b15801561100557600080fd5b505afa158015611019573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061103d9190810190613078565b6001600160a01b039081168252600054604080516334d2b0af60e21b81529051919092169163d34ac2bc916004808301926020929190829003018186803b15801561108757600080fd5b505afa15801561109b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110bf9190810190613078565b6001600160a01b039081166020808401919091526000546040805163205dd91360e21b815290519190931692638177644c926004808301939192829003018186803b15801561110d57600080fd5b505afa158015611121573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506111459190810190613078565b6001600160a01b0316604082015260005b84518110156113e45782818151811061116b57fe5b60200260200101516020015142116040518060600160405280602a8152602001613b4d602a9139906111b05760405162461bcd60e51b815260040161028491906138f9565b506001600160a01b03861633148061125657508281815181106111cf57fe5b602002602001015160a001516001600160a01b031663f22430e8876040518263ffffffff1660e01b815260040161120691906137c2565b60206040518083038186803b15801561121e57600080fd5b505afa158015611232573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112569190810190613273565b604051806060016040528060288152602001613af1602891399061128d5760405162461bcd60e51b815260040161028491906138f9565b5060006112d584838151811061129f57fe5b60200260200101518784815181106112b357fe5b60200260200101518785815181106112c757fe5b6020026020010151866122ac565b905080156112ee576112ee8782868581518110610e1957fe5b82600001516001600160a01b031663f5298aca8888858151811061130e57fe5b602002602001015188868151811061132257fe5b60200260200101516040518463ffffffff1660e01b81526004016113489392919061386c565b600060405180830381600087803b15801561136257600080fd5b505af1158015611376573d6000803e3d6000fd5b505050507f7dd684d9b29996680eb4c0ae7461d9983dadb8ebf5e04b3e99fae858334861b4878784815181106113a857fe5b60200260200101518785815181106113bc57fe5b60200260200101516040516113d39392919061386c565b60405180910390a150600101611156565b505050505050565b6113f4612d9a565b6000809054906101000a90046001600160a01b03166001600160a01b0316638177644c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561144157600080fd5b505afa158015611455573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114799190810190613078565b6001600160a01b03908116825260a0850151811660208084019190915260808601518216604080850191909152600054815163beb5bd8160e01b8152915193169263beb5bd8192600480840193919291829003018186803b1580156114dd57600080fd5b505afa1580156114f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115159190810190613078565b6001600160a01b0390811660608301526000546040805163f366751760e01b81529051919092169163f3667517916004808301926020929190829003018186803b15801561156257600080fd5b505afa158015611576573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061159a9190810190613078565b6001600160a01b0316608082015260006115b3856106da565b8251604051634cd280bb60e11b81529192506001600160a01b0316906399a50176906115e590849089906004016138b1565b602060405180830381600087803b1580156115ff57600080fd5b505af1158015611613573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116379190810190613273565b6040518060400160405280600d81526020016c10d3d4914e9393d517d413d3d3609a1b8152509061167b5760405162461bcd60e51b815260040161028491906138f9565b50600081815260046020908152604091829020548251808401909352601983527810d3d4914e951250d2d15497d5d054d7d0d05390d153131151603a1b9183019190915260ff16156116e05760405162461bcd60e51b815260040161028491906138f9565b5081602001516001600160a01b0316633a6f60a9866040518263ffffffff1660e01b8152600401611711919061396a565b60206040518083038186803b15801561172957600080fd5b505afa15801561173d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506117619190810190613273565b6040518060400160405280601f81526020017f434f52453a53594e5448455449435f56414c49444154494f4e5f4552524f5200815250906117b55760405162461bcd60e51b815260040161028491906138f9565b508151604051634cfb42f760e11b81526000916001600160a01b0316906399f685ee906117e89085908a906004016138b1565b6040805180830381600087803b15801561180157600080fd5b505af1158015611815573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611839919081019061335a565b50905061184c818663ffffffff61218416565b83604001516001600160a01b031663dd62ed3e3386606001516040518363ffffffff1660e01b81526004016118829291906137d0565b60206040518083038186803b15801561189a57600080fd5b505afa1580156118ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118d2919081019061333c565b10156040518060400160405280601f81526020017f434f52453a4e4f545f454e4f5547485f544f4b454e5f414c4c4f57414e434500815250906119285760405162461bcd60e51b815260040161028491906138f9565b5082606001516001600160a01b0316630a5ea466846040015133306119568a8761218490919063ffffffff16565b6040518563ffffffff1660e01b815260040161197594939291906138d1565b600060405180830381600087803b15801561198f57600080fd5b505af11580156119a3573d6000803e3d6000fd5b505050506119f96119bd868361218490919063ffffffff16565b60a08801516001600160a01b03908116600090815260026020908152604080832060808d0151909416835292905220549063ffffffff61290816565b60a08701516001600160a01b0390811660009081526002602090815260408083206080808d0151861685529252918290209390935591850151915163644ee7e760e11b815291169063c89dcfce90611a5990879086908a9060040161386c565b600060405180830381600087803b158015611a7357600080fd5b505af1158015611a87573d6000803e3d6000fd5b505050507f85d052cab00efbc0bc1dd4c180b3c1cbb34e891b8bf10c0836cd3591d327790c8460008488604051611ac19493929190613813565b60405180910390a1505050505050565b611ad9612d9a565b6000809054906101000a90046001600160a01b03166001600160a01b0316638177644c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b2657600080fd5b505afa158015611b3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b5e9190810190613078565b6001600160a01b03908116825260a0850151811660208084019190915260808601518216604080850191909152600054815163beb5bd8160e01b8152915193169263beb5bd8192600480840193919291829003018186803b158015611bc257600080fd5b505afa158015611bd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611bfa9190810190613078565b6001600160a01b0390811660608301526000546040805163f366751760e01b81529051919092169163f3667517916004808301926020929190829003018186803b158015611c4757600080fd5b505afa158015611c5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611c7f9190810190613078565b6001600160a01b031660808201526000611c98856106da565b8251604051634cd280bb60e11b81529192506001600160a01b0316906399a5017690611cca90849089906004016138b1565b602060405180830381600087803b158015611ce457600080fd5b505af1158015611cf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d1c9190810190613273565b156040518060400160405280601181526020017010d3d4914e90d0539517d09157d413d3d3607a1b81525090611d655760405162461bcd60e51b815260040161028491906138f9565b50600081815260046020908152604091829020548251808401909352601983527810d3d4914e951250d2d15497d5d054d7d0d05390d153131151603a1b9183019190915260ff1615611dca5760405162461bcd60e51b815260040161028491906138f9565b5081602001516001600160a01b0316633a6f60a9866040518263ffffffff1660e01b8152600401611dfb919061396a565b60206040518083038186803b158015611e1357600080fd5b505afa158015611e27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611e4b9190810190613273565b6040518060400160405280601f81526020017f434f52453a53594e5448455449435f56414c49444154494f4e5f4552524f520081525090611e9f5760405162461bcd60e51b815260040161028491906138f9565b50611ea8612d7c565b8251604051634cfb42f760e11b81526001600160a01b03909116906399f685ee90611ed99085908a906004016138b1565b6040805180830381600087803b158015611ef257600080fd5b505af1158015611f06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611f2a919081019061335a565b60208301819052908252611f5f908690611f53908460005b60200201519063ffffffff61290816565b9063ffffffff61218416565b83604001516001600160a01b031663dd62ed3e3386606001516040518363ffffffff1660e01b8152600401611f959291906137d0565b60206040518083038186803b158015611fad57600080fd5b505afa158015611fc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611fe5919081019061333c565b10156040518060400160405280601f81526020017f434f52453a4e4f545f454e4f5547485f544f4b454e5f414c4c4f57414e4345008152509061203b5760405162461bcd60e51b815260040161028491906138f9565b5082606001516001600160a01b0316630a5ea466846040015133306120778a611f538860016002811061206a57fe5b6020020151896000611f42565b6040518563ffffffff1660e01b815260040161209694939291906138d1565b600060405180830381600087803b1580156120b057600080fd5b505af11580156120c4573d6000803e3d6000fd5b5050505060808301518451602086015160405163a0ecdb3f60e01b81526001600160a01b039093169263a0ecdb3f9261210592909187908b90600401613851565b600060405180830381600087803b15801561211f57600080fd5b505af1158015612133573d6000803e3d6000fd5b505050507f85d052cab00efbc0bc1dd4c180b3c1cbb34e891b8bf10c0836cd3591d327790c8460006002811061216557fe5b602002015185600160200201518488604051611ac19493929190613851565b600082612193575060006121c1565b828202828482816121a057fe5b04146121be5760405162461bcd60e51b81526004016102849061392a565b90505b92915050565b6121d9826001600160a01b031661292d565b6121f55760405162461bcd60e51b81526004016102849061395a565b60006060836001600160a01b0316836040516122119190613750565b6000604051808303816000865af19150503d806000811461224e576040519150601f19603f3d011682016040523d82523d6000602084013e612253565b606091505b5091509150816122755760405162461bcd60e51b81526004016102849061391a565b80511561028d57808060200190516122909190810190613273565b61028d5760405162461bcd60e51b81526004016102849061393a565b606084015160009081906001600160a01b0316156123555782602001516001600160a01b0316632979d025876060015188602001516040518363ffffffff1660e01b81526004016122fe92919061387a565b60206040518083038186803b15801561231657600080fd5b505afa15801561232a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061234e919081019061333c565b9050612359565b5060005b612361612d7c565b8660a001516001600160a01b031663dd0060fd88846040518363ffffffff1660e01b815260040161239392919061397b565b604080518083038186803b1580156123aa57600080fd5b505afa1580156123be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506123e2919081019061335a565b6020830152815260006123f4886106da565b600081815260046020908152604091829020548251808401909352601983527810d3d4914e951250d2d15497d5d054d7d0d05390d153131151603a1b918301919091529192509060ff161561245c5760405162461bcd60e51b815260040161028491906138f9565b50612465612d7c565b85604001516001600160a01b03166399f685ee838b6040518363ffffffff1660e01b81526004016124979291906138b1565b6040805180830381600087803b1580156124b057600080fd5b505af11580156124c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506124e8919081019061335a565b602083015281526124f7612d7c565b61253961250e8560015b6020020151866000611f42565b61252d8660005b6020020151611f538660016020020151876000611f42565b9063ffffffff61296916565b8152612554612549856001612501565b61252d866001612515565b602082015260405163a085725960e01b815289907356c54b408c44b12f6c9219c9c73fcda4e783fc209063a0857259906125929087906004016138a3565b60206040518083038186803b1580156125aa57600080fd5b505af41580156125be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506125e2919081019061333c565b141561282b5786604001516001600160a01b03166399a50176848c6040518363ffffffff1660e01b815260040161261a9291906138b1565b602060405180830381600087803b15801561263457600080fd5b505af1158015612648573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061266c9190810190613273565b156127c3578351955061267f8689612184565b955085600260008c60a001516001600160a01b03166001600160a01b0316815260200190815260200160002060008c608001516001600160a01b03166001600160a01b031681526020019081526020016000205410156040518060400160405280601e81526020017f434f52453a494e53554646494349454e545f504f4f4c5f42414c414e43450000815250906127295760405162461bcd60e51b815260040161028491906138f9565b5060a08a01516001600160a01b03908116600090815260026020908152604080832060808f01519094168352929052205461276a908763ffffffff6129ab16565b600260008c60a001516001600160a01b03166001600160a01b0316815260200190815260200160002060008c608001516001600160a01b03166001600160a01b03168152602001908152602001600020819055506127d4565b805195506127d18689612184565b95505b6127ed888360005b60200201519063ffffffff61218416565b8611156128265760408701516128239061281690858d61280f8d8860006127dc565b8b036129ed565b879063ffffffff6129ab16565b95505b6128fb565b604051635b667cf960e01b815289907356c54b408c44b12f6c9219c9c73fcda4e783fc2090635b667cf9906128649087906004016138a3565b60206040518083038186803b15801561287c57600080fd5b505af4158015612890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506128b4919081019061333c565b1415610d9257602081015195506128cb8689612184565b95506128d9888360016127dc565b8611156128265760408701516128239061281690858d61280f8d8860016127dc565b5050505050949350505050565b6000828201838110156121be5760405162461bcd60e51b81526004016102849061390a565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081158015906129615750808214155b949350505050565b60006121be83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612ca6565b60006121be83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612cdf565b600080856001600160a01b031663b9080d2b86866040518363ffffffff1660e01b8152600401612a1e9291906138b1565b602060405180830381600087803b158015612a3857600080fd5b505af1158015612a4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612a709190810190613078565b90506000866001600160a01b031663fdead27287876040518363ffffffff1660e01b8152600401612aa29291906138b1565b602060405180830381600087803b158015612abc57600080fd5b505af1158015612ad0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612af4919081019061333c565b9050612b0c61271061252d868463ffffffff61218416565b925082612b1e57600092505050612961565b6000612b36600a61252d86600163ffffffff61218416565b90506000612b4a858363ffffffff6129ab16565b905060008060009054906101000a90046001600160a01b03166001600160a01b031663ec45d8ae6040518163ffffffff1660e01b815260040160206040518083038186803b158015612b9b57600080fd5b505afa158015612baf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612bd39190810190613078565b6001600160a01b03808216600090815260036020908152604080832060808e015190941683529290522054909150612c11908463ffffffff61290816565b6001600160a01b03808316600090815260036020818152604080842060808f01805187168652908352818520969096558a8516845291815281832094519093168252929091522054612c69908363ffffffff61290816565b6001600160a01b03958616600090815260036020908152604080832060808d01519099168352979052959095209490945550505050949350505050565b60008183612cc75760405162461bcd60e51b815260040161028491906138f9565b506000838581612cd357fe5b049150505b9392505050565b60008184841115612d035760405162461bcd60e51b815260040161028491906138f9565b505050900390565b6040518060c0016040528060008152602001600081526020016060815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681525090565b604080516060810182526000808252602082018190529181019190915290565b60405180604001604052806002906020820280388339509192915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b80356121c181613a94565b80516121c181613a94565b600082601f830112612def57600080fd5b6002612e02612dfd826139c1565b61399b565b91508183856020840282011115612e1857600080fd5b60005b83811015612e445781612e2e8882612dc8565b8452506020928301929190910190600101612e1b565b5050505092915050565b600082601f830112612e5f57600080fd5b8135612e6d612dfd826139de565b81815260209384019390925082018360005b83811015612e445781358601612e958882612fa1565b8452506020928301929190910190600101612e7f565b600082601f830112612ebc57600080fd5b8135612eca612dfd826139de565b91508181835260208401935060208101905083856020840282011115612eef57600080fd5b60005b83811015612e445781612f058882612f96565b8452506020928301929190910190600101612ef2565b600082601f830112612f2c57600080fd5b8135612f3a612dfd826139de565b91508181835260208401935060208101905083856020840282011115612f5f57600080fd5b60005b83811015612e445781612f758882612f96565b8452506020928301929190910190600101612f62565b80516121c181613aab565b80356121c181613ab4565b600060c08284031215612fb357600080fd5b612fbd60c061399b565b90506000612fcb8484612f96565b8252506020612fdc84848301612f96565b60208301525060408201356001600160401b03811115612ffb57600080fd5b61300784828501612eab565b604083015250606061301b84828501612dc8565b606083015250608061302f84828501612dc8565b60808301525060a061304384828501612dc8565b60a08301525092915050565b80516121c181613ab4565b60006020828403121561306c57600080fd5b60006129618484612dc8565b60006020828403121561308a57600080fd5b60006129618484612dd3565b600080604083850312156130a957600080fd5b60006130b58585612dc8565b92505060206130c685828601612dc8565b9150509250929050565b600080600080608085870312156130e657600080fd5b60006130f28787612dc8565b94505060208501356001600160401b0381111561310e57600080fd5b61311a87828801612f1b565b93505060408501356001600160401b0381111561313657600080fd5b61314287828801612f1b565b92505060608501356001600160401b0381111561315e57600080fd5b61316a87828801612e4e565b91505092959194509250565b6000806000806080858703121561318c57600080fd5b60006131988787612dc8565b94505060206131a987828801612f96565b93505060406131ba87828801612f96565b92505060608501356001600160401b038111156131d657600080fd5b61316a87828801612fa1565b6000806000606084860312156131f757600080fd5b83356001600160401b0381111561320d57600080fd5b61321986828701612f1b565b93505060208401356001600160401b0381111561323557600080fd5b61324186828701612f1b565b92505060408401356001600160401b0381111561325d57600080fd5b61326986828701612e4e565b9150509250925092565b60006020828403121561328557600080fd5b60006129618484612f8b565b6000602082840312156132a357600080fd5b60006129618484612f96565b6000602082840312156132c157600080fd5b81356001600160401b038111156132d757600080fd5b61296184828501612fa1565b6000806000608084860312156132f857600080fd5b83356001600160401b0381111561330e57600080fd5b61331a86828701612fa1565b935050602061332b86828701612f96565b925050604061326986828701612dde565b60006020828403121561334e57600080fd5b6000612961848461304f565b6000806040838503121561336d57600080fd5b6000613379858561304f565b92505060206130c68582860161304f565b60008060006060848603121561339f57600080fd5b60006133ab8686612f96565b93505060206133bc86828701612f96565b92505060408401356001600160401b038111156133d857600080fd5b61326986828701612fa1565b60006133f083836134d1565b505060200190565b61340181613a35565b82525050565b61340181613a16565b61340161341c82613a16565b613a73565b600061342c82613a04565b6134368185613a08565b9350613441836139fe565b8060005b8381101561346f57815161345988826133e4565b9750613464836139fe565b925050600101613445565b509495945050505050565b600061348582613a04565b61348f8185613a11565b935061349a836139fe565b8060005b8381101561346f5781516134b288826133e4565b97506134bd836139fe565b92505060010161349e565b61340181613a21565b61340181613a26565b60006134e582613a04565b6134ef8185613a11565b93506134ff818560208601613a47565b9290920192915050565b61340181613a3c565b600061351d82613a04565b6135278185613a08565b9350613537818560208601613a47565b61354081613a84565b9093019392505050565b6000613557601b83613a08565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000613590602083613a08565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b60006135c9602183613a08565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b600061360c602a83613a08565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b6000613658601f83613a08565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00815260200192915050565b6000613691601f83613a08565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160009060c08401906136d185826134d1565b5060208301516136e460208601826134d1565b50604083015184820360408601526136fc8282613421565b91505060608301516137116060860182613407565b5060808301516137246080860182613407565b5060a083015161373760a0860182613407565b509392505050565b61340161374b82613a26565b613a26565b6000612cd882846134da565b6000613768828961373f565b602082019150613778828861373f565b602082019150613788828761347a565b91506137948286613410565b6014820191506137a48285613410565b6014820191506137b48284613410565b506014019695505050505050565b602081016121c18284613407565b604081016137de82856133f8565b612cd86020830184613407565b606081016137f982866133f8565b61380660208301856134d1565b61296160408301846134d1565b608081016138218287613407565b61382e60208301866133f8565b61383b60408301856134d1565b61384860608301846134d1565b95945050505050565b6080810161385f8287613407565b61382e6020830186613407565b606081016137f98286613407565b604081016138888285613407565b612cd860208301846134d1565b602081016121c182846134c8565b602081016121c182846134d1565b604081016138bf82856134d1565b818103602083015261296181846136bd565b608081016138df8287613509565b6138ec60208301866133f8565b61383b6040830185613407565b602080825281016121be8184613512565b602080825281016121c18161354a565b602080825281016121c181613583565b602080825281016121c1816135bc565b602080825281016121c1816135ff565b602080825281016121c18161364b565b602080825281016121c181613684565b602080825281016121be81846136bd565b6040808252810161398c81856136bd565b9050612cd860208301846134d1565b6040518181016001600160401b03811182821017156139b957600080fd5b604052919050565b60006001600160401b038211156139d757600080fd5b5060200290565b60006001600160401b038211156139f457600080fd5b5060209081020190565b60200190565b5190565b90815260200190565b919050565b60006121c182613a29565b151590565b90565b6001600160a01b031690565b60006121c1825b60006121c182613a16565b60005b83811015613a62578181015183820152602001613a4a565b8381111561028d5750506000910152565b60006121c18260006121c182613a8e565b601f01601f191690565b60601b90565b613a9d81613a16565b8114613aa857600080fd5b50565b613a9d81613a21565b613a9d81613a2656fe434f52453a544f4b454e5f4944535f414e445f5155414e5449544945535f4c454e4754485f444f45535f4e4f545f4d41544348434f52453a53594e5448455449435f455845435554494f4e5f5741535f4e4f545f414c4c4f574544434f52453a544f4b454e5f4944535f414e445f44455249564154495645535f4c454e4754485f444f45535f4e4f545f4d41544348434f52453a455845435554494f4e5f4245464f52455f4d415455524954595f4e4f545f414c4c4f574544a365627a7a72315820b81b09c4918da42f6d048d3ed1a82db34fe18efa6274d34c7f2030bbb6326fdf6c6578706572696d656e74616cf564736f6c63430005100040000000000000000000000000c955f3c0d5a87710996d13b1f9aa3a77552d7a7e
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061010b5760003560e01c806354dc1b22116100a2578063a956fd1211610071578063a956fd1214610210578063ab85d5ec14610218578063d7acb44814610220578063d842b22b14610233578063eb9551221461023b5761010b565b806354dc1b22146101c25780635ab1bd53146101d55780636a990b6e146101ea5780639ecd27aa146101fd5761010b565b80632ac12622116100de5780632ac12622146101695780634b509592146101895780634df6d09d1461019c57806354af742a146101af5761010b565b80630d06dd6b146101105780631ac3ddeb1461012557806328fb2b0314610138578063291092b314610156575b600080fd5b61012361011e3660046131e2565b61024e565b005b61012361013336600461305a565b610293565b6101406102f8565b60405161014d91906138a3565b60405180910390f35b610123610164366004613176565b6102fd565b61017c610177366004613291565b610405565b60405161014d9190613895565b610140610197366004613096565b61041a565b6101236101aa3660046130d0565b610437565b6101236101bd36600461338a565b61046e565b6101236101d036600461338a565b61056e565b6101dd61064b565b60405161014d91906137c2565b6101406101f8366004613096565b61065a565b61012361020b3660046131e2565b610677565b61014061068d565b610140610692565b61012361022e3660046132e3565b610699565b6101406106d4565b6101406102493660046132af565b6106da565b60018054810190819055610263848484610727565b600154811461028d5760405162461bcd60e51b81526004016102849061394a565b60405180910390fd5b50505050565b600180548101908190553360008181526003602090815260408083206001600160a01b03871680855292528220805492905590916102d2919083610ed8565b5060015481146102f45760405162461bcd60e51b81526004016102849061394a565b5050565b600181565b6001805481018082556040805183815280820190915290916060919060208083019080388339505060408051600180825281830190925292935060609291506020808301908038833950506040805160018082528183019092529293506060929150602082015b61036c612d0b565b815260200190600190039081610364579050509050868360008151811061038f57fe5b60200260200101818152505085826000815181106103a957fe5b60200260200101818152505084816000815181106103c357fe5b60200260200101819052506103da88848484610f36565b50505060015481146103fe5760405162461bcd60e51b81526004016102849061394a565b5050505050565b60046020526000908152604090205460ff1681565b600260209081526000928352604080842090915290825290205481565b6001805481019081905561044d85858585610f36565b60015481146103fe5760405162461bcd60e51b81526004016102849061394a565b6001805481018082556040805183815280820190915290916060919060208083019080388339505060408051600180825281830190925292935060609291506020808301908038833950506040805160018082528183019092529293506060929150602082015b6104dd612d0b565b8152602001906001900390816104d5579050509050868360008151811061050057fe5b602002602001018181525050858260008151811061051a57fe5b602002602001018181525050848160008151811061053457fe5b602002602001018190525061054a838383610727565b505050600154811461028d5760405162461bcd60e51b81526004016102849061394a565b6001805481018082556040805183815280820190915290916060919060208083019080388339505060408051600180825281830190925292935060609291506020808301908038833950506040805160018082528183019092529293506060929150602082015b6105dd612d0b565b8152602001906001900390816105d5579050509050868360008151811061060057fe5b602002602001018181525050858260008151811061061a57fe5b602002602001018181525050848160008151811061063457fe5b602002602001018190525061054a33848484610f36565b6000546001600160a01b031690565b600360209081526000928352604080842090915290825290205481565b6001805481019081905561026333858585610f36565b600a81565b6212750081565b6001805481019081905560208201516001600160a01b03166106c95781516106c490859085906113ec565b610263565b610263848484611ad1565b61271081565b80516020808301516040808501516060860151608087015160a0880151935160009761070a97909695910161375c565b604051602081830303815290604052805190602001209050919050565b8151835114604051806060016040528060338152602001613abe60339139906107635760405162461bcd60e51b815260040161028491906138f9565b508051835114604051806060016040528060348152602001613b1960349139906107a05760405162461bcd60e51b815260040161028491906138f9565b506107a9612d5c565b6000809054906101000a90046001600160a01b03166001600160a01b031663f36675176040518163ffffffff1660e01b815260040160206040518083038186803b1580156107f657600080fd5b505afa15801561080a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061082e9190810190613078565b6001600160a01b039081168252600054604080516334d2b0af60e21b81529051919092169163d34ac2bc916004808301926020929190829003018186803b15801561087857600080fd5b505afa15801561088c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108b09190810190613078565b6001600160a01b039081166020808401919091526000546040805163205dd91360e21b815290519190931692638177644c926004808301939192829003018186803b1580156108fe57600080fd5b505afa158015610912573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506109369190810190613078565b6001600160a01b0316604082015260005b84518110156103fe5760006001600160a01b031683828151811061096757fe5b6020026020010151606001516001600160a01b031614156040518060400160405280602081526020017f434f52453a43414e545f43414e43454c5f44554d4d595f4f5241434c455f4944815250906109d25760405162461bcd60e51b815260040161028491906138f9565b5042621275008483815181106109e457fe5b6020026020010151602001510111158015610aac575081602001516001600160a01b031663c8384d2f848381518110610a1957fe5b602002602001015160600151858481518110610a3157fe5b6020026020010151602001516040518363ffffffff1660e01b8152600401610a5a92919061387a565b60206040518083038186803b158015610a7257600080fd5b505afa158015610a86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610aaa9190810190613273565b155b6040518060400160405280602081526020017f434f52453a43414e43454c4c4154494f4e5f49535f4e4f545f414c4c4f57454481525090610b005760405162461bcd60e51b815260040161028491906138f9565b506000610b1f848381518110610b1257fe5b60200260200101516106da565b60008181526004602052604090205490915060ff16610b8a5760008181526004602052604090819020805460ff19166001179055517f134fdd648feeaf30251f0157f9624ef8608ff9a042aad6d13e73f35d21d3f88d90610b819083906138a3565b60405180910390a15b610b92612d7c565b83604001516001600160a01b03166399f685ee83878681518110610bb257fe5b60200260200101516040518363ffffffff1660e01b8152600401610bd79291906138b1565b6040805180830381600087803b158015610bf057600080fd5b505af1158015610c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610c28919081019061335a565b602083015281528651600090889085908110610c4057fe5b6020026020010151837356c54b408c44b12f6c9219c9c73fcda4e783fc2063a085725990916040518263ffffffff1660e01b8152600401610c8191906138a3565b60206040518083038186803b158015610c9957600080fd5b505af4158015610cad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610cd1919081019061333c565b1415610ce7578160005b60200201519050610ddd565b878481518110610cf357fe5b6020026020010151837356c54b408c44b12f6c9219c9c73fcda4e783fc20635b667cf990916040518263ffffffff1660e01b8152600401610d3491906138a3565b60206040518083038186803b158015610d4c57600080fd5b505af4158015610d60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d84919081019061333c565b1415610d9257816001610cdb565b604080518082018252601a81527f434f52453a554e4b4e4f574e5f504f534954494f4e5f545950450000000000006020820152905162461bcd60e51b815261028491906004016138f9565b8015610e3d57610e3d33610e0d898781518110610df657fe5b60200260200101518461218490919063ffffffff16565b888781518110610e1957fe5b6020026020010151608001516001600160a01b0316610ed89092919063ffffffff16565b84600001516001600160a01b031663f5298aca338a8781518110610e5d57fe5b60200260200101518a8881518110610e7157fe5b60200260200101516040518463ffffffff1660e01b8152600401610e97939291906137eb565b600060405180830381600087803b158015610eb157600080fd5b505af1158015610ec5573d6000803e3d6000fd5b5050600190950194506109479350505050565b604051610f3190849063a9059cbb60e01b90610efa908690869060240161387a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526121c7565b505050565b8151835114604051806060016040528060338152602001613abe6033913990610f725760405162461bcd60e51b815260040161028491906138f9565b508051835114604051806060016040528060348152602001613b196034913990610faf5760405162461bcd60e51b815260040161028491906138f9565b50610fb8612d5c565b6000809054906101000a90046001600160a01b03166001600160a01b031663f36675176040518163ffffffff1660e01b815260040160206040518083038186803b15801561100557600080fd5b505afa158015611019573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061103d9190810190613078565b6001600160a01b039081168252600054604080516334d2b0af60e21b81529051919092169163d34ac2bc916004808301926020929190829003018186803b15801561108757600080fd5b505afa15801561109b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110bf9190810190613078565b6001600160a01b039081166020808401919091526000546040805163205dd91360e21b815290519190931692638177644c926004808301939192829003018186803b15801561110d57600080fd5b505afa158015611121573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506111459190810190613078565b6001600160a01b0316604082015260005b84518110156113e45782818151811061116b57fe5b60200260200101516020015142116040518060600160405280602a8152602001613b4d602a9139906111b05760405162461bcd60e51b815260040161028491906138f9565b506001600160a01b03861633148061125657508281815181106111cf57fe5b602002602001015160a001516001600160a01b031663f22430e8876040518263ffffffff1660e01b815260040161120691906137c2565b60206040518083038186803b15801561121e57600080fd5b505afa158015611232573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112569190810190613273565b604051806060016040528060288152602001613af1602891399061128d5760405162461bcd60e51b815260040161028491906138f9565b5060006112d584838151811061129f57fe5b60200260200101518784815181106112b357fe5b60200260200101518785815181106112c757fe5b6020026020010151866122ac565b905080156112ee576112ee8782868581518110610e1957fe5b82600001516001600160a01b031663f5298aca8888858151811061130e57fe5b602002602001015188868151811061132257fe5b60200260200101516040518463ffffffff1660e01b81526004016113489392919061386c565b600060405180830381600087803b15801561136257600080fd5b505af1158015611376573d6000803e3d6000fd5b505050507f7dd684d9b29996680eb4c0ae7461d9983dadb8ebf5e04b3e99fae858334861b4878784815181106113a857fe5b60200260200101518785815181106113bc57fe5b60200260200101516040516113d39392919061386c565b60405180910390a150600101611156565b505050505050565b6113f4612d9a565b6000809054906101000a90046001600160a01b03166001600160a01b0316638177644c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561144157600080fd5b505afa158015611455573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114799190810190613078565b6001600160a01b03908116825260a0850151811660208084019190915260808601518216604080850191909152600054815163beb5bd8160e01b8152915193169263beb5bd8192600480840193919291829003018186803b1580156114dd57600080fd5b505afa1580156114f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115159190810190613078565b6001600160a01b0390811660608301526000546040805163f366751760e01b81529051919092169163f3667517916004808301926020929190829003018186803b15801561156257600080fd5b505afa158015611576573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061159a9190810190613078565b6001600160a01b0316608082015260006115b3856106da565b8251604051634cd280bb60e11b81529192506001600160a01b0316906399a50176906115e590849089906004016138b1565b602060405180830381600087803b1580156115ff57600080fd5b505af1158015611613573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116379190810190613273565b6040518060400160405280600d81526020016c10d3d4914e9393d517d413d3d3609a1b8152509061167b5760405162461bcd60e51b815260040161028491906138f9565b50600081815260046020908152604091829020548251808401909352601983527810d3d4914e951250d2d15497d5d054d7d0d05390d153131151603a1b9183019190915260ff16156116e05760405162461bcd60e51b815260040161028491906138f9565b5081602001516001600160a01b0316633a6f60a9866040518263ffffffff1660e01b8152600401611711919061396a565b60206040518083038186803b15801561172957600080fd5b505afa15801561173d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506117619190810190613273565b6040518060400160405280601f81526020017f434f52453a53594e5448455449435f56414c49444154494f4e5f4552524f5200815250906117b55760405162461bcd60e51b815260040161028491906138f9565b508151604051634cfb42f760e11b81526000916001600160a01b0316906399f685ee906117e89085908a906004016138b1565b6040805180830381600087803b15801561180157600080fd5b505af1158015611815573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611839919081019061335a565b50905061184c818663ffffffff61218416565b83604001516001600160a01b031663dd62ed3e3386606001516040518363ffffffff1660e01b81526004016118829291906137d0565b60206040518083038186803b15801561189a57600080fd5b505afa1580156118ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118d2919081019061333c565b10156040518060400160405280601f81526020017f434f52453a4e4f545f454e4f5547485f544f4b454e5f414c4c4f57414e434500815250906119285760405162461bcd60e51b815260040161028491906138f9565b5082606001516001600160a01b0316630a5ea466846040015133306119568a8761218490919063ffffffff16565b6040518563ffffffff1660e01b815260040161197594939291906138d1565b600060405180830381600087803b15801561198f57600080fd5b505af11580156119a3573d6000803e3d6000fd5b505050506119f96119bd868361218490919063ffffffff16565b60a08801516001600160a01b03908116600090815260026020908152604080832060808d0151909416835292905220549063ffffffff61290816565b60a08701516001600160a01b0390811660009081526002602090815260408083206080808d0151861685529252918290209390935591850151915163644ee7e760e11b815291169063c89dcfce90611a5990879086908a9060040161386c565b600060405180830381600087803b158015611a7357600080fd5b505af1158015611a87573d6000803e3d6000fd5b505050507f85d052cab00efbc0bc1dd4c180b3c1cbb34e891b8bf10c0836cd3591d327790c8460008488604051611ac19493929190613813565b60405180910390a1505050505050565b611ad9612d9a565b6000809054906101000a90046001600160a01b03166001600160a01b0316638177644c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b2657600080fd5b505afa158015611b3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b5e9190810190613078565b6001600160a01b03908116825260a0850151811660208084019190915260808601518216604080850191909152600054815163beb5bd8160e01b8152915193169263beb5bd8192600480840193919291829003018186803b158015611bc257600080fd5b505afa158015611bd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611bfa9190810190613078565b6001600160a01b0390811660608301526000546040805163f366751760e01b81529051919092169163f3667517916004808301926020929190829003018186803b158015611c4757600080fd5b505afa158015611c5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611c7f9190810190613078565b6001600160a01b031660808201526000611c98856106da565b8251604051634cd280bb60e11b81529192506001600160a01b0316906399a5017690611cca90849089906004016138b1565b602060405180830381600087803b158015611ce457600080fd5b505af1158015611cf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d1c9190810190613273565b156040518060400160405280601181526020017010d3d4914e90d0539517d09157d413d3d3607a1b81525090611d655760405162461bcd60e51b815260040161028491906138f9565b50600081815260046020908152604091829020548251808401909352601983527810d3d4914e951250d2d15497d5d054d7d0d05390d153131151603a1b9183019190915260ff1615611dca5760405162461bcd60e51b815260040161028491906138f9565b5081602001516001600160a01b0316633a6f60a9866040518263ffffffff1660e01b8152600401611dfb919061396a565b60206040518083038186803b158015611e1357600080fd5b505afa158015611e27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611e4b9190810190613273565b6040518060400160405280601f81526020017f434f52453a53594e5448455449435f56414c49444154494f4e5f4552524f520081525090611e9f5760405162461bcd60e51b815260040161028491906138f9565b50611ea8612d7c565b8251604051634cfb42f760e11b81526001600160a01b03909116906399f685ee90611ed99085908a906004016138b1565b6040805180830381600087803b158015611ef257600080fd5b505af1158015611f06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611f2a919081019061335a565b60208301819052908252611f5f908690611f53908460005b60200201519063ffffffff61290816565b9063ffffffff61218416565b83604001516001600160a01b031663dd62ed3e3386606001516040518363ffffffff1660e01b8152600401611f959291906137d0565b60206040518083038186803b158015611fad57600080fd5b505afa158015611fc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611fe5919081019061333c565b10156040518060400160405280601f81526020017f434f52453a4e4f545f454e4f5547485f544f4b454e5f414c4c4f57414e4345008152509061203b5760405162461bcd60e51b815260040161028491906138f9565b5082606001516001600160a01b0316630a5ea466846040015133306120778a611f538860016002811061206a57fe5b6020020151896000611f42565b6040518563ffffffff1660e01b815260040161209694939291906138d1565b600060405180830381600087803b1580156120b057600080fd5b505af11580156120c4573d6000803e3d6000fd5b5050505060808301518451602086015160405163a0ecdb3f60e01b81526001600160a01b039093169263a0ecdb3f9261210592909187908b90600401613851565b600060405180830381600087803b15801561211f57600080fd5b505af1158015612133573d6000803e3d6000fd5b505050507f85d052cab00efbc0bc1dd4c180b3c1cbb34e891b8bf10c0836cd3591d327790c8460006002811061216557fe5b602002015185600160200201518488604051611ac19493929190613851565b600082612193575060006121c1565b828202828482816121a057fe5b04146121be5760405162461bcd60e51b81526004016102849061392a565b90505b92915050565b6121d9826001600160a01b031661292d565b6121f55760405162461bcd60e51b81526004016102849061395a565b60006060836001600160a01b0316836040516122119190613750565b6000604051808303816000865af19150503d806000811461224e576040519150601f19603f3d011682016040523d82523d6000602084013e612253565b606091505b5091509150816122755760405162461bcd60e51b81526004016102849061391a565b80511561028d57808060200190516122909190810190613273565b61028d5760405162461bcd60e51b81526004016102849061393a565b606084015160009081906001600160a01b0316156123555782602001516001600160a01b0316632979d025876060015188602001516040518363ffffffff1660e01b81526004016122fe92919061387a565b60206040518083038186803b15801561231657600080fd5b505afa15801561232a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061234e919081019061333c565b9050612359565b5060005b612361612d7c565b8660a001516001600160a01b031663dd0060fd88846040518363ffffffff1660e01b815260040161239392919061397b565b604080518083038186803b1580156123aa57600080fd5b505afa1580156123be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506123e2919081019061335a565b6020830152815260006123f4886106da565b600081815260046020908152604091829020548251808401909352601983527810d3d4914e951250d2d15497d5d054d7d0d05390d153131151603a1b918301919091529192509060ff161561245c5760405162461bcd60e51b815260040161028491906138f9565b50612465612d7c565b85604001516001600160a01b03166399f685ee838b6040518363ffffffff1660e01b81526004016124979291906138b1565b6040805180830381600087803b1580156124b057600080fd5b505af11580156124c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506124e8919081019061335a565b602083015281526124f7612d7c565b61253961250e8560015b6020020151866000611f42565b61252d8660005b6020020151611f538660016020020151876000611f42565b9063ffffffff61296916565b8152612554612549856001612501565b61252d866001612515565b602082015260405163a085725960e01b815289907356c54b408c44b12f6c9219c9c73fcda4e783fc209063a0857259906125929087906004016138a3565b60206040518083038186803b1580156125aa57600080fd5b505af41580156125be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506125e2919081019061333c565b141561282b5786604001516001600160a01b03166399a50176848c6040518363ffffffff1660e01b815260040161261a9291906138b1565b602060405180830381600087803b15801561263457600080fd5b505af1158015612648573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061266c9190810190613273565b156127c3578351955061267f8689612184565b955085600260008c60a001516001600160a01b03166001600160a01b0316815260200190815260200160002060008c608001516001600160a01b03166001600160a01b031681526020019081526020016000205410156040518060400160405280601e81526020017f434f52453a494e53554646494349454e545f504f4f4c5f42414c414e43450000815250906127295760405162461bcd60e51b815260040161028491906138f9565b5060a08a01516001600160a01b03908116600090815260026020908152604080832060808f01519094168352929052205461276a908763ffffffff6129ab16565b600260008c60a001516001600160a01b03166001600160a01b0316815260200190815260200160002060008c608001516001600160a01b03166001600160a01b03168152602001908152602001600020819055506127d4565b805195506127d18689612184565b95505b6127ed888360005b60200201519063ffffffff61218416565b8611156128265760408701516128239061281690858d61280f8d8860006127dc565b8b036129ed565b879063ffffffff6129ab16565b95505b6128fb565b604051635b667cf960e01b815289907356c54b408c44b12f6c9219c9c73fcda4e783fc2090635b667cf9906128649087906004016138a3565b60206040518083038186803b15801561287c57600080fd5b505af4158015612890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506128b4919081019061333c565b1415610d9257602081015195506128cb8689612184565b95506128d9888360016127dc565b8611156128265760408701516128239061281690858d61280f8d8860016127dc565b5050505050949350505050565b6000828201838110156121be5760405162461bcd60e51b81526004016102849061390a565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081158015906129615750808214155b949350505050565b60006121be83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612ca6565b60006121be83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612cdf565b600080856001600160a01b031663b9080d2b86866040518363ffffffff1660e01b8152600401612a1e9291906138b1565b602060405180830381600087803b158015612a3857600080fd5b505af1158015612a4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612a709190810190613078565b90506000866001600160a01b031663fdead27287876040518363ffffffff1660e01b8152600401612aa29291906138b1565b602060405180830381600087803b158015612abc57600080fd5b505af1158015612ad0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612af4919081019061333c565b9050612b0c61271061252d868463ffffffff61218416565b925082612b1e57600092505050612961565b6000612b36600a61252d86600163ffffffff61218416565b90506000612b4a858363ffffffff6129ab16565b905060008060009054906101000a90046001600160a01b03166001600160a01b031663ec45d8ae6040518163ffffffff1660e01b815260040160206040518083038186803b158015612b9b57600080fd5b505afa158015612baf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612bd39190810190613078565b6001600160a01b03808216600090815260036020908152604080832060808e015190941683529290522054909150612c11908463ffffffff61290816565b6001600160a01b03808316600090815260036020818152604080842060808f01805187168652908352818520969096558a8516845291815281832094519093168252929091522054612c69908363ffffffff61290816565b6001600160a01b03958616600090815260036020908152604080832060808d01519099168352979052959095209490945550505050949350505050565b60008183612cc75760405162461bcd60e51b815260040161028491906138f9565b506000838581612cd357fe5b049150505b9392505050565b60008184841115612d035760405162461bcd60e51b815260040161028491906138f9565b505050900390565b6040518060c0016040528060008152602001600081526020016060815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681525090565b604080516060810182526000808252602082018190529181019190915290565b60405180604001604052806002906020820280388339509192915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b80356121c181613a94565b80516121c181613a94565b600082601f830112612def57600080fd5b6002612e02612dfd826139c1565b61399b565b91508183856020840282011115612e1857600080fd5b60005b83811015612e445781612e2e8882612dc8565b8452506020928301929190910190600101612e1b565b5050505092915050565b600082601f830112612e5f57600080fd5b8135612e6d612dfd826139de565b81815260209384019390925082018360005b83811015612e445781358601612e958882612fa1565b8452506020928301929190910190600101612e7f565b600082601f830112612ebc57600080fd5b8135612eca612dfd826139de565b91508181835260208401935060208101905083856020840282011115612eef57600080fd5b60005b83811015612e445781612f058882612f96565b8452506020928301929190910190600101612ef2565b600082601f830112612f2c57600080fd5b8135612f3a612dfd826139de565b91508181835260208401935060208101905083856020840282011115612f5f57600080fd5b60005b83811015612e445781612f758882612f96565b8452506020928301929190910190600101612f62565b80516121c181613aab565b80356121c181613ab4565b600060c08284031215612fb357600080fd5b612fbd60c061399b565b90506000612fcb8484612f96565b8252506020612fdc84848301612f96565b60208301525060408201356001600160401b03811115612ffb57600080fd5b61300784828501612eab565b604083015250606061301b84828501612dc8565b606083015250608061302f84828501612dc8565b60808301525060a061304384828501612dc8565b60a08301525092915050565b80516121c181613ab4565b60006020828403121561306c57600080fd5b60006129618484612dc8565b60006020828403121561308a57600080fd5b60006129618484612dd3565b600080604083850312156130a957600080fd5b60006130b58585612dc8565b92505060206130c685828601612dc8565b9150509250929050565b600080600080608085870312156130e657600080fd5b60006130f28787612dc8565b94505060208501356001600160401b0381111561310e57600080fd5b61311a87828801612f1b565b93505060408501356001600160401b0381111561313657600080fd5b61314287828801612f1b565b92505060608501356001600160401b0381111561315e57600080fd5b61316a87828801612e4e565b91505092959194509250565b6000806000806080858703121561318c57600080fd5b60006131988787612dc8565b94505060206131a987828801612f96565b93505060406131ba87828801612f96565b92505060608501356001600160401b038111156131d657600080fd5b61316a87828801612fa1565b6000806000606084860312156131f757600080fd5b83356001600160401b0381111561320d57600080fd5b61321986828701612f1b565b93505060208401356001600160401b0381111561323557600080fd5b61324186828701612f1b565b92505060408401356001600160401b0381111561325d57600080fd5b61326986828701612e4e565b9150509250925092565b60006020828403121561328557600080fd5b60006129618484612f8b565b6000602082840312156132a357600080fd5b60006129618484612f96565b6000602082840312156132c157600080fd5b81356001600160401b038111156132d757600080fd5b61296184828501612fa1565b6000806000608084860312156132f857600080fd5b83356001600160401b0381111561330e57600080fd5b61331a86828701612fa1565b935050602061332b86828701612f96565b925050604061326986828701612dde565b60006020828403121561334e57600080fd5b6000612961848461304f565b6000806040838503121561336d57600080fd5b6000613379858561304f565b92505060206130c68582860161304f565b60008060006060848603121561339f57600080fd5b60006133ab8686612f96565b93505060206133bc86828701612f96565b92505060408401356001600160401b038111156133d857600080fd5b61326986828701612fa1565b60006133f083836134d1565b505060200190565b61340181613a35565b82525050565b61340181613a16565b61340161341c82613a16565b613a73565b600061342c82613a04565b6134368185613a08565b9350613441836139fe565b8060005b8381101561346f57815161345988826133e4565b9750613464836139fe565b925050600101613445565b509495945050505050565b600061348582613a04565b61348f8185613a11565b935061349a836139fe565b8060005b8381101561346f5781516134b288826133e4565b97506134bd836139fe565b92505060010161349e565b61340181613a21565b61340181613a26565b60006134e582613a04565b6134ef8185613a11565b93506134ff818560208601613a47565b9290920192915050565b61340181613a3c565b600061351d82613a04565b6135278185613a08565b9350613537818560208601613a47565b61354081613a84565b9093019392505050565b6000613557601b83613a08565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000613590602083613a08565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b60006135c9602183613a08565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b600061360c602a83613a08565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b6000613658601f83613a08565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00815260200192915050565b6000613691601f83613a08565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160009060c08401906136d185826134d1565b5060208301516136e460208601826134d1565b50604083015184820360408601526136fc8282613421565b91505060608301516137116060860182613407565b5060808301516137246080860182613407565b5060a083015161373760a0860182613407565b509392505050565b61340161374b82613a26565b613a26565b6000612cd882846134da565b6000613768828961373f565b602082019150613778828861373f565b602082019150613788828761347a565b91506137948286613410565b6014820191506137a48285613410565b6014820191506137b48284613410565b506014019695505050505050565b602081016121c18284613407565b604081016137de82856133f8565b612cd86020830184613407565b606081016137f982866133f8565b61380660208301856134d1565b61296160408301846134d1565b608081016138218287613407565b61382e60208301866133f8565b61383b60408301856134d1565b61384860608301846134d1565b95945050505050565b6080810161385f8287613407565b61382e6020830186613407565b606081016137f98286613407565b604081016138888285613407565b612cd860208301846134d1565b602081016121c182846134c8565b602081016121c182846134d1565b604081016138bf82856134d1565b818103602083015261296181846136bd565b608081016138df8287613509565b6138ec60208301866133f8565b61383b6040830185613407565b602080825281016121be8184613512565b602080825281016121c18161354a565b602080825281016121c181613583565b602080825281016121c1816135bc565b602080825281016121c1816135ff565b602080825281016121c18161364b565b602080825281016121c181613684565b602080825281016121be81846136bd565b6040808252810161398c81856136bd565b9050612cd860208301846134d1565b6040518181016001600160401b03811182821017156139b957600080fd5b604052919050565b60006001600160401b038211156139d757600080fd5b5060200290565b60006001600160401b038211156139f457600080fd5b5060209081020190565b60200190565b5190565b90815260200190565b919050565b60006121c182613a29565b151590565b90565b6001600160a01b031690565b60006121c1825b60006121c182613a16565b60005b83811015613a62578181015183820152602001613a4a565b8381111561028d5750506000910152565b60006121c18260006121c182613a8e565b601f01601f191690565b60601b90565b613a9d81613a16565b8114613aa857600080fd5b50565b613a9d81613a21565b613a9d81613a2656fe434f52453a544f4b454e5f4944535f414e445f5155414e5449544945535f4c454e4754485f444f45535f4e4f545f4d41544348434f52453a53594e5448455449435f455845435554494f4e5f5741535f4e4f545f414c4c4f574544434f52453a544f4b454e5f4944535f414e445f44455249564154495645535f4c454e4754485f444f45535f4e4f545f4d41544348434f52453a455845435554494f4e5f4245464f52455f4d415455524954595f4e4f545f414c4c4f574544a365627a7a72315820b81b09c4918da42f6d048d3ed1a82db34fe18efa6274d34c7f2030bbb6326fdf6c6578706572696d656e74616cf564736f6c63430005100040
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c955f3c0d5a87710996d13b1f9aa3a77552d7a7e
-----Decoded View---------------
Arg [0] : _registry (address): 0xC955F3c0d5a87710996D13B1f9AA3A77552D7a7E
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000c955f3c0d5a87710996d13b1f9aa3a77552d7a7e
Deployed Bytecode Sourcemap
100882:25719:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;100882:25719:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;107528:192;;;;;;;;;:::i;:::-;;102474:256;;;;;;;;;:::i;31276:49::-;;;:::i;:::-;;;;;;;;;;;;;;;;104576:489;;;;;;;;;:::i;102113:42::-;;;;;;;;;:::i;:::-;;;;;;;;101775:66;;;;;;;;;:::i;106050:228::-;;;;;;;;;:::i;106652:453::-;;;;;;;;;:::i;103740:467::-;;;;;;;;;:::i;30683:98::-;;;:::i;:::-;;;;;;;;102002:66;;;;;;;;;:::i;105419:206::-;;;;;;;;;:::i;31137:50::-;;;:::i;101553:61::-;;;:::i;103120:322::-;;;;;;;;;:::i;31031:47::-;;;:::i;19553:382::-;;;;;;;;;:::i;107528:192::-;18021:1;18004:18;;;;;;;;107667:45;107675:9;107686:11;107699:12;107667:7;:45::i;:::-;18116:13;;18100:12;:29;18092:73;;;;-1:-1:-1;;;18092:73:0;;;;;;;;;;;;;;;;;107528:192;;;;:::o;102474:256::-;18021:1;18004:18;;;;;;;;102578:10;-1:-1:-1;102567:22:0;;;:10;:22;;;;;;;;-1:-1:-1;;;;;102567:37:0;;;;;;;;;;;102615:41;;;102567:37;;102667:55;;102567:37;;102667:34;:55::i;:::-;18080:1;18116:13;;18100:12;:29;18092:73;;;;-1:-1:-1;;;18092:73:0;;;;;;;;;102474:256;;:::o;31276:49::-;31324:1;31276:49;:::o;104576:489::-;18021:1;18004:18;;;;;;;104741:16;;;;;;;;;;;;18004:18;;104713:25;;104741:16;;;;;;;105:10:-1;104741:16:0;88:34:-1;-1:-1;;104798:16:0;;;104812:1;104798:16;;;;;;;;;104713:44;;-1:-1:-1;104768:27:0;;104798:16;-1:-1:-1;104798:16:0;;;;;;105:10:-1;104798:16:0;88:34:-1;-1:-1;;104859:19:0;;;104876:1;104859:19;;;;;;;;;104768:46;;-1:-1:-1;104825:31:0;;104859:19;-1:-1:-1;104859:19:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;104825:53;;104905:8;104891;104900:1;104891:11;;;;;;;;;;;;;:22;;;;;104940:9;104924:10;104935:1;104924:13;;;;;;;;;;;;;:25;;;;;104977:11;104960;104972:1;104960:14;;;;;;;;;;;;;:28;;;;105001:56;105010:11;105023:8;105033:10;105045:11;105001:8;:56::i;:::-;18080:1;;;18116:13;;18100:12;:29;18092:73;;;;-1:-1:-1;;;18092:73:0;;;;;;;;;104576:489;;;;;:::o;102113:42::-;;;;;;;;;;;;;;;:::o;101775:66::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;106050:228::-;18021:1;18004:18;;;;;;;;106211:59;106220:11;106233:9;106244:11;106257:12;106211:8;:59::i;:::-;18116:13;;18100:12;:29;18092:73;;;;-1:-1:-1;;;18092:73:0;;;;;;;;106652:453;18021:1;18004:18;;;;;;;106795:16;;;;;;;;;;;;18004:18;;106767:25;;106795:16;;;;;;;105:10:-1;106795:16:0;88:34:-1;-1:-1;;106852:16:0;;;106866:1;106852:16;;;;;;;;;106767:44;;-1:-1:-1;106822:27:0;;106852:16;-1:-1:-1;106852:16:0;;;;;;105:10:-1;106852:16:0;88:34:-1;-1:-1;;106913:19:0;;;106930:1;106913:19;;;;;;;;;106822:46;;-1:-1:-1;106879:31:0;;106913:19;-1:-1:-1;106913:19:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;106879:53;;106959:8;106945;106954:1;106945:11;;;;;;;;;;;;;:22;;;;;106994:9;106978:10;106989:1;106978:13;;;;;;;;;;;;;:25;;;;;107031:11;107014;107026:1;107014:14;;;;;;;;;;;;;:28;;;;107055:42;107063:8;107073:10;107085:11;107055:7;:42::i;:::-;18080:1;;;18116:13;;18100:12;:29;18092:73;;;;-1:-1:-1;;;18092:73:0;;;;;;;;103740:467;18021:1;18004:18;;;;;;;103884:16;;;;;;;;;;;;18004:18;;103856:25;;103884:16;;;;;;;105:10:-1;103884:16:0;88:34:-1;-1:-1;;103941:16:0;;;103955:1;103941:16;;;;;;;;;103856:44;;-1:-1:-1;103911:27:0;;103941:16;-1:-1:-1;103941:16:0;;;;;;105:10:-1;103941:16:0;88:34:-1;-1:-1;;104002:19:0;;;104019:1;104002:19;;;;;;;;;103911:46;;-1:-1:-1;103968:31:0;;104002:19;-1:-1:-1;104002:19:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;103968:53;;104048:8;104034;104043:1;104034:11;;;;;;;;;;;;;:22;;;;;104083:9;104067:10;104078:1;104067:13;;;;;;;;;;;;;:25;;;;;104120:11;104103;104115:1;104103:14;;;;;;;;;;;;;:28;;;;104144:55;104153:10;104165:8;104175:10;104187:11;104144:8;:55::i;30683:98::-;30729:7;30764:8;-1:-1:-1;;;;;30764:8:0;30683:98;:::o;102002:66::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;105419:206::-;18021:1;18004:18;;;;;;;;105559:58;105568:10;105580:9;105591:11;105604:12;105559:8;:58::i;31137:50::-;31185:2;31137:50;:::o;101553:61::-;101607:7;101553:61;:::o;103120:322::-;18021:1;18004:18;;;;;;;;103251:13;;;;-1:-1:-1;;;;;103251:27:0;103247:188;;103333:13;;103295:52;;103309:11;;103322:9;;103295:13;:52::i;:::-;103247:188;;;103380:43;103388:11;103401:9;103412:10;103380:7;:43::i;31031:47::-;31073:5;31031:47;:::o;19553:382::-;19725:18;;19758:19;;;;;19792:18;;;;;19825:20;;;;19860:17;;;;19892:23;;;;19694:232;;19632:22;;19694:232;;19725:18;;19758:19;19892:23;19694:232;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;19694:232:0;;;19684:243;;;;;;19667:260;;19553:382;;;:::o;116727:3104::-;116883:11;:18;116863:9;:16;:38;116903:57;;;;;;;;;;;;;;;;;116855:106;;;;;-1:-1:-1;;;116855:106:0;;;;;;;;;;;117000:12;:19;116980:9;:16;:39;117021:58;;;;;;;;;;;;;;;;;116972:108;;;;;-1:-1:-1;;;116972:108:0;;;;;;;;;;;117121:37;;:::i;:::-;117362:8;;;;;;;;;-1:-1:-1;;;;;117362:8:0;-1:-1:-1;;;;;117362:18:0;;:20;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;117362:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117362:20:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;117362:20:0;;;;;;;;;-1:-1:-1;;;;;117331:52:0;;;;;:16;117435:8;:30;;;-1:-1:-1;;;117435:30:0;;;;:8;;;;;:28;;:30;;;;;;;;;;;;;;:8;:30;;;5:2:-1;;;;30:1;27;20:12;5:2;117435:30:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117435:30:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;117435:30:0;;;;;;;;;-1:-1:-1;;;;;117394:72:0;;;:21;;;;:72;;;;117524:8;;:33;;;-1:-1:-1;;;117524:33:0;;;;:8;;;;;:31;;:33;;;;;117394:21;;117524:33;;;;;:8;:33;;;5:2:-1;;;;30:1;27;20:12;5:2;117524:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117524:33:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;117524:33:0;;;;;;;;;-1:-1:-1;;;;;117477:81:0;:24;;;:81;117576:9;117571:2253;117591:9;:16;117587:1;:20;117571:2253;;;117742:1;-1:-1:-1;;;;;117706:38:0;:12;117719:1;117706:15;;;;;;;;;;;;;;:24;;;-1:-1:-1;;;;;117706:38:0;;;117746;;;;;;;;;;;;;;;;;117698:87;;;;;-1:-1:-1;;;117698:87:0;;;;;;;;;;;118005:3;101607:7;117948:12;117961:1;117948:15;;;;;;;;;;;;;;:23;;;:53;:60;;:162;;;;;118030:4;:21;;;-1:-1:-1;;;;;118030:29:0;;118060:12;118073:1;118060:15;;;;;;;;;;;;;;:24;;;118086:12;118099:1;118086:15;;;;;;;;;;;;;;:23;;;118030:80;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;118030:80:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;118030:80:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;118030:80:0;;;;;;;;;118029:81;117948:162;118129:38;;;;;;;;;;;;;;;;;117922:260;;;;;-1:-1:-1;;;117922:260:0;;;;;;;;;;;118244:22;118269:34;118287:12;118300:1;118287:15;;;;;;;;;;;;;;118269:17;:34::i;:::-;118401:25;;;;:9;:25;;;;;;118244:59;;-1:-1:-1;118401:25:0;;118396:147;;118447:25;;;;:9;:25;;;;;;;:32;;-1:-1:-1;;118447:32:0;118475:4;118447:32;;;118503:24;;;;;118457:14;;118503:24;;;;;;;;;;118396:147;118559:25;;:::i;:::-;118802:4;:24;;;-1:-1:-1;;;;;118802:34:0;;118837:14;118853:12;118866:1;118853:15;;;;;;;;;;;;;;118802:67;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;118802:67:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;118802:67:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;118802:67:0;;;;;;;;;118776:10;118788;;118775:94;;;119016:12;;118784:1;;119016:12;;119026:1;;119016:12;;;;;;;;;;;;118981:14;:29;;;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;118981:31:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;118981:31:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;118981:31:0;;;;;;;;;:47;118977:512;;;119104:7;119112:1;119104:10;;;;;119095:19;;118977:512;;;119241:9;119251:1;119241:12;;;;;;;;;;;;;;119205:14;:30;;;;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;119205:32:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;119205:32:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;119205:32:0;;;;;;;;;:48;119201:288;;;119330:7;119338:1;119330:10;;119201:288;119440:32;;;;;;;;;;;;;;;;119433:40;;-1:-1:-1;;;119433:40:0;;;;119440:32;119433:40;;;;119201:288;119558:10;;119554:133;;119589:82;119632:10;119644:26;119655:11;119667:1;119655:14;;;;;;;;;;;;;;119644:6;:10;;:26;;;;:::i;:::-;119596:12;119609:1;119596:15;;;;;;;;;;;;;;:21;;;-1:-1:-1;;;;;119589:42:0;;;:82;;;;;:::i;:::-;119749:4;:16;;;-1:-1:-1;;;;;119749:21:0;;119771:10;119783:9;119793:1;119783:12;;;;;;;;;;;;;;119797:11;119809:1;119797:14;;;;;;;;;;;;;;119749:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;119749:63:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;117609:3:0;;;;;-1:-1:-1;117571:2253:0;;-1:-1:-1;;;;117571:2253:0;13446:176;13555:58;;13529:85;;13548:5;;-1:-1:-1;;;13578:23:0;13555:58;;13603:2;;13607:5;;13555:58;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;13555:58:0;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;;;;13555:58:0;;;179:29:-1;;;;160:49;;;13529:18:0;:85::i;:::-;13446:176;;;:::o;114313:1991::-;114491:11;:18;114471:9;:16;:38;114511:57;;;;;;;;;;;;;;;;;114463:106;;;;;-1:-1:-1;;;114463:106:0;;;;;;;;;;;114608:12;:19;114588:9;:16;:39;114629:58;;;;;;;;;;;;;;;;;114580:108;;;;;-1:-1:-1;;;114580:108:0;;;;;;;;;;;114729:37;;:::i;:::-;114970:8;;;;;;;;;-1:-1:-1;;;;;114970:8:0;-1:-1:-1;;;;;114970:18:0;;:20;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;114970:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;114970:20:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;114970:20:0;;;;;;;;;-1:-1:-1;;;;;114939:52:0;;;;;:16;115043:8;:30;;;-1:-1:-1;;;115043:30:0;;;;:8;;;;;:28;;:30;;;;;;;;;;;;;;:8;:30;;;5:2:-1;;;;30:1;27;20:12;5:2;115043:30:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115043:30:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;115043:30:0;;;;;;;;;-1:-1:-1;;;;;115002:72:0;;;:21;;;;:72;;;;115132:8;;:33;;;-1:-1:-1;;;115132:33:0;;;;:8;;;;;:31;;:33;;;;;115002:21;;115132:33;;;;;:8;:33;;;5:2:-1;;;;30:1;27;20:12;5:2;115132:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115132:33:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;115132:33:0;;;;;;;;;-1:-1:-1;;;;;115085:81:0;:24;;;:81;115184:9;115179:1118;115199:9;:16;115195:1;:20;115179:1118;;;115313:12;115326:1;115313:15;;;;;;;;;;;;;;:23;;;115307:3;:29;115338:48;;;;;;;;;;;;;;;;;115299:88;;;;;-1:-1:-1;;;115299:88:0;;;;;;;;;;-1:-1:-1;;;;;;115566:25:0;;115581:10;115566:25;;:131;;;115629:12;115642:1;115629:15;;;;;;;;;;;;;;:27;;;-1:-1:-1;;;;;115612:72:0;;115685:11;115612:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;115612:85:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115612:85:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;115612:85:0;;;;;;;;;115716:46;;;;;;;;;;;;;;;;;115540:237;;;;;-1:-1:-1;;;115540:237:0;;;;;;;;;;;115843:14;115860:63;115871:12;115884:1;115871:15;;;;;;;;;;;;;;115888:9;115898:1;115888:12;;;;;;;;;;;;;;115902:11;115914:1;115902:14;;;;;;;;;;;;;;115918:4;115860:10;:63::i;:::-;115843:80;-1:-1:-1;115976:10:0;;115972:114;;116007:63;116050:11;116063:6;116014:12;116027:1;116014:15;;;;;;;116007:63;116148:4;:16;;;-1:-1:-1;;;;;116148:21:0;;116170:11;116183:9;116193:1;116183:12;;;;;;;;;;;;;;116197:11;116209:1;116197:14;;;;;;;;;;;;;;116148:64;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;116148:64:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;116148:64:0;;;;116234:51;116243:11;116256:9;116266:1;116256:12;;;;;;;;;;;;;;116270:11;116282:1;116270:14;;;;;;;;;;;;;;116234:51;;;;;;;;;;;;;;;;;-1:-1:-1;115217:3:0;;115179:1118;;;;114313:1991;;;;;:::o;108238:2469::-;108376:33;;:::i;:::-;108723:8;;;;;;;;;-1:-1:-1;;;;;108723:8:0;-1:-1:-1;;;;;108723:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;108723:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;108723:33:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;108723:33:0;;;;;;;;;-1:-1:-1;;;;;108676:81:0;;;;;108808:23;;;;108768:64;;:20;;;;:64;;;;-1:-1:-1;108869:17:0;;;108843:44;;:16;;;;:44;;;;108676:24;108931:8;:26;;-1:-1:-1;;;108931:26:0;;;;:8;;;:24;;:26;;;;;108768:20;;108931:26;;;;;;:8;:26;;;5:2:-1;;;;30:1;27;20:12;5:2;108931:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;108931:26:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;108931:26:0;;;;;;;;;-1:-1:-1;;;;;108898:60:0;;;:17;;;:60;109000:8;;:20;;;-1:-1:-1;;;109000:20:0;;;;:8;;;;;:18;;:20;;;;;;;;;;;;;;:8;:20;;;5:2:-1;;;;30:1;27;20:12;5:2;109000:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;109000:20:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;109000:20:0;;;;;;;;;-1:-1:-1;;;;;108969:52:0;:16;;;:52;109075:22;109100:30;109118:11;109100:17;:30::i;:::-;109225:24;;:60;;-1:-1:-1;;;109225:60:0;;109075:55;;-1:-1:-1;;;;;;109225:31:0;;;;:60;;109075:55;;109273:11;;109225:60;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;109225:60:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;109225:60:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;109225:60:0;;;;;;;;;109287:19;;;;;;;;;;;;;-1:-1:-1;;;109287:19:0;;;109217:90;;;;;-1:-1:-1;;;109217:90:0;;;;;;;;;;-1:-1:-1;109370:25:0;;;;:9;:25;;;;;;;;;;109397:31;;;;;;;;;;;-1:-1:-1;;;109397:31:0;;;;;;;109370:25;;109369:26;109361:68;;;;-1:-1:-1;;;109361:68:0;;;;;;;;;;;109523:4;:20;;;-1:-1:-1;;;;;109523:34:0;;109558:11;109523:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;109523:47:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;109523:47:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;109523:47:0;;;;;;;;;109572:37;;;;;;;;;;;;;;;;;109515:95;;;;;-1:-1:-1;;;109515:95:0;;;;;;;;;;-1:-1:-1;109733:24:0;;:63;;-1:-1:-1;;;109733:63:0;;109713:14;;-1:-1:-1;;;;;109733:34:0;;;;:63;;109768:14;;109784:11;;109733:63;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;109733:63:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;109733:63:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;109733:63:0;;;;;;;;;-1:-1:-1;109712:84:0;-1:-1:-1;110014:21:0;109712:84;110025:9;110014:21;:10;:21;:::i;:::-;109944:4;:16;;;-1:-1:-1;;;;;109944:26:0;;109971:10;109991:4;:17;;;109944:66;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;109944:66:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;109944:66:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;109944:66:0;;;;;;;;;:91;;110037:37;;;;;;;;;;;;;;;;;109936:139;;;;;-1:-1:-1;;;109936:139:0;;;;;;;;;;;110184:4;:17;;;-1:-1:-1;;;;;110184:29:0;;110214:4;:16;;;110232:10;110252:4;110259:21;110270:9;110259:6;:10;;:21;;;;:::i;:::-;110184:97;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;110184:97:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;110184:97:0;;;;110435:81;110494:21;110505:9;110494:6;:10;;:21;;;;:::i;:::-;110446:23;;;;-1:-1:-1;;;;;110435:35:0;;;;;;;:10;:35;;;;;;;;110471:17;;;;110435:54;;;;;;;;;;;:81;:58;:81;:::i;:::-;110389:23;;;;-1:-1:-1;;;;;110378:35:0;;;;;;;:10;:35;;;;;;;;110414:17;;;;;110378:54;;;;;;;;;;:138;;;;110567:16;;;;:58;;-1:-1:-1;;;110567:58:0;;:21;;;;;:58;;110589:8;;110599:14;;110615:9;;110567:58;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;110567:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;110567:58:0;;;;110643:56;110651:8;110669:1;110673:14;110689:9;110643:56;;;;;;;;;;;;;;;;;;108238:2469;;;;;;:::o;111253:2458::-;111397:27;;:::i;:::-;111738:8;;;;;;;;;-1:-1:-1;;;;;111738:8:0;-1:-1:-1;;;;;111738:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;111738:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;111738:33:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;111738:33:0;;;;;;;;;-1:-1:-1;;;;;111691:81:0;;;;;111823:23;;;;111783:64;;:20;;;;:64;;;;-1:-1:-1;111884:17:0;;;111858:44;;:16;;;;:44;;;;111691:24;111946:8;:26;;-1:-1:-1;;;111946:26:0;;;;:8;;;:24;;:26;;;;;111783:20;;111946:26;;;;;;:8;:26;;;5:2:-1;;;;30:1;27;20:12;5:2;111946:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;111946:26:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;111946:26:0;;;;;;;;;-1:-1:-1;;;;;111913:60:0;;;:17;;;:60;112015:8;;:20;;;-1:-1:-1;;;112015:20:0;;;;:8;;;;;:18;;:20;;;;;;;;;;;;;;:8;:20;;;5:2:-1;;;;30:1;27;20:12;5:2;112015:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;112015:20:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;112015:20:0;;;;;;;;;-1:-1:-1;;;;;111984:52:0;:16;;;:52;112090:22;112115:30;112133:11;112115:17;:30::i;:::-;112245:24;;:60;;-1:-1:-1;;;112245:60:0;;112090:55;;-1:-1:-1;;;;;;112245:31:0;;;;:60;;112090:55;;112293:11;;112245:60;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;112245:60:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;112245:60:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;112245:60:0;;;;;;;;;112244:61;112307:23;;;;;;;;;;;;;-1:-1:-1;;;112307:23:0;;;112236:95;;;;;-1:-1:-1;;;112236:95:0;;;;;;;;;;-1:-1:-1;112394:25:0;;;;:9;:25;;;;;;;;;;112421:31;;;;;;;;;;;-1:-1:-1;;;112421:31:0;;;;;;;112394:25;;112393:26;112385:68;;;;-1:-1:-1;;;112385:68:0;;;;;;;;;;;112547:4;:20;;;-1:-1:-1;;;;;112547:34:0;;112582:11;112547:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;112547:47:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;112547:47:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;112547:47:0;;;;;;;;;112596:37;;;;;;;;;;;;;;;;;112539:95;;;;;-1:-1:-1;;;112539:95:0;;;;;;;;;;;112647:25;;:::i;:::-;112874:24;;:63;;-1:-1:-1;;;112874:63:0;;-1:-1:-1;;;;;112874:34:0;;;;;;:63;;112909:14;;112925:11;;112874:63;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;112874:63:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;112874:63:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;112874:63:0;;;;;;;;;112848:10;112860;;112847:90;;;;;;113174:41;;113205:9;;113174:26;;112848:7;112856:1;113174:10;;;;;;:26;:14;:26;:::i;:::-;:30;:41;:30;:41;:::i;:::-;113104:4;:16;;;-1:-1:-1;;;;;113104:26:0;;113131:10;113151:4;:17;;;113104:66;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;113104:66:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;113104:66:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;113104:66:0;;;;;;;;;:111;;113217:37;;;;;;;;;;;;;;;;;113096:159;;;;;-1:-1:-1;;;113096:159:0;;;;;;;;;;;113364:4;:17;;;-1:-1:-1;;;;;113364:29:0;;113394:4;:16;;;113412:10;113432:4;113439:41;113470:9;113439:26;113454:7;113462:1;113454:10;;;;;;;;;;;113439:7;113447:1;113439:10;;:41;113364:117;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;113364:117:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;;;113543:16:0;;;;113565:13;;;113580;;;113543:78;;-1:-1:-1;;;113543:78:0;;-1:-1:-1;;;;;113543:21:0;;;;;;:78;;113565:13;;113595:14;;113611:9;;113543:78;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;113543:78:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;113543:78:0;;;;113639:64;113647:10;113658:1;113647:13;;;;;;;;;;;113662:10;113673:1;113662:13;;;;113677:14;113693:9;113639:64;;;;;;;;;;6415:471;6473:7;6718:6;6714:47;;-1:-1:-1;6748:1:0;6741:8;;6714:47;6785:5;;;6789:1;6785;:5;:1;6809:5;;;;;:10;6801:56;;;;-1:-1:-1;;;6801:56:0;;;;;;;;;6877:1;-1:-1:-1;6415:471:0;;;;;:::o;15485:1114::-;16089:27;16097:5;-1:-1:-1;;;;;16089:25:0;;:27::i;:::-;16081:71;;;;-1:-1:-1;;;16081:71:0;;;;;;;;;16226:12;16240:23;16275:5;-1:-1:-1;;;;;16267:19:0;16287:4;16267:25;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;16225:67:0;;;;16311:7;16303:52;;;;-1:-1:-1;;;16303:52:0;;;;;;;;;16372:17;;:21;16368:224;;16514:10;16503:30;;;;;;;;;;;;;;16495:85;;;;-1:-1:-1;;;16495:85:0;;;;;;;;120200:4349;120559:20;;;;120345:14;;;;-1:-1:-1;;;;;120559:34:0;;120555:188;;120617:5;:22;;;-1:-1:-1;;;;;120617:30:0;;120648:11;:20;;;120670:11;:19;;;120617:73;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;120617:73:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;120617:73:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;120617:73:0;;;;;;;;;120610:80;;120555:188;;;-1:-1:-1;120730:1:0;120555:188;120755:29;;:::i;:::-;120981:11;:23;;;-1:-1:-1;;;;;120964:60:0;;121025:11;121038:4;120964:79;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;120964:79:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;120964:79:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;120964:79:0;;;;;;;;;120930:14;120946;;120929:114;;;120942:1;121122:30;121140:11;121122:17;:30::i;:::-;121215:25;;;;:9;:25;;;;;;;;;;121242:31;;;;;;;;;;;-1:-1:-1;;;121242:31:0;;;;;;;121097:55;;-1:-1:-1;121242:31:0;121215:25;;121214:26;121206:68;;;;-1:-1:-1;;;121206:68:0;;;;;;;;;;;121287:25;;:::i;:::-;121501:5;:25;;;-1:-1:-1;;;;;121501:35:0;;121537:14;121553:11;121501:64;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;121501:64:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;121501:64:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;121501:64:0;;;;;;;;;121475:10;121487;;121474:91;;;121578:25;;:::i;:::-;121928:86;121979:34;121998:11;122010:1;121998:14;;;;;121979:11;121991:1;121979:14;;:34;121928:46;121959:11;121971:1;121959:14;;;;;121928:26;121943:7;121951:1;121943:10;;;;121928:7;121936:1;121928:10;;:46;:50;:86;:50;:86;:::i;:::-;121915:99;;122038:86;122089:34;122108:11;122120:1;122108:14;;122089:34;122038:46;122069:11;122081:1;122069:14;;122038:86;122025:10;;;:99;122199:31;;-1:-1:-1;;;122199:31:0;;122234:8;;122199:29;;;;:31;;:14;;:31;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;122199:31:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;122199:31:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;122199:31:0;;;;;;;;;:43;122195:2347;;;122311:5;:25;;;-1:-1:-1;;;;;122311:32:0;;122344:14;122360:11;122311:61;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;122311:61:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;122311:61:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;122311:61:0;;;;;;;;;122307:1020;;;122499:14;;;-1:-1:-1;122591:21:0;122499:14;122602:9;122591:10;:21::i;:::-;122582:30;;122796:6;122738:10;:35;122749:11;:23;;;-1:-1:-1;;;;;122738:35:0;-1:-1:-1;;;;;122738:35:0;;;;;;;;;;;;:54;122774:11;:17;;;-1:-1:-1;;;;;122738:54:0;-1:-1:-1;;;;;122738:54:0;;;;;;;;;;;;;:64;;122847:36;;;;;;;;;;;;;;;;;122708:194;;;;;-1:-1:-1;;;122708:194:0;;;;;;;;;;-1:-1:-1;123051:23:0;;;;-1:-1:-1;;;;;123040:35:0;;;;;;;:10;:35;;;;;;;;123076:17;;;;123040:54;;;;;;;;;;:66;;123099:6;123040:66;:58;:66;:::i;:::-;122983:10;:35;122994:11;:23;;;-1:-1:-1;;;;;122983:35:0;-1:-1:-1;;;;;122983:35:0;;;;;;;;;;;;:54;123019:11;:17;;;-1:-1:-1;;;;;122983:54:0;-1:-1:-1;;;;;122983:54:0;;;;;;;;;;;;:123;;;;122307:1020;;;123202:10;;;-1:-1:-1;123290:21:0;123202:10;123301:9;123290:10;:21::i;:::-;123281:30;;122307:1020;123461:25;123476:9;123461:7;123469:1;123461:10;;;;;;:25;:14;:25;:::i;:::-;123452:6;:34;123448:284;;;123624:25;;;;123604:112;;123615:100;;123651:14;123667:11;123689:25;123704:9;123689:7;123697:1;123689:10;;:25;123680:6;:34;123615:8;:100::i;:::-;123604:6;;:112;:10;:112;:::i;:::-;123595:121;;123448:284;122195:2347;;;123814:32;;-1:-1:-1;;;123814:32:0;;123850:8;;123814:30;;;;:32;;:14;;:32;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;123814:32:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;123814:32:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;123814:32:0;;;;;;;;;:44;123810:732;;;123927:10;;;;;-1:-1:-1;124007:21:0;123927:10;124018:9;124007:10;:21::i;:::-;123998:30;-1:-1:-1;124164:25:0;124179:9;124164:7;124172:1;124164:10;;:25;124155:6;:34;124151:259;;;124302:25;;;;124282:112;;124293:100;;124329:14;124345:11;124367:25;124382:9;124367:7;124375:1;124367:10;;123810:732;120200:4349;;;;;;;;;;;:::o;5043:181::-;5101:7;5133:5;;;5157:6;;;;5149:46;;;;-1:-1:-1;;;5149:46:0;;;;;;;;10276:810;10336:4;10995:20;;10838:66;11035:15;;;;;:42;;;11066:11;11054:8;:23;;11035:42;11027:51;10276:810;-1:-1:-1;;;;10276:810:0:o;7354:132::-;7412:7;7439:39;7443:1;7446;7439:39;;;;;;;;;;;;;;;;;:3;:39::i;5499:136::-;5557:7;5584:43;5588:1;5591;5584:43;;;;;;;;;;;;;;;;;:3;:43::i;124971:1627::-;125121:11;125228:21;125252:20;-1:-1:-1;;;;;125252:37:0;;125290:15;125307:11;125252:67;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;125252:67:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;125252:67:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;125252:67:0;;;;;;;;;125228:91;;125413:18;125434:20;-1:-1:-1;;;;;125434:40:0;;125475:15;125492:11;125434:70;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;125434:70:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;125434:70:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;125434:70:0;;;;;;;;;125413:91;-1:-1:-1;125605:44:0;31073:5;125605:23;:7;125413:91;125605:23;:11;:23;:::i;:44::-;125599:50;-1:-1:-1;125708:8:0;125704:49;;125740:1;125733:8;;;;;;125704:49;125872:16;125891:57;31185:2;125891:30;:3;31324:1;125891:30;:7;:30;:::i;:57::-;125872:76;-1:-1:-1;126033:17:0;126053;:3;125872:76;126053:17;:7;:17;:::i;:::-;126033:37;;126113:20;126136:8;;;;;;;;;-1:-1:-1;;;;;126136:8:0;-1:-1:-1;;;;;126136:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;126136:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;126136:26:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;126136:26:0;;;;;;;;;-1:-1:-1;;;;;126312:24:0;;;;;;;:10;:24;;;;;;;;126337:17;;;;126312:43;;;;;;;;;;126113:49;;-1:-1:-1;126312:57:0;;126360:8;126312:57;:47;:57;:::i;:::-;-1:-1:-1;;;;;126266:24:0;;;;;;;:10;:24;;;;;;;;126291:17;;;;;126266:43;;;;;;;;;;:103;;;;126531:25;;;;;;;;;;;126557:17;;126531:44;;;;;;;;;;;:59;;126580:9;126531:59;:48;:59;:::i;:::-;-1:-1:-1;;;;;126484:25:0;;;;;;;:10;:25;;;;;;;;126510:17;;;;126484:44;;;;;;;;;;;;:106;;;;-1:-1:-1;;;;124971:1627:0;;;;;;:::o;8016:345::-;8102:7;8204:12;8197:5;8189:28;;;;-1:-1:-1;;;8189:28:0;;;;;;;;;;;8228:9;8244:1;8240;:5;;;;;;;-1:-1:-1;;8016:345:0;;;;;;:::o;5972:192::-;6058:7;6094:12;6086:6;;;;6078:29;;;;-1:-1:-1;;;6078:29:0;;;;;;;;;;-1:-1:-1;;;6130:5:0;;;5972:192::o;100882:25719::-;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;100882:25719:0;;;;;;-1:-1:-1;;;;;100882:25719:0;;;;;;-1:-1:-1;;;;;100882:25719:0;;;;;:::o;:::-;;;;;;;;;-1:-1:-1;100882:25719:0;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;100882:25719:0;;;-1:-1:-1;;100882:25719:0:o;:::-;;;;;;;;;-1:-1:-1;100882:25719:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;5:130:-1:-;72:20;;97:33;72:20;97:33;;142:134;220:13;;238:33;220:13;238:33;;302:616;;417:3;410:4;402:6;398:17;394:27;384:2;;435:1;432;425:12;384:2;459:4;478:78;493:62;548:6;493:62;;;478:78;;;469:87;;573:5;632:6;679:3;671:4;663:6;659:17;654:3;650:27;647:36;644:2;;;696:1;693;686:12;644:2;721:1;706:206;731:6;728:1;725:13;706:206;;;789:3;811:37;844:3;832:10;811:37;;;799:50;;-1:-1;872:4;863:14;;;;891;;;;;753:1;746:9;706:206;;;710:14;377:541;;;;;;;;968:747;;1108:3;1101:4;1093:6;1089:17;1085:27;1075:2;;1126:1;1123;1116:12;1075:2;1163:6;1150:20;1185:103;1200:87;1280:6;1200:87;;1185:103;1316:21;;;1360:4;1348:17;;;;1176:112;;-1:-1;1373:14;;1348:17;1468:1;1453:256;1478:6;1475:1;1472:13;1453:256;;;1561:3;1548:17;1540:6;1536:30;1585:60;1641:3;1629:10;1585:60;;;1573:73;;-1:-1;1669:4;1660:14;;;;1688;;;;;1500:1;1493:9;1453:256;;1741:699;;1854:3;1847:4;1839:6;1835:17;1831:27;1821:2;;1872:1;1869;1862:12;1821:2;1909:6;1896:20;1931:76;1946:60;1999:6;1946:60;;1931:76;1922:85;;2024:5;2049:6;2042:5;2035:21;2079:4;2071:6;2067:17;2057:27;;2101:4;2096:3;2092:14;2085:21;;2154:6;2201:3;2193:4;2185:6;2181:17;2176:3;2172:27;2169:36;2166:2;;;2218:1;2215;2208:12;2166:2;2243:1;2228:206;2253:6;2250:1;2247:13;2228:206;;;2311:3;2333:37;2366:3;2354:10;2333:37;;;2321:50;;-1:-1;2394:4;2385:14;;;;2413;;;;;2275:1;2268:9;2228:206;;2466:707;;2583:3;2576:4;2568:6;2564:17;2560:27;2550:2;;2601:1;2598;2591:12;2550:2;2638:6;2625:20;2660:80;2675:64;2732:6;2675:64;;2660:80;2651:89;;2757:5;2782:6;2775:5;2768:21;2812:4;2804:6;2800:17;2790:27;;2834:4;2829:3;2825:14;2818:21;;2887:6;2934:3;2926:4;2918:6;2914:17;2909:3;2905:27;2902:36;2899:2;;;2951:1;2948;2941:12;2899:2;2976:1;2961:206;2986:6;2983:1;2980:13;2961:206;;;3044:3;3066:37;3099:3;3087:10;3066:37;;;3054:50;;-1:-1;3127:4;3118:14;;;;3146;;;;;3008:1;3001:9;2961:206;;3181:128;3256:13;;3274:30;3256:13;3274:30;;3316:130;3383:20;;3408:33;3383:20;3408:33;;3491:1169;;3603:4;3591:9;3586:3;3582:19;3578:30;3575:2;;;3621:1;3618;3611:12;3575:2;3639:20;3654:4;3639:20;;;3630:29;-1:-1;3711:1;3743:49;3788:3;3768:9;3743:49;;;3718:75;;-1:-1;3857:2;3890:49;3935:3;3911:22;;;3890:49;;;3883:4;3876:5;3872:16;3865:75;3814:137;4031:2;4020:9;4016:18;4003:32;-1:-1;;;;;4047:6;4044:30;4041:2;;;4087:1;4084;4077:12;4041:2;4122:70;4188:3;4179:6;4168:9;4164:22;4122:70;;;4115:4;4108:5;4104:16;4097:96;3961:243;4258:2;4291:49;4336:3;4327:6;4316:9;4312:22;4291:49;;;4284:4;4277:5;4273:16;4266:75;4214:138;4403:3;4437:49;4482:3;4473:6;4462:9;4458:22;4437:49;;;4430:4;4423:5;4419:16;4412:75;4362:136;4555:3;4589:49;4634:3;4625:6;4614:9;4610:22;4589:49;;;4582:4;4575:5;4571:16;4564:75;4508:142;3569:1091;;;;;6022:134;6100:13;;6118:33;6100:13;6118:33;;6163:241;;6267:2;6255:9;6246:7;6242:23;6238:32;6235:2;;;6283:1;6280;6273:12;6235:2;6318:1;6335:53;6380:7;6360:9;6335:53;;6411:263;;6526:2;6514:9;6505:7;6501:23;6497:32;6494:2;;;6542:1;6539;6532:12;6494:2;6577:1;6594:64;6650:7;6630:9;6594:64;;6681:366;;;6802:2;6790:9;6781:7;6777:23;6773:32;6770:2;;;6818:1;6815;6808:12;6770:2;6853:1;6870:53;6915:7;6895:9;6870:53;;;6860:63;;6832:97;6960:2;6978:53;7023:7;7014:6;7003:9;6999:22;6978:53;;;6968:63;;6939:98;6764:283;;;;;;7054:1071;;;;;7307:3;7295:9;7286:7;7282:23;7278:33;7275:2;;;7324:1;7321;7314:12;7275:2;7359:1;7376:53;7421:7;7401:9;7376:53;;;7366:63;;7338:97;7494:2;7483:9;7479:18;7466:32;-1:-1;;;;;7510:6;7507:30;7504:2;;;7550:1;7547;7540:12;7504:2;7570:78;7640:7;7631:6;7620:9;7616:22;7570:78;;;7560:88;;7445:209;7713:2;7702:9;7698:18;7685:32;-1:-1;;;;;7729:6;7726:30;7723:2;;;7769:1;7766;7759:12;7723:2;7789:78;7859:7;7850:6;7839:9;7835:22;7789:78;;;7779:88;;7664:209;7932:2;7921:9;7917:18;7904:32;-1:-1;;;;;7948:6;7945:30;7942:2;;;7988:1;7985;7978:12;7942:2;8008:101;8101:7;8092:6;8081:9;8077:22;8008:101;;;7998:111;;7883:232;7269:856;;;;;;;;8132:757;;;;;8314:3;8302:9;8293:7;8289:23;8285:33;8282:2;;;8331:1;8328;8321:12;8282:2;8366:1;8383:53;8428:7;8408:9;8383:53;;;8373:63;;8345:97;8473:2;8491:53;8536:7;8527:6;8516:9;8512:22;8491:53;;;8481:63;;8452:98;8581:2;8599:53;8644:7;8635:6;8624:9;8620:22;8599:53;;;8589:63;;8560:98;8717:2;8706:9;8702:18;8689:32;-1:-1;;;;;8733:6;8730:30;8727:2;;;8773:1;8770;8763:12;8727:2;8793:80;8865:7;8856:6;8845:9;8841:22;8793:80;;8896:945;;;;9132:2;9120:9;9111:7;9107:23;9103:32;9100:2;;;9148:1;9145;9138:12;9100:2;9183:31;;-1:-1;;;;;9223:30;;9220:2;;;9266:1;9263;9256:12;9220:2;9286:78;9356:7;9347:6;9336:9;9332:22;9286:78;;;9276:88;;9162:208;9429:2;9418:9;9414:18;9401:32;-1:-1;;;;;9445:6;9442:30;9439:2;;;9485:1;9482;9475:12;9439:2;9505:78;9575:7;9566:6;9555:9;9551:22;9505:78;;;9495:88;;9380:209;9648:2;9637:9;9633:18;9620:32;-1:-1;;;;;9664:6;9661:30;9658:2;;;9704:1;9701;9694:12;9658:2;9724:101;9817:7;9808:6;9797:9;9793:22;9724:101;;;9714:111;;9599:232;9094:747;;;;;;9848:257;;9960:2;9948:9;9939:7;9935:23;9931:32;9928:2;;;9976:1;9973;9966:12;9928:2;10011:1;10028:61;10081:7;10061:9;10028:61;;10112:241;;10216:2;10204:9;10195:7;10191:23;10187:32;10184:2;;;10232:1;10229;10222:12;10184:2;10267:1;10284:53;10329:7;10309:9;10284:53;;10360:381;;10491:2;10479:9;10470:7;10466:23;10462:32;10459:2;;;10507:1;10504;10497:12;10459:2;10542:31;;-1:-1;;;;;10582:30;;10579:2;;;10625:1;10622;10615:12;10579:2;10645:80;10717:7;10708:6;10697:9;10693:22;10645:80;;10748:678;;;;10936:3;10924:9;10915:7;10911:23;10907:33;10904:2;;;10953:1;10950;10943:12;10904:2;10988:31;;-1:-1;;;;;11028:30;;11025:2;;;11071:1;11068;11061:12;11025:2;11091:80;11163:7;11154:6;11143:9;11139:22;11091:80;;;11081:90;;10967:210;11208:2;11226:53;11271:7;11262:6;11251:9;11247:22;11226:53;;;11216:63;;11187:98;11316:2;11334:76;11402:7;11393:6;11382:9;11378:22;11334:76;;11433:263;;11548:2;11536:9;11527:7;11523:23;11519:32;11516:2;;;11564:1;11561;11554:12;11516:2;11599:1;11616:64;11672:7;11652:9;11616:64;;11703:399;;;11835:2;11823:9;11814:7;11810:23;11806:32;11803:2;;;11851:1;11848;11841:12;11803:2;11886:1;11903:64;11959:7;11939:9;11903:64;;;11893:74;;11865:108;12004:2;12022:64;12078:7;12069:6;12058:9;12054:22;12022:64;;12109:631;;;;12274:2;12262:9;12253:7;12249:23;12245:32;12242:2;;;12290:1;12287;12280:12;12242:2;12325:1;12342:53;12387:7;12367:9;12342:53;;;12332:63;;12304:97;12432:2;12450:53;12495:7;12486:6;12475:9;12471:22;12450:53;;;12440:63;;12411:98;12568:2;12557:9;12553:18;12540:32;-1:-1;;;;;12584:6;12581:30;12578:2;;;12624:1;12621;12614:12;12578:2;12644:80;12716:7;12707:6;12696:9;12692:22;12644:80;;12748:173;;12835:46;12877:3;12869:6;12835:46;;;-1:-1;;12910:4;12901:14;;12828:93;13127:142;13218:45;13257:5;13218:45;;;13213:3;13206:58;13200:69;;;13276:103;13349:24;13367:5;13349:24;;13506:152;13607:45;13627:24;13645:5;13627:24;;;13607:45;;13696:654;;13827:50;13871:5;13827:50;;;13890:76;13959:6;13954:3;13890:76;;;13883:83;;13987:52;14033:5;13987:52;;;14059:7;14087:1;14072:256;14097:6;14094:1;14091:13;14072:256;;;14164:6;14158:13;14185:63;14244:3;14229:13;14185:63;;;14178:70;;14265:56;14314:6;14265:56;;;14255:66;-1:-1;;14119:1;14112:9;14072:256;;;-1:-1;14341:3;;13806:544;-1:-1;;;;;13806:544;14389:718;;14548:50;14592:5;14548:50;;;14611:104;14708:6;14703:3;14611:104;;;14604:111;;14736:52;14782:5;14736:52;;;14808:7;14836:1;14821:264;14846:6;14843:1;14840:13;14821:264;;;14913:6;14907:13;14934:71;15001:3;14986:13;14934:71;;;14927:78;;15022:56;15071:6;15022:56;;;15012:66;-1:-1;;14868:1;14861:9;14821:264;;15115:104;15192:21;15207:5;15192:21;;15226:113;15309:24;15327:5;15309:24;;15474:356;;15602:38;15634:5;15602:38;;;15652:88;15733:6;15728:3;15652:88;;;15645:95;;15745:52;15790:6;15785:3;15778:4;15771:5;15767:16;15745:52;;;15809:16;;;;;15582:248;-1:-1;;15582:248;15837:152;15933:50;15977:5;15933:50;;15996:347;;16108:39;16141:5;16108:39;;;16159:71;16223:6;16218:3;16159:71;;;16152:78;;16235:52;16280:6;16275:3;16268:4;16261:5;16257:16;16235:52;;;16308:29;16330:6;16308:29;;;16299:39;;;;16088:255;-1:-1;;;16088:255;16697:327;;16857:67;16921:2;16916:3;16857:67;;;16957:29;16937:50;;17015:2;17006:12;;16843:181;-1:-1;;16843:181;17033:332;;17193:67;17257:2;17252:3;17193:67;;;17293:34;17273:55;;17356:2;17347:12;;17179:186;-1:-1;;17179:186;17374:370;;17534:67;17598:2;17593:3;17534:67;;;17634:34;17614:55;;-1:-1;;;17698:2;17689:12;;17682:25;17735:2;17726:12;;17520:224;-1:-1;;17520:224;17753:379;;17913:67;17977:2;17972:3;17913:67;;;18013:34;17993:55;;-1:-1;;;18077:2;18068:12;;18061:34;18123:2;18114:12;;17899:233;-1:-1;;17899:233;18141:331;;18301:67;18365:2;18360:3;18301:67;;;18401:33;18381:54;;18463:2;18454:12;;18287:185;-1:-1;;18287:185;18481:331;;18641:67;18705:2;18700:3;18641:67;;;18741:33;18721:54;;18803:2;18794:12;;18627:185;-1:-1;;18627:185;18893:1236;19116:23;;18893:1236;;19048:4;19039:14;;;19145:63;19043:3;19116:23;19145:63;;;19068:146;19290:4;19283:5;19279:16;19273:23;19302:63;19359:4;19354:3;19350:14;19336:12;19302:63;;;19224:147;19446:4;19439:5;19435:16;19429:23;19498:3;19492:4;19488:14;19481:4;19476:3;19472:14;19465:38;19518:99;19612:4;19598:12;19518:99;;;19510:107;;19381:248;19706:4;19699:5;19695:16;19689:23;19718:63;19775:4;19770:3;19766:14;19752:12;19718:63;;;19639:148;19861:4;19854:5;19850:16;19844:23;19873:63;19930:4;19925:3;19921:14;19907:12;19873:63;;;19797:145;20022:4;20015:5;20011:16;20005:23;20034:63;20091:4;20086:3;20082:14;20068:12;20034:63;;;-1:-1;20120:4;19021:1108;-1:-1;;;19021:1108;21796:152;21897:45;21917:24;21935:5;21917:24;;;21897:45;;21955:262;;22099:93;22188:3;22179:6;22099:93;;22224:1013;;22529:75;22600:3;22591:6;22529:75;;;22626:2;22621:3;22617:12;22610:19;;22640:75;22711:3;22702:6;22640:75;;;22737:2;22732:3;22728:12;22721:19;;22758:121;22875:3;22866:6;22758:121;;;22751:128;;22890:75;22961:3;22952:6;22890:75;;;22987:2;22982:3;22978:12;22971:19;;23001:75;23072:3;23063:6;23001:75;;;23098:2;23093:3;23089:12;23082:19;;23112:75;23183:3;23174:6;23112:75;;;-1:-1;23209:2;23200:12;;22517:720;-1:-1;;;;;;22517:720;23244:213;23362:2;23347:18;;23376:71;23351:9;23420:6;23376:71;;23464:340;23618:2;23603:18;;23632:79;23607:9;23684:6;23632:79;;;23722:72;23790:2;23779:9;23775:18;23766:6;23722:72;;23811:451;23993:2;23978:18;;24007:79;23982:9;24059:6;24007:79;;;24097:72;24165:2;24154:9;24150:18;24141:6;24097:72;;;24180;24248:2;24237:9;24233:18;24224:6;24180:72;;24269:563;24479:3;24464:19;;24494:71;24468:9;24538:6;24494:71;;;24576:80;24652:2;24641:9;24637:18;24628:6;24576:80;;;24667:72;24735:2;24724:9;24720:18;24711:6;24667:72;;;24750;24818:2;24807:9;24803:18;24794:6;24750:72;;;24450:382;;;;;;;;24839:547;25041:3;25026:19;;25056:71;25030:9;25100:6;25056:71;;;25138:72;25206:2;25195:9;25191:18;25182:6;25138:72;;25393:435;25567:2;25552:18;;25581:71;25556:9;25625:6;25581:71;;25835:324;25981:2;25966:18;;25995:71;25970:9;26039:6;25995:71;;;26077:72;26145:2;26134:9;26130:18;26121:6;26077:72;;26608:201;26720:2;26705:18;;26734:65;26709:9;26772:6;26734:65;;26816:213;26934:2;26919:18;;26948:71;26923:9;26992:6;26948:71;;27272:472;27468:2;27453:18;;27482:71;27457:9;27526:6;27482:71;;;27601:9;27595:4;27591:20;27586:2;27575:9;27571:18;27564:48;27626:108;27729:4;27720:6;27626:108;;28238:589;28461:3;28446:19;;28476:84;28450:9;28533:6;28476:84;;;28571:80;28647:2;28636:9;28632:18;28623:6;28571:80;;;28662:72;28730:2;28719:9;28715:18;28706:6;28662:72;;28834:293;28968:2;28982:47;;;28953:18;;29043:74;28953:18;29103:6;29043:74;;29442:407;29633:2;29647:47;;;29618:18;;29708:131;29618:18;29708:131;;29856:407;30047:2;30061:47;;;30032:18;;30122:131;30032:18;30122:131;;30270:407;30461:2;30475:47;;;30446:18;;30536:131;30446:18;30536:131;;30684:407;30875:2;30889:47;;;30860:18;;30950:131;30860:18;30950:131;;31098:407;31289:2;31303:47;;;31274:18;;31364:131;31274:18;31364:131;;31512:407;31703:2;31717:47;;;31688:18;;31778:131;31688:18;31778:131;;31926:369;32098:2;32112:47;;;32083:18;;32173:112;32083:18;32271:6;32173:112;;32302:480;32502:2;32516:47;;;32487:18;;32577:112;32487:18;32675:6;32577:112;;;32569:120;;32700:72;32768:2;32757:9;32753:18;32744:6;32700:72;;33009:256;33071:2;33065:9;33097:17;;;-1:-1;;;;;33157:34;;33193:22;;;33154:62;33151:2;;;33229:1;33226;33219:12;33151:2;33245;33238:22;33049:216;;-1:-1;33049:216;33272:244;;-1:-1;;;;;33421:6;33418:30;33415:2;;;33461:1;33458;33451:12;33415:2;-1:-1;33496:4;33484:17;;33352:164;33523:327;;-1:-1;;;;;33697:6;33694:30;33691:2;;;33737:1;33734;33727:12;33691:2;-1:-1;33772:4;33760:17;;;33825:15;;33628:222;34475:147;34595:4;34586:14;;34543:79;34629:133;34728:12;;34699:63;35263:168;35371:19;;;35420:4;35411:14;;35364:67;35440:160;35591:3;35569:31;-1:-1;35569:31;35933:91;;35995:24;36013:5;35995:24;;36031:85;36097:13;36090:21;;36073:43;36123:72;36185:5;36168:27;36202:121;-1:-1;;;;;36264:54;;36247:76;36409:129;;36496:37;36527:5;36545:147;;36637:50;36681:5;36637:50;;37071:268;37136:1;37143:101;37157:6;37154:1;37151:13;37143:101;;;37224:11;;;37218:18;37205:11;;;37198:39;37179:2;37172:10;37143:101;;;37259:6;37256:1;37253:13;37250:2;;;-1:-1;;37324:1;37306:16;;37299:27;37120:219;37347:95;;37411:26;37431:5;37449:89;37513:20;37527:5;37513:20;;37626:97;37714:2;37694:14;-1:-1;;37690:28;;37674:49;37731:94;37805:2;37801:14;;37773:52;37833:117;37902:24;37920:5;37902:24;;;37895:5;37892:35;37882:2;;37941:1;37938;37931:12;37882:2;37876:74;;37957:111;38023:21;38038:5;38023:21;;38075:117;38144:24;38162:5;38144:24;
Swarm Source
bzzr://b81b09c4918da42f6d048d3ed1a82db34fe18efa6274d34c7f2030bbb6326fdf
Loading...
Loading
Loading...
Loading
OVERVIEW
Holds and distributes Opium Protocol's funds, validates derivatives logicLoading...
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.