| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Core
Compiler Version
v0.5.16+commit.9c3226ce
Contract Source Code (Solidity)
/**
*Submitted for verification at Etherscan.io on 2021-10-08
*/
// 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_INSUFFICIENT_P2P_BALANCE = "CORE:INSUFFICIENT_P2P_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 = 0;
}
// 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 {
// Token description
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function totalSupply() public view returns (uint256);
function exists(uint256 _tokenId) public view returns (bool);
function implementsERC721() public pure returns (bool);
function tokenByIndex(uint256 _index) public view returns (uint256);
function tokenOfOwnerByIndex(address _owner, uint256 _index) public view returns (uint256 _tokenId);
function tokenURI(uint256 _tokenId) public view returns (string memory tokenUri);
function getApproved(uint256 _tokenId) public view returns (address);
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);
// Non-Fungible Safe Transfer From
function safeTransferFrom(address _from, address _to, uint256 _tokenId) public;
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory _data) public;
// Non-Fungible Unsafe Transfer From
function transferFrom(address _from, address _to, uint256 _tokenId) public;
// Fungible Unsafe Transfer
function transfer(address _to, uint256 _tokenId, uint256 _quantity) public;
// Fungible Unsafe Transfer From
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;
// Fungible Safe Batch Transfer From
function safeBatchTransferFrom(address _from, address _to, uint256[] memory _tokenIds, uint256[] memory _amounts) public;
function safeBatchTransferFrom(address _from, address _to, uint256[] memory _tokenIds, uint256[] memory _amounts, bytes memory _data) public;
// Fungible Unsafe Batch Transfer From
function batchTransferFrom(address _from, address _to, uint256[] memory _tokenIds, uint256[] memory _amounts) public;
// Approvals
function setApprovalForAll(address _operator, bool _approved) public;
function approve(address _to, uint256 _tokenId) public;
function getApproved(uint256 _tokenId, address _tokenOwner) public view returns (address);
function isApprovedForAll(address _owner, address _operator) public view returns (bool isOperator);
function isApprovedOrOwner(address _spender, address _owner, uint256 _tokenId) public view returns (bool);
function permit(address _holder, address _spender, uint256 _nonce, uint256 _expiry, bool _allowed, bytes calldata _signature) external;
// Composable
function compose(uint256[] memory _tokenIds, uint256[] memory _tokenRatio, uint256 _quantity) public;
function decompose(uint256 _portfolioId, uint256[] memory _tokenIds, uint256[] memory _tokenRatio, uint256 _quantity) public;
function recompose(uint256 _portfolioId, uint256[] memory _initialTokenIds, uint256[] memory _initialTokenRatio, uint256[] memory _finalTokenIds, uint256[] memory _finalTokenRatio, uint256 _quantity) 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 to address");
// Number of transfers to execute
uint256 nTransfer = _tokenIds.length;
// Don't do useless calculations
if (_from == _to) {
for (uint256 i = 0; i < nTransfer; i++) {
emit Transfer(_from, _to, _tokenIds[i]);
emit TransferWithQuantity(_from, _to, _tokenIds[i], _amounts[i]);
}
return;
}
for (uint256 i = 0; i < nTransfer; i++) {
require(_amounts[i] <= balanceOf(_from, _tokenIds[i]), "Quantity greater than from balance");
_updateTokenBalance(_from, _tokenIds[i], _amounts[i], ObjectLib.Operations.SUB);
_updateTokenBalance(_to, _tokenIds[i], _amounts[i], ObjectLib.Operations.ADD);
emit Transfer(_from, _to, _tokenIds[i]);
emit TransferWithQuantity(_from, _to, _tokenIds[i], _amounts[i]);
}
// 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[];
using SafeMath 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].mul(_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].mul(_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].mul(_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].mul(_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.mul(_quantity));
} else if (_initialTokenRatio[initialIndex] < _finalTokenRatio[finalIndex]) {
uint256 diff = _finalTokenRatio[finalIndex] - _initialTokenRatio[initialIndex];
_burn(msg.sender, _initialTokenIds[initialIndex], diff.mul(_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 p2p derivatives
// This mapping holds balances of p2p positions
// p2pVaults[derivativeHash] => availableBalance
mapping(bytes32 => uint256) public p2pVaults;
// Derivative payouts cache
// Once paid out (executed), the payout ratio is stored in cache
mapping(bytes32 => uint256[2]) public derivativePayouts;
// 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));
// Increment p2p positions balance by collected margin: vault += (margins[0] + margins[1]) * quantity
_increaseP2PVault(
derivativeHash,
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 margin required according to logic from Opium.SyntheticAggregator (if pooled derivative, the margin is not cached)
// 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].mul(_quantities[i]);
// Check if it's a pooled position
if (vars.syntheticAggregator.isPool(derivativeHash, _derivatives[i])) {
// Check sufficiency of syntheticId balance in poolVaults
require(
poolVaults[_derivatives[i].syntheticId][_derivatives[i].token] >= payout
,
ERROR_CORE_INSUFFICIENT_POOL_BALANCE
);
// Subtract paid out margin from poolVault
poolVaults[_derivatives[i].syntheticId][_derivatives[i].token] = poolVaults[_derivatives[i].syntheticId][_derivatives[i].token].sub(payout);
} else {
// Subtract paid out margin from p2pVault
_decreaseP2PVault(derivativeHash, payout);
}
// Check if `_tokenId` is an ID of SHORT position
} else if (derivativeHash.getShortTokenId() == _tokenIds[i]) {
// Set payout to sellerPayout
payout = margins[1].mul(_quantities[i]);
// Subtract paid out margin from p2pVault
_decreaseP2PVault(derivativeHash, payout);
} 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);
}
// 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]));
// If cached buer and seller payouts are both zero, then cache is not initialized, because total zero margin is not allowed by SyntheticAggregator
// Initialize cache
if (derivativePayouts[derivativeHash][0] == 0 && derivativePayouts[derivativeHash][1] == 0) {
// Cache buyer payout
derivativePayouts[derivativeHash][0] = payouts[0];
// Cache seller payout
derivativePayouts[derivativeHash][1] = payouts[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 cached buyerPayout
payout = derivativePayouts[derivativeHash][0];
// Multiply payout by quantity
payout = payout.mul(_quantity);
// Subtract payout from p2pVault
_decreaseP2PVault(derivativeHash, payout);
}
// 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 cached sellerPayout
payout = derivativePayouts[derivativeHash][1];
// Multiply payout by quantity
payout = payout.mul(_quantity);
// Subtract payout from p2pVault
_decreaseP2PVault(derivativeHash, payout);
// 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);
}
function _increaseP2PVault(bytes32 _derivativeHash, uint256 _amount) private {
p2pVaults[_derivativeHash] = p2pVaults[_derivativeHash].add(_amount);
}
function _decreaseP2PVault(bytes32 _derivativeHash, uint256 _amount) private {
require(
p2pVaults[_derivativeHash] >= _amount,
ERROR_CORE_INSUFFICIENT_P2P_BALANCE
);
p2pVaults[_derivativeHash] = p2pVaults[_derivativeHash].sub(_amount);
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"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":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"derivativePayouts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","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":"bytes32","name":"","type":"bytes32"}],"name":"p2pVaults","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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
60806040523480156200001157600080fd5b5060405162004192380380620041928339810160408190526200003491620000aa565b600080546001600160a01b0319166001600160a01b03831617905560405181907f27fe5f0c1c3b1ed427cc63d0f05759ffdecf9aec9e18d31ef366fc8a6cb5dc3b9062000083908390620000e4565b60405180910390a150506001805562000120565b8051620000a48162000106565b92915050565b600060208284031215620000bd57600080fd5b6000620000cb848462000097565b949350505050565b620000de81620000f4565b82525050565b60208101620000a48284620000d3565b60006001600160a01b038216620000a4565b6200011181620000f4565b81146200011d57600080fd5b50565b61406280620001306000396000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c80635ab1bd53116100ad578063ab85d5ec11610071578063ab85d5ec14610241578063d7acb44814610249578063d842b22b1461025c578063eb95512214610264578063f1015a161461027757610121565b80635ab1bd53146101eb5780635d419a9c146102005780636a990b6e146102135780639ecd27aa14610226578063a956fd121461023957610121565b80632ac12622116100f45780632ac126221461017f5780634b5095921461019f5780634df6d09d146101b257806354af742a146101c557806354dc1b22146101d857610121565b80630d06dd6b146101265780631ac3ddeb1461013b57806328fb2b031461014e578063291092b31461016c575b600080fd5b61013961013436600461365b565b61028a565b005b6101396101493660046134d3565b6102cf565b610156610334565b6040516101639190613d4c565b60405180910390f35b61013961017a3660046135ef565b610339565b61019261018d36600461370a565b610441565b6040516101639190613d3e565b6101566101ad36600461350f565b610456565b6101396101c0366004613549565b610473565b6101396101d3366004613833565b6104aa565b6101396101e6366004613833565b6105aa565b6101f3610687565b6040516101639190613c6b565b61015661020e366004613728565b610696565b61015661022136600461350f565b6106b8565b61013961023436600461365b565b6106d5565b6101566106eb565b6101566106f0565b61013961025736600461378c565b6106f7565b610156610732565b610156610272366004613758565b610738565b61015661028536600461370a565b610785565b6001805481019081905561029f848484610797565b60015481146102c95760405162461bcd60e51b81526004016102c090613df3565b60405180910390fd5b50505050565b600180548101908190553360008181526005602090815260408083206001600160a01b038716808552925282208054929055909161030e9190836111f4565b5060015481146103305760405162461bcd60e51b81526004016102c090613df3565b5050565b600081565b6001805481018082556040805183815280820190915290916060919060208083019080388339505060408051600180825281830190925292935060609291506020808301908038833950506040805160018082528183019092529293506060929150602082015b6103a8613184565b8152602001906001900390816103a057905050905086836000815181106103cb57fe5b60200260200101818152505085826000815181106103e557fe5b60200260200101818152505084816000815181106103ff57fe5b602002602001018190525061041688848484611252565b505050600154811461043a5760405162461bcd60e51b81526004016102c090613df3565b5050505050565b60066020526000908152604090205460ff1681565b600260209081526000928352604080842090915290825290205481565b6001805481019081905561048985858585611252565b600154811461043a5760405162461bcd60e51b81526004016102c090613df3565b6001805481018082556040805183815280820190915290916060919060208083019080388339505060408051600180825281830190925292935060609291506020808301908038833950506040805160018082528183019092529293506060929150602082015b610519613184565b815260200190600190039081610511579050509050868360008151811061053c57fe5b602002602001018181525050858260008151811061055657fe5b602002602001018181525050848160008151811061057057fe5b6020026020010181905250610586838383610797565b50505060015481146102c95760405162461bcd60e51b81526004016102c090613df3565b6001805481018082556040805183815280820190915290916060919060208083019080388339505060408051600180825281830190925292935060609291506020808301908038833950506040805160018082528183019092529293506060929150602082015b610619613184565b815260200190600190039081610611579050509050868360008151811061063c57fe5b602002602001018181525050858260008151811061065657fe5b602002602001018181525050848160008151811061067057fe5b602002602001018190525061058633848484611252565b6000546001600160a01b031690565b600460205281600052604060002081600281106106af57fe5b01549150829050565b600560209081526000928352604080842090915290825290205481565b6001805481019081905561029f33858585611252565b600a81565b6212750081565b6001805481019081905560208201516001600160a01b03166107275781516107229085908590611708565b61029f565b61029f848484611ded565b61271081565b80516020808301516040808501516060860151608087015160a08801519351600097610768979096959101613c05565b604051602081830303815290604052805190602001209050919050565b60036020526000908152604090205481565b8151835114604051806060016040528060338152602001613f6760339139906107d35760405162461bcd60e51b81526004016102c09190613da2565b508051835114604051806060016040528060348152602001613fc260349139906108105760405162461bcd60e51b81526004016102c09190613da2565b506108196131d5565b6000809054906101000a90046001600160a01b03166001600160a01b031663f36675176040518163ffffffff1660e01b815260040160206040518083038186803b15801561086657600080fd5b505afa15801561087a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061089e91908101906134f1565b6001600160a01b039081168252600054604080516334d2b0af60e21b81529051919092169163d34ac2bc916004808301926020929190829003018186803b1580156108e857600080fd5b505afa1580156108fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061092091908101906134f1565b6001600160a01b039081166020808401919091526000546040805163205dd91360e21b815290519190931692638177644c926004808301939192829003018186803b15801561096e57600080fd5b505afa158015610982573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506109a691908101906134f1565b6001600160a01b0316604082015260005b845181101561043a5760006001600160a01b03168382815181106109d757fe5b6020026020010151606001516001600160a01b031614156040518060400160405280602081526020017f434f52453a43414e545f43414e43454c5f44554d4d595f4f5241434c455f494481525090610a425760405162461bcd60e51b81526004016102c09190613da2565b504262127500848381518110610a5457fe5b6020026020010151602001510111158015610b1c575081602001516001600160a01b031663c8384d2f848381518110610a8957fe5b602002602001015160600151858481518110610aa157fe5b6020026020010151602001516040518363ffffffff1660e01b8152600401610aca929190613d23565b60206040518083038186803b158015610ae257600080fd5b505afa158015610af6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b1a91908101906136ec565b155b6040518060400160405280602081526020017f434f52453a43414e43454c4c4154494f4e5f49535f4e4f545f414c4c4f57454481525090610b705760405162461bcd60e51b81526004016102c09190613da2565b506000610b8f848381518110610b8257fe5b6020026020010151610738565b60008181526006602052604090205490915060ff16610bfa5760008181526006602052604090819020805460ff19166001179055517f134fdd648feeaf30251f0157f9624ef8608ff9a042aad6d13e73f35d21d3f88d90610bf1908390613d4c565b60405180910390a15b610c026131f5565b83604001516001600160a01b03166399f685ee83878681518110610c2257fe5b60200260200101516040518363ffffffff1660e01b8152600401610c47929190613d5a565b6040805180830381600087803b158015610c6057600080fd5b505af1158015610c74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610c989190810190613803565b602083015281528651600090889085908110610cb057fe5b6020026020010151837356c54b408c44b12f6c9219c9c73fcda4e783fc2063a085725990916040518263ffffffff1660e01b8152600401610cf19190613d4c565b60206040518083038186803b158015610d0957600080fd5b505af4158015610d1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d4191908101906137e5565b141561100057610d7c878581518110610d5657fe5b602002602001015183600060028110610d6b57fe5b60200201519063ffffffff6124ca16565b905084604001516001600160a01b03166399a5017684888781518110610d9e57fe5b60200260200101516040518363ffffffff1660e01b8152600401610dc3929190613d5a565b602060405180830381600087803b158015610ddd57600080fd5b505af1158015610df1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e1591908101906136ec565b15610ff1578060026000888781518110610e2b57fe5b602002602001015160a001516001600160a01b03166001600160a01b031681526020019081526020016000206000888781518110610e6557fe5b6020026020010151608001516001600160a01b03166001600160a01b031681526020019081526020016000205410156040518060400160405280601e81526020017f434f52453a494e53554646494349454e545f504f4f4c5f42414c414e4345000081525090610ee85760405162461bcd60e51b81526004016102c09190613da2565b50610f728160026000898881518110610efd57fe5b602002602001015160a001516001600160a01b03166001600160a01b031681526020019081526020016000206000898881518110610f3757fe5b6020026020010151608001516001600160a01b03166001600160a01b031681526020019081526020016000205461250d90919063ffffffff16565b60026000888781518110610f8257fe5b602002602001015160a001516001600160a01b03166001600160a01b031681526020019081526020016000206000888781518110610fbc57fe5b6020026020010151608001516001600160a01b03166001600160a01b0316815260200190815260200160002081905550610ffb565b610ffb838261254f565b61111e565b87848151811061100c57fe5b6020026020010151837356c54b408c44b12f6c9219c9c73fcda4e783fc20635b667cf990916040518263ffffffff1660e01b815260040161104d9190613d4c565b60206040518083038186803b15801561106557600080fd5b505af4158015611079573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061109d91908101906137e5565b14156110d3576110c78785815181106110b257fe5b602002602001015183600160028110610d6b57fe5b9050610ffb838261254f565b604080518082018252601a81527f434f52453a554e4b4e4f574e5f504f534954494f4e5f545950450000000000006020820152905162461bcd60e51b81526102c09190600401613da2565b801561115957611159338288878151811061113557fe5b6020026020010151608001516001600160a01b03166111f49092919063ffffffff16565b84600001516001600160a01b031663f5298aca338a878151811061117957fe5b60200260200101518a888151811061118d57fe5b60200260200101516040518463ffffffff1660e01b81526004016111b393929190613c94565b600060405180830381600087803b1580156111cd57600080fd5b505af11580156111e1573d6000803e3d6000fd5b5050600190950194506109b79350505050565b60405161124d90849063a9059cbb60e01b906112169086908690602401613d23565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526125f0565b505050565b8151835114604051806060016040528060338152602001613f67603391399061128e5760405162461bcd60e51b81526004016102c09190613da2565b508051835114604051806060016040528060348152602001613fc260349139906112cb5760405162461bcd60e51b81526004016102c09190613da2565b506112d46131d5565b6000809054906101000a90046001600160a01b03166001600160a01b031663f36675176040518163ffffffff1660e01b815260040160206040518083038186803b15801561132157600080fd5b505afa158015611335573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061135991908101906134f1565b6001600160a01b039081168252600054604080516334d2b0af60e21b81529051919092169163d34ac2bc916004808301926020929190829003018186803b1580156113a357600080fd5b505afa1580156113b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113db91908101906134f1565b6001600160a01b039081166020808401919091526000546040805163205dd91360e21b815290519190931692638177644c926004808301939192829003018186803b15801561142957600080fd5b505afa15801561143d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061146191908101906134f1565b6001600160a01b0316604082015260005b84518110156117005782818151811061148757fe5b60200260200101516020015142116040518060600160405280602a8152602001613ff6602a9139906114cc5760405162461bcd60e51b81526004016102c09190613da2565b506001600160a01b03861633148061157257508281815181106114eb57fe5b602002602001015160a001516001600160a01b031663f22430e8876040518263ffffffff1660e01b81526004016115229190613c6b565b60206040518083038186803b15801561153a57600080fd5b505afa15801561154e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061157291908101906136ec565b604051806060016040528060288152602001613f9a60289139906115a95760405162461bcd60e51b81526004016102c09190613da2565b5060006115f18483815181106115bb57fe5b60200260200101518784815181106115cf57fe5b60200260200101518785815181106115e357fe5b6020026020010151866126d5565b9050801561160a5761160a878286858151811061113557fe5b82600001516001600160a01b031663f5298aca8888858151811061162a57fe5b602002602001015188868151811061163e57fe5b60200260200101516040518463ffffffff1660e01b815260040161166493929190613d15565b600060405180830381600087803b15801561167e57600080fd5b505af1158015611692573d6000803e3d6000fd5b505050507f7dd684d9b29996680eb4c0ae7461d9983dadb8ebf5e04b3e99fae858334861b4878784815181106116c457fe5b60200260200101518785815181106116d857fe5b60200260200101516040516116ef93929190613d15565b60405180910390a150600101611472565b505050505050565b611710613213565b6000809054906101000a90046001600160a01b03166001600160a01b0316638177644c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561175d57600080fd5b505afa158015611771573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061179591908101906134f1565b6001600160a01b03908116825260a0850151811660208084019190915260808601518216604080850191909152600054815163beb5bd8160e01b8152915193169263beb5bd8192600480840193919291829003018186803b1580156117f957600080fd5b505afa15801561180d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061183191908101906134f1565b6001600160a01b0390811660608301526000546040805163f366751760e01b81529051919092169163f3667517916004808301926020929190829003018186803b15801561187e57600080fd5b505afa158015611892573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118b691908101906134f1565b6001600160a01b0316608082015260006118cf85610738565b8251604051634cd280bb60e11b81529192506001600160a01b0316906399a50176906119019084908990600401613d5a565b602060405180830381600087803b15801561191b57600080fd5b505af115801561192f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061195391908101906136ec565b6040518060400160405280600d81526020016c10d3d4914e9393d517d413d3d3609a1b815250906119975760405162461bcd60e51b81526004016102c09190613da2565b50600081815260066020908152604091829020548251808401909352601983527810d3d4914e951250d2d15497d5d054d7d0d05390d153131151603a1b9183019190915260ff16156119fc5760405162461bcd60e51b81526004016102c09190613da2565b5081602001516001600160a01b0316633a6f60a9866040518263ffffffff1660e01b8152600401611a2d9190613e13565b60206040518083038186803b158015611a4557600080fd5b505afa158015611a59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a7d91908101906136ec565b6040518060400160405280601f81526020017f434f52453a53594e5448455449435f56414c49444154494f4e5f4552524f520081525090611ad15760405162461bcd60e51b81526004016102c09190613da2565b508151604051634cfb42f760e11b81526000916001600160a01b0316906399f685ee90611b049085908a90600401613d5a565b6040805180830381600087803b158015611b1d57600080fd5b505af1158015611b31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b559190810190613803565b509050611b68818663ffffffff6124ca16565b83604001516001600160a01b031663dd62ed3e3386606001516040518363ffffffff1660e01b8152600401611b9e929190613c79565b60206040518083038186803b158015611bb657600080fd5b505afa158015611bca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611bee91908101906137e5565b10156040518060400160405280601f81526020017f434f52453a4e4f545f454e4f5547485f544f4b454e5f414c4c4f57414e43450081525090611c445760405162461bcd60e51b81526004016102c09190613da2565b5082606001516001600160a01b0316630a5ea46684604001513330611c728a876124ca90919063ffffffff16565b6040518563ffffffff1660e01b8152600401611c919493929190613d7a565b600060405180830381600087803b158015611cab57600080fd5b505af1158015611cbf573d6000803e3d6000fd5b50505050611d15611cd986836124ca90919063ffffffff16565b60a08801516001600160a01b03908116600090815260026020908152604080832060808d0151909416835292905220549063ffffffff612da216565b60a08701516001600160a01b0390811660009081526002602090815260408083206080808d0151861685529252918290209390935591850151915163644ee7e760e11b815291169063c89dcfce90611d7590879086908a90600401613d15565b600060405180830381600087803b158015611d8f57600080fd5b505af1158015611da3573d6000803e3d6000fd5b505050507f85d052cab00efbc0bc1dd4c180b3c1cbb34e891b8bf10c0836cd3591d327790c8460008488604051611ddd9493929190613cbc565b60405180910390a1505050505050565b611df5613213565b6000809054906101000a90046001600160a01b03166001600160a01b0316638177644c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e4257600080fd5b505afa158015611e56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611e7a91908101906134f1565b6001600160a01b03908116825260a0850151811660208084019190915260808601518216604080850191909152600054815163beb5bd8160e01b8152915193169263beb5bd8192600480840193919291829003018186803b158015611ede57600080fd5b505afa158015611ef2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611f1691908101906134f1565b6001600160a01b0390811660608301526000546040805163f366751760e01b81529051919092169163f3667517916004808301926020929190829003018186803b158015611f6357600080fd5b505afa158015611f77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611f9b91908101906134f1565b6001600160a01b031660808201526000611fb485610738565b8251604051634cd280bb60e11b81529192506001600160a01b0316906399a5017690611fe69084908990600401613d5a565b602060405180830381600087803b15801561200057600080fd5b505af1158015612014573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061203891908101906136ec565b156040518060400160405280601181526020017010d3d4914e90d0539517d09157d413d3d3607a1b815250906120815760405162461bcd60e51b81526004016102c09190613da2565b50600081815260066020908152604091829020548251808401909352601983527810d3d4914e951250d2d15497d5d054d7d0d05390d153131151603a1b9183019190915260ff16156120e65760405162461bcd60e51b81526004016102c09190613da2565b5081602001516001600160a01b0316633a6f60a9866040518263ffffffff1660e01b81526004016121179190613e13565b60206040518083038186803b15801561212f57600080fd5b505afa158015612143573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061216791908101906136ec565b6040518060400160405280601f81526020017f434f52453a53594e5448455449435f56414c49444154494f4e5f4552524f5200815250906121bb5760405162461bcd60e51b81526004016102c09190613da2565b506121c46131f5565b8251604051634cfb42f760e11b81526001600160a01b03909116906399f685ee906121f59085908a90600401613d5a565b6040805180830381600087803b15801561220e57600080fd5b505af1158015612222573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506122469190810190613803565b6020830181905290825261227b90869061226f908460005b60200201519063ffffffff612da216565b9063ffffffff6124ca16565b83604001516001600160a01b031663dd62ed3e3386606001516040518363ffffffff1660e01b81526004016122b1929190613c79565b60206040518083038186803b1580156122c957600080fd5b505afa1580156122dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061230191908101906137e5565b10156040518060400160405280601f81526020017f434f52453a4e4f545f454e4f5547485f544f4b454e5f414c4c4f57414e434500815250906123575760405162461bcd60e51b81526004016102c09190613da2565b5082606001516001600160a01b0316630a5ea466846040015133306123938a61226f8860016002811061238657fe5b602002015189600061225e565b6040518563ffffffff1660e01b81526004016123b29493929190613d7a565b600060405180830381600087803b1580156123cc57600080fd5b505af11580156123e0573d6000803e3d6000fd5b5050505061240e826124098761226f856001600281106123fc57fe5b602002015186600061225e565b612dc7565b60808301518451602086015160405163a0ecdb3f60e01b81526001600160a01b039093169263a0ecdb3f9261244b92909187908b90600401613cfa565b600060405180830381600087803b15801561246557600080fd5b505af1158015612479573d6000803e3d6000fd5b505050507f85d052cab00efbc0bc1dd4c180b3c1cbb34e891b8bf10c0836cd3591d327790c846000600281106124ab57fe5b602002015185600160200201518488604051611ddd9493929190613cfa565b6000826124d957506000612507565b828202828482816124e657fe5b04146125045760405162461bcd60e51b81526004016102c090613dd3565b90505b92915050565b600061250483836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612de6565b80600360008481526020019081526020016000205410156040518060400160405280601d81526020017f434f52453a494e53554646494349454e545f5032505f42414c414e4345000000815250906125ba5760405162461bcd60e51b81526004016102c09190613da2565b506000828152600360205260409020546125da908263ffffffff61250d16565b6000928352600360205260409092209190915550565b612602826001600160a01b0316612e17565b61261e5760405162461bcd60e51b81526004016102c090613e03565b60006060836001600160a01b03168360405161263a9190613bf9565b6000604051808303816000865af19150503d8060008114612677576040519150601f19603f3d011682016040523d82523d6000602084013e61267c565b606091505b50915091508161269e5760405162461bcd60e51b81526004016102c090613dc3565b8051156102c957808060200190516126b991908101906136ec565b6102c95760405162461bcd60e51b81526004016102c090613de3565b606084015160009081906001600160a01b03161561277e5782602001516001600160a01b0316632979d025876060015188602001516040518363ffffffff1660e01b8152600401612727929190613d23565b60206040518083038186803b15801561273f57600080fd5b505afa158015612753573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061277791908101906137e5565b9050612782565b5060005b61278a6131f5565b8660a001516001600160a01b031663dd0060fd88846040518363ffffffff1660e01b81526004016127bc929190613e24565b604080518083038186803b1580156127d357600080fd5b505afa1580156127e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061280b9190810190613803565b60208301528152600061281d88610738565b600081815260066020908152604091829020548251808401909352601983527810d3d4914e951250d2d15497d5d054d7d0d05390d153131151603a1b918301919091529192509060ff16156128855760405162461bcd60e51b81526004016102c09190613da2565b5061288e6131f5565b85604001516001600160a01b03166399f685ee838b6040518363ffffffff1660e01b81526004016128c0929190613d5a565b6040805180830381600087803b1580156128d957600080fd5b505af11580156128ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506129119190810190613803565b602083015281526129206131f5565b61295961292e8560016123fc565b61294d8660005b602002015161226f866001602002015187600061225e565b9063ffffffff612e5316565b81526129746129698560016123fc565b61294d866001612935565b6020808301919091526000848152600490915260409020541580156129a85750600083815260046020526040902060010154155b156129cd57805160008481526004602090815260409091209182558201516001909101555b60405163a085725960e01b815289907356c54b408c44b12f6c9219c9c73fcda4e783fc209063a085725990612a06908790600401613d4c565b60206040518083038186803b158015612a1e57600080fd5b505af4158015612a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612a5691908101906137e5565b1415612ca85786604001516001600160a01b03166399a50176848c6040518363ffffffff1660e01b8152600401612a8e929190613d5a565b602060405180830381600087803b158015612aa857600080fd5b505af1158015612abc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612ae091908101906136ec565b15612c375783519550612af386896124ca565b955085600260008c60a001516001600160a01b03166001600160a01b0316815260200190815260200160002060008c608001516001600160a01b03166001600160a01b031681526020019081526020016000205410156040518060400160405280601e81526020017f434f52453a494e53554646494349454e545f504f4f4c5f42414c414e4345000081525090612b9d5760405162461bcd60e51b81526004016102c09190613da2565b5060a08a01516001600160a01b03908116600090815260026020908152604080832060808f015190941683529290522054612bde908763ffffffff61250d16565b600260008c60a001516001600160a01b03166001600160a01b0316815260200190815260200160002060008c608001516001600160a01b03166001600160a01b0316815260200190815260200160002081905550612c5e565b6000838152600460205260409020549550612c5286896124ca565b9550612c5e838761254f565b612c6a88836000610d6b565b861115612ca3576040870151612ca090612c9390858d612c8c8d886000610d6b565b8b03612e95565b879063ffffffff61250d16565b95505b612d95565b604051635b667cf960e01b815289907356c54b408c44b12f6c9219c9c73fcda4e783fc2090635b667cf990612ce1908790600401613d4c565b60206040518083038186803b158015612cf957600080fd5b505af4158015612d0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d3191908101906137e5565b14156110d3576000838152600460205260409020600101549550612d5b868963ffffffff6124ca16565b9550612d67838761254f565b612d7388836001610d6b565b861115612ca3576040870151612ca090612c9390858d612c8c8d886001610d6b565b5050505050949350505050565b6000828201838110156125045760405162461bcd60e51b81526004016102c090613db3565b6000828152600360205260409020546125da908263ffffffff612da216565b60008184841115612e0a5760405162461bcd60e51b81526004016102c09190613da2565b50508183035b9392505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708115801590612e4b5750808214155b949350505050565b600061250483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061314d565b600080856001600160a01b031663b9080d2b86866040518363ffffffff1660e01b8152600401612ec6929190613d5a565b602060405180830381600087803b158015612ee057600080fd5b505af1158015612ef4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612f1891908101906134f1565b90506000866001600160a01b031663fdead27287876040518363ffffffff1660e01b8152600401612f4a929190613d5a565b602060405180830381600087803b158015612f6457600080fd5b505af1158015612f78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612f9c91908101906137e5565b9050612fb461271061294d868463ffffffff6124ca16565b925082612fc657600092505050612e4b565b6000612fdd600a61294d868463ffffffff6124ca16565b90506000612ff1858363ffffffff61250d16565b905060008060009054906101000a90046001600160a01b03166001600160a01b031663ec45d8ae6040518163ffffffff1660e01b815260040160206040518083038186803b15801561304257600080fd5b505afa158015613056573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061307a91908101906134f1565b6001600160a01b03808216600090815260056020908152604080832060808e0151909416835292905220549091506130b8908463ffffffff612da216565b6001600160a01b03808316600090815260056020818152604080842060808f01805187168652908352818520969096558a8516845291815281832094519093168252929091522054613110908363ffffffff612da216565b6001600160a01b03958616600090815260056020908152604080832060808d01519099168352979052959095209490945550505050949350505050565b6000818361316e5760405162461bcd60e51b81526004016102c09190613da2565b50600083858161317a57fe5b0495945050505050565b6040518060c0016040528060008152602001600081526020016060815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681525090565b604080516060810182526000808252602082018190529181019190915290565b60405180604001604052806002906020820280388339509192915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b803561250781613f3d565b805161250781613f3d565b600082601f83011261326857600080fd5b600261327b61327682613e6a565b613e44565b9150818385602084028201111561329157600080fd5b60005b838110156132bd57816132a78882613241565b8452506020928301929190910190600101613294565b5050505092915050565b600082601f8301126132d857600080fd5b81356132e661327682613e87565b81815260209384019390925082018360005b838110156132bd578135860161330e888261341a565b84525060209283019291909101906001016132f8565b600082601f83011261333557600080fd5b813561334361327682613e87565b9150818183526020840193506020810190508385602084028201111561336857600080fd5b60005b838110156132bd578161337e888261340f565b845250602092830192919091019060010161336b565b600082601f8301126133a557600080fd5b81356133b361327682613e87565b915081818352602084019350602081019050838560208402820111156133d857600080fd5b60005b838110156132bd57816133ee888261340f565b84525060209283019291909101906001016133db565b805161250781613f54565b803561250781613f5d565b600060c0828403121561342c57600080fd5b61343660c0613e44565b90506000613444848461340f565b82525060206134558484830161340f565b60208301525060408201356001600160401b0381111561347457600080fd5b61348084828501613324565b604083015250606061349484828501613241565b60608301525060806134a884828501613241565b60808301525060a06134bc84828501613241565b60a08301525092915050565b805161250781613f5d565b6000602082840312156134e557600080fd5b6000612e4b8484613241565b60006020828403121561350357600080fd5b6000612e4b848461324c565b6000806040838503121561352257600080fd5b600061352e8585613241565b925050602061353f85828601613241565b9150509250929050565b6000806000806080858703121561355f57600080fd5b600061356b8787613241565b94505060208501356001600160401b0381111561358757600080fd5b61359387828801613394565b93505060408501356001600160401b038111156135af57600080fd5b6135bb87828801613394565b92505060608501356001600160401b038111156135d757600080fd5b6135e3878288016132c7565b91505092959194509250565b6000806000806080858703121561360557600080fd5b60006136118787613241565b94505060206136228782880161340f565b93505060406136338782880161340f565b92505060608501356001600160401b0381111561364f57600080fd5b6135e38782880161341a565b60008060006060848603121561367057600080fd5b83356001600160401b0381111561368657600080fd5b61369286828701613394565b93505060208401356001600160401b038111156136ae57600080fd5b6136ba86828701613394565b92505060408401356001600160401b038111156136d657600080fd5b6136e2868287016132c7565b9150509250925092565b6000602082840312156136fe57600080fd5b6000612e4b8484613404565b60006020828403121561371c57600080fd5b6000612e4b848461340f565b6000806040838503121561373b57600080fd5b6000613747858561340f565b925050602061353f8582860161340f565b60006020828403121561376a57600080fd5b81356001600160401b0381111561378057600080fd5b612e4b8482850161341a565b6000806000608084860312156137a157600080fd5b83356001600160401b038111156137b757600080fd5b6137c38682870161341a565b93505060206137d48682870161340f565b92505060406136e286828701613257565b6000602082840312156137f757600080fd5b6000612e4b84846134c8565b6000806040838503121561381657600080fd5b600061382285856134c8565b925050602061353f858286016134c8565b60008060006060848603121561384857600080fd5b6000613854868661340f565b93505060206138658682870161340f565b92505060408401356001600160401b0381111561388157600080fd5b6136e28682870161341a565b6000613899838361397a565b505060200190565b6138aa81613ede565b82525050565b6138aa81613ebf565b6138aa6138c582613ebf565b613f1c565b60006138d582613ead565b6138df8185613eb1565b93506138ea83613ea7565b8060005b83811015613918578151613902888261388d565b975061390d83613ea7565b9250506001016138ee565b509495945050505050565b600061392e82613ead565b6139388185613eba565b935061394383613ea7565b8060005b8381101561391857815161395b888261388d565b975061396683613ea7565b925050600101613947565b6138aa81613eca565b6138aa81613ecf565b600061398e82613ead565b6139988185613eba565b93506139a8818560208601613ef0565b9290920192915050565b6138aa81613ee5565b60006139c682613ead565b6139d08185613eb1565b93506139e0818560208601613ef0565b6139e981613f2d565b9093019392505050565b6000613a00601b83613eb1565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000613a39602083613eb1565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b6000613a72602183613eb1565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000613ab5602a83613eb1565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b6000613b01601f83613eb1565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00815260200192915050565b6000613b3a601f83613eb1565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160009060c0840190613b7a858261397a565b506020830151613b8d602086018261397a565b5060408301518482036040860152613ba582826138ca565b9150506060830151613bba60608601826138b0565b506080830151613bcd60808601826138b0565b5060a0830151613be060a08601826138b0565b509392505050565b6138aa613bf482613ecf565b613ecf565b6000612e108284613983565b6000613c118289613be8565b602082019150613c218288613be8565b602082019150613c318287613923565b9150613c3d82866138b9565b601482019150613c4d82856138b9565b601482019150613c5d82846138b9565b506014019695505050505050565b6020810161250782846138b0565b60408101613c8782856138a1565b612e1060208301846138b0565b60608101613ca282866138a1565b613caf602083018561397a565b612e4b604083018461397a565b60808101613cca82876138b0565b613cd760208301866138a1565b613ce4604083018561397a565b613cf1606083018461397a565b95945050505050565b60808101613d0882876138b0565b613cd760208301866138b0565b60608101613ca282866138b0565b60408101613d3182856138b0565b612e10602083018461397a565b602081016125078284613971565b60208101612507828461397a565b60408101613d68828561397a565b8181036020830152612e4b8184613b66565b60808101613d8882876139b2565b613d9560208301866138a1565b613ce460408301856138b0565b6020808252810161250481846139bb565b60208082528101612507816139f3565b6020808252810161250781613a2c565b6020808252810161250781613a65565b6020808252810161250781613aa8565b6020808252810161250781613af4565b6020808252810161250781613b2d565b602080825281016125048184613b66565b60408082528101613e358185613b66565b9050612e10602083018461397a565b6040518181016001600160401b0381118282101715613e6257600080fd5b604052919050565b60006001600160401b03821115613e8057600080fd5b5060200290565b60006001600160401b03821115613e9d57600080fd5b5060209081020190565b60200190565b5190565b90815260200190565b919050565b600061250782613ed2565b151590565b90565b6001600160a01b031690565b6000612507825b600061250782613ebf565b60005b83811015613f0b578181015183820152602001613ef3565b838111156102c95750506000910152565b600061250782600061250782613f37565b601f01601f191690565b60601b90565b613f4681613ebf565b8114613f5157600080fd5b50565b613f4681613eca565b613f4681613ecf56fe434f52453a544f4b454e5f4944535f414e445f5155414e5449544945535f4c454e4754485f444f45535f4e4f545f4d41544348434f52453a53594e5448455449435f455845435554494f4e5f5741535f4e4f545f414c4c4f574544434f52453a544f4b454e5f4944535f414e445f44455249564154495645535f4c454e4754485f444f45535f4e4f545f4d41544348434f52453a455845435554494f4e5f4245464f52455f4d415455524954595f4e4f545f414c4c4f574544a365627a7a723158204b77c9a170e86eaa4dad533a12f3f73c8d9e9d797af48d084b34168928bec65a6c6578706572696d656e74616cf564736f6c634300051000400000000000000000000000007f5f4087006ba4f4985b32f9d1079ee2f8594af8
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101215760003560e01c80635ab1bd53116100ad578063ab85d5ec11610071578063ab85d5ec14610241578063d7acb44814610249578063d842b22b1461025c578063eb95512214610264578063f1015a161461027757610121565b80635ab1bd53146101eb5780635d419a9c146102005780636a990b6e146102135780639ecd27aa14610226578063a956fd121461023957610121565b80632ac12622116100f45780632ac126221461017f5780634b5095921461019f5780634df6d09d146101b257806354af742a146101c557806354dc1b22146101d857610121565b80630d06dd6b146101265780631ac3ddeb1461013b57806328fb2b031461014e578063291092b31461016c575b600080fd5b61013961013436600461365b565b61028a565b005b6101396101493660046134d3565b6102cf565b610156610334565b6040516101639190613d4c565b60405180910390f35b61013961017a3660046135ef565b610339565b61019261018d36600461370a565b610441565b6040516101639190613d3e565b6101566101ad36600461350f565b610456565b6101396101c0366004613549565b610473565b6101396101d3366004613833565b6104aa565b6101396101e6366004613833565b6105aa565b6101f3610687565b6040516101639190613c6b565b61015661020e366004613728565b610696565b61015661022136600461350f565b6106b8565b61013961023436600461365b565b6106d5565b6101566106eb565b6101566106f0565b61013961025736600461378c565b6106f7565b610156610732565b610156610272366004613758565b610738565b61015661028536600461370a565b610785565b6001805481019081905561029f848484610797565b60015481146102c95760405162461bcd60e51b81526004016102c090613df3565b60405180910390fd5b50505050565b600180548101908190553360008181526005602090815260408083206001600160a01b038716808552925282208054929055909161030e9190836111f4565b5060015481146103305760405162461bcd60e51b81526004016102c090613df3565b5050565b600081565b6001805481018082556040805183815280820190915290916060919060208083019080388339505060408051600180825281830190925292935060609291506020808301908038833950506040805160018082528183019092529293506060929150602082015b6103a8613184565b8152602001906001900390816103a057905050905086836000815181106103cb57fe5b60200260200101818152505085826000815181106103e557fe5b60200260200101818152505084816000815181106103ff57fe5b602002602001018190525061041688848484611252565b505050600154811461043a5760405162461bcd60e51b81526004016102c090613df3565b5050505050565b60066020526000908152604090205460ff1681565b600260209081526000928352604080842090915290825290205481565b6001805481019081905561048985858585611252565b600154811461043a5760405162461bcd60e51b81526004016102c090613df3565b6001805481018082556040805183815280820190915290916060919060208083019080388339505060408051600180825281830190925292935060609291506020808301908038833950506040805160018082528183019092529293506060929150602082015b610519613184565b815260200190600190039081610511579050509050868360008151811061053c57fe5b602002602001018181525050858260008151811061055657fe5b602002602001018181525050848160008151811061057057fe5b6020026020010181905250610586838383610797565b50505060015481146102c95760405162461bcd60e51b81526004016102c090613df3565b6001805481018082556040805183815280820190915290916060919060208083019080388339505060408051600180825281830190925292935060609291506020808301908038833950506040805160018082528183019092529293506060929150602082015b610619613184565b815260200190600190039081610611579050509050868360008151811061063c57fe5b602002602001018181525050858260008151811061065657fe5b602002602001018181525050848160008151811061067057fe5b602002602001018190525061058633848484611252565b6000546001600160a01b031690565b600460205281600052604060002081600281106106af57fe5b01549150829050565b600560209081526000928352604080842090915290825290205481565b6001805481019081905561029f33858585611252565b600a81565b6212750081565b6001805481019081905560208201516001600160a01b03166107275781516107229085908590611708565b61029f565b61029f848484611ded565b61271081565b80516020808301516040808501516060860151608087015160a08801519351600097610768979096959101613c05565b604051602081830303815290604052805190602001209050919050565b60036020526000908152604090205481565b8151835114604051806060016040528060338152602001613f6760339139906107d35760405162461bcd60e51b81526004016102c09190613da2565b508051835114604051806060016040528060348152602001613fc260349139906108105760405162461bcd60e51b81526004016102c09190613da2565b506108196131d5565b6000809054906101000a90046001600160a01b03166001600160a01b031663f36675176040518163ffffffff1660e01b815260040160206040518083038186803b15801561086657600080fd5b505afa15801561087a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061089e91908101906134f1565b6001600160a01b039081168252600054604080516334d2b0af60e21b81529051919092169163d34ac2bc916004808301926020929190829003018186803b1580156108e857600080fd5b505afa1580156108fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061092091908101906134f1565b6001600160a01b039081166020808401919091526000546040805163205dd91360e21b815290519190931692638177644c926004808301939192829003018186803b15801561096e57600080fd5b505afa158015610982573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506109a691908101906134f1565b6001600160a01b0316604082015260005b845181101561043a5760006001600160a01b03168382815181106109d757fe5b6020026020010151606001516001600160a01b031614156040518060400160405280602081526020017f434f52453a43414e545f43414e43454c5f44554d4d595f4f5241434c455f494481525090610a425760405162461bcd60e51b81526004016102c09190613da2565b504262127500848381518110610a5457fe5b6020026020010151602001510111158015610b1c575081602001516001600160a01b031663c8384d2f848381518110610a8957fe5b602002602001015160600151858481518110610aa157fe5b6020026020010151602001516040518363ffffffff1660e01b8152600401610aca929190613d23565b60206040518083038186803b158015610ae257600080fd5b505afa158015610af6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b1a91908101906136ec565b155b6040518060400160405280602081526020017f434f52453a43414e43454c4c4154494f4e5f49535f4e4f545f414c4c4f57454481525090610b705760405162461bcd60e51b81526004016102c09190613da2565b506000610b8f848381518110610b8257fe5b6020026020010151610738565b60008181526006602052604090205490915060ff16610bfa5760008181526006602052604090819020805460ff19166001179055517f134fdd648feeaf30251f0157f9624ef8608ff9a042aad6d13e73f35d21d3f88d90610bf1908390613d4c565b60405180910390a15b610c026131f5565b83604001516001600160a01b03166399f685ee83878681518110610c2257fe5b60200260200101516040518363ffffffff1660e01b8152600401610c47929190613d5a565b6040805180830381600087803b158015610c6057600080fd5b505af1158015610c74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610c989190810190613803565b602083015281528651600090889085908110610cb057fe5b6020026020010151837356c54b408c44b12f6c9219c9c73fcda4e783fc2063a085725990916040518263ffffffff1660e01b8152600401610cf19190613d4c565b60206040518083038186803b158015610d0957600080fd5b505af4158015610d1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d4191908101906137e5565b141561100057610d7c878581518110610d5657fe5b602002602001015183600060028110610d6b57fe5b60200201519063ffffffff6124ca16565b905084604001516001600160a01b03166399a5017684888781518110610d9e57fe5b60200260200101516040518363ffffffff1660e01b8152600401610dc3929190613d5a565b602060405180830381600087803b158015610ddd57600080fd5b505af1158015610df1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e1591908101906136ec565b15610ff1578060026000888781518110610e2b57fe5b602002602001015160a001516001600160a01b03166001600160a01b031681526020019081526020016000206000888781518110610e6557fe5b6020026020010151608001516001600160a01b03166001600160a01b031681526020019081526020016000205410156040518060400160405280601e81526020017f434f52453a494e53554646494349454e545f504f4f4c5f42414c414e4345000081525090610ee85760405162461bcd60e51b81526004016102c09190613da2565b50610f728160026000898881518110610efd57fe5b602002602001015160a001516001600160a01b03166001600160a01b031681526020019081526020016000206000898881518110610f3757fe5b6020026020010151608001516001600160a01b03166001600160a01b031681526020019081526020016000205461250d90919063ffffffff16565b60026000888781518110610f8257fe5b602002602001015160a001516001600160a01b03166001600160a01b031681526020019081526020016000206000888781518110610fbc57fe5b6020026020010151608001516001600160a01b03166001600160a01b0316815260200190815260200160002081905550610ffb565b610ffb838261254f565b61111e565b87848151811061100c57fe5b6020026020010151837356c54b408c44b12f6c9219c9c73fcda4e783fc20635b667cf990916040518263ffffffff1660e01b815260040161104d9190613d4c565b60206040518083038186803b15801561106557600080fd5b505af4158015611079573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061109d91908101906137e5565b14156110d3576110c78785815181106110b257fe5b602002602001015183600160028110610d6b57fe5b9050610ffb838261254f565b604080518082018252601a81527f434f52453a554e4b4e4f574e5f504f534954494f4e5f545950450000000000006020820152905162461bcd60e51b81526102c09190600401613da2565b801561115957611159338288878151811061113557fe5b6020026020010151608001516001600160a01b03166111f49092919063ffffffff16565b84600001516001600160a01b031663f5298aca338a878151811061117957fe5b60200260200101518a888151811061118d57fe5b60200260200101516040518463ffffffff1660e01b81526004016111b393929190613c94565b600060405180830381600087803b1580156111cd57600080fd5b505af11580156111e1573d6000803e3d6000fd5b5050600190950194506109b79350505050565b60405161124d90849063a9059cbb60e01b906112169086908690602401613d23565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526125f0565b505050565b8151835114604051806060016040528060338152602001613f67603391399061128e5760405162461bcd60e51b81526004016102c09190613da2565b508051835114604051806060016040528060348152602001613fc260349139906112cb5760405162461bcd60e51b81526004016102c09190613da2565b506112d46131d5565b6000809054906101000a90046001600160a01b03166001600160a01b031663f36675176040518163ffffffff1660e01b815260040160206040518083038186803b15801561132157600080fd5b505afa158015611335573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061135991908101906134f1565b6001600160a01b039081168252600054604080516334d2b0af60e21b81529051919092169163d34ac2bc916004808301926020929190829003018186803b1580156113a357600080fd5b505afa1580156113b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113db91908101906134f1565b6001600160a01b039081166020808401919091526000546040805163205dd91360e21b815290519190931692638177644c926004808301939192829003018186803b15801561142957600080fd5b505afa15801561143d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061146191908101906134f1565b6001600160a01b0316604082015260005b84518110156117005782818151811061148757fe5b60200260200101516020015142116040518060600160405280602a8152602001613ff6602a9139906114cc5760405162461bcd60e51b81526004016102c09190613da2565b506001600160a01b03861633148061157257508281815181106114eb57fe5b602002602001015160a001516001600160a01b031663f22430e8876040518263ffffffff1660e01b81526004016115229190613c6b565b60206040518083038186803b15801561153a57600080fd5b505afa15801561154e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061157291908101906136ec565b604051806060016040528060288152602001613f9a60289139906115a95760405162461bcd60e51b81526004016102c09190613da2565b5060006115f18483815181106115bb57fe5b60200260200101518784815181106115cf57fe5b60200260200101518785815181106115e357fe5b6020026020010151866126d5565b9050801561160a5761160a878286858151811061113557fe5b82600001516001600160a01b031663f5298aca8888858151811061162a57fe5b602002602001015188868151811061163e57fe5b60200260200101516040518463ffffffff1660e01b815260040161166493929190613d15565b600060405180830381600087803b15801561167e57600080fd5b505af1158015611692573d6000803e3d6000fd5b505050507f7dd684d9b29996680eb4c0ae7461d9983dadb8ebf5e04b3e99fae858334861b4878784815181106116c457fe5b60200260200101518785815181106116d857fe5b60200260200101516040516116ef93929190613d15565b60405180910390a150600101611472565b505050505050565b611710613213565b6000809054906101000a90046001600160a01b03166001600160a01b0316638177644c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561175d57600080fd5b505afa158015611771573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061179591908101906134f1565b6001600160a01b03908116825260a0850151811660208084019190915260808601518216604080850191909152600054815163beb5bd8160e01b8152915193169263beb5bd8192600480840193919291829003018186803b1580156117f957600080fd5b505afa15801561180d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061183191908101906134f1565b6001600160a01b0390811660608301526000546040805163f366751760e01b81529051919092169163f3667517916004808301926020929190829003018186803b15801561187e57600080fd5b505afa158015611892573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118b691908101906134f1565b6001600160a01b0316608082015260006118cf85610738565b8251604051634cd280bb60e11b81529192506001600160a01b0316906399a50176906119019084908990600401613d5a565b602060405180830381600087803b15801561191b57600080fd5b505af115801561192f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061195391908101906136ec565b6040518060400160405280600d81526020016c10d3d4914e9393d517d413d3d3609a1b815250906119975760405162461bcd60e51b81526004016102c09190613da2565b50600081815260066020908152604091829020548251808401909352601983527810d3d4914e951250d2d15497d5d054d7d0d05390d153131151603a1b9183019190915260ff16156119fc5760405162461bcd60e51b81526004016102c09190613da2565b5081602001516001600160a01b0316633a6f60a9866040518263ffffffff1660e01b8152600401611a2d9190613e13565b60206040518083038186803b158015611a4557600080fd5b505afa158015611a59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a7d91908101906136ec565b6040518060400160405280601f81526020017f434f52453a53594e5448455449435f56414c49444154494f4e5f4552524f520081525090611ad15760405162461bcd60e51b81526004016102c09190613da2565b508151604051634cfb42f760e11b81526000916001600160a01b0316906399f685ee90611b049085908a90600401613d5a565b6040805180830381600087803b158015611b1d57600080fd5b505af1158015611b31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b559190810190613803565b509050611b68818663ffffffff6124ca16565b83604001516001600160a01b031663dd62ed3e3386606001516040518363ffffffff1660e01b8152600401611b9e929190613c79565b60206040518083038186803b158015611bb657600080fd5b505afa158015611bca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611bee91908101906137e5565b10156040518060400160405280601f81526020017f434f52453a4e4f545f454e4f5547485f544f4b454e5f414c4c4f57414e43450081525090611c445760405162461bcd60e51b81526004016102c09190613da2565b5082606001516001600160a01b0316630a5ea46684604001513330611c728a876124ca90919063ffffffff16565b6040518563ffffffff1660e01b8152600401611c919493929190613d7a565b600060405180830381600087803b158015611cab57600080fd5b505af1158015611cbf573d6000803e3d6000fd5b50505050611d15611cd986836124ca90919063ffffffff16565b60a08801516001600160a01b03908116600090815260026020908152604080832060808d0151909416835292905220549063ffffffff612da216565b60a08701516001600160a01b0390811660009081526002602090815260408083206080808d0151861685529252918290209390935591850151915163644ee7e760e11b815291169063c89dcfce90611d7590879086908a90600401613d15565b600060405180830381600087803b158015611d8f57600080fd5b505af1158015611da3573d6000803e3d6000fd5b505050507f85d052cab00efbc0bc1dd4c180b3c1cbb34e891b8bf10c0836cd3591d327790c8460008488604051611ddd9493929190613cbc565b60405180910390a1505050505050565b611df5613213565b6000809054906101000a90046001600160a01b03166001600160a01b0316638177644c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e4257600080fd5b505afa158015611e56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611e7a91908101906134f1565b6001600160a01b03908116825260a0850151811660208084019190915260808601518216604080850191909152600054815163beb5bd8160e01b8152915193169263beb5bd8192600480840193919291829003018186803b158015611ede57600080fd5b505afa158015611ef2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611f1691908101906134f1565b6001600160a01b0390811660608301526000546040805163f366751760e01b81529051919092169163f3667517916004808301926020929190829003018186803b158015611f6357600080fd5b505afa158015611f77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611f9b91908101906134f1565b6001600160a01b031660808201526000611fb485610738565b8251604051634cd280bb60e11b81529192506001600160a01b0316906399a5017690611fe69084908990600401613d5a565b602060405180830381600087803b15801561200057600080fd5b505af1158015612014573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061203891908101906136ec565b156040518060400160405280601181526020017010d3d4914e90d0539517d09157d413d3d3607a1b815250906120815760405162461bcd60e51b81526004016102c09190613da2565b50600081815260066020908152604091829020548251808401909352601983527810d3d4914e951250d2d15497d5d054d7d0d05390d153131151603a1b9183019190915260ff16156120e65760405162461bcd60e51b81526004016102c09190613da2565b5081602001516001600160a01b0316633a6f60a9866040518263ffffffff1660e01b81526004016121179190613e13565b60206040518083038186803b15801561212f57600080fd5b505afa158015612143573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061216791908101906136ec565b6040518060400160405280601f81526020017f434f52453a53594e5448455449435f56414c49444154494f4e5f4552524f5200815250906121bb5760405162461bcd60e51b81526004016102c09190613da2565b506121c46131f5565b8251604051634cfb42f760e11b81526001600160a01b03909116906399f685ee906121f59085908a90600401613d5a565b6040805180830381600087803b15801561220e57600080fd5b505af1158015612222573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506122469190810190613803565b6020830181905290825261227b90869061226f908460005b60200201519063ffffffff612da216565b9063ffffffff6124ca16565b83604001516001600160a01b031663dd62ed3e3386606001516040518363ffffffff1660e01b81526004016122b1929190613c79565b60206040518083038186803b1580156122c957600080fd5b505afa1580156122dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061230191908101906137e5565b10156040518060400160405280601f81526020017f434f52453a4e4f545f454e4f5547485f544f4b454e5f414c4c4f57414e434500815250906123575760405162461bcd60e51b81526004016102c09190613da2565b5082606001516001600160a01b0316630a5ea466846040015133306123938a61226f8860016002811061238657fe5b602002015189600061225e565b6040518563ffffffff1660e01b81526004016123b29493929190613d7a565b600060405180830381600087803b1580156123cc57600080fd5b505af11580156123e0573d6000803e3d6000fd5b5050505061240e826124098761226f856001600281106123fc57fe5b602002015186600061225e565b612dc7565b60808301518451602086015160405163a0ecdb3f60e01b81526001600160a01b039093169263a0ecdb3f9261244b92909187908b90600401613cfa565b600060405180830381600087803b15801561246557600080fd5b505af1158015612479573d6000803e3d6000fd5b505050507f85d052cab00efbc0bc1dd4c180b3c1cbb34e891b8bf10c0836cd3591d327790c846000600281106124ab57fe5b602002015185600160200201518488604051611ddd9493929190613cfa565b6000826124d957506000612507565b828202828482816124e657fe5b04146125045760405162461bcd60e51b81526004016102c090613dd3565b90505b92915050565b600061250483836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612de6565b80600360008481526020019081526020016000205410156040518060400160405280601d81526020017f434f52453a494e53554646494349454e545f5032505f42414c414e4345000000815250906125ba5760405162461bcd60e51b81526004016102c09190613da2565b506000828152600360205260409020546125da908263ffffffff61250d16565b6000928352600360205260409092209190915550565b612602826001600160a01b0316612e17565b61261e5760405162461bcd60e51b81526004016102c090613e03565b60006060836001600160a01b03168360405161263a9190613bf9565b6000604051808303816000865af19150503d8060008114612677576040519150601f19603f3d011682016040523d82523d6000602084013e61267c565b606091505b50915091508161269e5760405162461bcd60e51b81526004016102c090613dc3565b8051156102c957808060200190516126b991908101906136ec565b6102c95760405162461bcd60e51b81526004016102c090613de3565b606084015160009081906001600160a01b03161561277e5782602001516001600160a01b0316632979d025876060015188602001516040518363ffffffff1660e01b8152600401612727929190613d23565b60206040518083038186803b15801561273f57600080fd5b505afa158015612753573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061277791908101906137e5565b9050612782565b5060005b61278a6131f5565b8660a001516001600160a01b031663dd0060fd88846040518363ffffffff1660e01b81526004016127bc929190613e24565b604080518083038186803b1580156127d357600080fd5b505afa1580156127e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061280b9190810190613803565b60208301528152600061281d88610738565b600081815260066020908152604091829020548251808401909352601983527810d3d4914e951250d2d15497d5d054d7d0d05390d153131151603a1b918301919091529192509060ff16156128855760405162461bcd60e51b81526004016102c09190613da2565b5061288e6131f5565b85604001516001600160a01b03166399f685ee838b6040518363ffffffff1660e01b81526004016128c0929190613d5a565b6040805180830381600087803b1580156128d957600080fd5b505af11580156128ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506129119190810190613803565b602083015281526129206131f5565b61295961292e8560016123fc565b61294d8660005b602002015161226f866001602002015187600061225e565b9063ffffffff612e5316565b81526129746129698560016123fc565b61294d866001612935565b6020808301919091526000848152600490915260409020541580156129a85750600083815260046020526040902060010154155b156129cd57805160008481526004602090815260409091209182558201516001909101555b60405163a085725960e01b815289907356c54b408c44b12f6c9219c9c73fcda4e783fc209063a085725990612a06908790600401613d4c565b60206040518083038186803b158015612a1e57600080fd5b505af4158015612a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612a5691908101906137e5565b1415612ca85786604001516001600160a01b03166399a50176848c6040518363ffffffff1660e01b8152600401612a8e929190613d5a565b602060405180830381600087803b158015612aa857600080fd5b505af1158015612abc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612ae091908101906136ec565b15612c375783519550612af386896124ca565b955085600260008c60a001516001600160a01b03166001600160a01b0316815260200190815260200160002060008c608001516001600160a01b03166001600160a01b031681526020019081526020016000205410156040518060400160405280601e81526020017f434f52453a494e53554646494349454e545f504f4f4c5f42414c414e4345000081525090612b9d5760405162461bcd60e51b81526004016102c09190613da2565b5060a08a01516001600160a01b03908116600090815260026020908152604080832060808f015190941683529290522054612bde908763ffffffff61250d16565b600260008c60a001516001600160a01b03166001600160a01b0316815260200190815260200160002060008c608001516001600160a01b03166001600160a01b0316815260200190815260200160002081905550612c5e565b6000838152600460205260409020549550612c5286896124ca565b9550612c5e838761254f565b612c6a88836000610d6b565b861115612ca3576040870151612ca090612c9390858d612c8c8d886000610d6b565b8b03612e95565b879063ffffffff61250d16565b95505b612d95565b604051635b667cf960e01b815289907356c54b408c44b12f6c9219c9c73fcda4e783fc2090635b667cf990612ce1908790600401613d4c565b60206040518083038186803b158015612cf957600080fd5b505af4158015612d0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d3191908101906137e5565b14156110d3576000838152600460205260409020600101549550612d5b868963ffffffff6124ca16565b9550612d67838761254f565b612d7388836001610d6b565b861115612ca3576040870151612ca090612c9390858d612c8c8d886001610d6b565b5050505050949350505050565b6000828201838110156125045760405162461bcd60e51b81526004016102c090613db3565b6000828152600360205260409020546125da908263ffffffff612da216565b60008184841115612e0a5760405162461bcd60e51b81526004016102c09190613da2565b50508183035b9392505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708115801590612e4b5750808214155b949350505050565b600061250483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061314d565b600080856001600160a01b031663b9080d2b86866040518363ffffffff1660e01b8152600401612ec6929190613d5a565b602060405180830381600087803b158015612ee057600080fd5b505af1158015612ef4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612f1891908101906134f1565b90506000866001600160a01b031663fdead27287876040518363ffffffff1660e01b8152600401612f4a929190613d5a565b602060405180830381600087803b158015612f6457600080fd5b505af1158015612f78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612f9c91908101906137e5565b9050612fb461271061294d868463ffffffff6124ca16565b925082612fc657600092505050612e4b565b6000612fdd600a61294d868463ffffffff6124ca16565b90506000612ff1858363ffffffff61250d16565b905060008060009054906101000a90046001600160a01b03166001600160a01b031663ec45d8ae6040518163ffffffff1660e01b815260040160206040518083038186803b15801561304257600080fd5b505afa158015613056573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061307a91908101906134f1565b6001600160a01b03808216600090815260056020908152604080832060808e0151909416835292905220549091506130b8908463ffffffff612da216565b6001600160a01b03808316600090815260056020818152604080842060808f01805187168652908352818520969096558a8516845291815281832094519093168252929091522054613110908363ffffffff612da216565b6001600160a01b03958616600090815260056020908152604080832060808d01519099168352979052959095209490945550505050949350505050565b6000818361316e5760405162461bcd60e51b81526004016102c09190613da2565b50600083858161317a57fe5b0495945050505050565b6040518060c0016040528060008152602001600081526020016060815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681525090565b604080516060810182526000808252602082018190529181019190915290565b60405180604001604052806002906020820280388339509192915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b803561250781613f3d565b805161250781613f3d565b600082601f83011261326857600080fd5b600261327b61327682613e6a565b613e44565b9150818385602084028201111561329157600080fd5b60005b838110156132bd57816132a78882613241565b8452506020928301929190910190600101613294565b5050505092915050565b600082601f8301126132d857600080fd5b81356132e661327682613e87565b81815260209384019390925082018360005b838110156132bd578135860161330e888261341a565b84525060209283019291909101906001016132f8565b600082601f83011261333557600080fd5b813561334361327682613e87565b9150818183526020840193506020810190508385602084028201111561336857600080fd5b60005b838110156132bd578161337e888261340f565b845250602092830192919091019060010161336b565b600082601f8301126133a557600080fd5b81356133b361327682613e87565b915081818352602084019350602081019050838560208402820111156133d857600080fd5b60005b838110156132bd57816133ee888261340f565b84525060209283019291909101906001016133db565b805161250781613f54565b803561250781613f5d565b600060c0828403121561342c57600080fd5b61343660c0613e44565b90506000613444848461340f565b82525060206134558484830161340f565b60208301525060408201356001600160401b0381111561347457600080fd5b61348084828501613324565b604083015250606061349484828501613241565b60608301525060806134a884828501613241565b60808301525060a06134bc84828501613241565b60a08301525092915050565b805161250781613f5d565b6000602082840312156134e557600080fd5b6000612e4b8484613241565b60006020828403121561350357600080fd5b6000612e4b848461324c565b6000806040838503121561352257600080fd5b600061352e8585613241565b925050602061353f85828601613241565b9150509250929050565b6000806000806080858703121561355f57600080fd5b600061356b8787613241565b94505060208501356001600160401b0381111561358757600080fd5b61359387828801613394565b93505060408501356001600160401b038111156135af57600080fd5b6135bb87828801613394565b92505060608501356001600160401b038111156135d757600080fd5b6135e3878288016132c7565b91505092959194509250565b6000806000806080858703121561360557600080fd5b60006136118787613241565b94505060206136228782880161340f565b93505060406136338782880161340f565b92505060608501356001600160401b0381111561364f57600080fd5b6135e38782880161341a565b60008060006060848603121561367057600080fd5b83356001600160401b0381111561368657600080fd5b61369286828701613394565b93505060208401356001600160401b038111156136ae57600080fd5b6136ba86828701613394565b92505060408401356001600160401b038111156136d657600080fd5b6136e2868287016132c7565b9150509250925092565b6000602082840312156136fe57600080fd5b6000612e4b8484613404565b60006020828403121561371c57600080fd5b6000612e4b848461340f565b6000806040838503121561373b57600080fd5b6000613747858561340f565b925050602061353f8582860161340f565b60006020828403121561376a57600080fd5b81356001600160401b0381111561378057600080fd5b612e4b8482850161341a565b6000806000608084860312156137a157600080fd5b83356001600160401b038111156137b757600080fd5b6137c38682870161341a565b93505060206137d48682870161340f565b92505060406136e286828701613257565b6000602082840312156137f757600080fd5b6000612e4b84846134c8565b6000806040838503121561381657600080fd5b600061382285856134c8565b925050602061353f858286016134c8565b60008060006060848603121561384857600080fd5b6000613854868661340f565b93505060206138658682870161340f565b92505060408401356001600160401b0381111561388157600080fd5b6136e28682870161341a565b6000613899838361397a565b505060200190565b6138aa81613ede565b82525050565b6138aa81613ebf565b6138aa6138c582613ebf565b613f1c565b60006138d582613ead565b6138df8185613eb1565b93506138ea83613ea7565b8060005b83811015613918578151613902888261388d565b975061390d83613ea7565b9250506001016138ee565b509495945050505050565b600061392e82613ead565b6139388185613eba565b935061394383613ea7565b8060005b8381101561391857815161395b888261388d565b975061396683613ea7565b925050600101613947565b6138aa81613eca565b6138aa81613ecf565b600061398e82613ead565b6139988185613eba565b93506139a8818560208601613ef0565b9290920192915050565b6138aa81613ee5565b60006139c682613ead565b6139d08185613eb1565b93506139e0818560208601613ef0565b6139e981613f2d565b9093019392505050565b6000613a00601b83613eb1565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000613a39602083613eb1565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b6000613a72602183613eb1565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000613ab5602a83613eb1565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b6000613b01601f83613eb1565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00815260200192915050565b6000613b3a601f83613eb1565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160009060c0840190613b7a858261397a565b506020830151613b8d602086018261397a565b5060408301518482036040860152613ba582826138ca565b9150506060830151613bba60608601826138b0565b506080830151613bcd60808601826138b0565b5060a0830151613be060a08601826138b0565b509392505050565b6138aa613bf482613ecf565b613ecf565b6000612e108284613983565b6000613c118289613be8565b602082019150613c218288613be8565b602082019150613c318287613923565b9150613c3d82866138b9565b601482019150613c4d82856138b9565b601482019150613c5d82846138b9565b506014019695505050505050565b6020810161250782846138b0565b60408101613c8782856138a1565b612e1060208301846138b0565b60608101613ca282866138a1565b613caf602083018561397a565b612e4b604083018461397a565b60808101613cca82876138b0565b613cd760208301866138a1565b613ce4604083018561397a565b613cf1606083018461397a565b95945050505050565b60808101613d0882876138b0565b613cd760208301866138b0565b60608101613ca282866138b0565b60408101613d3182856138b0565b612e10602083018461397a565b602081016125078284613971565b60208101612507828461397a565b60408101613d68828561397a565b8181036020830152612e4b8184613b66565b60808101613d8882876139b2565b613d9560208301866138a1565b613ce460408301856138b0565b6020808252810161250481846139bb565b60208082528101612507816139f3565b6020808252810161250781613a2c565b6020808252810161250781613a65565b6020808252810161250781613aa8565b6020808252810161250781613af4565b6020808252810161250781613b2d565b602080825281016125048184613b66565b60408082528101613e358185613b66565b9050612e10602083018461397a565b6040518181016001600160401b0381118282101715613e6257600080fd5b604052919050565b60006001600160401b03821115613e8057600080fd5b5060200290565b60006001600160401b03821115613e9d57600080fd5b5060209081020190565b60200190565b5190565b90815260200190565b919050565b600061250782613ed2565b151590565b90565b6001600160a01b031690565b6000612507825b600061250782613ebf565b60005b83811015613f0b578181015183820152602001613ef3565b838111156102c95750506000910152565b600061250782600061250782613f37565b601f01601f191690565b60601b90565b613f4681613ebf565b8114613f5157600080fd5b50565b613f4681613eca565b613f4681613ecf56fe434f52453a544f4b454e5f4944535f414e445f5155414e5449544945535f4c454e4754485f444f45535f4e4f545f4d41544348434f52453a53594e5448455449435f455845435554494f4e5f5741535f4e4f545f414c4c4f574544434f52453a544f4b454e5f4944535f414e445f44455249564154495645535f4c454e4754485f444f45535f4e4f545f4d41544348434f52453a455845435554494f4e5f4245464f52455f4d415455524954595f4e4f545f414c4c4f574544a365627a7a723158204b77c9a170e86eaa4dad533a12f3f73c8d9e9d797af48d084b34168928bec65a6c6578706572696d656e74616cf564736f6c63430005100040
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000007f5f4087006ba4f4985b32f9d1079ee2f8594af8
-----Decoded View---------------
Arg [0] : _registry (address): 0x7f5F4087006BA4F4985b32f9d1079Ee2F8594Af8
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000007f5f4087006ba4f4985b32f9d1079ee2f8594af8
Deployed Bytecode Sourcemap
101112:28637:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;101112:28637:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;108120:192;;;;;;;;;:::i;:::-;;103066:256;;;;;;;;;:::i;30147:49::-;;;:::i;:::-;;;;;;;;;;;;;;;;105168:489;;;;;;;;;:::i;102705:42::-;;;;;;;;;:::i;:::-;;;;;;;;102005:66;;;;;;;;;:::i;106642:228::-;;;;;;;;;:::i;107244:453::-;;;;;;;;;:::i;104332:467::-;;;;;;;;;:::i;29554:98::-;;;:::i;:::-;;;;;;;;102378:55;;;;;;;;;:::i;102594:66::-;;;;;;;;;:::i;106011:206::-;;;;;;;;;:::i;30008:50::-;;;:::i;101783:61::-;;;:::i;103712:322::-;;;;;;;;;:::i;29902:47::-;;;:::i;18319:382::-;;;;;;;;;:::i;102222:44::-;;;;;;;;;:::i;108120:192::-;16787:1;16770:18;;;;;;;;108259:45;108267:9;108278:11;108291:12;108259:7;:45::i;:::-;16882:13;;16866:12;:29;16858:73;;;;-1:-1:-1;;;16858:73:0;;;;;;;;;;;;;;;;;108120:192;;;;:::o;103066:256::-;16787:1;16770:18;;;;;;;;103170:10;-1:-1:-1;103159:22:0;;;:10;:22;;;;;;;;-1:-1:-1;;;;;103159:37:0;;;;;;;;;;;103207:41;;;103159:37;;103259:55;;103159:37;;103259:34;:55::i;:::-;16846:1;16882:13;;16866:12;:29;16858:73;;;;-1:-1:-1;;;16858:73:0;;;;;;;;;103066:256;;:::o;30147:49::-;30195:1;30147:49;:::o;105168:489::-;16787:1;16770:18;;;;;;;105333:16;;;;;;;;;;;;16770:18;;105305:25;;105333:16;;;;;;;105:10:-1;105333:16:0;88:34:-1;-1:-1;;105390:16:0;;;105404:1;105390:16;;;;;;;;;105305:44;;-1:-1:-1;105360:27:0;;105390:16;-1:-1:-1;105390:16:0;;;;;;105:10:-1;105390:16:0;88:34:-1;-1:-1;;105451:19:0;;;105468:1;105451:19;;;;;;;;;105360:46;;-1:-1:-1;105417:31:0;;105451:19;-1:-1:-1;105451:19:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;105417:53;;105497:8;105483;105492:1;105483:11;;;;;;;;;;;;;:22;;;;;105532:9;105516:10;105527:1;105516:13;;;;;;;;;;;;;:25;;;;;105569:11;105552;105564:1;105552:14;;;;;;;;;;;;;:28;;;;105593:56;105602:11;105615:8;105625:10;105637:11;105593:8;:56::i;:::-;16846:1;;;16882:13;;16866:12;:29;16858:73;;;;-1:-1:-1;;;16858:73:0;;;;;;;;;105168:489;;;;;:::o;102705:42::-;;;;;;;;;;;;;;;:::o;102005:66::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;106642:228::-;16787:1;16770:18;;;;;;;;106803:59;106812:11;106825:9;106836:11;106849:12;106803:8;:59::i;:::-;16882:13;;16866:12;:29;16858:73;;;;-1:-1:-1;;;16858:73:0;;;;;;;;107244:453;16787:1;16770:18;;;;;;;107387:16;;;;;;;;;;;;16770:18;;107359:25;;107387:16;;;;;;;105:10:-1;107387:16:0;88:34:-1;-1:-1;;107444:16:0;;;107458:1;107444:16;;;;;;;;;107359:44;;-1:-1:-1;107414:27:0;;107444:16;-1:-1:-1;107444:16:0;;;;;;105:10:-1;107444:16:0;88:34:-1;-1:-1;;107505:19:0;;;107522:1;107505:19;;;;;;;;;107414:46;;-1:-1:-1;107471:31:0;;107505:19;-1:-1:-1;107505:19:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;107471:53;;107551:8;107537;107546:1;107537:11;;;;;;;;;;;;;:22;;;;;107586:9;107570:10;107581:1;107570:13;;;;;;;;;;;;;:25;;;;;107623:11;107606;107618:1;107606:14;;;;;;;;;;;;;:28;;;;107647:42;107655:8;107665:10;107677:11;107647:7;:42::i;:::-;16846:1;;;16882:13;;16866:12;:29;16858:73;;;;-1:-1:-1;;;16858:73:0;;;;;;;;104332:467;16787:1;16770:18;;;;;;;104476:16;;;;;;;;;;;;16770:18;;104448:25;;104476:16;;;;;;;105:10:-1;104476:16:0;88:34:-1;-1:-1;;104533:16:0;;;104547:1;104533:16;;;;;;;;;104448:44;;-1:-1:-1;104503:27:0;;104533:16;-1:-1:-1;104533:16:0;;;;;;105:10:-1;104533:16:0;88:34:-1;-1:-1;;104594:19:0;;;104611:1;104594:19;;;;;;;;;104503:46;;-1:-1:-1;104560:31:0;;104594:19;-1:-1:-1;104594:19:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;104560:53;;104640:8;104626;104635:1;104626:11;;;;;;;;;;;;;:22;;;;;104675:9;104659:10;104670:1;104659:13;;;;;;;;;;;;;:25;;;;;104712:11;104695;104707:1;104695:14;;;;;;;;;;;;;:28;;;;104736:55;104745:10;104757:8;104767:10;104779:11;104736:8;:55::i;29554:98::-;29600:7;29635:8;-1:-1:-1;;;;;29635:8:0;29554:98;:::o;102378:55::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;102378:55:0;;-1:-1:-1;102378:55:0:o;102594:66::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;106011:206::-;16787:1;16770:18;;;;;;;;106151:58;106160:10;106172:9;106183:11;106196:12;106151:8;:58::i;30008:50::-;30056:2;30008:50;:::o;101783:61::-;101837:7;101783:61;:::o;103712:322::-;16787:1;16770:18;;;;;;;;103843:13;;;;-1:-1:-1;;;;;103843:27:0;103839:188;;103925:13;;103887:52;;103901:11;;103914:9;;103887:13;:52::i;:::-;103839:188;;;103972:43;103980:11;103993:9;104004:10;103972:7;:43::i;29902:47::-;29944:5;29902:47;:::o;18319:382::-;18491:18;;18524:19;;;;;18558:18;;;;;18591:20;;;;18626:17;;;;18658:23;;;;18460:232;;18398:22;;18460:232;;18491:18;;18524:19;18658:23;18460:232;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;18460:232:0;;;18450:243;;;;;;18433:260;;18319:382;;;:::o;102222:44::-;;;;;;;;;;;;;:::o;117556:4158::-;117712:11;:18;117692:9;:16;:38;117732:57;;;;;;;;;;;;;;;;;117684:106;;;;;-1:-1:-1;;;117684:106:0;;;;;;;;;;;117829:12;:19;117809:9;:16;:39;117850:58;;;;;;;;;;;;;;;;;117801:108;;;;;-1:-1:-1;;;117801:108:0;;;;;;;;;;;117950:37;;:::i;:::-;118191:8;;;;;;;;;-1:-1:-1;;;;;118191:8:0;-1:-1:-1;;;;;118191:18:0;;:20;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;118191:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;118191: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;118191:20:0;;;;;;;;;-1:-1:-1;;;;;118160:52:0;;;;;:16;118264:8;:30;;;-1:-1:-1;;;118264:30:0;;;;:8;;;;;:28;;:30;;;;;;;;;;;;;;:8;:30;;;5:2:-1;;;;30:1;27;20:12;5:2;118264:30:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;118264: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;118264:30:0;;;;;;;;;-1:-1:-1;;;;;118223:72:0;;;:21;;;;:72;;;;118353:8;;:33;;;-1:-1:-1;;;118353:33:0;;;;:8;;;;;:31;;:33;;;;;118223:21;;118353:33;;;;;:8;:33;;;5:2:-1;;;;30:1;27;20:12;5:2;118353:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;118353: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;118353:33:0;;;;;;;;;-1:-1:-1;;;;;118306:81:0;:24;;;:81;118405:9;118400:3307;118420:9;:16;118416:1;:20;118400:3307;;;118571:1;-1:-1:-1;;;;;118535:38:0;:12;118548:1;118535:15;;;;;;;;;;;;;;:24;;;-1:-1:-1;;;;;118535:38:0;;;118575;;;;;;;;;;;;;;;;;118527:87;;;;;-1:-1:-1;;;118527:87:0;;;;;;;;;;;118834:3;101837:7;118777:12;118790:1;118777:15;;;;;;;;;;;;;;:23;;;:53;:60;;:162;;;;;118859:4;:21;;;-1:-1:-1;;;;;118859:29:0;;118889:12;118902:1;118889:15;;;;;;;;;;;;;;:24;;;118915:12;118928:1;118915:15;;;;;;;;;;;;;;:23;;;118859:80;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;118859:80:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;118859: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;118859:80:0;;;;;;;;;118858:81;118777:162;118958:38;;;;;;;;;;;;;;;;;118751:260;;;;;-1:-1:-1;;;118751:260:0;;;;;;;;;;;119073:22;119098:34;119116:12;119129:1;119116:15;;;;;;;;;;;;;;119098:17;:34::i;:::-;119230:25;;;;:9;:25;;;;;;119073:59;;-1:-1:-1;119230:25:0;;119225:147;;119276:25;;;;:9;:25;;;;;;;:32;;-1:-1:-1;;119276:32:0;119304:4;119276:32;;;119332:24;;;;;119286:14;;119332:24;;;;;;;;;;119225:147;119388:25;;:::i;:::-;119673:4;:24;;;-1:-1:-1;;;;;119673:34:0;;119708:14;119724:12;119737:1;119724:15;;;;;;;;;;;;;;119673:67;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;119673:67:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;119673: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;119673:67:0;;;;;;;;;119647:10;119659;;119646:94;;;119887:12;;119655:1;;119887:12;;119897:1;;119887:12;;;;;;;;;;;;119852:14;:29;;;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;119852:31:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;119852: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;119852:31:0;;;;;;;;;:47;119848:1532;;;119975:30;119990:11;120002:1;119990:14;;;;;;;;;;;;;;119975:7;119983:1;119975:10;;;;;;;;;;;;:30;:14;:30;:::i;:::-;119966:39;;120082:4;:24;;;-1:-1:-1;;;;;120082:31:0;;120114:14;120130:12;120143:1;120130:15;;;;;;;;;;;;;;120082:64;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;120082:64:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;120082: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;120082:64:0;;;;;;;;;120078:791;;;120350:6;120284:10;:39;120295:12;120308:1;120295:15;;;;;;;;;;;;;;:27;;;-1:-1:-1;;;;;120284:39:0;-1:-1:-1;;;;;120284:39:0;;;;;;;;;;;;:62;120324:12;120337:1;120324:15;;;;;;;;;;;;;;:21;;;-1:-1:-1;;;;;120284:62:0;-1:-1:-1;;;;;120284:62:0;;;;;;;;;;;;;:72;;120409:36;;;;;;;;;;;;;;;;;120250:218;;;;;-1:-1:-1;;;120250:218:0;;;;;;;;;;;120622:74;120689:6;120622:10;:39;120633:12;120646:1;120633:15;;;;;;;;;;;;;;:27;;;-1:-1:-1;;;;;120622:39:0;-1:-1:-1;;;;;120622:39:0;;;;;;;;;;;;:62;120662:12;120675:1;120662:15;;;;;;;;;;;;;;:21;;;-1:-1:-1;;;;;120622:62:0;-1:-1:-1;;;;;120622:62:0;;;;;;;;;;;;;:66;;:74;;;;:::i;:::-;120557:10;:39;120568:12;120581:1;120568:15;;;;;;;;;;;;;;:27;;;-1:-1:-1;;;;;120557:39:0;-1:-1:-1;;;;;120557:39:0;;;;;;;;;;;;:62;120597:12;120610:1;120597:15;;;;;;;;;;;;;;:21;;;-1:-1:-1;;;;;120557:62:0;-1:-1:-1;;;;;120557:62:0;;;;;;;;;;;;:139;;;;120078:791;;;120808:41;120826:14;120842:6;120808:17;:41::i;:::-;119848:1532;;;120993:9;121003:1;120993:12;;;;;;;;;;;;;;120957:14;:30;;;;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;120957:32:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;120957: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;120957:32:0;;;;;;;;;:48;120953:427;;;121082:30;121097:11;121109:1;121097:14;;;;;;;;;;;;;;121082:7;121090:1;121082:10;;;;;;:30;121073:39;;121190:41;121208:14;121224:6;121190:17;:41::i;120953:427::-;121331:32;;;;;;;;;;;;;;;;121324:40;;-1:-1:-1;;;121324:40:0;;;;121331:32;121324:40;;;;120953:427;121461:10;;121457:113;;121492:62;121535:10;121547:6;121499:12;121512:1;121499:15;;;;;;;;;;;;;;:21;;;-1:-1:-1;;;;;121492:42:0;;;:62;;;;;:::i;:::-;121632:4;:16;;;-1:-1:-1;;;;;121632:21:0;;121654:10;121666:9;121676:1;121666:12;;;;;;;;;;;;;;121680:11;121692:1;121680:14;;;;;;;;;;;;;;121632:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;121632:63:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;118438:3:0;;;;;-1:-1:-1;118400:3307:0;;-1:-1:-1;;;;118400:3307:0;12212:176;12321:58;;12295:85;;12314:5;;-1:-1:-1;;;12344:23:0;12321:58;;12369:2;;12373:5;;12321:58;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;12321:58:0;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;;;;12321:58:0;;;179:29:-1;;;;160:49;;;12295:18:0;:85::i;:::-;12212:176;;;:::o;115142:1991::-;115320:11;:18;115300:9;:16;:38;115340:57;;;;;;;;;;;;;;;;;115292:106;;;;;-1:-1:-1;;;115292:106:0;;;;;;;;;;;115437:12;:19;115417:9;:16;:39;115458:58;;;;;;;;;;;;;;;;;115409:108;;;;;-1:-1:-1;;;115409:108:0;;;;;;;;;;;115558:37;;:::i;:::-;115799:8;;;;;;;;;-1:-1:-1;;;;;115799:8:0;-1:-1:-1;;;;;115799:18:0;;:20;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;115799:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115799: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;115799:20:0;;;;;;;;;-1:-1:-1;;;;;115768:52:0;;;;;:16;115872:8;:30;;;-1:-1:-1;;;115872:30:0;;;;:8;;;;;:28;;:30;;;;;;;;;;;;;;:8;:30;;;5:2:-1;;;;30:1;27;20:12;5:2;115872:30:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115872: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;115872:30:0;;;;;;;;;-1:-1:-1;;;;;115831:72:0;;;:21;;;;:72;;;;115961:8;;:33;;;-1:-1:-1;;;115961:33:0;;;;:8;;;;;:31;;:33;;;;;115831:21;;115961:33;;;;;:8;:33;;;5:2:-1;;;;30:1;27;20:12;5:2;115961:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115961: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;115961:33:0;;;;;;;;;-1:-1:-1;;;;;115914:81:0;:24;;;:81;116013:9;116008:1118;116028:9;:16;116024:1;:20;116008:1118;;;116142:12;116155:1;116142:15;;;;;;;;;;;;;;:23;;;116136:3;:29;116167:48;;;;;;;;;;;;;;;;;116128:88;;;;;-1:-1:-1;;;116128:88:0;;;;;;;;;;-1:-1:-1;;;;;;116395:25:0;;116410:10;116395:25;;:131;;;116458:12;116471:1;116458:15;;;;;;;;;;;;;;:27;;;-1:-1:-1;;;;;116441:72:0;;116514:11;116441:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;116441:85:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;116441: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;116441:85:0;;;;;;;;;116545:46;;;;;;;;;;;;;;;;;116369:237;;;;;-1:-1:-1;;;116369:237:0;;;;;;;;;;;116672:14;116689:63;116700:12;116713:1;116700:15;;;;;;;;;;;;;;116717:9;116727:1;116717:12;;;;;;;;;;;;;;116731:11;116743:1;116731:14;;;;;;;;;;;;;;116747:4;116689:10;:63::i;:::-;116672:80;-1:-1:-1;116805:10:0;;116801:114;;116836:63;116879:11;116892:6;116843:12;116856:1;116843:15;;;;;;;116836:63;116977:4;:16;;;-1:-1:-1;;;;;116977:21:0;;116999:11;117012:9;117022:1;117012:12;;;;;;;;;;;;;;117026:11;117038:1;117026:14;;;;;;;;;;;;;;116977:64;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;116977:64:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;116977:64:0;;;;117063:51;117072:11;117085:9;117095:1;117085:12;;;;;;;;;;;;;;117099:11;117111:1;117099:14;;;;;;;;;;;;;;117063:51;;;;;;;;;;;;;;;;;-1:-1:-1;116046:3:0;;116008:1118;;;;115142:1991;;;;;:::o;108830:2469::-;108968:33;;:::i;:::-;109315:8;;;;;;;;;-1:-1:-1;;;;;109315:8:0;-1:-1:-1;;;;;109315:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;109315:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;109315: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;109315:33:0;;;;;;;;;-1:-1:-1;;;;;109268:81:0;;;;;109400:23;;;;109360:64;;:20;;;;:64;;;;-1:-1:-1;109461:17:0;;;109435:44;;:16;;;;:44;;;;109268:24;109523:8;:26;;-1:-1:-1;;;109523:26:0;;;;:8;;;:24;;:26;;;;;109360:20;;109523:26;;;;;;:8;:26;;;5:2:-1;;;;30:1;27;20:12;5:2;109523:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;109523: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;109523:26:0;;;;;;;;;-1:-1:-1;;;;;109490:60:0;;;:17;;;:60;109592:8;;:20;;;-1:-1:-1;;;109592:20:0;;;;:8;;;;;:18;;:20;;;;;;;;;;;;;;:8;:20;;;5:2:-1;;;;30:1;27;20:12;5:2;109592:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;109592: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;109592:20:0;;;;;;;;;-1:-1:-1;;;;;109561:52:0;:16;;;:52;109667:22;109692:30;109710:11;109692:17;:30::i;:::-;109817:24;;:60;;-1:-1:-1;;;109817:60:0;;109667:55;;-1:-1:-1;;;;;;109817:31:0;;;;:60;;109667:55;;109865:11;;109817:60;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;109817:60:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;109817: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;109817:60:0;;;;;;;;;109879:19;;;;;;;;;;;;;-1:-1:-1;;;109879:19:0;;;109809:90;;;;;-1:-1:-1;;;109809:90:0;;;;;;;;;;-1:-1:-1;109962:25:0;;;;:9;:25;;;;;;;;;;109989:31;;;;;;;;;;;-1:-1:-1;;;109989:31:0;;;;;;;109962:25;;109961:26;109953:68;;;;-1:-1:-1;;;109953:68:0;;;;;;;;;;;110115:4;:20;;;-1:-1:-1;;;;;110115:34:0;;110150:11;110115:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;110115:47:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;110115: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;110115:47:0;;;;;;;;;110164:37;;;;;;;;;;;;;;;;;110107:95;;;;;-1:-1:-1;;;110107:95:0;;;;;;;;;;-1:-1:-1;110325:24:0;;:63;;-1:-1:-1;;;110325:63:0;;110305:14;;-1:-1:-1;;;;;110325:34:0;;;;:63;;110360:14;;110376:11;;110325:63;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;110325:63:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;110325: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;110325:63:0;;;;;;;;;-1:-1:-1;110304:84:0;-1:-1:-1;110606:21:0;110304:84;110617:9;110606:21;:10;:21;:::i;:::-;110536:4;:16;;;-1:-1:-1;;;;;110536:26:0;;110563:10;110583:4;:17;;;110536:66;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;110536:66:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;110536: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;110536:66:0;;;;;;;;;:91;;110629:37;;;;;;;;;;;;;;;;;110528:139;;;;;-1:-1:-1;;;110528:139:0;;;;;;;;;;;110776:4;:17;;;-1:-1:-1;;;;;110776:29:0;;110806:4;:16;;;110824:10;110844:4;110851:21;110862:9;110851:6;:10;;:21;;;;:::i;:::-;110776:97;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;110776:97:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;110776:97:0;;;;111027:81;111086:21;111097:9;111086:6;:10;;:21;;;;:::i;:::-;111038:23;;;;-1:-1:-1;;;;;111027:35:0;;;;;;;:10;:35;;;;;;;;111063:17;;;;111027:54;;;;;;;;;;;:81;:58;:81;:::i;:::-;110981:23;;;;-1:-1:-1;;;;;110970:35:0;;;;;;;:10;:35;;;;;;;;111006:17;;;;;110970:54;;;;;;;;;;:138;;;;111159:16;;;;:58;;-1:-1:-1;;;111159:58:0;;:21;;;;;:58;;111181:8;;111191:14;;111207:9;;111159:58;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;111159:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;111159:58:0;;;;111235:56;111243:8;111261:1;111265:14;111281:9;111235:56;;;;;;;;;;;;;;;;;;108830:2469;;;;;;:::o;111845:2695::-;111989:27;;:::i;:::-;112330:8;;;;;;;;;-1:-1:-1;;;;;112330:8:0;-1:-1:-1;;;;;112330:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;112330:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;112330: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;112330:33:0;;;;;;;;;-1:-1:-1;;;;;112283:81:0;;;;;112415:23;;;;112375:64;;:20;;;;:64;;;;-1:-1:-1;112476:17:0;;;112450:44;;:16;;;;:44;;;;112283:24;112538:8;:26;;-1:-1:-1;;;112538:26:0;;;;:8;;;:24;;:26;;;;;112375:20;;112538:26;;;;;;:8;:26;;;5:2:-1;;;;30:1;27;20:12;5:2;112538:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;112538: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;112538:26:0;;;;;;;;;-1:-1:-1;;;;;112505:60:0;;;:17;;;:60;112607:8;;:20;;;-1:-1:-1;;;112607:20:0;;;;:8;;;;;:18;;:20;;;;;;;;;;;;;;:8;:20;;;5:2:-1;;;;30:1;27;20:12;5:2;112607:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;112607: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;112607:20:0;;;;;;;;;-1:-1:-1;;;;;112576:52:0;:16;;;:52;112682:22;112707:30;112725:11;112707:17;:30::i;:::-;112837:24;;:60;;-1:-1:-1;;;112837:60:0;;112682:55;;-1:-1:-1;;;;;;112837:31:0;;;;:60;;112682:55;;112885:11;;112837:60;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;112837:60:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;112837: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;112837:60:0;;;;;;;;;112836:61;112899:23;;;;;;;;;;;;;-1:-1:-1;;;112899:23:0;;;112828:95;;;;;-1:-1:-1;;;112828:95:0;;;;;;;;;;-1:-1:-1;112986:25:0;;;;:9;:25;;;;;;;;;;113013:31;;;;;;;;;;;-1:-1:-1;;;113013:31:0;;;;;;;112986:25;;112985:26;112977:68;;;;-1:-1:-1;;;112977:68:0;;;;;;;;;;;113139:4;:20;;;-1:-1:-1;;;;;113139:34:0;;113174:11;113139:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;113139:47:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;113139: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;113139:47:0;;;;;;;;;113188:37;;;;;;;;;;;;;;;;;113131:95;;;;;-1:-1:-1;;;113131:95:0;;;;;;;;;;;113239:25;;:::i;:::-;113466:24;;:63;;-1:-1:-1;;;113466:63:0;;-1:-1:-1;;;;;113466:34:0;;;;;;:63;;113501:14;;113517:11;;113466:63;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;113466:63:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;113466: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;113466:63:0;;;;;;;;;113440:10;113452;;113439:90;;;;;;113766:41;;113797:9;;113766:26;;113440:7;113448:1;113766:10;;;;;;:26;:14;:26;:::i;:::-;:30;:41;:30;:41;:::i;:::-;113696:4;:16;;;-1:-1:-1;;;;;113696:26:0;;113723:10;113743:4;:17;;;113696:66;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;113696:66:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;113696: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;113696:66:0;;;;;;;;;:111;;113809:37;;;;;;;;;;;;;;;;;113688:159;;;;;-1:-1:-1;;;113688:159:0;;;;;;;;;;;113956:4;:17;;;-1:-1:-1;;;;;113956:29:0;;113986:4;:16;;;114004:10;114024:4;114031:41;114062:9;114031:26;114046:7;114054:1;114046:10;;;;;;;;;;;114031:7;114039:1;114031:10;;:41;113956:117;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;113956:117:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;113956:117:0;;;;114197:113;114229:14;114258:41;114289:9;114258:26;114273:7;114281:1;114273:10;;;;;;;;;;;114258:7;114266:1;114258:10;;:41;114197:17;:113::i;:::-;114372:16;;;;114394:13;;;114409;;;114372:78;;-1:-1:-1;;;114372:78:0;;-1:-1:-1;;;;;114372:21:0;;;;;;:78;;114394:13;;114424:14;;114440:9;;114372:78;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;114372:78:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;114372:78:0;;;;114468:64;114476:10;114487:1;114476:13;;;;;;;;;;;114491:10;114502:1;114491:13;;;;114506:14;114522:9;114468:64;;;;;;;;;;5181:471;5239:7;5484:6;5480:47;;-1:-1:-1;5514:1:0;5507:8;;5480:47;5551:5;;;5555:1;5551;:5;:1;5575:5;;;;;:10;5567:56;;;;-1:-1:-1;;;5567:56:0;;;;;;;;;5643:1;-1:-1:-1;5181:471:0;;;;;:::o;4265:136::-;4323:7;4350:43;4354:1;4357;4350:43;;;;;;;;;;;;;;;;;:3;:43::i;129451:295::-;129591:7;129561:9;:26;129571:15;129561:26;;;;;;;;;;;;:37;;129613:35;;;;;;;;;;;;;;;;;129539:120;;;;;-1:-1:-1;;;129539:120:0;;;;;;;;;;-1:-1:-1;129699:26:0;;;;:9;:26;;;;;;:39;;129730:7;129699:39;:30;:39;:::i;:::-;129670:26;;;;:9;:26;;;;;;:68;;;;-1:-1:-1;129451:295:0:o;14251:1114::-;14855:27;14863:5;-1:-1:-1;;;;;14855:25:0;;:27::i;:::-;14847:71;;;;-1:-1:-1;;;14847:71:0;;;;;;;;;14992:12;15006:23;15041:5;-1:-1:-1;;;;;15033:19:0;15053:4;15033: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;;14991:67:0;;;;15077:7;15069:52;;;;-1:-1:-1;;;15069:52:0;;;;;;;;;15138:17;;:21;15134:224;;15280:10;15269:30;;;;;;;;;;;;;;15261:85;;;;-1:-1:-1;;;15261:85:0;;;;;;;;122083:5139;122442:20;;;;122228:14;;;;-1:-1:-1;;;;;122442:34:0;;122438:188;;122500:5;:22;;;-1:-1:-1;;;;;122500:30:0;;122531:11;:20;;;122553:11;:19;;;122500:73;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;122500:73:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;122500: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;122500:73:0;;;;;;;;;122493:80;;122438:188;;;-1:-1:-1;122613:1:0;122438:188;122638:29;;:::i;:::-;122864:11;:23;;;-1:-1:-1;;;;;122847:60:0;;122908:11;122921:4;122847:79;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;122847:79:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;122847: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;122847:79:0;;;;;;;;;122813:14;122829;;122812:114;;;122825:1;123005:30;123023:11;123005:17;:30::i;:::-;123098:25;;;;:9;:25;;;;;;;;;;123125:31;;;;;;;;;;;-1:-1:-1;;;123125:31:0;;;;;;;122980:55;;-1:-1:-1;123125:31:0;123098:25;;123097:26;123089:68;;;;-1:-1:-1;;;123089:68:0;;;;;;;;;;;123170:25;;:::i;:::-;123384:5;:25;;;-1:-1:-1;;;;;123384:35:0;;123420:14;123436:11;123384:64;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;123384:64:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;123384: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;123384:64:0;;;;;;;;;123358:10;123370;;123357:91;;;123461:25;;:::i;:::-;123811:86;123862:34;123881:11;123893:1;123881:14;;123862:34;123811:46;123842:11;123854:1;123842:14;;;;;123811:26;123826:7;123834:1;123826:10;;;;123811:7;123819:1;123811:10;;:46;:50;:86;:50;:86;:::i;:::-;123798:99;;123921:86;123972:34;123991:11;124003:1;123991:14;;123972:34;123921:46;123952:11;123964:1;123952:14;;123921:86;123908:10;;;;:99;;;;124209:33;;;;:17;:33;;;;;;:36;:41;:86;;;;-1:-1:-1;124254:33:0;;;;:17;:33;;;;;124288:1;124254:36;;:41;124209:86;124205:303;;;124386:10;;124394:1;124347:33;;;:17;124386:10;124347:33;;;;;;;:49;;;124486:10;;;124494:1;124447:36;;;:49;124205:303;124590:31;;-1:-1:-1;;;124590:31:0;;124625:8;;124590:29;;;;:31;;:14;;:31;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;124590:31:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;124590: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;124590:31:0;;;;;;;;;:43;124586:2629;;;124702:5;:25;;;-1:-1:-1;;;;;124702:32:0;;124735:14;124751:11;124702:61;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;124702:61:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;124702: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;124702:61:0;;;;;;;;;124698:1165;;;124890:14;;;-1:-1:-1;124982:21:0;124890:14;124993:9;124982:10;:21::i;:::-;124973:30;;125187:6;125129:10;:35;125140:11;:23;;;-1:-1:-1;;;;;125129:35:0;-1:-1:-1;;;;;125129:35:0;;;;;;;;;;;;:54;125165:11;:17;;;-1:-1:-1;;;;;125129:54:0;-1:-1:-1;;;;;125129:54:0;;;;;;;;;;;;;:64;;125238:36;;;;;;;;;;;;;;;;;125099:194;;;;;-1:-1:-1;;;125099:194:0;;;;;;;;;;-1:-1:-1;125442:23:0;;;;-1:-1:-1;;;;;125431:35:0;;;;;;;:10;:35;;;;;;;;125467:17;;;;125431:54;;;;;;;;;;:66;;125490:6;125431:66;:58;:66;:::i;:::-;125374:10;:35;125385:11;:23;;;-1:-1:-1;;;;;125374:35:0;-1:-1:-1;;;;;125374:35:0;;;;;;;;;;;;:54;125410:11;:17;;;-1:-1:-1;;;;;125374:54:0;-1:-1:-1;;;;;125374:54:0;;;;;;;;;;;;:123;;;;124698:1165;;;125600:33;;;;:17;:33;;;;;:36;;-1:-1:-1;125714:21:0;125600:36;125725:9;125714:10;:21::i;:::-;125705:30;;125806:41;125824:14;125840:6;125806:17;:41::i;:::-;125997:25;126012:9;125997:7;126005:1;125997:10;;:25;125988:6;:34;125984:284;;;126160:25;;;;126140:112;;126151:100;;126187:14;126203:11;126225:25;126240:9;126225:7;126233:1;126225:10;;:25;126216:6;:34;126151:8;:100::i;:::-;126140:6;;:112;:10;:112;:::i;:::-;126131:121;;125984:284;124586:2629;;;126350:32;;-1:-1:-1;;;126350:32:0;;126386:8;;126350:30;;;;:32;;:14;;:32;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;126350:32:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;126350: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;126350:32:0;;;;;;;;;:44;126346:869;;;126470:33;;;;:17;:33;;;;;126504:1;126470:36;;;-1:-1:-1;126576:21:0;126470:36;126587:9;126576:21;:10;:21;:::i;:::-;126567:30;;126660:41;126678:14;126694:6;126660:17;:41::i;:::-;126837:25;126852:9;126837:7;126845:1;126837:10;;:25;126828:6;:34;126824:259;;;126975:25;;;;126955:112;;126966:100;;127002:14;127018:11;127040:25;127055:9;127040:7;127048:1;127040:10;;126346:869;122083:5139;;;;;;;;;;;:::o;3809:181::-;3867:7;3899:5;;;3923:6;;;;3915:46;;;;-1:-1:-1;;;3915:46:0;;;;;;;;129279:164;129396:26;;;;:9;:26;;;;;;:39;;129427:7;129396:39;:30;:39;:::i;4738:192::-;4824:7;4860:12;4852:6;;;;4844:29;;;;-1:-1:-1;;;4844:29:0;;;;;;;;;;-1:-1:-1;;4896:5:0;;;4738:192;;;;;;:::o;9042:810::-;9102:4;9761:20;;9604:66;9801:15;;;;;:42;;;9832:11;9820:8;:23;;9801:42;9793:51;9042:810;-1:-1:-1;;;;9042:810:0:o;6120:132::-;6178:7;6205:39;6209:1;6212;6205:39;;;;;;;;;;;;;;;;;:3;:39::i;127644:1627::-;127794:11;127901:21;127925:20;-1:-1:-1;;;;;127925:37:0;;127963:15;127980:11;127925:67;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;127925:67:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;127925: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;127925:67:0;;;;;;;;;127901:91;;128086:18;128107:20;-1:-1:-1;;;;;128107:40:0;;128148:15;128165:11;128107:70;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;128107:70:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;128107: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;128107:70:0;;;;;;;;;128086:91;-1:-1:-1;128278:44:0;29944:5;128278:23;:7;128086:91;128278:23;:11;:23;:::i;:44::-;128272:50;-1:-1:-1;128381:8:0;128377:49;;128413:1;128406:8;;;;;;128377:49;128545:16;128564:57;30056:2;128564:30;:3;128545:16;128564:30;:7;:30;:::i;:57::-;128545:76;-1:-1:-1;128706:17:0;128726;:3;128545:76;128726:17;:7;:17;:::i;:::-;128706:37;;128786:20;128809:8;;;;;;;;;-1:-1:-1;;;;;128809:8:0;-1:-1:-1;;;;;128809:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;128809:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;128809: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;128809:26:0;;;;;;;;;-1:-1:-1;;;;;128985:24:0;;;;;;;:10;:24;;;;;;;;129010:17;;;;128985:43;;;;;;;;;;128786:49;;-1:-1:-1;128985:57:0;;129033:8;128985:57;:47;:57;:::i;:::-;-1:-1:-1;;;;;128939:24:0;;;;;;;:10;:24;;;;;;;;128964:17;;;;;128939:43;;;;;;;;;;:103;;;;129204:25;;;;;;;;;;;129230:17;;129204:44;;;;;;;;;;;:59;;129253:9;129204:59;:48;:59;:::i;:::-;-1:-1:-1;;;;;129157:25:0;;;;;;;:10;:25;;;;;;;;129183:17;;;;129157:44;;;;;;;;;;;;:106;;;;-1:-1:-1;;;;127644:1627:0;;;;;;:::o;6782:345::-;6868:7;6970:12;6963:5;6955:28;;;;-1:-1:-1;;;6955:28:0;;;;;;;;;;;6994:9;7010:1;7006;:5;;;;;;;6782:345;-1:-1:-1;;;;;6782:345:0:o;101112:28637::-;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;101112:28637:0;;;;;;-1:-1:-1;;;;;101112:28637:0;;;;;;-1:-1:-1;;;;;101112:28637:0;;;;;:::o;:::-;;;;;;;;;-1:-1:-1;101112:28637:0;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;101112:28637:0;;;-1:-1:-1;;101112:28637:0:o;:::-;;;;;;;;;-1:-1:-1;101112:28637: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:366;;;10481:2;10469:9;10460:7;10456:23;10452:32;10449:2;;;10497:1;10494;10487:12;10449:2;10532:1;10549:53;10594:7;10574:9;10549:53;;;10539:63;;10511:97;10639:2;10657:53;10702:7;10693:6;10682:9;10678:22;10657:53;;10733:381;;10864:2;10852:9;10843:7;10839:23;10835:32;10832:2;;;10880:1;10877;10870:12;10832:2;10915:31;;-1:-1;;;;;10955:30;;10952:2;;;10998:1;10995;10988:12;10952:2;11018:80;11090:7;11081:6;11070:9;11066:22;11018:80;;11121:678;;;;11309:3;11297:9;11288:7;11284:23;11280:33;11277:2;;;11326:1;11323;11316:12;11277:2;11361:31;;-1:-1;;;;;11401:30;;11398:2;;;11444:1;11441;11434:12;11398:2;11464:80;11536:7;11527:6;11516:9;11512:22;11464:80;;;11454:90;;11340:210;11581:2;11599:53;11644:7;11635:6;11624:9;11620:22;11599:53;;;11589:63;;11560:98;11689:2;11707:76;11775:7;11766:6;11755:9;11751:22;11707:76;;11806:263;;11921:2;11909:9;11900:7;11896:23;11892:32;11889:2;;;11937:1;11934;11927:12;11889:2;11972:1;11989:64;12045:7;12025:9;11989:64;;12076:399;;;12208:2;12196:9;12187:7;12183:23;12179:32;12176:2;;;12224:1;12221;12214:12;12176:2;12259:1;12276:64;12332:7;12312:9;12276:64;;;12266:74;;12238:108;12377:2;12395:64;12451:7;12442:6;12431:9;12427:22;12395:64;;12482:631;;;;12647:2;12635:9;12626:7;12622:23;12618:32;12615:2;;;12663:1;12660;12653:12;12615:2;12698:1;12715:53;12760:7;12740:9;12715:53;;;12705:63;;12677:97;12805:2;12823:53;12868:7;12859:6;12848:9;12844:22;12823:53;;;12813:63;;12784:98;12941:2;12930:9;12926:18;12913:32;-1:-1;;;;;12957:6;12954:30;12951:2;;;12997:1;12994;12987:12;12951:2;13017:80;13089:7;13080:6;13069:9;13065:22;13017:80;;13121:173;;13208:46;13250:3;13242:6;13208:46;;;-1:-1;;13283:4;13274:14;;13201:93;13500:142;13591:45;13630:5;13591:45;;;13586:3;13579:58;13573:69;;;13649:103;13722:24;13740:5;13722:24;;13879:152;13980:45;14000:24;14018:5;14000:24;;;13980:45;;14069:654;;14200:50;14244:5;14200:50;;;14263:76;14332:6;14327:3;14263:76;;;14256:83;;14360:52;14406:5;14360:52;;;14432:7;14460:1;14445:256;14470:6;14467:1;14464:13;14445:256;;;14537:6;14531:13;14558:63;14617:3;14602:13;14558:63;;;14551:70;;14638:56;14687:6;14638:56;;;14628:66;-1:-1;;14492:1;14485:9;14445:256;;;-1:-1;14714:3;;14179:544;-1:-1;;;;;14179:544;14762:718;;14921:50;14965:5;14921:50;;;14984:104;15081:6;15076:3;14984:104;;;14977:111;;15109:52;15155:5;15109:52;;;15181:7;15209:1;15194:264;15219:6;15216:1;15213:13;15194:264;;;15286:6;15280:13;15307:71;15374:3;15359:13;15307:71;;;15300:78;;15395:56;15444:6;15395:56;;;15385:66;-1:-1;;15241:1;15234:9;15194:264;;15488:104;15565:21;15580:5;15565:21;;15599:113;15682:24;15700:5;15682:24;;15847:356;;15975:38;16007:5;15975:38;;;16025:88;16106:6;16101:3;16025:88;;;16018:95;;16118:52;16163:6;16158:3;16151:4;16144:5;16140:16;16118:52;;;16182:16;;;;;15955:248;-1:-1;;15955:248;16210:152;16306:50;16350:5;16306:50;;16369:347;;16481:39;16514:5;16481:39;;;16532:71;16596:6;16591:3;16532:71;;;16525:78;;16608:52;16653:6;16648:3;16641:4;16634:5;16630:16;16608:52;;;16681:29;16703:6;16681:29;;;16672:39;;;;16461:255;-1:-1;;;16461:255;17070:327;;17230:67;17294:2;17289:3;17230:67;;;17330:29;17310:50;;17388:2;17379:12;;17216:181;-1:-1;;17216:181;17406:332;;17566:67;17630:2;17625:3;17566:67;;;17666:34;17646:55;;17729:2;17720:12;;17552:186;-1:-1;;17552:186;17747:370;;17907:67;17971:2;17966:3;17907:67;;;18007:34;17987:55;;-1:-1;;;18071:2;18062:12;;18055:25;18108:2;18099:12;;17893:224;-1:-1;;17893:224;18126:379;;18286:67;18350:2;18345:3;18286:67;;;18386:34;18366:55;;-1:-1;;;18450:2;18441:12;;18434:34;18496:2;18487:12;;18272:233;-1:-1;;18272:233;18514:331;;18674:67;18738:2;18733:3;18674:67;;;18774:33;18754:54;;18836:2;18827:12;;18660:185;-1:-1;;18660:185;18854:331;;19014:67;19078:2;19073:3;19014:67;;;19114:33;19094:54;;19176:2;19167:12;;19000:185;-1:-1;;19000:185;19266:1236;19489:23;;19266:1236;;19421:4;19412:14;;;19518:63;19416:3;19489:23;19518:63;;;19441:146;19663:4;19656:5;19652:16;19646:23;19675:63;19732:4;19727:3;19723:14;19709:12;19675:63;;;19597:147;19819:4;19812:5;19808:16;19802:23;19871:3;19865:4;19861:14;19854:4;19849:3;19845:14;19838:38;19891:99;19985:4;19971:12;19891:99;;;19883:107;;19754:248;20079:4;20072:5;20068:16;20062:23;20091:63;20148:4;20143:3;20139:14;20125:12;20091:63;;;20012:148;20234:4;20227:5;20223:16;20217:23;20246:63;20303:4;20298:3;20294:14;20280:12;20246:63;;;20170:145;20395:4;20388:5;20384:16;20378:23;20407:63;20464:4;20459:3;20455:14;20441:12;20407:63;;;-1:-1;20493:4;19394:1108;-1:-1;;;19394:1108;22169:152;22270:45;22290:24;22308:5;22290:24;;;22270:45;;22328:262;;22472:93;22561:3;22552:6;22472:93;;22597:1013;;22902:75;22973:3;22964:6;22902:75;;;22999:2;22994:3;22990:12;22983:19;;23013:75;23084:3;23075:6;23013:75;;;23110:2;23105:3;23101:12;23094:19;;23131:121;23248:3;23239:6;23131:121;;;23124:128;;23263:75;23334:3;23325:6;23263:75;;;23360:2;23355:3;23351:12;23344:19;;23374:75;23445:3;23436:6;23374:75;;;23471:2;23466:3;23462:12;23455:19;;23485:75;23556:3;23547:6;23485:75;;;-1:-1;23582:2;23573:12;;22890:720;-1:-1;;;;;;22890:720;23617:213;23735:2;23720:18;;23749:71;23724:9;23793:6;23749:71;;23837:340;23991:2;23976:18;;24005:79;23980:9;24057:6;24005:79;;;24095:72;24163:2;24152:9;24148:18;24139:6;24095:72;;24184:451;24366:2;24351:18;;24380:79;24355:9;24432:6;24380:79;;;24470:72;24538:2;24527:9;24523:18;24514:6;24470:72;;;24553;24621:2;24610:9;24606:18;24597:6;24553:72;;24642:563;24852:3;24837:19;;24867:71;24841:9;24911:6;24867:71;;;24949:80;25025:2;25014:9;25010:18;25001:6;24949:80;;;25040:72;25108:2;25097:9;25093:18;25084:6;25040:72;;;25123;25191:2;25180:9;25176:18;25167:6;25123:72;;;24823:382;;;;;;;;25212:547;25414:3;25399:19;;25429:71;25403:9;25473:6;25429:71;;;25511:72;25579:2;25568:9;25564:18;25555:6;25511:72;;25766:435;25940:2;25925:18;;25954:71;25929:9;25998:6;25954:71;;26208:324;26354:2;26339:18;;26368:71;26343:9;26412:6;26368:71;;;26450:72;26518:2;26507:9;26503:18;26494:6;26450:72;;26981:201;27093:2;27078:18;;27107:65;27082:9;27145:6;27107:65;;27189:213;27307:2;27292:18;;27321:71;27296:9;27365:6;27321:71;;27645:472;27841:2;27826:18;;27855:71;27830:9;27899:6;27855:71;;;27974:9;27968:4;27964:20;27959:2;27948:9;27944:18;27937:48;27999:108;28102:4;28093:6;27999:108;;28611:589;28834:3;28819:19;;28849:84;28823:9;28906:6;28849:84;;;28944:80;29020:2;29009:9;29005:18;28996:6;28944:80;;;29035:72;29103:2;29092:9;29088:18;29079:6;29035:72;;29207:293;29341:2;29355:47;;;29326:18;;29416:74;29326:18;29476:6;29416:74;;29815:407;30006:2;30020:47;;;29991:18;;30081:131;29991:18;30081:131;;30229:407;30420:2;30434:47;;;30405:18;;30495:131;30405:18;30495:131;;30643:407;30834:2;30848:47;;;30819:18;;30909:131;30819:18;30909:131;;31057:407;31248:2;31262:47;;;31233:18;;31323:131;31233:18;31323:131;;31471:407;31662:2;31676:47;;;31647:18;;31737:131;31647:18;31737:131;;31885:407;32076:2;32090:47;;;32061:18;;32151:131;32061:18;32151:131;;32299:369;32471:2;32485:47;;;32456:18;;32546:112;32456:18;32644:6;32546:112;;32675:480;32875:2;32889:47;;;32860:18;;32950:112;32860:18;33048:6;32950:112;;;32942:120;;33073:72;33141:2;33130:9;33126:18;33117:6;33073:72;;33382:256;33444:2;33438:9;33470:17;;;-1:-1;;;;;33530:34;;33566:22;;;33527:62;33524:2;;;33602:1;33599;33592:12;33524:2;33618;33611:22;33422:216;;-1:-1;33422:216;33645:244;;-1:-1;;;;;33794:6;33791:30;33788:2;;;33834:1;33831;33824:12;33788:2;-1:-1;33869:4;33857:17;;33725:164;33896:327;;-1:-1;;;;;34070:6;34067:30;34064:2;;;34110:1;34107;34100:12;34064:2;-1:-1;34145:4;34133:17;;;34198:15;;34001:222;34848:147;34968:4;34959:14;;34916:79;35002:133;35101:12;;35072:63;35636:168;35744:19;;;35793:4;35784:14;;35737:67;35813:160;35964:3;35942:31;-1:-1;35942:31;36306:91;;36368:24;36386:5;36368:24;;36404:85;36470:13;36463:21;;36446:43;36496:72;36558:5;36541:27;36575:121;-1:-1;;;;;36637:54;;36620:76;36782:129;;36869:37;36900:5;36918:147;;37010:50;37054:5;37010:50;;37444:268;37509:1;37516:101;37530:6;37527:1;37524:13;37516:101;;;37597:11;;;37591:18;37578:11;;;37571:39;37552:2;37545:10;37516:101;;;37632:6;37629:1;37626:13;37623:2;;;-1:-1;;37697:1;37679:16;;37672:27;37493:219;37720:95;;37784:26;37804:5;37822:89;37886:20;37900:5;37886:20;;37999:97;38087:2;38067:14;-1:-1;;38063:28;;38047:49;38104:94;38178:2;38174:14;;38146:52;38206:117;38275:24;38293:5;38275:24;;;38268:5;38265:35;38255:2;;38314:1;38311;38304:12;38255:2;38249:74;;38330:111;38396:21;38411:5;38396:21;;38448:117;38517:24;38535:5;38517:24;
Swarm Source
bzzr://4b77c9a170e86eaa4dad533a12f3f73c8d9e9d797af48d084b34168928bec65a
Loading...
Loading
Loading...
Loading
Net Worth in USD
$6,813.49
Net Worth in ETH
3.320396
Token Allocations
OSETH
86.10%
SETH2
11.01%
1INCH
2.86%
Others
0.03%
Multichain Portfolio | 34 Chains
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.