Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SwaprateMatch
Compiler Version
v0.5.16+commit.9c3226ce
Contract Source Code (Solidity)
/**
*Submitted for verification at Etherscan.io on 2021-10-08
*/
// 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: 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/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);
}
}
// File: contracts/Errors/MatchingErrors.sol
pragma solidity 0.5.16;
contract MatchingErrors {
string constant internal ERROR_MATCH_CANCELLATION_NOT_ALLOWED = "MATCH:CANCELLATION_NOT_ALLOWED";
string constant internal ERROR_MATCH_ALREADY_CANCELED = "MATCH:ALREADY_CANCELED";
string constant internal ERROR_MATCH_ORDER_WAS_CANCELED = "MATCH:ORDER_WAS_CANCELED";
string constant internal ERROR_MATCH_TAKER_ADDRESS_WRONG = "MATCH:TAKER_ADDRESS_WRONG";
string constant internal ERROR_MATCH_ORDER_IS_EXPIRED = "MATCH:ORDER_IS_EXPIRED";
string constant internal ERROR_MATCH_SENDER_ADDRESS_WRONG = "MATCH:SENDER_ADDRESS_WRONG";
string constant internal ERROR_MATCH_SIGNATURE_NOT_VERIFIED = "MATCH:SIGNATURE_NOT_VERIFIED";
string constant internal ERROR_MATCH_NOT_ENOUGH_ALLOWED_FEES = "MATCH:NOT_ENOUGH_ALLOWED_FEES";
}
// File: contracts/Lib/LibEIP712.sol
pragma solidity 0.5.16;
/// @title Opium.Lib.LibEIP712 contract implements the domain of EIP712 for meta transactions
contract LibEIP712 {
// EIP712Domain structure
// name - protocol name
// version - protocol version
// verifyingContract - signed message verifying contract
struct EIP712Domain {
string name;
string version;
address verifyingContract;
}
// Calculate typehash of ERC712Domain
bytes32 constant internal EIP712DOMAIN_TYPEHASH = keccak256(abi.encodePacked(
"EIP712Domain(",
"string name,",
"string version,",
"address verifyingContract",
")"
));
// solhint-disable-next-line var-name-mixedcase
bytes32 internal DOMAIN_SEPARATOR;
// Calculate domain separator at creation
constructor () public {
DOMAIN_SEPARATOR = keccak256(abi.encode(
EIP712DOMAIN_TYPEHASH,
keccak256("Opium Network"),
keccak256("1"),
address(this)
));
}
/// @notice Hashes EIP712Message
/// @param hashStruct bytes32 Hash of structured message
/// @return result bytes32 Hash of EIP712Message
function hashEIP712Message(bytes32 hashStruct) internal view returns (bytes32 result) {
bytes32 domainSeparator = DOMAIN_SEPARATOR;
assembly {
// Load free memory pointer
let memPtr := mload(64)
mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header
mstore(add(memPtr, 2), domainSeparator) // EIP712 domain hash
mstore(add(memPtr, 34), hashStruct) // Hash of struct
// Compute hash
result := keccak256(memPtr, 66)
}
return result;
}
}
// File: contracts/Matching/SwaprateMatch/LibSwaprateOrder.sol
pragma solidity 0.5.16;
/// @title Opium.Matching.SwaprateMatch.LibSwaprateOrder contract implements EIP712 signed SwaprateOrder for Opium.Matching.SwaprateMatch
contract LibSwaprateOrder is LibEIP712 {
/**
Structure of order
Description should be considered from the order signer (maker) perspective
syntheticId - address of derivative syntheticId
oracleId - address of derivative oracleId
token - address of derivative margin token
makerMarginAddress - address of token that maker is willing to pay with
takerMarginAddress - address of token that maker is willing to receive
makerAddress - address of maker
takerAddress - address of counterparty (taker). If zero address, then taker could be anyone
senderAddress - address which is allowed to settle the order on-chain. If zero address, then anyone could settle
relayerAddress - address of the relayer fee recipient
affiliateAddress - address of the affiliate fee recipient
feeTokenAddress - address of token which is used for fees
endTime - timestamp of derivative maturity
quantity - quantity of positions maker wants to receive
partialFill - whether maker allows partial fill of it's order
param0...param9 - additional params to pass it to syntheticId
relayerFee - amount of fee in feeToken that should be paid to relayer
affiliateFee - amount of fee in feeToken that should be paid to affiliate
nonce - unique order ID
signature - Signature of EIP712 message. Not used in hash, but then set for order processing purposes
*/
struct SwaprateOrder {
address syntheticId;
address oracleId;
address token;
address makerAddress;
address takerAddress;
address senderAddress;
address relayerAddress;
address affiliateAddress;
address feeTokenAddress;
uint256 endTime;
uint256 quantity;
uint256 partialFill;
uint256 param0;
uint256 param1;
uint256 param2;
uint256 param3;
uint256 param4;
uint256 param5;
uint256 param6;
uint256 param7;
uint256 param8;
uint256 param9;
uint256 relayerFee;
uint256 affiliateFee;
uint256 nonce;
// Not used in hash
bytes signature;
}
// Calculate typehash of Order
bytes32 constant internal EIP712_ORDER_TYPEHASH = keccak256(abi.encodePacked(
"Order(",
"address syntheticId,",
"address oracleId,",
"address token,",
"address makerAddress,",
"address takerAddress,",
"address senderAddress,",
"address relayerAddress,",
"address affiliateAddress,",
"address feeTokenAddress,",
"uint256 endTime,",
"uint256 quantity,",
"uint256 partialFill,",
"uint256 param0,",
"uint256 param1,",
"uint256 param2,",
"uint256 param3,",
"uint256 param4,",
"uint256 param5,",
"uint256 param6,",
"uint256 param7,",
"uint256 param8,",
"uint256 param9,",
"uint256 relayerFee,",
"uint256 affiliateFee,",
"uint256 nonce",
")"
));
/// @notice Hashes the order
/// @param _order SwaprateOrder Order to hash
/// @return hash bytes32 Order hash
function hashOrder(SwaprateOrder memory _order) public pure returns (bytes32 hash) {
hash = keccak256(
abi.encodePacked(
abi.encodePacked(
EIP712_ORDER_TYPEHASH,
uint256(_order.syntheticId),
uint256(_order.oracleId),
uint256(_order.token),
uint256(_order.makerAddress),
uint256(_order.takerAddress),
uint256(_order.senderAddress),
uint256(_order.relayerAddress),
uint256(_order.affiliateAddress),
uint256(_order.feeTokenAddress)
),
abi.encodePacked(
_order.endTime,
_order.quantity,
_order.partialFill
),
abi.encodePacked(
_order.param0,
_order.param1,
_order.param2,
_order.param3,
_order.param4
),
abi.encodePacked(
_order.param5,
_order.param6,
_order.param7,
_order.param8,
_order.param9
),
abi.encodePacked(
_order.relayerFee,
_order.affiliateFee,
_order.nonce
)
)
);
}
/// @notice Verifies order signature
/// @param _hash bytes32 Hash of the order
/// @param _signature bytes Signature of the order
/// @param _address address Address of the order signer
/// @return bool Returns whether `_signature` is valid and was created by `_address`
function verifySignature(bytes32 _hash, bytes memory _signature, address _address) internal view returns (bool) {
require(_signature.length == 65, "ORDER:INVALID_SIGNATURE_LENGTH");
bytes32 digest = hashEIP712Message(_hash);
address recovered = retrieveAddress(digest, _signature);
return _address == recovered;
}
/// @notice Helping function to recover signer address
/// @param _hash bytes32 Hash for signature
/// @param _signature bytes Signature
/// @return address Returns address of signature creator
function retrieveAddress(bytes32 _hash, bytes memory _signature) private pure returns (address) {
bytes32 r;
bytes32 s;
uint8 v;
// 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
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;
}
// If the version is correct return the signer address
if (v != 27 && v != 28) {
return (address(0));
} else {
// solium-disable-next-line arg-overflow
return ecrecover(_hash, v, r, s);
}
}
}
// File: contracts/Matching/SwaprateMatch/SwaprateMatchBase.sol
pragma solidity 0.5.16;
/// @title Opium.Matching.SwaprateMatchBase contract implements logic for order validation and cancelation
contract SwaprateMatchBase is MatchingErrors, LibSwaprateOrder, UsingRegistry, ReentrancyGuard {
using SafeMath for uint256;
using LibPosition for bytes32;
using SafeERC20 for IERC20;
// Emmitted when order was canceled
event Canceled(bytes32 orderHash);
// Canceled orders
// This mapping holds hashes of canceled orders
// canceled[orderHash] => canceled
mapping (bytes32 => bool) public canceled;
// Verified orders
// This mapping holds hashes of verified orders to verify only once
// verified[orderHash] => verified
mapping (bytes32 => bool) public verified;
// Vaults for fees
// This mapping holds balances of relayers and affiliates fees to withdraw
// balances[feeRecipientAddress][tokenAddress] => balances
mapping (address => mapping (address => uint256)) public balances;
// Keeps whether fee was already taken
mapping (bytes32 => bool) public feeTaken;
/// @notice Calling this function maker of the order could cancel it on-chain
/// @param _order SwaprateOrder
function cancel(SwaprateOrder memory _order) public {
require(msg.sender == _order.makerAddress, ERROR_MATCH_CANCELLATION_NOT_ALLOWED);
bytes32 orderHash = hashOrder(_order);
require(!canceled[orderHash], ERROR_MATCH_ALREADY_CANCELED);
canceled[orderHash] = true;
emit Canceled(orderHash);
}
/// @notice Function to withdraw fees from orders for relayer and affiliates
/// @param _token IERC20 Instance of token to withdraw
function withdraw(IERC20 _token) public nonReentrant {
uint256 balance = balances[msg.sender][address(_token)];
balances[msg.sender][address(_token)] = 0;
_token.safeTransfer(msg.sender, balance);
}
/// @notice This function checks whether order was canceled
/// @param _hash bytes32 Hash of the order
function validateNotCanceled(bytes32 _hash) internal view {
require(!canceled[_hash], ERROR_MATCH_ORDER_WAS_CANCELED);
}
/// @notice This function validates takerAddress of _leftOrder. It should match either with _rightOrder.makerAddress or be set to zero address
/// @param _leftOrder SwaprateOrder Left order
/// @param _rightOrder SwaprateOrder Right order
function validateTakerAddress(SwaprateOrder memory _leftOrder, SwaprateOrder memory _rightOrder) pure internal {
require(
_leftOrder.takerAddress == address(0) ||
_leftOrder.takerAddress == _rightOrder.makerAddress,
ERROR_MATCH_TAKER_ADDRESS_WRONG
);
}
/// @notice This function validates whether sender address equals to `msg.sender` or set to zero address
/// @param _order SwaprateOrder
function validateSenderAddress(SwaprateOrder memory _order) internal view {
require(
_order.senderAddress == address(0) ||
_order.senderAddress == msg.sender,
ERROR_MATCH_SENDER_ADDRESS_WRONG
);
}
/// @notice This function validates order signature if not validated before
/// @param orderHash bytes32 Hash of the order
/// @param _order SwaprateOrder
function validateSignature(bytes32 orderHash, SwaprateOrder memory _order) internal {
if (verified[orderHash]) {
return;
}
bool result = verifySignature(orderHash, _order.signature, _order.makerAddress);
require(result, ERROR_MATCH_SIGNATURE_NOT_VERIFIED);
verified[orderHash] = true;
}
/// @notice This function is responsible for taking relayer and affiliate fees, if they were not taken already
/// @param _orderHash bytes32 Hash of the order
/// @param _order Order Order itself
function takeFees(bytes32 _orderHash, SwaprateOrder memory _order) internal {
// Check if fee was already taken
if (feeTaken[_orderHash]) {
return;
}
// Check if feeTokenAddress is not set to zero address
if (_order.feeTokenAddress == address(0)) {
return;
}
// Calculate total amount of fees needs to be transfered
uint256 fees = _order.relayerFee.add(_order.affiliateFee);
// If total amount of fees is non-zero
if (fees == 0) {
return;
}
// Create instance of fee token
IERC20 feeToken = IERC20(_order.feeTokenAddress);
// Create instance of TokenSpender
TokenSpender tokenSpender = TokenSpender(registry.getTokenSpender());
// Check if user has enough token approval to pay the fees
require(feeToken.allowance(_order.makerAddress, address(tokenSpender)) >= fees, ERROR_MATCH_NOT_ENOUGH_ALLOWED_FEES);
// Transfer fee
tokenSpender.claimTokens(feeToken, _order.makerAddress, address(this), fees);
// Get opium address
address opiumAddress = registry.getOpiumAddress();
// Add commission to relayer balance, or to opium balance if relayer is not set
if (_order.relayerAddress != address(0)) {
balances[_order.relayerAddress][_order.feeTokenAddress] = balances[_order.relayerAddress][_order.feeTokenAddress].add(_order.relayerFee);
} else {
balances[opiumAddress][_order.feeTokenAddress] = balances[opiumAddress][_order.feeTokenAddress].add(_order.relayerFee);
}
// Add commission to affiliate balance, or to opium balance if affiliate is not set
if (_order.affiliateAddress != address(0)) {
balances[_order.affiliateAddress][_order.feeTokenAddress] = balances[_order.affiliateAddress][_order.feeTokenAddress].add(_order.affiliateFee);
} else {
balances[opiumAddress][_order.feeTokenAddress] = balances[opiumAddress][_order.feeTokenAddress].add(_order.affiliateFee);
}
// Mark the fee of token as taken
feeTaken[_orderHash] = true;
}
/// @notice Helper to get minimal of two integers
/// @param _a uint256 First integer
/// @param _b uint256 Second integer
/// @return uint256 Minimal integer
function min(uint256 _a, uint256 _b) internal pure returns (uint256) {
return _a < _b ? _a : _b;
}
}
// File: contracts/Matching/SwaprateMatch/SwaprateMatch.sol
pragma solidity 0.5.16;
/// @title Opium.Matching.SwaprateMatch contract implements create() function to settle a pair of orders and create derivatives for order makers
contract SwaprateMatch is SwaprateMatchBase, LibDerivative {
// Orders filled quantity
// This mapping holds orders filled quantity
// filled[orderHash] => filled
mapping (bytes32 => uint256) public filled;
/// @notice Calls constructors of super-contracts
/// @param _registry address Address of Opium.registry
constructor (address _registry) public UsingRegistry(_registry) {}
/// @notice This function receives left and right orders, derivative related to it
/// @param _leftOrder Order
/// @param _rightOrder Order
/// @param _derivative Derivative Data of derivative for validation and calculation purposes
function create(SwaprateOrder memory _leftOrder, SwaprateOrder memory _rightOrder, Derivative memory _derivative) public nonReentrant {
// New deals must not offer tokenIds
require(
_leftOrder.syntheticId == _rightOrder.syntheticId,
"MATCH:NOT_CREATION"
);
// Validate taker if set
validateTakerAddress(_leftOrder, _rightOrder);
validateTakerAddress(_rightOrder, _leftOrder);
// Validate sender if set
validateSenderAddress(_leftOrder);
validateSenderAddress(_rightOrder);
// Validate if was canceled
// orderHashes[0] - leftOrderHash
// orderHashes[1] - rightOrderHash
bytes32[2] memory orderHashes;
orderHashes[0] = hashOrder(_leftOrder);
validateNotCanceled(orderHashes[0]);
validateSignature(orderHashes[0], _leftOrder);
orderHashes[1] = hashOrder(_rightOrder);
validateNotCanceled(orderHashes[1]);
validateSignature(orderHashes[1], _rightOrder);
// Calculate derivative hash and get margin
// margins[0] - leftMargin
// margins[1] - rightMargin
(uint256[2] memory margins, ) = _calculateDerivativeAndGetMargin(_derivative);
// Calculate and validate availabilities of orders and fill them
uint256 fillable = _checkFillability(orderHashes[0], _leftOrder, orderHashes[1], _rightOrder);
// Validate derivative parameters with orders
_verifyDerivative(_leftOrder, _rightOrder, _derivative);
// Take fees
takeFees(orderHashes[0], _leftOrder);
takeFees(orderHashes[1], _rightOrder);
// Send margin to Core
_distributeFunds(_leftOrder, _rightOrder, _derivative, margins, fillable);
// Settle contracts
Core(registry.getCore()).create(_derivative, fillable, [_leftOrder.makerAddress, _rightOrder.makerAddress]);
}
// PRIVATE FUNCTIONS
/// @notice Calculates derivative hash and gets margin
/// @param _derivative Derivative
/// @return margins uint256[2] left and right margin
/// @return derivativeHash bytes32 Hash of the derivative
function _calculateDerivativeAndGetMargin(Derivative memory _derivative) private returns (uint256[2] memory margins, bytes32 derivativeHash) {
// Calculate derivative related data for validation
derivativeHash = getDerivativeHash(_derivative);
// Get cached total margin required according to logic
// margins[0] - leftMargin
// margins[1] - rightMargin
(margins[0], margins[1]) = SyntheticAggregator(registry.getSyntheticAggregator()).getMargin(derivativeHash, _derivative);
// Check if it's not pool
require(!SyntheticAggregator(registry.getSyntheticAggregator()).isPool(derivativeHash, _derivative), "MATCH:CANT_BE_POOL");
}
/// @notice Calculate and validate availabilities of orders and fill them
/// @param _leftOrderHash bytes32
/// @param _leftOrder SwaprateOrder
/// @param _rightOrderHash bytes32
/// @param _rightOrder SwaprateOrder
/// @return fillable uint256
function _checkFillability(bytes32 _leftOrderHash, SwaprateOrder memory _leftOrder, bytes32 _rightOrderHash, SwaprateOrder memory _rightOrder) private returns (uint256 fillable) {
// Calculate availabilities of orders
uint256 leftAvailable = _leftOrder.quantity.sub(filled[_leftOrderHash]);
uint256 rightAvailable = _rightOrder.quantity.sub(filled[_rightOrderHash]);
require(leftAvailable != 0 && rightAvailable !=0, "MATCH:NO_AVAILABLE");
// We could only fill minimum available of both counterparties
fillable = min(leftAvailable, rightAvailable);
// Check fillable with order conditions about partial fill requirements
if (_leftOrder.partialFill == 0 && _rightOrder.partialFill == 0) {
require(_leftOrder.quantity == _rightOrder.quantity, "MATCH:FULL_FILL_NOT_POSSIBLE");
} else if (_leftOrder.partialFill == 0 && _rightOrder.partialFill == 1) {
require(_leftOrder.quantity <= rightAvailable, "MATCH:FULL_FILL_NOT_POSSIBLE");
} else if (_leftOrder.partialFill == 1 && _rightOrder.partialFill == 0) {
require(leftAvailable >= _rightOrder.quantity, "MATCH:FULL_FILL_NOT_POSSIBLE");
}
// Update filled
filled[_leftOrderHash] = filled[_leftOrderHash].add(fillable);
filled[_rightOrderHash] = filled[_rightOrderHash].add(fillable);
}
/// @notice Validate derivative parameters with orders
/// @param _leftOrder SwaprateOrder
/// @param _rightOrder SwaprateOrder
/// @param _derivative Derivative
function _verifyDerivative(SwaprateOrder memory _leftOrder, SwaprateOrder memory _rightOrder, Derivative memory _derivative) private pure {
string memory orderError = "MATCH:DERIVATIVE_PARAM_IS_WRONG";
// Validate derivative endTime
require(
_derivative.endTime == _leftOrder.endTime &&
_derivative.endTime == _rightOrder.endTime,
orderError
);
// Validate derivative syntheticId
require(
_derivative.syntheticId == _leftOrder.syntheticId &&
_derivative.syntheticId == _rightOrder.syntheticId,
orderError
);
// Validate derivative oracleId
require(
_derivative.oracleId == _leftOrder.oracleId &&
_derivative.oracleId == _rightOrder.oracleId,
orderError
);
// Validate derivative token
require(
_derivative.token == _leftOrder.token &&
_derivative.token == _rightOrder.token,
orderError
);
// Validate derivative params
require(_derivative.params.length >= 20, "MATCH:DERIVATIVE_PARAMS_LENGTH_IS_WRONG");
// Validate left order params
require(_leftOrder.param0 == _derivative.params[0], orderError);
require(_leftOrder.param1 == _derivative.params[1], orderError);
require(_leftOrder.param2 == _derivative.params[2], orderError);
require(_leftOrder.param3 == _derivative.params[3], orderError);
require(_leftOrder.param4 == _derivative.params[4], orderError);
require(_leftOrder.param5 == _derivative.params[5], orderError);
require(_leftOrder.param6 == _derivative.params[6], orderError);
require(_leftOrder.param7 == _derivative.params[7], orderError);
require(_leftOrder.param8 == _derivative.params[8], orderError);
require(_leftOrder.param9 == _derivative.params[9], orderError);
// Validate right order params
require(_rightOrder.param0 == _derivative.params[10], orderError);
require(_rightOrder.param1 == _derivative.params[11], orderError);
require(_rightOrder.param2 == _derivative.params[12], orderError);
require(_rightOrder.param3 == _derivative.params[13], orderError);
require(_rightOrder.param4 == _derivative.params[14], orderError);
require(_rightOrder.param5 == _derivative.params[15], orderError);
require(_rightOrder.param6 == _derivative.params[16], orderError);
require(_rightOrder.param7 == _derivative.params[17], orderError);
require(_rightOrder.param8 == _derivative.params[18], orderError);
require(_rightOrder.param9 == _derivative.params[19], orderError);
}
/// @notice Distributes funds to core
/// @param _leftOrder SwaprateOrder
/// @param _rightOrder SwaprateOrder
/// @param _derivative Derivative
/// @param margins uint256[2] left and right margin
/// @param _fillable uint256 How many positions are fillable
function _distributeFunds(SwaprateOrder memory _leftOrder, SwaprateOrder memory _rightOrder, Derivative memory _derivative, uint256[2] memory margins, uint256 _fillable) private {
IERC20 marginToken = IERC20(_derivative.token);
TokenSpender tokenSpender = TokenSpender(registry.getTokenSpender());
// Transfer margin from left to Match and send to Core
if (margins[0] != 0) {
// Check allowance for margins
require(marginToken.allowance(_leftOrder.makerAddress, address(tokenSpender)) >= margins[0].mul(_fillable), "MATCH:NOT_ENOUGH_ALLOWED_MARGIN");
// Transfer margins from buyer to Match
tokenSpender.claimTokens(marginToken, _leftOrder.makerAddress, address(this), margins[0].mul(_fillable));
}
// Transfer margin from right to Match and send to Core
if (margins[1] != 0) {
// Check allowance for premiums + margin
require(marginToken.allowance(_rightOrder.makerAddress, address(tokenSpender)) >= margins[1].mul(_fillable), "MATCH:NOT_ENOUGH_ALLOWED_MARGIN");
// Transfer margins from seller to Match
tokenSpender.claimTokens(marginToken, _rightOrder.makerAddress, address(this), margins[1].mul(_fillable));
}
if (margins[0].add(margins[1]) != 0) {
// Approve margin to Core for derivative creation
require(marginToken.approve(address(tokenSpender), margins[0].add(margins[1]).mul(_fillable)), "MATCH:COULDNT_APPROVE_MARGIN_FOR_CORE");
}
}
}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":"orderHash","type":"bytes32"}],"name":"Canceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"registry","type":"address"}],"name":"RegistrySet","type":"event"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"balances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"syntheticId","type":"address"},{"internalType":"address","name":"oracleId","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"address","name":"relayerAddress","type":"address"},{"internalType":"address","name":"affiliateAddress","type":"address"},{"internalType":"address","name":"feeTokenAddress","type":"address"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"uint256","name":"partialFill","type":"uint256"},{"internalType":"uint256","name":"param0","type":"uint256"},{"internalType":"uint256","name":"param1","type":"uint256"},{"internalType":"uint256","name":"param2","type":"uint256"},{"internalType":"uint256","name":"param3","type":"uint256"},{"internalType":"uint256","name":"param4","type":"uint256"},{"internalType":"uint256","name":"param5","type":"uint256"},{"internalType":"uint256","name":"param6","type":"uint256"},{"internalType":"uint256","name":"param7","type":"uint256"},{"internalType":"uint256","name":"param8","type":"uint256"},{"internalType":"uint256","name":"param9","type":"uint256"},{"internalType":"uint256","name":"relayerFee","type":"uint256"},{"internalType":"uint256","name":"affiliateFee","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LibSwaprateOrder.SwaprateOrder","name":"_order","type":"tuple"}],"name":"cancel","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"canceled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"syntheticId","type":"address"},{"internalType":"address","name":"oracleId","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"address","name":"relayerAddress","type":"address"},{"internalType":"address","name":"affiliateAddress","type":"address"},{"internalType":"address","name":"feeTokenAddress","type":"address"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"uint256","name":"partialFill","type":"uint256"},{"internalType":"uint256","name":"param0","type":"uint256"},{"internalType":"uint256","name":"param1","type":"uint256"},{"internalType":"uint256","name":"param2","type":"uint256"},{"internalType":"uint256","name":"param3","type":"uint256"},{"internalType":"uint256","name":"param4","type":"uint256"},{"internalType":"uint256","name":"param5","type":"uint256"},{"internalType":"uint256","name":"param6","type":"uint256"},{"internalType":"uint256","name":"param7","type":"uint256"},{"internalType":"uint256","name":"param8","type":"uint256"},{"internalType":"uint256","name":"param9","type":"uint256"},{"internalType":"uint256","name":"relayerFee","type":"uint256"},{"internalType":"uint256","name":"affiliateFee","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LibSwaprateOrder.SwaprateOrder","name":"_leftOrder","type":"tuple"},{"components":[{"internalType":"address","name":"syntheticId","type":"address"},{"internalType":"address","name":"oracleId","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"address","name":"relayerAddress","type":"address"},{"internalType":"address","name":"affiliateAddress","type":"address"},{"internalType":"address","name":"feeTokenAddress","type":"address"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"uint256","name":"partialFill","type":"uint256"},{"internalType":"uint256","name":"param0","type":"uint256"},{"internalType":"uint256","name":"param1","type":"uint256"},{"internalType":"uint256","name":"param2","type":"uint256"},{"internalType":"uint256","name":"param3","type":"uint256"},{"internalType":"uint256","name":"param4","type":"uint256"},{"internalType":"uint256","name":"param5","type":"uint256"},{"internalType":"uint256","name":"param6","type":"uint256"},{"internalType":"uint256","name":"param7","type":"uint256"},{"internalType":"uint256","name":"param8","type":"uint256"},{"internalType":"uint256","name":"param9","type":"uint256"},{"internalType":"uint256","name":"relayerFee","type":"uint256"},{"internalType":"uint256","name":"affiliateFee","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LibSwaprateOrder.SwaprateOrder","name":"_rightOrder","type":"tuple"},{"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":"create","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"feeTaken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"filled","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":[{"components":[{"internalType":"address","name":"syntheticId","type":"address"},{"internalType":"address","name":"oracleId","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"address","name":"relayerAddress","type":"address"},{"internalType":"address","name":"affiliateAddress","type":"address"},{"internalType":"address","name":"feeTokenAddress","type":"address"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"uint256","name":"partialFill","type":"uint256"},{"internalType":"uint256","name":"param0","type":"uint256"},{"internalType":"uint256","name":"param1","type":"uint256"},{"internalType":"uint256","name":"param2","type":"uint256"},{"internalType":"uint256","name":"param3","type":"uint256"},{"internalType":"uint256","name":"param4","type":"uint256"},{"internalType":"uint256","name":"param5","type":"uint256"},{"internalType":"uint256","name":"param6","type":"uint256"},{"internalType":"uint256","name":"param7","type":"uint256"},{"internalType":"uint256","name":"param8","type":"uint256"},{"internalType":"uint256","name":"param9","type":"uint256"},{"internalType":"uint256","name":"relayerFee","type":"uint256"},{"internalType":"uint256","name":"affiliateFee","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LibSwaprateOrder.SwaprateOrder","name":"_order","type":"tuple"}],"name":"hashOrder","outputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"verified","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60806040523480156200001157600080fd5b5060405162003bf538038062003bf5833981016040819052620000349162000129565b806040516020016200004690620002a1565b604051602081830303815290604052805190602001206040516200006a90620002e2565b6040518091039020604051620000809062000294565b6040519081900381206200009b9392913090602001620002ff565b60408051808303601f19018152908290528051602090910120600055600180546001600160a01b0319166001600160a01b0384161790557f27fe5f0c1c3b1ed427cc63d0f05759ffdecf9aec9e18d31ef366fc8a6cb5dc3b9062000101908390620002ef565b60405180910390a15050600160025562000380565b8051620001238162000366565b92915050565b6000602082840312156200013c57600080fd5b60006200014a848462000116565b949350505050565b6200015d816200034a565b82525050565b6200015d8162000357565b60006200017d600c8362000345565b6b1cdd1c9a5b99c81b985b594b60a21b8152600c0192915050565b6000620001a760198362000345565b7f6164647265737320766572696679696e67436f6e747261637400000000000000815260190192915050565b6000620001e260018362000345565b602960f81b815260010192915050565b600062000201600f8362000345565b6e1cdd1c9a5b99c81d995c9cda5bdb8b608a1b8152600f0192915050565b60006200022e60018362000345565b603160f81b815260010192915050565b60006200024d600d8362000345565b6c08a92a06e626488dedac2d2dc5609b1b8152600d0192915050565b600062000278600d8362000345565b6c4f7069756d204e6574776f726b60981b8152600d0192915050565b600062000123826200021f565b6000620002ae826200023e565b9150620002bb826200016e565b9150620002c882620001f2565b9150620002d58262000198565b91506200012382620001d3565b6000620001238262000269565b6020810162000123828462000152565b608081016200030f828762000163565b6200031e602083018662000163565b6200032d604083018562000163565b6200033c606083018462000152565b95945050505050565b919050565b600062000123826200035a565b90565b6001600160a01b031690565b62000371816200034a565b81146200037d57600080fd5b50565b61386580620003906000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80635ab1bd53116100715780635ab1bd5314610132578063c23f001f14610147578063c59e43e51461015a578063e6cd370e1461016d578063eb95512214610180578063fdd2f04714610193576100a9565b80630411e552146100ae5780631c439266146100d7578063288cdc91146100ea5780632d5bb2791461010a57806351cff8d91461011d575b600080fd5b6100c16100bc3660046125d7565b6101a6565b6040516100ce9190613519565b60405180910390f35b6100c16100e53660046125d7565b6101bb565b6100fd6100f83660046125d7565b6101d0565b6040516100ce9190613527565b6100fd610118366004612648565b6101e2565b61013061012b3660046125f5565b6103c1565b005b61013a610430565b6040516100ce91906134d5565b6100fd61015536600461257f565b61043f565b6100c16101683660046125d7565b61045c565b61013061017b36600461267d565b610471565b6100fd61018e366004612613565b6106b9565b6101306101a1366004612648565b6106e9565b60066020526000908152604090205460ff1681565b60036020526000908152604090205460ff1681565b60076020526000908152604090205481565b60006040516020016101f3906132b6565b6040516020818303038152906040528051906020012082600001516001600160a01b031683602001516001600160a01b031684604001516001600160a01b031685606001516001600160a01b031686608001516001600160a01b03168760a001516001600160a01b03168860c001516001600160a01b03168960e001516001600160a01b03168a61010001516001600160a01b03166040516020016102a19a999897969594939291906131b5565b6040516020818303038152906040528261012001518361014001518461016001516040516020016102d493929190613445565b60408051601f19818403018152908290526101808501516101a08601516101c08701516101e08801516102008901519495610312959060200161347c565b60408051601f19818403018152908290526102208601516102408701516102608801516102808901516102a08a01519495610350959060200161347c565b604051602081830303815290604052856102c00151866102e0015187610300015160405160200161038393929190613445565b60408051601f19818403018152908290526103a4959493929160200161326f565b604051602081830303815290604052805190602001209050919050565b60028054600101908190553360008181526005602090815260408083206001600160a01b038716808552925282208054929055909161040191908361081d565b50600254811461042c5760405162461bcd60e51b81526004016104239061368c565b60405180910390fd5b5050565b6001546001600160a01b031690565b600560209081526000928352604080842090915290825290205481565b60046020526000908152604090205460ff1681565b6002805460010190819055825184516001600160a01b039081169116146104aa5760405162461bcd60e51b8152600401610423906135cc565b6104b4848461087b565b6104be838561087b565b6104c784610902565b6104d083610902565b6104d8612128565b6104e1856101e2565b81526104f48160005b602002015161097c565b805161050090866109e4565b610509846101e2565b60208201526105198160016104ea565b602081015161052890856109e4565b610530612128565b61053984610a8c565b50825160208401519192506000916105549190899089610cc9565b9050610561878787610e83565b825161056d908861154f565b602083015161057c908761154f565b6105898787878585611a1b565b600160009054906101000a90046001600160a01b03166001600160a01b031663da4fbe526040518163ffffffff1660e01b815260040160206040518083038186803b1580156105d757600080fd5b505afa1580156105eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061060f9190810190612561565b6040805180820182526060808b01516001600160a01b039081168352908a0151811660208301529151631af5968960e31b8152929091169163d7acb4489161065d91899186916004016136ac565b600060405180830381600087803b15801561067757600080fd5b505af115801561068b573d6000803e3d6000fd5b5050505050505060025481146106b35760405162461bcd60e51b81526004016104239061368c565b50505050565b80516020808301516040808501516060860151608087015160a088015193516000976103a49790969591016133df565b80606001516001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4d415443483a43414e43454c4c4154494f4e5f4e4f545f414c4c4f5745440000815250906107565760405162461bcd60e51b815260040161042391906135bb565b506000610762826101e2565b600081815260036020908152604091829020548251808401909352601683527513505510d20e9053149150511657d0d05390d153115160521b918301919091529192509060ff16156107c75760405162461bcd60e51b815260040161042391906135bb565b5060008181526003602052604090819020805460ff19166001179055517f134fdd648feeaf30251f0157f9624ef8608ff9a042aad6d13e73f35d21d3f88d90610811908390613527565b60405180910390a15050565b60405161087690849063a9059cbb60e01b9061083f90869086906024016134fe565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611df2565b505050565b60808201516001600160a01b031615806108ae575080606001516001600160a01b031682608001516001600160a01b0316145b6040518060400160405280601981526020017f4d415443483a54414b45525f414444524553535f57524f4e4700000000000000815250906108765760405162461bcd60e51b815260040161042391906135bb565b60a08101516001600160a01b03161580610928575060a08101516001600160a01b031633145b6040518060400160405280601a81526020017f4d415443483a53454e4445525f414444524553535f57524f4e470000000000008152509061042c5760405162461bcd60e51b815260040161042391906135bb565b600081815260036020908152604091829020548251808401909352601883527f4d415443483a4f524445525f5741535f43414e43454c454400000000000000009183019190915260ff161561042c5760405162461bcd60e51b815260040161042391906135bb565b60008281526004602052604090205460ff1615610a005761042c565b6000610a16838361032001518460600151611ed7565b9050806040518060400160405280601c81526020017f4d415443483a5349474e41545552455f4e4f545f56455249464945440000000081525090610a6d5760405162461bcd60e51b815260040161042391906135bb565b50506000828152600460205260409020805460ff191660011790555050565b610a94612128565b6000610a9f836106b9565b9050600160009054906101000a90046001600160a01b03166001600160a01b0316638177644c6040518163ffffffff1660e01b815260040160206040518083038186803b158015610aef57600080fd5b505afa158015610b03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b279190810190612561565b6001600160a01b03166399f685ee82856040518363ffffffff1660e01b8152600401610b54929190613535565b6040805180830381600087803b158015610b6d57600080fd5b505af1158015610b81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ba5919081019061272f565b6020808501919091529083526001546040805163205dd91360e21b815290516001600160a01b0390921692638177644c92600480840193829003018186803b158015610bf057600080fd5b505afa158015610c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610c289190810190612561565b6001600160a01b03166399a5017682856040518363ffffffff1660e01b8152600401610c55929190613535565b602060405180830381600087803b158015610c6f57600080fd5b505af1158015610c83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ca791908101906125b9565b15610cc45760405162461bcd60e51b81526004016104239061364c565b915091565b6000848152600760205260408120546101408501518291610cf0919063ffffffff611f2d16565b6000858152600760205260408120546101408601519293509091610d199163ffffffff611f2d16565b90508115801590610d2957508015155b610d455760405162461bcd60e51b8152600401610423906135ec565b610d4f8282611f78565b92508561016001516000148015610d695750610160840151155b15610d9c5783610140015186610140015114610d975760405162461bcd60e51b81526004016104239061366c565b610e20565b610160860151158015610db457508361016001516001145b15610dde57808661014001511115610d975760405162461bcd60e51b81526004016104239061366c565b8561016001516001148015610df65750610160840151155b15610e2057836101400151821015610e205760405162461bcd60e51b81526004016104239061366c565b600087815260076020526040902054610e3f908463ffffffff611f8e16565b600088815260076020526040808220929092558681522054610e67908463ffffffff611f8e16565b6000958652600760205260409095209490945550949350505050565b60606040518060400160405280601f81526020017f4d415443483a444552495641544956455f504152414d5f49535f57524f4e470081525090508361012001518260200151148015610edd57508261012001518260200151145b8190610efc5760405162461bcd60e51b815260040161042391906135bb565b5083600001516001600160a01b03168260a001516001600160a01b0316148015610f3f575082600001516001600160a01b03168260a001516001600160a01b0316145b8190610f5e5760405162461bcd60e51b815260040161042391906135bb565b5083602001516001600160a01b031682606001516001600160a01b0316148015610fa1575082602001516001600160a01b031682606001516001600160a01b0316145b8190610fc05760405162461bcd60e51b815260040161042391906135bb565b5083604001516001600160a01b031682608001516001600160a01b0316148015611003575082604001516001600160a01b031682608001516001600160a01b0316145b81906110225760405162461bcd60e51b815260040161042391906135bb565b50601482604001515110156110495760405162461bcd60e51b81526004016104239061363c565b816040015160008151811061105a57fe5b60200260200101518461018001511481906110885760405162461bcd60e51b815260040161042391906135bb565b50816040015160018151811061109a57fe5b6020026020010151846101a001511481906110c85760405162461bcd60e51b815260040161042391906135bb565b5081604001516002815181106110da57fe5b6020026020010151846101c001511481906111085760405162461bcd60e51b815260040161042391906135bb565b50816040015160038151811061111a57fe5b6020026020010151846101e001511481906111485760405162461bcd60e51b815260040161042391906135bb565b50816040015160048151811061115a57fe5b60200260200101518461020001511481906111885760405162461bcd60e51b815260040161042391906135bb565b50816040015160058151811061119a57fe5b60200260200101518461022001511481906111c85760405162461bcd60e51b815260040161042391906135bb565b5081604001516006815181106111da57fe5b60200260200101518461024001511481906112085760405162461bcd60e51b815260040161042391906135bb565b50816040015160078151811061121a57fe5b60200260200101518461026001511481906112485760405162461bcd60e51b815260040161042391906135bb565b50816040015160088151811061125a57fe5b60200260200101518461028001511481906112885760405162461bcd60e51b815260040161042391906135bb565b50816040015160098151811061129a57fe5b6020026020010151846102a001511481906112c85760405162461bcd60e51b815260040161042391906135bb565b508160400151600a815181106112da57fe5b60200260200101518361018001511481906113085760405162461bcd60e51b815260040161042391906135bb565b508160400151600b8151811061131a57fe5b6020026020010151836101a001511481906113485760405162461bcd60e51b815260040161042391906135bb565b508160400151600c8151811061135a57fe5b6020026020010151836101c001511481906113885760405162461bcd60e51b815260040161042391906135bb565b508160400151600d8151811061139a57fe5b6020026020010151836101e001511481906113c85760405162461bcd60e51b815260040161042391906135bb565b508160400151600e815181106113da57fe5b60200260200101518361020001511481906114085760405162461bcd60e51b815260040161042391906135bb565b508160400151600f8151811061141a57fe5b60200260200101518361022001511481906114485760405162461bcd60e51b815260040161042391906135bb565b50816040015160108151811061145a57fe5b60200260200101518361024001511481906114885760405162461bcd60e51b815260040161042391906135bb565b50816040015160118151811061149a57fe5b60200260200101518361026001511481906114c85760405162461bcd60e51b815260040161042391906135bb565b5081604001516012815181106114da57fe5b60200260200101518361028001511481906115085760405162461bcd60e51b815260040161042391906135bb565b50816040015160138151811061151a57fe5b6020026020010151836102a001511481906115485760405162461bcd60e51b815260040161042391906135bb565b5050505050565b60008281526006602052604090205460ff161561156b5761042c565b6101008101516001600160a01b03166115835761042c565b60006115a2826102e00151836102c00151611f8e90919063ffffffff16565b9050806115af575061042c565b6101008201516001546040805163beb5bd8160e01b815290516000926001600160a01b03169163beb5bd81916004808301926020929190829003018186803b1580156115fa57600080fd5b505afa15801561160e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116329190810190612561565b905082826001600160a01b031663dd62ed3e8660600151846040518363ffffffff1660e01b81526004016116679291906134e3565b60206040518083038186803b15801561167f57600080fd5b505afa158015611693573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116b79190810190612711565b10156040518060400160405280601d81526020017f4d415443483a4e4f545f454e4f5547485f414c4c4f5745445f464545530000008152509061170d5760405162461bcd60e51b815260040161042391906135bb565b50606084015160405163052f523360e11b81526001600160a01b03831691630a5ea4669161174391869130908990600401613593565b600060405180830381600087803b15801561175d57600080fd5b505af1158015611771573d6000803e3d6000fd5b505050506000600160009054906101000a90046001600160a01b03166001600160a01b031663ec45d8ae6040518163ffffffff1660e01b815260040160206040518083038186803b1580156117c557600080fd5b505afa1580156117d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506117fd9190810190612561565b60c08601519091506001600160a01b03161561188f576102c085015160c08601516001600160a01b0390811660009081526005602090815260408083206101008b0151909416835292905220546118599163ffffffff611f8e16565b60c08601516001600160a01b0390811660009081526005602090815260408083206101008b0151909416835292905220556118fd565b6102c08501516001600160a01b0380831660009081526005602090815260408083206101008b0151909416835292905220546118d09163ffffffff611f8e16565b6001600160a01b0380831660009081526005602090815260408083206101008b0151909416835292905220555b60e08501516001600160a01b03161561198c576102e085015160e08601516001600160a01b0390811660009081526005602090815260408083206101008b0151909416835292905220546119569163ffffffff611f8e16565b60e08601516001600160a01b0390811660009081526005602090815260408083206101008b0151909416835292905220556119fa565b6102e08501516001600160a01b0380831660009081526005602090815260408083206101008b0151909416835292905220546119cd9163ffffffff611f8e16565b6001600160a01b0380831660009081526005602090815260408083206101008b0151909416835292905220555b5050506000838152600660205260409020805460ff19166001179055505050565b60808301516001546040805163beb5bd8160e01b815290516000926001600160a01b03169163beb5bd81916004808301926020929190829003018186803b158015611a6557600080fd5b505afa158015611a79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a9d9190810190612561565b845190915015611bd957611ac0838560005b60200201519063ffffffff611fb316565b6060880151604051636eb1769f60e11b81526001600160a01b0385169163dd62ed3e91611af2919086906004016134e3565b60206040518083038186803b158015611b0a57600080fd5b505afa158015611b1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b429190810190612711565b1015611b605760405162461bcd60e51b81526004016104239061361c565b806001600160a01b0316630a5ea46683896060015130611b87888a600060028110611aaf57fe5b6040518563ffffffff1660e01b8152600401611ba69493929190613593565b600060405180830381600087803b158015611bc057600080fd5b505af1158015611bd4573d6000803e3d6000fd5b505050505b602084015115611d0857611bef83856001611aaf565b6060870151604051636eb1769f60e11b81526001600160a01b0385169163dd62ed3e91611c21919086906004016134e3565b60206040518083038186803b158015611c3957600080fd5b505afa158015611c4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611c719190810190612711565b1015611c8f5760405162461bcd60e51b81526004016104239061361c565b806001600160a01b0316630a5ea46683886060015130611cb6888a600160028110611aaf57fe5b6040518563ffffffff1660e01b8152600401611cd59493929190613593565b600060405180830381600087803b158015611cef57600080fd5b505af1158015611d03573d6000803e3d6000fd5b505050505b6020840151611d26908560005b60200201519063ffffffff611f8e16565b15611de9576001600160a01b03821663095ea7b382611d5e86611d5289600160200201518a6000611d15565b9063ffffffff611fb316565b6040518363ffffffff1660e01b8152600401611d7b9291906134fe565b602060405180830381600087803b158015611d9557600080fd5b505af1158015611da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611dcd91908101906125b9565b611de95760405162461bcd60e51b81526004016104239061365c565b50505050505050565b611e04826001600160a01b0316611fed565b611e205760405162461bcd60e51b81526004016104239061369c565b60006060836001600160a01b031683604051611e3c9190613263565b6000604051808303816000865af19150503d8060008114611e79576040519150601f19603f3d011682016040523d82523d6000602084013e611e7e565b606091505b509150915081611ea05760405162461bcd60e51b81526004016104239061360c565b8051156106b35780806020019051611ebb91908101906125b9565b6106b35760405162461bcd60e51b81526004016104239061367c565b60008251604114611efa5760405162461bcd60e51b8152600401610423906135dc565b6000611f0585612029565b90506000611f13828661204e565b6001600160a01b03858116911614925050505b9392505050565b6000611f6f83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506120fc565b90505b92915050565b6000818310611f875781611f6f565b5090919050565b600082820183811015611f6f5760405162461bcd60e51b8152600401610423906135fc565b600082611fc257506000611f72565b82820282848281611fcf57fe5b0414611f6f5760405162461bcd60e51b81526004016104239061362c565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081158015906120215750808214155b949350505050565b60005460405161190160f01b8152600281019190915260228101919091526042902090565b6020810151604082015160608301516000929190831a601b81101561207157601b015b8060ff16601b1415801561208957508060ff16601c14155b1561209a5760009350505050611f72565b600186828585604051600081526020016040526040516120bd9493929190613555565b6020604051602081039080840390855afa1580156120df573d6000803e3d6000fd5b505050602060405103519350505050611f72565b50505092915050565b600081848411156121205760405162461bcd60e51b815260040161042391906135bb565b505050900390565b60405180604001604052806002906020820280388339509192915050565b8035611f72816137f0565b8051611f72816137f0565b600082601f83011261216d57600080fd5b813561218061217b82613700565b6136d9565b915081818352602084019350602081019050838560208402820111156121a557600080fd5b60005b838110156121d157816121bb88826121e6565b84525060209283019291909101906001016121a8565b5050505092915050565b8051611f7281613807565b8035611f7281613810565b600082601f83011261220257600080fd5b813561221061217b82613721565b9150808252602083016020830185838301111561222c57600080fd5b6120f3838284613797565b8035611f7281613819565b600060c0828403121561225457600080fd5b61225e60c06136d9565b9050600061226c84846121e6565b825250602061227d848483016121e6565b602083015250604082013567ffffffffffffffff81111561229d57600080fd5b6122a98482850161215c565b60408301525060606122bd84828501612146565b60608301525060806122d184828501612146565b60808301525060a06122e584828501612146565b60a08301525092915050565b6000610340828403121561230457600080fd5b61230f6103406136d9565b9050600061231d8484612146565b825250602061232e84848301612146565b602083015250604061234284828501612146565b604083015250606061235684828501612146565b606083015250608061236a84828501612146565b60808301525060a061237e84828501612146565b60a08301525060c061239284828501612146565b60c08301525060e06123a684828501612146565b60e0830152506101006123bb84828501612146565b610100830152506101206123d1848285016121e6565b610120830152506101406123e7848285016121e6565b610140830152506101606123fd848285016121e6565b61016083015250610180612413848285016121e6565b610180830152506101a0612429848285016121e6565b6101a0830152506101c061243f848285016121e6565b6101c0830152506101e0612455848285016121e6565b6101e08301525061020061246b848285016121e6565b61020083015250610220612481848285016121e6565b61022083015250610240612497848285016121e6565b610240830152506102606124ad848285016121e6565b610260830152506102806124c3848285016121e6565b610280830152506102a06124d9848285016121e6565b6102a0830152506102c06124ef848285016121e6565b6102c0830152506102e0612505848285016121e6565b6102e08301525061030061251b848285016121e6565b6103008301525061032082013567ffffffffffffffff81111561253d57600080fd5b612549848285016121f1565b6103208301525092915050565b8051611f7281613810565b60006020828403121561257357600080fd5b60006120218484612151565b6000806040838503121561259257600080fd5b600061259e8585612146565b92505060206125af85828601612146565b9150509250929050565b6000602082840312156125cb57600080fd5b600061202184846121db565b6000602082840312156125e957600080fd5b600061202184846121e6565b60006020828403121561260757600080fd5b60006120218484612237565b60006020828403121561262557600080fd5b813567ffffffffffffffff81111561263c57600080fd5b61202184828501612242565b60006020828403121561265a57600080fd5b813567ffffffffffffffff81111561267157600080fd5b612021848285016122f1565b60008060006060848603121561269257600080fd5b833567ffffffffffffffff8111156126a957600080fd5b6126b5868287016122f1565b935050602084013567ffffffffffffffff8111156126d257600080fd5b6126de868287016122f1565b925050604084013567ffffffffffffffff8111156126fb57600080fd5b61270786828701612242565b9150509250925092565b60006020828403121561272357600080fd5b60006120218484612556565b6000806040838503121561274257600080fd5b600061274e8585612556565b92505060206125af85828601612556565b600061276b838361277f565b505060200190565b600061276b83836128a3565b6127888161376a565b82525050565b61278861279a8261376a565b6137cf565b6127a881613752565b6127b2818461375c565b92506127bd82613749565b8060005b838110156127eb5781516127d5878261275f565b96506127e08361374c565b9250506001016127c1565b505050505050565b60006127fe82613758565b6128088185613761565b93506128138361374c565b8060005b8381101561284157815161282b8882612773565b97506128368361374c565b925050600101612817565b509495945050505050565b600061285782613758565b612861818561375c565b935061286c8361374c565b8060005b838110156128415781516128848882612773565b975061288f8361374c565b925050600101612870565b61278881613775565b61278881613749565b6127886128b882613749565b613749565b60006128c882613758565b6128d2818561375c565b93506128e28185602086016137a3565b9290920192915050565b6127888161377a565b600061290082613758565b61290a8185613761565b935061291a8185602086016137a3565b612923816137e0565b9093019392505050565b600061293a600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4d8b608a1b8152600f0192915050565b6000612965601283613761565b7126a0aa21a41d2727aa2fa1a922a0aa24a7a760711b815260200192915050565b6000612993601e83613761565b7f4f524445523a494e56414c49445f5349474e41545552455f4c454e4754480000815260200192915050565b60006129cc60118361375c565b701d5a5b9d0c8d4d881c5d585b9d1a5d1e4b607a1b815260110192915050565b60006129f960168361375c565b751859191c995cdcc81cd95b99195c9059191c995cdccb60521b815260160192915050565b6000612a2b600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4c8b608a1b8152600f0192915050565b6000612a5660158361375c565b741d5a5b9d0c8d4d881859999a5b1a585d195199594b605a1b815260150192915050565b6000612a8760068361375c565b6509ee4c8cae4560d31b815260060192915050565b6000612aa9601283613761565b714d415443483a4e4f5f415641494c41424c4560701b815260200192915050565b6000612ad7600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4dcb608a1b8152600f0192915050565b6000612b02601b83613761565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000612b3b60158361375c565b741859191c995cdcc81b585ad95c9059191c995cdccb605a1b815260150192915050565b6000612b6c602083613761565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b6000612ba5600d8361375c565b6c75696e74323536206e6f6e636560981b8152600d0192915050565b6000612bce60018361375c565b602960f81b815260010192915050565b6000612beb60188361375c565b7f6164647265737320666565546f6b656e416464726573732c0000000000000000815260180192915050565b6000612c24600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4e4b608a1b8152600f0192915050565b6000612c4f60108361375c565b6f1d5a5b9d0c8d4d88195b99151a5b594b60821b815260100192915050565b6000612c7b600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4ccb608a1b8152600f0192915050565b6000612ca660178361375c565b7f616464726573732072656c61796572416464726573732c000000000000000000815260170192915050565b6000612cdf60198361375c565b7f6164647265737320616666696c69617465416464726573732c00000000000000815260190192915050565b6000612d18601f83613761565b7f4d415443483a4e4f545f454e4f5547485f414c4c4f5745445f4d415247494e00815260200192915050565b6000612d51600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4c4b608a1b8152600f0192915050565b6000612d7c60118361375c565b701859191c995cdcc81bdc9858db1952590b607a1b815260110192915050565b6000612da9602183613761565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000612dec602783613761565b7f4d415443483a444552495641544956455f504152414d535f4c454e4754485f49815266535f57524f4e4760c81b602082015260400192915050565b6000612e35600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4d4b608a1b8152600f0192915050565b6000612e6060148361375c565b731d5a5b9d0c8d4d881c185c9d1a585b119a5b1b0b60621b815260140192915050565b6000612e90601283613761565b7113505510d20e90d0539517d09157d413d3d360721b815260200192915050565b6000612ebe600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4c0b608a1b8152600f0192915050565b6000612ee9602583613761565b7f4d415443483a434f554c444e545f415050524f56455f4d415247494e5f464f528152645f434f524560d81b602082015260400192915050565b6000612f30600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4e0b608a1b8152600f0192915050565b6000612f5b60148361375c565b731859191c995cdcc81cde5b9d1a195d1a58d2590b60621b815260140192915050565b6000612f8b600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4d0b608a1b8152600f0192915050565b6000612fb6601c83613761565b7f4d415443483a46554c4c5f46494c4c5f4e4f545f504f535349424c4500000000815260200192915050565b6000612fef602a83613761565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b600061303b60138361375c565b721d5a5b9d0c8d4d881c995b185e595c9199594b606a1b815260130192915050565b600061306a601f83613761565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00815260200192915050565b60006130a360158361375c565b741859191c995cdcc81d185ad95c9059191c995cdccb605a1b815260150192915050565b60006130d4601f83613761565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b600061310d600e8361375c565b6d1859191c995cdcc81d1bdad95b8b60921b8152600e0192915050565b805160009060c084019061313e85826128a3565b50602083015161315160208601826128a3565b506040830151848203604086015261316982826127f3565b915050606083015161317e606086018261277f565b506080830151613191608086018261277f565b5060a08301516131a460a086018261277f565b509392505050565b61278881613791565b60006131c1828d6128ac565b6020820191506131d1828c6128ac565b6020820191506131e1828b6128ac565b6020820191506131f1828a6128ac565b60208201915061320182896128ac565b60208201915061321182886128ac565b60208201915061322182876128ac565b60208201915061323182866128ac565b60208201915061324182856128ac565b60208201915061325182846128ac565b506020019a9950505050505050505050565b6000611f2682846128bd565b600061327b82886128bd565b915061328782876128bd565b915061329382866128bd565b915061329f82856128bd565b91506132ab82846128bd565b979650505050505050565b60006132c182612a7a565b91506132cc82612f4e565b91506132d782612d6f565b91506132e282613100565b91506132ed82612b2e565b91506132f882613096565b9150613303826129ec565b915061330e82612c99565b915061331982612cd2565b915061332482612bde565b915061332f82612c42565b915061333a826129bf565b915061334582612e53565b915061335082612eb1565b915061335b82612d44565b915061336682612a1e565b915061337182612c6e565b915061337c82612f7e565b915061338782612e28565b91506133928261292d565b915061339d82612aca565b91506133a882612f23565b91506133b382612c17565b91506133be8261302e565b91506133c982612a49565b91506133d482612b98565b9150611f7282612bc1565b60006133eb82896128ac565b6020820191506133fb82886128ac565b60208201915061340b828761284c565b9150613417828661278e565b601482019150613427828561278e565b601482019150613437828461278e565b506014019695505050505050565b600061345182866128ac565b60208201915061346182856128ac565b60208201915061347182846128ac565b506020019392505050565b600061348882886128ac565b60208201915061349882876128ac565b6020820191506134a882866128ac565b6020820191506134b882856128ac565b6020820191506134c882846128ac565b5060200195945050505050565b60208101611f72828461277f565b604081016134f1828561277f565b611f26602083018461277f565b6040810161350c828561277f565b611f2660208301846128a3565b60208101611f72828461289a565b60208101611f7282846128a3565b6040810161354382856128a3565b8181036020830152612021818461312a565b6080810161356382876128a3565b61357060208301866131ac565b61357d60408301856128a3565b61358a60608301846128a3565b95945050505050565b608081016135a182876128ec565b6135ae602083018661277f565b61357d604083018561277f565b60208082528101611f6f81846128f5565b60208082528101611f7281612958565b60208082528101611f7281612986565b60208082528101611f7281612a9c565b60208082528101611f7281612af5565b60208082528101611f7281612b5f565b60208082528101611f7281612d0b565b60208082528101611f7281612d9c565b60208082528101611f7281612ddf565b60208082528101611f7281612e83565b60208082528101611f7281612edc565b60208082528101611f7281612fa9565b60208082528101611f7281612fe2565b60208082528101611f728161305d565b60208082528101611f72816130c7565b608080825281016136bd818661312a565b90506136cc60208301856128a3565b612021604083018461279f565b60405181810167ffffffffffffffff811182821017156136f857600080fd5b604052919050565b600067ffffffffffffffff82111561371757600080fd5b5060209081020190565b600067ffffffffffffffff82111561373857600080fd5b506020601f91909101601f19160190565b90565b60200190565b50600290565b5190565b919050565b90815260200190565b6000611f7282613785565b151590565b6000611f728261376a565b6001600160a01b031690565b60ff1690565b82818337506000910152565b60005b838110156137be5781810151838201526020016137a6565b838111156106b35750506000910152565b6000611f72826000611f72826137ea565b601f01601f191690565b60601b90565b6137f98161376a565b811461380457600080fd5b50565b6137f981613775565b6137f981613749565b6137f98161377a56fea365627a7a72315820a2abb4efe867fef9d1260029b16b5e4b8411d67b24e304ebe007220072d8e48e6c6578706572696d656e74616cf564736f6c634300051000400000000000000000000000007f5f4087006ba4f4985b32f9d1079ee2f8594af8
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80635ab1bd53116100715780635ab1bd5314610132578063c23f001f14610147578063c59e43e51461015a578063e6cd370e1461016d578063eb95512214610180578063fdd2f04714610193576100a9565b80630411e552146100ae5780631c439266146100d7578063288cdc91146100ea5780632d5bb2791461010a57806351cff8d91461011d575b600080fd5b6100c16100bc3660046125d7565b6101a6565b6040516100ce9190613519565b60405180910390f35b6100c16100e53660046125d7565b6101bb565b6100fd6100f83660046125d7565b6101d0565b6040516100ce9190613527565b6100fd610118366004612648565b6101e2565b61013061012b3660046125f5565b6103c1565b005b61013a610430565b6040516100ce91906134d5565b6100fd61015536600461257f565b61043f565b6100c16101683660046125d7565b61045c565b61013061017b36600461267d565b610471565b6100fd61018e366004612613565b6106b9565b6101306101a1366004612648565b6106e9565b60066020526000908152604090205460ff1681565b60036020526000908152604090205460ff1681565b60076020526000908152604090205481565b60006040516020016101f3906132b6565b6040516020818303038152906040528051906020012082600001516001600160a01b031683602001516001600160a01b031684604001516001600160a01b031685606001516001600160a01b031686608001516001600160a01b03168760a001516001600160a01b03168860c001516001600160a01b03168960e001516001600160a01b03168a61010001516001600160a01b03166040516020016102a19a999897969594939291906131b5565b6040516020818303038152906040528261012001518361014001518461016001516040516020016102d493929190613445565b60408051601f19818403018152908290526101808501516101a08601516101c08701516101e08801516102008901519495610312959060200161347c565b60408051601f19818403018152908290526102208601516102408701516102608801516102808901516102a08a01519495610350959060200161347c565b604051602081830303815290604052856102c00151866102e0015187610300015160405160200161038393929190613445565b60408051601f19818403018152908290526103a4959493929160200161326f565b604051602081830303815290604052805190602001209050919050565b60028054600101908190553360008181526005602090815260408083206001600160a01b038716808552925282208054929055909161040191908361081d565b50600254811461042c5760405162461bcd60e51b81526004016104239061368c565b60405180910390fd5b5050565b6001546001600160a01b031690565b600560209081526000928352604080842090915290825290205481565b60046020526000908152604090205460ff1681565b6002805460010190819055825184516001600160a01b039081169116146104aa5760405162461bcd60e51b8152600401610423906135cc565b6104b4848461087b565b6104be838561087b565b6104c784610902565b6104d083610902565b6104d8612128565b6104e1856101e2565b81526104f48160005b602002015161097c565b805161050090866109e4565b610509846101e2565b60208201526105198160016104ea565b602081015161052890856109e4565b610530612128565b61053984610a8c565b50825160208401519192506000916105549190899089610cc9565b9050610561878787610e83565b825161056d908861154f565b602083015161057c908761154f565b6105898787878585611a1b565b600160009054906101000a90046001600160a01b03166001600160a01b031663da4fbe526040518163ffffffff1660e01b815260040160206040518083038186803b1580156105d757600080fd5b505afa1580156105eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061060f9190810190612561565b6040805180820182526060808b01516001600160a01b039081168352908a0151811660208301529151631af5968960e31b8152929091169163d7acb4489161065d91899186916004016136ac565b600060405180830381600087803b15801561067757600080fd5b505af115801561068b573d6000803e3d6000fd5b5050505050505060025481146106b35760405162461bcd60e51b81526004016104239061368c565b50505050565b80516020808301516040808501516060860151608087015160a088015193516000976103a49790969591016133df565b80606001516001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4d415443483a43414e43454c4c4154494f4e5f4e4f545f414c4c4f5745440000815250906107565760405162461bcd60e51b815260040161042391906135bb565b506000610762826101e2565b600081815260036020908152604091829020548251808401909352601683527513505510d20e9053149150511657d0d05390d153115160521b918301919091529192509060ff16156107c75760405162461bcd60e51b815260040161042391906135bb565b5060008181526003602052604090819020805460ff19166001179055517f134fdd648feeaf30251f0157f9624ef8608ff9a042aad6d13e73f35d21d3f88d90610811908390613527565b60405180910390a15050565b60405161087690849063a9059cbb60e01b9061083f90869086906024016134fe565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611df2565b505050565b60808201516001600160a01b031615806108ae575080606001516001600160a01b031682608001516001600160a01b0316145b6040518060400160405280601981526020017f4d415443483a54414b45525f414444524553535f57524f4e4700000000000000815250906108765760405162461bcd60e51b815260040161042391906135bb565b60a08101516001600160a01b03161580610928575060a08101516001600160a01b031633145b6040518060400160405280601a81526020017f4d415443483a53454e4445525f414444524553535f57524f4e470000000000008152509061042c5760405162461bcd60e51b815260040161042391906135bb565b600081815260036020908152604091829020548251808401909352601883527f4d415443483a4f524445525f5741535f43414e43454c454400000000000000009183019190915260ff161561042c5760405162461bcd60e51b815260040161042391906135bb565b60008281526004602052604090205460ff1615610a005761042c565b6000610a16838361032001518460600151611ed7565b9050806040518060400160405280601c81526020017f4d415443483a5349474e41545552455f4e4f545f56455249464945440000000081525090610a6d5760405162461bcd60e51b815260040161042391906135bb565b50506000828152600460205260409020805460ff191660011790555050565b610a94612128565b6000610a9f836106b9565b9050600160009054906101000a90046001600160a01b03166001600160a01b0316638177644c6040518163ffffffff1660e01b815260040160206040518083038186803b158015610aef57600080fd5b505afa158015610b03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b279190810190612561565b6001600160a01b03166399f685ee82856040518363ffffffff1660e01b8152600401610b54929190613535565b6040805180830381600087803b158015610b6d57600080fd5b505af1158015610b81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ba5919081019061272f565b6020808501919091529083526001546040805163205dd91360e21b815290516001600160a01b0390921692638177644c92600480840193829003018186803b158015610bf057600080fd5b505afa158015610c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610c289190810190612561565b6001600160a01b03166399a5017682856040518363ffffffff1660e01b8152600401610c55929190613535565b602060405180830381600087803b158015610c6f57600080fd5b505af1158015610c83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ca791908101906125b9565b15610cc45760405162461bcd60e51b81526004016104239061364c565b915091565b6000848152600760205260408120546101408501518291610cf0919063ffffffff611f2d16565b6000858152600760205260408120546101408601519293509091610d199163ffffffff611f2d16565b90508115801590610d2957508015155b610d455760405162461bcd60e51b8152600401610423906135ec565b610d4f8282611f78565b92508561016001516000148015610d695750610160840151155b15610d9c5783610140015186610140015114610d975760405162461bcd60e51b81526004016104239061366c565b610e20565b610160860151158015610db457508361016001516001145b15610dde57808661014001511115610d975760405162461bcd60e51b81526004016104239061366c565b8561016001516001148015610df65750610160840151155b15610e2057836101400151821015610e205760405162461bcd60e51b81526004016104239061366c565b600087815260076020526040902054610e3f908463ffffffff611f8e16565b600088815260076020526040808220929092558681522054610e67908463ffffffff611f8e16565b6000958652600760205260409095209490945550949350505050565b60606040518060400160405280601f81526020017f4d415443483a444552495641544956455f504152414d5f49535f57524f4e470081525090508361012001518260200151148015610edd57508261012001518260200151145b8190610efc5760405162461bcd60e51b815260040161042391906135bb565b5083600001516001600160a01b03168260a001516001600160a01b0316148015610f3f575082600001516001600160a01b03168260a001516001600160a01b0316145b8190610f5e5760405162461bcd60e51b815260040161042391906135bb565b5083602001516001600160a01b031682606001516001600160a01b0316148015610fa1575082602001516001600160a01b031682606001516001600160a01b0316145b8190610fc05760405162461bcd60e51b815260040161042391906135bb565b5083604001516001600160a01b031682608001516001600160a01b0316148015611003575082604001516001600160a01b031682608001516001600160a01b0316145b81906110225760405162461bcd60e51b815260040161042391906135bb565b50601482604001515110156110495760405162461bcd60e51b81526004016104239061363c565b816040015160008151811061105a57fe5b60200260200101518461018001511481906110885760405162461bcd60e51b815260040161042391906135bb565b50816040015160018151811061109a57fe5b6020026020010151846101a001511481906110c85760405162461bcd60e51b815260040161042391906135bb565b5081604001516002815181106110da57fe5b6020026020010151846101c001511481906111085760405162461bcd60e51b815260040161042391906135bb565b50816040015160038151811061111a57fe5b6020026020010151846101e001511481906111485760405162461bcd60e51b815260040161042391906135bb565b50816040015160048151811061115a57fe5b60200260200101518461020001511481906111885760405162461bcd60e51b815260040161042391906135bb565b50816040015160058151811061119a57fe5b60200260200101518461022001511481906111c85760405162461bcd60e51b815260040161042391906135bb565b5081604001516006815181106111da57fe5b60200260200101518461024001511481906112085760405162461bcd60e51b815260040161042391906135bb565b50816040015160078151811061121a57fe5b60200260200101518461026001511481906112485760405162461bcd60e51b815260040161042391906135bb565b50816040015160088151811061125a57fe5b60200260200101518461028001511481906112885760405162461bcd60e51b815260040161042391906135bb565b50816040015160098151811061129a57fe5b6020026020010151846102a001511481906112c85760405162461bcd60e51b815260040161042391906135bb565b508160400151600a815181106112da57fe5b60200260200101518361018001511481906113085760405162461bcd60e51b815260040161042391906135bb565b508160400151600b8151811061131a57fe5b6020026020010151836101a001511481906113485760405162461bcd60e51b815260040161042391906135bb565b508160400151600c8151811061135a57fe5b6020026020010151836101c001511481906113885760405162461bcd60e51b815260040161042391906135bb565b508160400151600d8151811061139a57fe5b6020026020010151836101e001511481906113c85760405162461bcd60e51b815260040161042391906135bb565b508160400151600e815181106113da57fe5b60200260200101518361020001511481906114085760405162461bcd60e51b815260040161042391906135bb565b508160400151600f8151811061141a57fe5b60200260200101518361022001511481906114485760405162461bcd60e51b815260040161042391906135bb565b50816040015160108151811061145a57fe5b60200260200101518361024001511481906114885760405162461bcd60e51b815260040161042391906135bb565b50816040015160118151811061149a57fe5b60200260200101518361026001511481906114c85760405162461bcd60e51b815260040161042391906135bb565b5081604001516012815181106114da57fe5b60200260200101518361028001511481906115085760405162461bcd60e51b815260040161042391906135bb565b50816040015160138151811061151a57fe5b6020026020010151836102a001511481906115485760405162461bcd60e51b815260040161042391906135bb565b5050505050565b60008281526006602052604090205460ff161561156b5761042c565b6101008101516001600160a01b03166115835761042c565b60006115a2826102e00151836102c00151611f8e90919063ffffffff16565b9050806115af575061042c565b6101008201516001546040805163beb5bd8160e01b815290516000926001600160a01b03169163beb5bd81916004808301926020929190829003018186803b1580156115fa57600080fd5b505afa15801561160e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116329190810190612561565b905082826001600160a01b031663dd62ed3e8660600151846040518363ffffffff1660e01b81526004016116679291906134e3565b60206040518083038186803b15801561167f57600080fd5b505afa158015611693573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116b79190810190612711565b10156040518060400160405280601d81526020017f4d415443483a4e4f545f454e4f5547485f414c4c4f5745445f464545530000008152509061170d5760405162461bcd60e51b815260040161042391906135bb565b50606084015160405163052f523360e11b81526001600160a01b03831691630a5ea4669161174391869130908990600401613593565b600060405180830381600087803b15801561175d57600080fd5b505af1158015611771573d6000803e3d6000fd5b505050506000600160009054906101000a90046001600160a01b03166001600160a01b031663ec45d8ae6040518163ffffffff1660e01b815260040160206040518083038186803b1580156117c557600080fd5b505afa1580156117d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506117fd9190810190612561565b60c08601519091506001600160a01b03161561188f576102c085015160c08601516001600160a01b0390811660009081526005602090815260408083206101008b0151909416835292905220546118599163ffffffff611f8e16565b60c08601516001600160a01b0390811660009081526005602090815260408083206101008b0151909416835292905220556118fd565b6102c08501516001600160a01b0380831660009081526005602090815260408083206101008b0151909416835292905220546118d09163ffffffff611f8e16565b6001600160a01b0380831660009081526005602090815260408083206101008b0151909416835292905220555b60e08501516001600160a01b03161561198c576102e085015160e08601516001600160a01b0390811660009081526005602090815260408083206101008b0151909416835292905220546119569163ffffffff611f8e16565b60e08601516001600160a01b0390811660009081526005602090815260408083206101008b0151909416835292905220556119fa565b6102e08501516001600160a01b0380831660009081526005602090815260408083206101008b0151909416835292905220546119cd9163ffffffff611f8e16565b6001600160a01b0380831660009081526005602090815260408083206101008b0151909416835292905220555b5050506000838152600660205260409020805460ff19166001179055505050565b60808301516001546040805163beb5bd8160e01b815290516000926001600160a01b03169163beb5bd81916004808301926020929190829003018186803b158015611a6557600080fd5b505afa158015611a79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a9d9190810190612561565b845190915015611bd957611ac0838560005b60200201519063ffffffff611fb316565b6060880151604051636eb1769f60e11b81526001600160a01b0385169163dd62ed3e91611af2919086906004016134e3565b60206040518083038186803b158015611b0a57600080fd5b505afa158015611b1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611b429190810190612711565b1015611b605760405162461bcd60e51b81526004016104239061361c565b806001600160a01b0316630a5ea46683896060015130611b87888a600060028110611aaf57fe5b6040518563ffffffff1660e01b8152600401611ba69493929190613593565b600060405180830381600087803b158015611bc057600080fd5b505af1158015611bd4573d6000803e3d6000fd5b505050505b602084015115611d0857611bef83856001611aaf565b6060870151604051636eb1769f60e11b81526001600160a01b0385169163dd62ed3e91611c21919086906004016134e3565b60206040518083038186803b158015611c3957600080fd5b505afa158015611c4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611c719190810190612711565b1015611c8f5760405162461bcd60e51b81526004016104239061361c565b806001600160a01b0316630a5ea46683886060015130611cb6888a600160028110611aaf57fe5b6040518563ffffffff1660e01b8152600401611cd59493929190613593565b600060405180830381600087803b158015611cef57600080fd5b505af1158015611d03573d6000803e3d6000fd5b505050505b6020840151611d26908560005b60200201519063ffffffff611f8e16565b15611de9576001600160a01b03821663095ea7b382611d5e86611d5289600160200201518a6000611d15565b9063ffffffff611fb316565b6040518363ffffffff1660e01b8152600401611d7b9291906134fe565b602060405180830381600087803b158015611d9557600080fd5b505af1158015611da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611dcd91908101906125b9565b611de95760405162461bcd60e51b81526004016104239061365c565b50505050505050565b611e04826001600160a01b0316611fed565b611e205760405162461bcd60e51b81526004016104239061369c565b60006060836001600160a01b031683604051611e3c9190613263565b6000604051808303816000865af19150503d8060008114611e79576040519150601f19603f3d011682016040523d82523d6000602084013e611e7e565b606091505b509150915081611ea05760405162461bcd60e51b81526004016104239061360c565b8051156106b35780806020019051611ebb91908101906125b9565b6106b35760405162461bcd60e51b81526004016104239061367c565b60008251604114611efa5760405162461bcd60e51b8152600401610423906135dc565b6000611f0585612029565b90506000611f13828661204e565b6001600160a01b03858116911614925050505b9392505050565b6000611f6f83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506120fc565b90505b92915050565b6000818310611f875781611f6f565b5090919050565b600082820183811015611f6f5760405162461bcd60e51b8152600401610423906135fc565b600082611fc257506000611f72565b82820282848281611fcf57fe5b0414611f6f5760405162461bcd60e51b81526004016104239061362c565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081158015906120215750808214155b949350505050565b60005460405161190160f01b8152600281019190915260228101919091526042902090565b6020810151604082015160608301516000929190831a601b81101561207157601b015b8060ff16601b1415801561208957508060ff16601c14155b1561209a5760009350505050611f72565b600186828585604051600081526020016040526040516120bd9493929190613555565b6020604051602081039080840390855afa1580156120df573d6000803e3d6000fd5b505050602060405103519350505050611f72565b50505092915050565b600081848411156121205760405162461bcd60e51b815260040161042391906135bb565b505050900390565b60405180604001604052806002906020820280388339509192915050565b8035611f72816137f0565b8051611f72816137f0565b600082601f83011261216d57600080fd5b813561218061217b82613700565b6136d9565b915081818352602084019350602081019050838560208402820111156121a557600080fd5b60005b838110156121d157816121bb88826121e6565b84525060209283019291909101906001016121a8565b5050505092915050565b8051611f7281613807565b8035611f7281613810565b600082601f83011261220257600080fd5b813561221061217b82613721565b9150808252602083016020830185838301111561222c57600080fd5b6120f3838284613797565b8035611f7281613819565b600060c0828403121561225457600080fd5b61225e60c06136d9565b9050600061226c84846121e6565b825250602061227d848483016121e6565b602083015250604082013567ffffffffffffffff81111561229d57600080fd5b6122a98482850161215c565b60408301525060606122bd84828501612146565b60608301525060806122d184828501612146565b60808301525060a06122e584828501612146565b60a08301525092915050565b6000610340828403121561230457600080fd5b61230f6103406136d9565b9050600061231d8484612146565b825250602061232e84848301612146565b602083015250604061234284828501612146565b604083015250606061235684828501612146565b606083015250608061236a84828501612146565b60808301525060a061237e84828501612146565b60a08301525060c061239284828501612146565b60c08301525060e06123a684828501612146565b60e0830152506101006123bb84828501612146565b610100830152506101206123d1848285016121e6565b610120830152506101406123e7848285016121e6565b610140830152506101606123fd848285016121e6565b61016083015250610180612413848285016121e6565b610180830152506101a0612429848285016121e6565b6101a0830152506101c061243f848285016121e6565b6101c0830152506101e0612455848285016121e6565b6101e08301525061020061246b848285016121e6565b61020083015250610220612481848285016121e6565b61022083015250610240612497848285016121e6565b610240830152506102606124ad848285016121e6565b610260830152506102806124c3848285016121e6565b610280830152506102a06124d9848285016121e6565b6102a0830152506102c06124ef848285016121e6565b6102c0830152506102e0612505848285016121e6565b6102e08301525061030061251b848285016121e6565b6103008301525061032082013567ffffffffffffffff81111561253d57600080fd5b612549848285016121f1565b6103208301525092915050565b8051611f7281613810565b60006020828403121561257357600080fd5b60006120218484612151565b6000806040838503121561259257600080fd5b600061259e8585612146565b92505060206125af85828601612146565b9150509250929050565b6000602082840312156125cb57600080fd5b600061202184846121db565b6000602082840312156125e957600080fd5b600061202184846121e6565b60006020828403121561260757600080fd5b60006120218484612237565b60006020828403121561262557600080fd5b813567ffffffffffffffff81111561263c57600080fd5b61202184828501612242565b60006020828403121561265a57600080fd5b813567ffffffffffffffff81111561267157600080fd5b612021848285016122f1565b60008060006060848603121561269257600080fd5b833567ffffffffffffffff8111156126a957600080fd5b6126b5868287016122f1565b935050602084013567ffffffffffffffff8111156126d257600080fd5b6126de868287016122f1565b925050604084013567ffffffffffffffff8111156126fb57600080fd5b61270786828701612242565b9150509250925092565b60006020828403121561272357600080fd5b60006120218484612556565b6000806040838503121561274257600080fd5b600061274e8585612556565b92505060206125af85828601612556565b600061276b838361277f565b505060200190565b600061276b83836128a3565b6127888161376a565b82525050565b61278861279a8261376a565b6137cf565b6127a881613752565b6127b2818461375c565b92506127bd82613749565b8060005b838110156127eb5781516127d5878261275f565b96506127e08361374c565b9250506001016127c1565b505050505050565b60006127fe82613758565b6128088185613761565b93506128138361374c565b8060005b8381101561284157815161282b8882612773565b97506128368361374c565b925050600101612817565b509495945050505050565b600061285782613758565b612861818561375c565b935061286c8361374c565b8060005b838110156128415781516128848882612773565b975061288f8361374c565b925050600101612870565b61278881613775565b61278881613749565b6127886128b882613749565b613749565b60006128c882613758565b6128d2818561375c565b93506128e28185602086016137a3565b9290920192915050565b6127888161377a565b600061290082613758565b61290a8185613761565b935061291a8185602086016137a3565b612923816137e0565b9093019392505050565b600061293a600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4d8b608a1b8152600f0192915050565b6000612965601283613761565b7126a0aa21a41d2727aa2fa1a922a0aa24a7a760711b815260200192915050565b6000612993601e83613761565b7f4f524445523a494e56414c49445f5349474e41545552455f4c454e4754480000815260200192915050565b60006129cc60118361375c565b701d5a5b9d0c8d4d881c5d585b9d1a5d1e4b607a1b815260110192915050565b60006129f960168361375c565b751859191c995cdcc81cd95b99195c9059191c995cdccb60521b815260160192915050565b6000612a2b600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4c8b608a1b8152600f0192915050565b6000612a5660158361375c565b741d5a5b9d0c8d4d881859999a5b1a585d195199594b605a1b815260150192915050565b6000612a8760068361375c565b6509ee4c8cae4560d31b815260060192915050565b6000612aa9601283613761565b714d415443483a4e4f5f415641494c41424c4560701b815260200192915050565b6000612ad7600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4dcb608a1b8152600f0192915050565b6000612b02601b83613761565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000612b3b60158361375c565b741859191c995cdcc81b585ad95c9059191c995cdccb605a1b815260150192915050565b6000612b6c602083613761565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b6000612ba5600d8361375c565b6c75696e74323536206e6f6e636560981b8152600d0192915050565b6000612bce60018361375c565b602960f81b815260010192915050565b6000612beb60188361375c565b7f6164647265737320666565546f6b656e416464726573732c0000000000000000815260180192915050565b6000612c24600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4e4b608a1b8152600f0192915050565b6000612c4f60108361375c565b6f1d5a5b9d0c8d4d88195b99151a5b594b60821b815260100192915050565b6000612c7b600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4ccb608a1b8152600f0192915050565b6000612ca660178361375c565b7f616464726573732072656c61796572416464726573732c000000000000000000815260170192915050565b6000612cdf60198361375c565b7f6164647265737320616666696c69617465416464726573732c00000000000000815260190192915050565b6000612d18601f83613761565b7f4d415443483a4e4f545f454e4f5547485f414c4c4f5745445f4d415247494e00815260200192915050565b6000612d51600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4c4b608a1b8152600f0192915050565b6000612d7c60118361375c565b701859191c995cdcc81bdc9858db1952590b607a1b815260110192915050565b6000612da9602183613761565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000612dec602783613761565b7f4d415443483a444552495641544956455f504152414d535f4c454e4754485f49815266535f57524f4e4760c81b602082015260400192915050565b6000612e35600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4d4b608a1b8152600f0192915050565b6000612e6060148361375c565b731d5a5b9d0c8d4d881c185c9d1a585b119a5b1b0b60621b815260140192915050565b6000612e90601283613761565b7113505510d20e90d0539517d09157d413d3d360721b815260200192915050565b6000612ebe600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4c0b608a1b8152600f0192915050565b6000612ee9602583613761565b7f4d415443483a434f554c444e545f415050524f56455f4d415247494e5f464f528152645f434f524560d81b602082015260400192915050565b6000612f30600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4e0b608a1b8152600f0192915050565b6000612f5b60148361375c565b731859191c995cdcc81cde5b9d1a195d1a58d2590b60621b815260140192915050565b6000612f8b600f8361375c565b6e1d5a5b9d0c8d4d881c185c985b4d0b608a1b8152600f0192915050565b6000612fb6601c83613761565b7f4d415443483a46554c4c5f46494c4c5f4e4f545f504f535349424c4500000000815260200192915050565b6000612fef602a83613761565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b600061303b60138361375c565b721d5a5b9d0c8d4d881c995b185e595c9199594b606a1b815260130192915050565b600061306a601f83613761565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00815260200192915050565b60006130a360158361375c565b741859191c995cdcc81d185ad95c9059191c995cdccb605a1b815260150192915050565b60006130d4601f83613761565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b600061310d600e8361375c565b6d1859191c995cdcc81d1bdad95b8b60921b8152600e0192915050565b805160009060c084019061313e85826128a3565b50602083015161315160208601826128a3565b506040830151848203604086015261316982826127f3565b915050606083015161317e606086018261277f565b506080830151613191608086018261277f565b5060a08301516131a460a086018261277f565b509392505050565b61278881613791565b60006131c1828d6128ac565b6020820191506131d1828c6128ac565b6020820191506131e1828b6128ac565b6020820191506131f1828a6128ac565b60208201915061320182896128ac565b60208201915061321182886128ac565b60208201915061322182876128ac565b60208201915061323182866128ac565b60208201915061324182856128ac565b60208201915061325182846128ac565b506020019a9950505050505050505050565b6000611f2682846128bd565b600061327b82886128bd565b915061328782876128bd565b915061329382866128bd565b915061329f82856128bd565b91506132ab82846128bd565b979650505050505050565b60006132c182612a7a565b91506132cc82612f4e565b91506132d782612d6f565b91506132e282613100565b91506132ed82612b2e565b91506132f882613096565b9150613303826129ec565b915061330e82612c99565b915061331982612cd2565b915061332482612bde565b915061332f82612c42565b915061333a826129bf565b915061334582612e53565b915061335082612eb1565b915061335b82612d44565b915061336682612a1e565b915061337182612c6e565b915061337c82612f7e565b915061338782612e28565b91506133928261292d565b915061339d82612aca565b91506133a882612f23565b91506133b382612c17565b91506133be8261302e565b91506133c982612a49565b91506133d482612b98565b9150611f7282612bc1565b60006133eb82896128ac565b6020820191506133fb82886128ac565b60208201915061340b828761284c565b9150613417828661278e565b601482019150613427828561278e565b601482019150613437828461278e565b506014019695505050505050565b600061345182866128ac565b60208201915061346182856128ac565b60208201915061347182846128ac565b506020019392505050565b600061348882886128ac565b60208201915061349882876128ac565b6020820191506134a882866128ac565b6020820191506134b882856128ac565b6020820191506134c882846128ac565b5060200195945050505050565b60208101611f72828461277f565b604081016134f1828561277f565b611f26602083018461277f565b6040810161350c828561277f565b611f2660208301846128a3565b60208101611f72828461289a565b60208101611f7282846128a3565b6040810161354382856128a3565b8181036020830152612021818461312a565b6080810161356382876128a3565b61357060208301866131ac565b61357d60408301856128a3565b61358a60608301846128a3565b95945050505050565b608081016135a182876128ec565b6135ae602083018661277f565b61357d604083018561277f565b60208082528101611f6f81846128f5565b60208082528101611f7281612958565b60208082528101611f7281612986565b60208082528101611f7281612a9c565b60208082528101611f7281612af5565b60208082528101611f7281612b5f565b60208082528101611f7281612d0b565b60208082528101611f7281612d9c565b60208082528101611f7281612ddf565b60208082528101611f7281612e83565b60208082528101611f7281612edc565b60208082528101611f7281612fa9565b60208082528101611f7281612fe2565b60208082528101611f728161305d565b60208082528101611f72816130c7565b608080825281016136bd818661312a565b90506136cc60208301856128a3565b612021604083018461279f565b60405181810167ffffffffffffffff811182821017156136f857600080fd5b604052919050565b600067ffffffffffffffff82111561371757600080fd5b5060209081020190565b600067ffffffffffffffff82111561373857600080fd5b506020601f91909101601f19160190565b90565b60200190565b50600290565b5190565b919050565b90815260200190565b6000611f7282613785565b151590565b6000611f728261376a565b6001600160a01b031690565b60ff1690565b82818337506000910152565b60005b838110156137be5781810151838201526020016137a6565b838111156106b35750506000910152565b6000611f72826000611f72826137ea565b601f01601f191690565b60601b90565b6137f98161376a565b811461380457600080fd5b50565b6137f981613775565b6137f981613749565b6137f98161377a56fea365627a7a72315820a2abb4efe867fef9d1260029b16b5e4b8411d67b24e304ebe007220072d8e48e6c6578706572696d656e74616cf564736f6c63430005100040
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
146530:10182:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;146530:10182:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;140855:41;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;140328;;;;;;;;;:::i;146715:42::-;;;;;;;;;:::i;:::-;;;;;;;;136258:1549;;;;;;;;;:::i;141518:230::-;;;;;;;;;:::i;:::-;;29554:98;;;:::i;:::-;;;;;;;;140737:65;;;;;;;;;:::i;140515:41::-;;;;;;;;;:::i;147212:1975::-;;;;;;;;;:::i;953:382::-;;;;;;;;;:::i;141025:343::-;;;;;;;;;:::i;140855:41::-;;;;;;;;;;;;;;;:::o;140328:::-;;;;;;;;;;;;;;;:::o;146715:42::-;;;;;;;;;;;;;:::o;136258:1549::-;136327:12;135280:842;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;135280:842:0;;;135270:853;;;;;;136509:6;:18;;;-1:-1:-1;;;;;136501:27:0;136559:6;:15;;;-1:-1:-1;;;;;136551:24:0;136606:6;:12;;;-1:-1:-1;;;;;136598:21:0;136652:6;:19;;;-1:-1:-1;;;;;136644:28:0;136703:6;:19;;;-1:-1:-1;;;;;136695:28:0;136756:6;:20;;;-1:-1:-1;;;;;136748:29:0;136810:6;:21;;;-1:-1:-1;;;;;136802:30:0;136863:6;:23;;;-1:-1:-1;;;;;136855:32:0;136920:6;:22;;;-1:-1:-1;;;;;136912:31:0;136418:544;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;136418:544:0;;;137020:6;:14;;;137057:6;:15;;;137095:6;:18;;;136981:151;;;;;;;;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;136981:151:0;;;;137190:13;;;;137226;;;;137262;;;;137298;;;;137334;;;;136981:151;;137151:215;;137334:13;49:4:-1;137151:215:0;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;137151:215:0;;;;137424:13;;;;137460;;;;137496;;;;137532;;;;137568;;;;137151:215;;137385;;137568:13;49:4:-1;137385:215:0;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;137385:215:0;;;137658:6;:17;;;137698:6;:19;;;137742:6;:12;;;137619:154;;;;;;;;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;137619:154:0;;;;136383:1405;;;;;;49:4:-1;136383:1405:0;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;136383:1405:0;;;136359:1440;;;;;;136352:1447;;136258:1549;;;:::o;141518:230::-;18112:13;:18;;18129:1;18112:18;;;;;141609:10;-1:-1:-1;141600:20:0;;;:8;:20;;;;;;;;-1:-1:-1;;;;;141600:37:0;;;;;;;;;;;141648:41;;;141600:37;;141700:40;;141600:37;;141700:19;:40::i;:::-;18188:1;18224:13;;18208:12;:29;18200:73;;;;-1:-1:-1;;;18200:73:0;;;;;;;;;;;;;;;;;141518:230;;:::o;29554:98::-;29635:8;;-1:-1:-1;;;;;29635:8:0;29554:98;:::o;140737:65::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;140515:41::-;;;;;;;;;;;;;;;:::o;147212:1975::-;18112:13;:18;;18129:1;18112:18;;;;;147451:23;;147425:22;;-1:-1:-1;;;;;147425:49:0;;;;;;147403:117;;;;-1:-1:-1;;;147403:117:0;;;;;;;;;147567:45;147588:10;147600:11;147567:20;:45::i;:::-;147623;147644:11;147657:10;147623:20;:45::i;:::-;147716:33;147738:10;147716:21;:33::i;:::-;147760:34;147782:11;147760:21;:34::i;:::-;147931:29;;:::i;:::-;147988:21;147998:10;147988:9;:21::i;:::-;147971:38;;148020:35;147971:11;147983:1;148040:14;;;;;148020:19;:35::i;:::-;148084:14;;148066:45;;148100:10;148066:17;:45::i;:::-;148141:22;148151:11;148141:9;:22::i;:::-;148124:14;;;:39;148174:35;148124:11;148136:1;148194:14;;148174:35;148238:14;;;;148220:46;;148254:11;148220:17;:46::i;:::-;148406:25;;:::i;:::-;148437:45;148470:11;148437:32;:45::i;:::-;-1:-1:-1;148606:14:0;;;148634;;;148405:77;;-1:-1:-1;148569:16:0;;148588:74;;148606:14;148622:10;;148650:11;148588:17;:74::i;:::-;148569:93;;148730:55;148748:10;148760:11;148773;148730:17;:55::i;:::-;148829:14;;148820:36;;148845:10;148820:8;:36::i;:::-;148876:14;;;;148867:37;;148892:11;148867:8;:37::i;:::-;148949:73;148966:10;148978:11;148991;149004:7;149013:8;148949:16;:73::i;:::-;149077:8;;;;;;;;;-1:-1:-1;;;;;149077:8:0;-1:-1:-1;;;;;149077:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;149077:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;149077:18: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;149077:18:0;;;;;;;;;149072:107;;;;;;;;149128:23;;;;;-1:-1:-1;;;;;149072:107:0;;;;;149153:24;;;;149072:107;;;;;;;;-1:-1:-1;;;149072:107:0;;:31;;;;;;;:107;;149104:11;;149117:8;;149072:107;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;149072:107:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;149072:107:0;;;;18188:1;;;18224:13;;18208:12;:29;18200:73;;;;-1:-1:-1;;;18200:73:0;;;;;;;;;147212:1975;;;;:::o;953:382::-;1125:18;;1158:19;;;;;1192:18;;;;;1225:20;;;;1260:17;;;;1292:23;;;;1094:232;;1032:22;;1094:232;;1125:18;;1158:19;1292:23;1094:232;;;141025:343;141110:6;:19;;;-1:-1:-1;;;;;141096:33:0;:10;-1:-1:-1;;;;;141096:33:0;;141131:36;;;;;;;;;;;;;;;;;141088:80;;;;;-1:-1:-1;;;141088:80:0;;;;;;;;;;;141179:17;141199;141209:6;141199:9;:17::i;:::-;141236:19;;;;:8;:19;;;;;;;;;;141257:28;;;;;;;;;;;-1:-1:-1;;;141257:28:0;;;;;;;141179:37;;-1:-1:-1;141257:28:0;141236:19;;141235:20;141227:59;;;;-1:-1:-1;;;141227:59:0;;;;;;;;;;-1:-1:-1;141297:19:0;;;;:8;:19;;;;;;;:26;;-1:-1:-1;;141297:26:0;141319:4;141297:26;;;141341:19;;;;;141306:9;;141341:19;;;;;;;;;;141025:343;;:::o;13554:176::-;13663:58;;13637:85;;13656:5;;-1:-1:-1;;;13686:23:0;13663:58;;13711:2;;13715:5;;13663:58;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;13663:58:0;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;;;;13663:58:0;;;179:29:-1;;;;160:49;;;13637:18:0;:85::i;:::-;13554:176;;;:::o;142265:314::-;142409:23;;;;-1:-1:-1;;;;;142409:37:0;;;:105;;;142490:11;:24;;;-1:-1:-1;;;;;142463:51:0;:10;:23;;;-1:-1:-1;;;;;142463:51:0;;142409:105;142529:31;;;;;;;;;;;;;;;;;142387:184;;;;;-1:-1:-1;;;142387:184:0;;;;;;;;;142734:258;142841:20;;;;-1:-1:-1;;;;;142841:34:0;;;:85;;-1:-1:-1;142892:20:0;;;;-1:-1:-1;;;;;142892:34:0;142916:10;142892:34;142841:85;142941:32;;;;;;;;;;;;;;;;;142819:165;;;;;-1:-1:-1;;;142819:165:0;;;;;;;;;141869:134;141947:15;;;;:8;:15;;;;;;;;;;141964:30;;;;;;;;;;;;;;;;;;;141947:15;;141946:16;141938:57;;;;-1:-1:-1;;;141938:57:0;;;;;;;;;143170:363;143269:19;;;;:8;:19;;;;;;;;143265:58;;;143305:7;;143265:58;143335:11;143349:65;143365:9;143376:6;:16;;;143394:6;:19;;;143349:15;:65::i;:::-;143335:79;;143435:6;143443:34;;;;;;;;;;;;;;;;;143427:51;;;;;-1:-1:-1;;;143427:51:0;;;;;;;;;;-1:-1:-1;;143499:19:0;;;;:8;:19;;;;;:26;;-1:-1:-1;;143499:26:0;143521:4;143499:26;;;143170:363;;:::o;149443:708::-;149533:25;;:::i;:::-;149560:22;149673:30;149691:11;149673:17;:30::i;:::-;149656:47;;149900:8;;;;;;;;;-1:-1:-1;;;;;149900:8:0;-1:-1:-1;;;;;149900:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;149900:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;149900: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;149900:33:0;;;;;;;;;-1:-1:-1;;;;;149880:64:0;;149945:14;149961:11;149880:93;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;149880:93:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;149880:93: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;149880:93:0;;;;;;;;;149854:10;149866;;;149853:120;;;;;;;149874:1;150050:8;:33;;;-1:-1:-1;;;150050:33:0;;;;-1:-1:-1;;;;;150050:8:0;;;;:31;;:33;;;;;;;;;;:8;:33;;;5:2:-1;;;;30:1;27;20:12;5:2;150050:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;150050: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;150050:33:0;;;;;;;;;-1:-1:-1;;;;;150030:61:0;;150092:14;150108:11;150030:90;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;150030:90:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;150030:90: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;150030:90:0;;;;;;;;;150029:91;150021:122;;;;-1:-1:-1;;;150021:122:0;;;;;;;;;149443:708;;;:::o;150434:1409::-;150594:16;150718:22;;;:6;:22;;;;;;150694:19;;;;150594:16;;150694:47;;:19;:47;:23;:47;:::i;:::-;150752:22;150802:23;;;:6;:23;;;;;;150777:20;;;;150670:71;;-1:-1:-1;150752:22:0;;150777:49;;;:24;:49;:::i;:::-;150752:74;-1:-1:-1;150847:18:0;;;;;:40;;-1:-1:-1;150869:18:0;;;150847:40;150839:71;;;;-1:-1:-1;;;150839:71:0;;;;;;;;;151006:34;151010:13;151025:14;151006:3;:34::i;:::-;150995:45;;151138:10;:22;;;151164:1;151138:27;:59;;;;-1:-1:-1;151169:23:0;;;;:28;151138:59;151134:528;;;151245:11;:20;;;151222:10;:19;;;:43;151214:84;;;;-1:-1:-1;;;151214:84:0;;;;;;;;;151134:528;;;151320:22;;;;:27;:59;;;;;151351:11;:23;;;151378:1;151351:28;151320:59;151316:346;;;151427:14;151404:10;:19;;;:37;;151396:78;;;;-1:-1:-1;;;151396:78:0;;;;;;;;151316:346;151496:10;:22;;;151522:1;151496:27;:59;;;;-1:-1:-1;151527:23:0;;;;:28;151496:59;151492:170;;;151597:11;:20;;;151580:13;:37;;151572:78;;;;-1:-1:-1;;;151572:78:0;;;;;;;;;151725:22;;;;:6;:22;;;;;;:36;;151752:8;151725:36;:26;:36;:::i;:::-;151700:22;;;;:6;:22;;;;;;:61;;;;151798:23;;;;;:37;;151826:8;151798:37;:27;:37;:::i;:::-;151772:23;;;;:6;:23;;;;;;:63;;;;-1:-1:-1;150434:1409:0;;-1:-1:-1;;;;150434:1409:0:o;152033:2794::-;152182:24;:60;;;;;;;;;;;;;;;;;;;152340:10;:18;;;152317:11;:19;;;:41;:100;;;;;152398:11;:19;;;152375:11;:19;;;:42;152317:100;152432:10;152295:158;;;;;-1:-1:-1;;;152295:158:0;;;;;;;;;;;152559:10;:22;;;-1:-1:-1;;;;;152532:49:0;:11;:23;;;-1:-1:-1;;;;;152532:49:0;;:116;;;;;152625:11;:23;;;-1:-1:-1;;;;;152598:50:0;:11;:23;;;-1:-1:-1;;;;;152598:50:0;;152532:116;152663:10;152510:174;;;;;-1:-1:-1;;;152510:174:0;;;;;;;;;;;152784:10;:19;;;-1:-1:-1;;;;;152760:43:0;:11;:20;;;-1:-1:-1;;;;;152760:43:0;;:104;;;;;152844:11;:20;;;-1:-1:-1;;;;;152820:44:0;:11;:20;;;-1:-1:-1;;;;;152820:44:0;;152760:104;152879:10;152738:162;;;;;-1:-1:-1;;;152738:162:0;;;;;;;;;;;152994:10;:16;;;-1:-1:-1;;;;;152973:37:0;:11;:17;;;-1:-1:-1;;;;;152973:37:0;;:92;;;;;153048:11;:17;;;-1:-1:-1;;;;;153027:38:0;:11;:17;;;-1:-1:-1;;;;;153027:38:0;;152973:92;153080:10;152951:150;;;;;-1:-1:-1;;;152951:150:0;;;;;;;;;;;153190:2;153161:11;:18;;;:25;:31;;153153:83;;;;-1:-1:-1;;;153153:83:0;;;;;;;;;153317:11;:18;;;153336:1;153317:21;;;;;;;;;;;;;;153296:10;:17;;;:42;153340:10;153288:63;;;;;-1:-1:-1;;;153288:63:0;;;;;;;;;;;153391:11;:18;;;153410:1;153391:21;;;;;;;;;;;;;;153370:10;:17;;;:42;153414:10;153362:63;;;;;-1:-1:-1;;;153362:63:0;;;;;;;;;;;153465:11;:18;;;153484:1;153465:21;;;;;;;;;;;;;;153444:10;:17;;;:42;153488:10;153436:63;;;;;-1:-1:-1;;;153436:63:0;;;;;;;;;;;153539:11;:18;;;153558:1;153539:21;;;;;;;;;;;;;;153518:10;:17;;;:42;153562:10;153510:63;;;;;-1:-1:-1;;;153510:63:0;;;;;;;;;;;153613:11;:18;;;153632:1;153613:21;;;;;;;;;;;;;;153592:10;:17;;;:42;153636:10;153584:63;;;;;-1:-1:-1;;;153584:63:0;;;;;;;;;;;153687:11;:18;;;153706:1;153687:21;;;;;;;;;;;;;;153666:10;:17;;;:42;153710:10;153658:63;;;;;-1:-1:-1;;;153658:63:0;;;;;;;;;;;153761:11;:18;;;153780:1;153761:21;;;;;;;;;;;;;;153740:10;:17;;;:42;153784:10;153732:63;;;;;-1:-1:-1;;;153732:63:0;;;;;;;;;;;153835:11;:18;;;153854:1;153835:21;;;;;;;;;;;;;;153814:10;:17;;;:42;153858:10;153806:63;;;;;-1:-1:-1;;;153806:63:0;;;;;;;;;;;153909:11;:18;;;153928:1;153909:21;;;;;;;;;;;;;;153888:10;:17;;;:42;153932:10;153880:63;;;;;-1:-1:-1;;;153880:63:0;;;;;;;;;;;153983:11;:18;;;154002:1;153983:21;;;;;;;;;;;;;;153962:10;:17;;;:42;154006:10;153954:63;;;;;-1:-1:-1;;;153954:63:0;;;;;;;;;;;154100:11;:18;;;154119:2;154100:22;;;;;;;;;;;;;;154078:11;:18;;;:44;154124:10;154070:65;;;;;-1:-1:-1;;;154070:65:0;;;;;;;;;;;154176:11;:18;;;154195:2;154176:22;;;;;;;;;;;;;;154154:11;:18;;;:44;154200:10;154146:65;;;;;-1:-1:-1;;;154146:65:0;;;;;;;;;;;154252:11;:18;;;154271:2;154252:22;;;;;;;;;;;;;;154230:11;:18;;;:44;154276:10;154222:65;;;;;-1:-1:-1;;;154222:65:0;;;;;;;;;;;154328:11;:18;;;154347:2;154328:22;;;;;;;;;;;;;;154306:11;:18;;;:44;154352:10;154298:65;;;;;-1:-1:-1;;;154298:65:0;;;;;;;;;;;154404:11;:18;;;154423:2;154404:22;;;;;;;;;;;;;;154382:11;:18;;;:44;154428:10;154374:65;;;;;-1:-1:-1;;;154374:65:0;;;;;;;;;;;154480:11;:18;;;154499:2;154480:22;;;;;;;;;;;;;;154458:11;:18;;;:44;154504:10;154450:65;;;;;-1:-1:-1;;;154450:65:0;;;;;;;;;;;154556:11;:18;;;154575:2;154556:22;;;;;;;;;;;;;;154534:11;:18;;;:44;154580:10;154526:65;;;;;-1:-1:-1;;;154526:65:0;;;;;;;;;;;154632:11;:18;;;154651:2;154632:22;;;;;;;;;;;;;;154610:11;:18;;;:44;154656:10;154602:65;;;;;-1:-1:-1;;;154602:65:0;;;;;;;;;;;154708:11;:18;;;154727:2;154708:22;;;;;;;;;;;;;;154686:11;:18;;;:44;154732:10;154678:65;;;;;-1:-1:-1;;;154678:65:0;;;;;;;;;;;154784:11;:18;;;154803:2;154784:22;;;;;;;;;;;;;;154762:11;:18;;;:44;154808:10;154754:65;;;;;-1:-1:-1;;;154754:65:0;;;;;;;;;;;152033:2794;;;;:::o;143752:2228::-;143886:20;;;;:8;:20;;;;;;;;143882:59;;;143923:7;;143882:59;144021:22;;;;-1:-1:-1;;;;;144021:36:0;144017:75;;144074:7;;144017:75;144170:12;144185:42;144207:6;:19;;;144185:6;:17;;;:21;;:42;;;;:::i;:::-;144170:57;-1:-1:-1;144292:9:0;144288:48;;144318:7;;;144288:48;144414:22;;;;144535:8;;:26;;;-1:-1:-1;;;144535:26:0;;;;144389:15;;-1:-1:-1;;;;;144535:8:0;;:24;;:26;;;;;;;;;;;;;;:8;:26;;;5:2:-1;;;;30:1;27;20:12;5:2;144535:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;144535: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;144535:26:0;;;;;;;;;144494:68;;144717:4;144651:8;-1:-1:-1;;;;;144651:18:0;;144670:6;:19;;;144699:12;144651:62;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;144651:62:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;144651:62: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;144651:62:0;;;;;;;;;:70;;144723:35;;;;;;;;;;;;;;;;;144643:116;;;;;-1:-1:-1;;;144643:116:0;;;;;;;;;;-1:-1:-1;144830:19:0;;;;144795:76;;-1:-1:-1;;;144795:76:0;;-1:-1:-1;;;;;144795:24:0;;;;;:76;;144820:8;;144859:4;;144866;;144795:76;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;144795:76:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;144795:76:0;;;;144914:20;144937:8;;;;;;;;;-1:-1:-1;;;;;144937:8:0;-1:-1:-1;;;;;144937:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;144937:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;144937: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;144937:26:0;;;;;;;;;145069:21;;;;144914:49;;-1:-1:-1;;;;;;145069:35:0;;145065:355;;145239:17;;;;145188:21;;;;-1:-1:-1;;;;;145179:31:0;;;;;;;:8;:31;;;;;;;;145211:22;;;;145179:55;;;;;;;;;;:78;;;:59;:78;:::i;:::-;145130:21;;;;-1:-1:-1;;;;;145121:31:0;;;;;;;:8;:31;;;;;;;;145153:22;;;;145121:55;;;;;;;;;:136;145065:355;;;145390:17;;;;-1:-1:-1;;;;;145339:22:0;;;;;;;:8;:22;;;;;;;;145362;;;;145339:46;;;;;;;;;;:69;;;:50;:69;:::i;:::-;-1:-1:-1;;;;;145290:22:0;;;;;;;:8;:22;;;;;;;;145313;;;;145290:46;;;;;;;;;:118;145065:355;145529:23;;;;-1:-1:-1;;;;;145529:37:0;;145525:365;;145705:19;;;;145652:23;;;;-1:-1:-1;;;;;145643:33:0;;;;;;;:8;:33;;;;;;;;145677:22;;;;145643:57;;;;;;;;;;:82;;;:61;:82;:::i;:::-;145592:23;;;;-1:-1:-1;;;;;145583:33:0;;;;;;;:8;:33;;;;;;;;145617:22;;;;145583:57;;;;;;;;;:142;145525:365;;;145858:19;;;;-1:-1:-1;;;;;145807:22:0;;;;;;;:8;:22;;;;;;;;145830;;;;145807:46;;;;;;;;;;:71;;;:50;:71;:::i;:::-;-1:-1:-1;;;;;145758:22:0;;;;;;;:8;:22;;;;;;;;145781;;;;145758:46;;;;;;;;;:120;145525:365;-1:-1:-1;;;145945:20:0;;;;:8;:20;;;;;:27;;-1:-1:-1;;145945:27:0;145968:4;145945:27;;;-1:-1:-1;143752:2228:0;;:::o;155123:1586::-;155340:17;;;;155410:8;;:26;;;-1:-1:-1;;;155410:26:0;;;;155312:18;;-1:-1:-1;;;;;155410:8:0;;:24;;:26;;;;;;;;;;;;;;:8;:26;;;5:2:-1;;;;30:1;27;20:12;5:2;155410:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;155410: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;155410:26:0;;;;;;;;;155518:10;;155369:68;;-1:-1:-1;155518:15:0;155514:408;;155675:25;155690:9;155675:7;155683:1;155675:10;;;;;;:25;:14;:25;:::i;:::-;155624:23;;;;155602:69;;-1:-1:-1;;;155602:69:0;;-1:-1:-1;;;;;155602:21:0;;;;;:69;;155624:23;155657:12;;155602:69;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;155602:69:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;155602:69: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;155602:69:0;;;;;;;;;:98;;155594:142;;;;-1:-1:-1;;;155594:142:0;;;;;;;;;155806:12;-1:-1:-1;;;;;155806:24:0;;155831:11;155844:10;:23;;;155877:4;155884:25;155899:9;155884:7;155892:1;155884:10;;;;;;:25;155806:104;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;155806:104:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;155806:104:0;;;;155514:408;156011:10;;;;:15;156007:421;;156179:25;156194:9;156179:7;156187:1;156179:10;;:25;156127:24;;;;156105:70;;-1:-1:-1;;;156105:70:0;;-1:-1:-1;;;;;156105:21:0;;;;;:70;;156127:24;156161:12;;156105:70;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;156105:70:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;156105: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;156105:70:0;;;;;;;;;:99;;156097:143;;;;-1:-1:-1;;;156097:143:0;;;;;;;;;156311:12;-1:-1:-1;;;;;156311:24:0;;156336:11;156349;:24;;;156383:4;156390:25;156405:9;156390:7;156398:1;156390:10;;;;;;:25;156311:105;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;156311:105:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;156311:105:0;;;;156007:421;156459:10;;;;156444:26;;156459:7;156452:1;156444:10;;;;;;:26;:14;:26;:::i;:::-;:31;156440:262;;-1:-1:-1;;;;;156563:19:0;;;156591:12;156606:41;156637:9;156606:26;156621:7;156629:1;156621:10;;;;156606:7;156614:1;156606:10;;:26;:30;:41;:30;:41;:::i;:::-;156563:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;156563:85:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;156563: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;156563:85:0;;;;;;;;;156555:135;;;;-1:-1:-1;;;156555:135:0;;;;;;;;;155123:1586;;;;;;;:::o;15593:1114::-;16197:27;16205:5;-1:-1:-1;;;;;16197:25:0;;:27::i;:::-;16189:71;;;;-1:-1:-1;;;16189:71:0;;;;;;;;;16334:12;16348:23;16383:5;-1:-1:-1;;;;;16375:19:0;16395:4;16375: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;;16333:67:0;;;;16419:7;16411:52;;;;-1:-1:-1;;;16411:52:0;;;;;;;;;16480:17;;:21;16476:224;;16622:10;16611:30;;;;;;;;;;;;;;16603:85;;;;-1:-1:-1;;;16603:85:0;;;;;;;;138112:356;138218:4;138243:10;:17;138264:2;138243:23;138235:66;;;;-1:-1:-1;;;138235:66:0;;;;;;;;;138314:14;138331:24;138349:5;138331:17;:24::i;:::-;138314:41;;138366:17;138386:35;138402:6;138410:10;138386:15;:35::i;:::-;-1:-1:-1;;;;;138439:21:0;;;;;;;-1:-1:-1;;;138112:356:0;;;;;;:::o;5607:136::-;5665:7;5692:43;5696:1;5699;5692:43;;;;;;;;;;;;;;;;;:3;:43::i;:::-;5685:50;;5607:136;;;;;:::o;146167:112::-;146227:7;146259:2;146254;:7;:17;;146269:2;146254:17;;;-1:-1:-1;146264:2:0;;146167:112;-1:-1:-1;146167:112:0:o;5151:181::-;5209:7;5241:5;;;5265:6;;;;5257:46;;;;-1:-1:-1;;;5257:46:0;;;;;;;;6523:471;6581:7;6826:6;6822:47;;-1:-1:-1;6856:1:0;6849:8;;6822:47;6893:5;;;6897:1;6893;:5;:1;6917:5;;;;;:10;6909:56;;;;-1:-1:-1;;;6909:56:0;;;;;;;;10384:810;10444:4;11103:20;;10946:66;11143:15;;;;;:42;;;11174:11;11162:8;:23;;11143:42;11135:51;10384:810;-1:-1:-1;;;;10384:810:0:o;131881:707::-;131951:14;132004:16;132118:2;132112:9;-1:-1:-1;;;132137:82:0;;132270:1;132258:14;;132251:39;;;;132388:2;132376:15;;132369:35;;;;132543:2;132525:21;;;131881:707::o;138690:1001::-;139155:2;139139:19;;139133:26;139200:2;139184:19;;139178:26;139253:2;139237:19;;139231:26;138777:7;;139133:26;139178;139223:35;;139381:2;139377:6;;139373:46;;;139405:2;139400:7;139373:46;139499:1;:7;;139504:2;139499:7;;:18;;;;;139510:1;:7;;139515:2;139510:7;;139499:18;139495:189;;;139550:1;139534:19;;;;;;;139495:189;139647:25;139657:5;139664:1;139667;139670;139647:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;139647:25:0;;;;;;;;139640:32;;;;;;;139495:189;138690:1001;;;;;;;:::o;6080:192::-;6166:7;6202:12;6194:6;;;;6186:29;;;;-1:-1:-1;;;6186:29:0;;;;;;;;;;-1:-1:-1;;;6238:5:0;;;6080:192::o;146530:10182::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;146530:10182:0;;;-1:-1:-1;;146530:10182:0:o;5:130:-1:-;72:20;;97:33;72:20;97:33;;142:134;220:13;;238:33;220:13;238:33;;301:699;;414:3;407:4;399:6;395:17;391:27;381:2;;432:1;429;422:12;381:2;469:6;456:20;491:76;506:60;559:6;506:60;;;491:76;;;482:85;;584:5;609:6;602:5;595:21;639:4;631:6;627:17;617:27;;661:4;656:3;652:14;645:21;;714:6;761:3;753:4;745:6;741:17;736:3;732:27;729:36;726:2;;;778:1;775;768:12;726:2;803:1;788:206;813:6;810:1;807:13;788:206;;;871:3;893:37;926:3;914:10;893:37;;;881:50;;-1:-1;954:4;945:14;;;;973;;;;;835:1;828:9;788:206;;;792:14;374:626;;;;;;;;1008:128;1083:13;;1101:30;1083:13;1101:30;;1143:130;1210:20;;1235:33;1210:20;1235:33;;1281:432;;1378:3;1371:4;1363:6;1359:17;1355:27;1345:2;;1396:1;1393;1386:12;1345:2;1433:6;1420:20;1455:60;1470:44;1507:6;1470:44;;1455:60;1446:69;;1535:6;1528:5;1521:21;1571:4;1563:6;1559:17;1604:4;1597:5;1593:16;1639:3;1630:6;1625:3;1621:16;1618:25;1615:2;;;1656:1;1653;1646:12;1615:2;1666:41;1700:6;1695:3;1690;1666:41;;1721:158;1802:20;;1827:47;1802:20;1827:47;;1924:1172;;2039:4;2027:9;2022:3;2018:19;2014:30;2011:2;;;2057:1;2054;2047:12;2011:2;2075:20;2090:4;2075:20;;;2066:29;-1:-1;2147:1;2179:49;2224:3;2204:9;2179:49;;;2154:75;;-1:-1;2293:2;2326:49;2371:3;2347:22;;;2326:49;;;2319:4;2312:5;2308:16;2301:75;2250:137;2467:2;2456:9;2452:18;2439:32;2491:18;2483:6;2480:30;2477:2;;;2523:1;2520;2513:12;2477:2;2558:70;2624:3;2615:6;2604:9;2600:22;2558:70;;;2551:4;2544:5;2540:16;2533:96;2397:243;2694:2;2727:49;2772:3;2763:6;2752:9;2748:22;2727:49;;;2720:4;2713:5;2709:16;2702:75;2650:138;2839:3;2873:49;2918:3;2909:6;2898:9;2894:22;2873:49;;;2866:4;2859:5;2855:16;2848:75;2798:136;2991:3;3025:49;3070:3;3061:6;3050:9;3046:22;3025:49;;;3018:4;3011:5;3007:16;3000:75;2944:142;2005:1091;;;;;3147:4206;;3267:6;3255:9;3250:3;3246:19;3242:32;3239:2;;;3287:1;3284;3277:12;3239:2;3305:22;3320:6;3305:22;;;3296:31;-1:-1;3384:1;3416:49;3461:3;3441:9;3416:49;;;3391:75;;-1:-1;3531:2;3564:49;3609:3;3585:22;;;3564:49;;;3557:4;3550:5;3546:16;3539:75;3487:138;3676:2;3709:49;3754:3;3745:6;3734:9;3730:22;3709:49;;;3702:4;3695:5;3691:16;3684:75;3635:135;3828:2;3861:49;3906:3;3897:6;3886:9;3882:22;3861:49;;;3854:4;3847:5;3843:16;3836:75;3780:142;3980:3;4014:49;4059:3;4050:6;4039:9;4035:22;4014:49;;;4007:4;4000:5;3996:16;3989:75;3932:143;4134:3;4168:49;4213:3;4204:6;4193:9;4189:22;4168:49;;;4161:4;4154:5;4150:16;4143:75;4085:144;4289:3;4323:49;4368:3;4359:6;4348:9;4344:22;4323:49;;;4316:4;4309:5;4305:16;4298:75;4239:145;4446:3;4480:49;4525:3;4516:6;4505:9;4501:22;4480:49;;;4473:4;4466:5;4462:16;4455:75;4394:147;4602:3;4638:49;4683:3;4674:6;4663:9;4659:22;4638:49;;;4629:6;4622:5;4618:18;4611:77;4551:148;4752:3;4788:49;4833:3;4824:6;4813:9;4809:22;4788:49;;;4779:6;4772:5;4768:18;4761:77;4709:140;4903:3;4939:49;4984:3;4975:6;4964:9;4960:22;4939:49;;;4930:6;4923:5;4919:18;4912:77;4859:141;5057:3;5093:49;5138:3;5129:6;5118:9;5114:22;5093:49;;;5084:6;5077:5;5073:18;5066:77;5010:144;5206:3;5242:49;5287:3;5278:6;5267:9;5263:22;5242:49;;;5233:6;5226:5;5222:18;5215:77;5164:139;5355:3;5391:49;5436:3;5427:6;5416:9;5412:22;5391:49;;;5382:6;5375:5;5371:18;5364:77;5313:139;5504:3;5540:49;5585:3;5576:6;5565:9;5561:22;5540:49;;;5531:6;5524:5;5520:18;5513:77;5462:139;5653:3;5689:49;5734:3;5725:6;5714:9;5710:22;5689:49;;;5680:6;5673:5;5669:18;5662:77;5611:139;5802:3;5838:49;5883:3;5874:6;5863:9;5859:22;5838:49;;;5829:6;5822:5;5818:18;5811:77;5760:139;5951:3;5987:49;6032:3;6023:6;6012:9;6008:22;5987:49;;;5978:6;5971:5;5967:18;5960:77;5909:139;6100:3;6136:49;6181:3;6172:6;6161:9;6157:22;6136:49;;;6127:6;6120:5;6116:18;6109:77;6058:139;6249:3;6285:49;6330:3;6321:6;6310:9;6306:22;6285:49;;;6276:6;6269:5;6265:18;6258:77;6207:139;6398:3;6434:49;6479:3;6470:6;6459:9;6455:22;6434:49;;;6425:6;6418:5;6414:18;6407:77;6356:139;6547:3;6583:49;6628:3;6619:6;6608:9;6604:22;6583:49;;;6574:6;6567:5;6563:18;6556:77;6505:139;6700:3;6736:49;6781:3;6772:6;6761:9;6757:22;6736:49;;;6727:6;6720:5;6716:18;6709:77;6654:143;6855:3;6891:49;6936:3;6927:6;6916:9;6912:22;6891:49;;;6882:6;6875:5;6871:18;6864:77;6807:145;7003:3;7039:49;7084:3;7075:6;7064:9;7060:22;7039:49;;;7030:6;7023:5;7019:18;7012:77;6962:138;7183:3;7172:9;7168:19;7155:33;7208:18;7200:6;7197:30;7194:2;;;7240:1;7237;7230:12;7194:2;7277:54;7327:3;7318:6;7307:9;7303:22;7277:54;;;7268:6;7261:5;7257:18;7250:82;7110:233;3233:4120;;;;;7497:134;7575:13;;7593:33;7575:13;7593:33;;7638:263;;7753:2;7741:9;7732:7;7728:23;7724:32;7721:2;;;7769:1;7766;7759:12;7721:2;7804:1;7821:64;7877:7;7857:9;7821:64;;7908:366;;;8029:2;8017:9;8008:7;8004:23;8000:32;7997:2;;;8045:1;8042;8035:12;7997:2;8080:1;8097:53;8142:7;8122:9;8097:53;;;8087:63;;8059:97;8187:2;8205:53;8250:7;8241:6;8230:9;8226:22;8205:53;;;8195:63;;8166:98;7991:283;;;;;;8281:257;;8393:2;8381:9;8372:7;8368:23;8364:32;8361:2;;;8409:1;8406;8399:12;8361:2;8444:1;8461:61;8514:7;8494:9;8461:61;;8545:241;;8649:2;8637:9;8628:7;8624:23;8620:32;8617:2;;;8665:1;8662;8655:12;8617:2;8700:1;8717:53;8762:7;8742:9;8717:53;;8793:269;;8911:2;8899:9;8890:7;8886:23;8882:32;8879:2;;;8927:1;8924;8917:12;8879:2;8962:1;8979:67;9038:7;9018:9;8979:67;;9069:379;;9199:2;9187:9;9178:7;9174:23;9170:32;9167:2;;;9215:1;9212;9205:12;9167:2;9250:31;;9301:18;9290:30;;9287:2;;;9333:1;9330;9323:12;9287:2;9353:79;9424:7;9415:6;9404:9;9400:22;9353:79;;9455:389;;9590:2;9578:9;9569:7;9565:23;9561:32;9558:2;;;9606:1;9603;9596:12;9558:2;9641:31;;9692:18;9681:30;;9678:2;;;9724:1;9721;9714:12;9678:2;9744:84;9820:7;9811:6;9800:9;9796:22;9744:84;;9851:925;;;;10077:2;10065:9;10056:7;10052:23;10048:32;10045:2;;;10093:1;10090;10083:12;10045:2;10128:31;;10179:18;10168:30;;10165:2;;;10211:1;10208;10201:12;10165:2;10231:84;10307:7;10298:6;10287:9;10283:22;10231:84;;;10221:94;;10107:214;10380:2;10369:9;10365:18;10352:32;10404:18;10396:6;10393:30;10390:2;;;10436:1;10433;10426:12;10390:2;10456:84;10532:7;10523:6;10512:9;10508:22;10456:84;;;10446:94;;10331:215;10605:2;10594:9;10590:18;10577:32;10629:18;10621:6;10618:30;10615:2;;;10661:1;10658;10651:12;10615:2;10681:79;10752:7;10743:6;10732:9;10728:22;10681:79;;;10671:89;;10556:210;10039:737;;;;;;10783:263;;10898:2;10886:9;10877:7;10873:23;10869:32;10866:2;;;10914:1;10911;10904:12;10866:2;10949:1;10966:64;11022:7;11002:9;10966:64;;11053:399;;;11185:2;11173:9;11164:7;11160:23;11156:32;11153:2;;;11201:1;11198;11191:12;11153:2;11236:1;11253:64;11309:7;11289:9;11253:64;;;11243:74;;11215:108;11354:2;11372:64;11428:7;11419:6;11408:9;11404:22;11372:64;;11460:173;;11547:46;11589:3;11581:6;11547:46;;;-1:-1;;11622:4;11613:14;;11540:93;11642:173;;11729:46;11771:3;11763:6;11729:46;;12021:103;12094:24;12112:5;12094:24;;;12089:3;12082:37;12076:48;;;12251:152;12352:45;12372:24;12390:5;12372:24;;;12352:45;;12443:660;12576:52;12622:5;12576:52;;;12641:84;12718:6;12713:3;12641:84;;;12634:91;;12746:54;12794:5;12746:54;;;12820:7;12848:1;12833:258;12858:6;12855:1;12852:13;12833:258;;;12925:6;12919:13;12946:63;13005:3;12990:13;12946:63;;;12939:70;;13026:58;13077:6;13026:58;;;13016:68;-1:-1;;12880:1;12873:9;12833:258;;;12837:14;12555:548;;;;;;13142:654;;13273:50;13317:5;13273:50;;;13336:76;13405:6;13400:3;13336:76;;;13329:83;;13433:52;13479:5;13433:52;;;13505:7;13533:1;13518:256;13543:6;13540:1;13537:13;13518:256;;;13610:6;13604:13;13631:63;13690:3;13675:13;13631:63;;;13624:70;;13711:56;13760:6;13711:56;;;13701:66;-1:-1;;13565:1;13558:9;13518:256;;;-1:-1;13787:3;;13252:544;-1:-1;;;;;13252:544;13835:718;;13994:50;14038:5;13994:50;;;14057:104;14154:6;14149:3;14057:104;;;14050:111;;14182:52;14228:5;14182:52;;;14254:7;14282:1;14267:264;14292:6;14289:1;14286:13;14267:264;;;14359:6;14353:13;14380:71;14447:3;14432:13;14380:71;;;14373:78;;14468:56;14517:6;14468:56;;;14458:66;-1:-1;;14314:1;14307:9;14267:264;;14561:104;14638:21;14653:5;14638:21;;14672:113;14755:24;14773:5;14755:24;;14792:152;14893:45;14913:24;14931:5;14913:24;;;14893:45;;14951:356;;15079:38;15111:5;15079:38;;;15129:88;15210:6;15205:3;15129:88;;;15122:95;;15222:52;15267:6;15262:3;15255:4;15248:5;15244:16;15222:52;;;15286:16;;;;;15059:248;-1:-1;;15059:248;15314:154;15411:51;15456:5;15411:51;;15475:347;;15587:39;15620:5;15587:39;;;15638:71;15702:6;15697:3;15638:71;;;15631:78;;15714:52;15759:6;15754:3;15747:4;15740:5;15736:16;15714:52;;;15787:29;15809:6;15787:29;;;15778:39;;;;15567:255;-1:-1;;;15567:255;16176:351;;16354:85;16436:2;16431:3;16354:85;;;-1:-1;;;16452:38;;16518:2;16509:12;;16340:187;-1:-1;;16340:187;16536:318;;16696:67;16760:2;16755:3;16696:67;;;-1:-1;;;16776:41;;16845:2;16836:12;;16682:172;-1:-1;;16682:172;16863:330;;17023:67;17087:2;17082:3;17023:67;;;17123:32;17103:53;;17184:2;17175:12;;17009:184;-1:-1;;17009:184;17202:353;;17380:85;17462:2;17457:3;17380:85;;;-1:-1;;;17478:40;;17546:2;17537:12;;17366:189;-1:-1;;17366:189;17564:358;;17742:85;17824:2;17819:3;17742:85;;;-1:-1;;;17840:45;;17913:2;17904:12;;17728:194;-1:-1;;17728:194;17931:351;;18109:85;18191:2;18186:3;18109:85;;;-1:-1;;;18207:38;;18273:2;18264:12;;18095:187;-1:-1;;18095:187;18291:357;;18469:85;18551:2;18546:3;18469:85;;;-1:-1;;;18567:44;;18639:2;18630:12;;18455:193;-1:-1;;18455:193;18657:340;;18835:84;18917:1;18912:3;18835:84;;;-1:-1;;;18932:29;;18989:1;18980:11;;18821:176;-1:-1;;18821:176;19006:318;;19166:67;19230:2;19225:3;19166:67;;;-1:-1;;;19246:41;;19315:2;19306:12;;19152:172;-1:-1;;19152:172;19333:351;;19511:85;19593:2;19588:3;19511:85;;;-1:-1;;;19609:38;;19675:2;19666:12;;19497:187;-1:-1;;19497:187;19693:327;;19853:67;19917:2;19912:3;19853:67;;;19953:29;19933:50;;20011:2;20002:12;;19839:181;-1:-1;;19839:181;20029:357;;20207:85;20289:2;20284:3;20207:85;;;-1:-1;;;20305:44;;20377:2;20368:12;;20193:193;-1:-1;;20193:193;20395:332;;20555:67;20619:2;20614:3;20555:67;;;20655:34;20635:55;;20718:2;20709:12;;20541:186;-1:-1;;20541:186;20736:349;;20914:85;20996:2;20991:3;20914:85;;;-1:-1;;;21012:36;;21076:2;21067:12;;20900:185;-1:-1;;20900:185;21094:335;;21272:84;21354:1;21349:3;21272:84;;;-1:-1;;;21369:24;;21421:1;21412:11;;21258:171;-1:-1;;21258:171;21438:360;;21616:85;21698:2;21693:3;21616:85;;;21734:26;21714:47;;21789:2;21780:12;;21602:196;-1:-1;;21602:196;21807:351;;21985:85;22067:2;22062:3;21985:85;;;-1:-1;;;22083:38;;22149:2;22140:12;;21971:187;-1:-1;;21971:187;22167:352;;22345:85;22427:2;22422:3;22345:85;;;-1:-1;;;22443:39;;22510:2;22501:12;;22331:188;-1:-1;;22331:188;22528:351;;22706:85;22788:2;22783:3;22706:85;;;-1:-1;;;22804:38;;22870:2;22861:12;;22692:187;-1:-1;;22692:187;22888:359;;23066:85;23148:2;23143:3;23066:85;;;23184:25;23164:46;;23238:2;23229:12;;23052:195;-1:-1;;23052:195;23256:361;;23434:85;23516:2;23511:3;23434:85;;;23552:27;23532:48;;23608:2;23599:12;;23420:197;-1:-1;;23420:197;23626:331;;23786:67;23850:2;23845:3;23786:67;;;23886:33;23866:54;;23948:2;23939:12;;23772:185;-1:-1;;23772:185;23966:351;;24144:85;24226:2;24221:3;24144:85;;;-1:-1;;;24242:38;;24308:2;24299:12;;24130:187;-1:-1;;24130:187;24326:353;;24504:85;24586:2;24581:3;24504:85;;;-1:-1;;;24602:40;;24670:2;24661:12;;24490:189;-1:-1;;24490:189;24688:370;;24848:67;24912:2;24907:3;24848:67;;;24948:34;24928:55;;-1:-1;;;25012:2;25003:12;;24996:25;25049:2;25040:12;;24834:224;-1:-1;;24834:224;25067:376;;25227:67;25291:2;25286:3;25227:67;;;25327:34;25307:55;;-1:-1;;;25391:2;25382:12;;25375:31;25434:2;25425:12;;25213:230;-1:-1;;25213:230;25452:351;;25630:85;25712:2;25707:3;25630:85;;;-1:-1;;;25728:38;;25794:2;25785:12;;25616:187;-1:-1;;25616:187;25812:356;;25990:85;26072:2;26067:3;25990:85;;;-1:-1;;;26088:43;;26159:2;26150:12;;25976:192;-1:-1;;25976:192;26177:318;;26337:67;26401:2;26396:3;26337:67;;;-1:-1;;;26417:41;;26486:2;26477:12;;26323:172;-1:-1;;26323:172;26504:351;;26682:85;26764:2;26759:3;26682:85;;;-1:-1;;;26780:38;;26846:2;26837:12;;26668:187;-1:-1;;26668:187;26864:374;;27024:67;27088:2;27083:3;27024:67;;;27124:34;27104:55;;-1:-1;;;27188:2;27179:12;;27172:29;27229:2;27220:12;;27010:228;-1:-1;;27010:228;27247:351;;27425:85;27507:2;27502:3;27425:85;;;-1:-1;;;27523:38;;27589:2;27580:12;;27411:187;-1:-1;;27411:187;27607:356;;27785:85;27867:2;27862:3;27785:85;;;-1:-1;;;27883:43;;27954:2;27945:12;;27771:192;-1:-1;;27771:192;27972:351;;28150:85;28232:2;28227:3;28150:85;;;-1:-1;;;28248:38;;28314:2;28305:12;;28136:187;-1:-1;;28136:187;28332:328;;28492:67;28556:2;28551:3;28492:67;;;28592:30;28572:51;;28651:2;28642:12;;28478:182;-1:-1;;28478:182;28669:379;;28829:67;28893:2;28888:3;28829:67;;;28929:34;28909:55;;-1:-1;;;28993:2;28984:12;;28977:34;29039:2;29030:12;;28815:233;-1:-1;;28815:233;29057:355;;29235:85;29317:2;29312:3;29235:85;;;-1:-1;;;29333:42;;29403:2;29394:12;;29221:191;-1:-1;;29221:191;29421:331;;29581:67;29645:2;29640:3;29581:67;;;29681:33;29661:54;;29743:2;29734:12;;29567:185;-1:-1;;29567:185;29761:357;;29939:85;30021:2;30016:3;29939:85;;;-1:-1;;;30037:44;;30109:2;30100:12;;29925:193;-1:-1;;29925:193;30127:331;;30287:67;30351:2;30346:3;30287:67;;;30387:33;30367:54;;30449:2;30440:12;;30273:185;-1:-1;;30273:185;30467:350;;30645:85;30727:2;30722:3;30645:85;;;-1:-1;;;30743:37;;30808:2;30799:12;;30631:186;-1:-1;;30631:186;30898:1234;31119:23;;30898:1234;;31051:4;31042:14;;;31148:63;31046:3;31119:23;31148:63;;;31071:146;31293:4;31286:5;31282:16;31276:23;31305:63;31362:4;31357:3;31353:14;31339:12;31305:63;;;31227:147;31449:4;31442:5;31438:16;31432:23;31501:3;31495:4;31491:14;31484:4;31479:3;31475:14;31468:38;31521:99;31615:4;31601:12;31521:99;;;31513:107;;31384:248;31709:4;31702:5;31698:16;31692:23;31721:63;31778:4;31773:3;31769:14;31755:12;31721:63;;;31642:148;31864:4;31857:5;31853:16;31847:23;31876:63;31933:4;31928:3;31924:14;31910:12;31876:63;;;31800:145;32025:4;32018:5;32014:16;32008:23;32037:63;32094:4;32089:3;32085:14;32071:12;32037:63;;;-1:-1;32123:4;31024:1108;-1:-1;;;31024:1108;32646:107;32725:22;32741:5;32725:22;;32760:1495;;33131:75;33202:3;33193:6;33131:75;;;33228:2;33223:3;33219:12;33212:19;;33242:75;33313:3;33304:6;33242:75;;;33339:2;33334:3;33330:12;33323:19;;33353:75;33424:3;33415:6;33353:75;;;33450:2;33445:3;33441:12;33434:19;;33464:75;33535:3;33526:6;33464:75;;;33561:2;33556:3;33552:12;33545:19;;33575:75;33646:3;33637:6;33575:75;;;33672:2;33667:3;33663:12;33656:19;;33686:75;33757:3;33748:6;33686:75;;;33783:2;33778:3;33774:12;33767:19;;33797:75;33868:3;33859:6;33797:75;;;33894:2;33889:3;33885:12;33878:19;;33908:75;33979:3;33970:6;33908:75;;;34005:2;34000:3;33996:12;33989:19;;34019:75;34090:3;34081:6;34019:75;;;34116:2;34111:3;34107:12;34100:19;;34130:75;34201:3;34192:6;34130:75;;;-1:-1;34227:2;34218:12;;33119:1136;-1:-1;;;;;;;;;;33119:1136;34262:262;;34406:93;34495:3;34486:6;34406:93;;34531:890;;34859:93;34948:3;34939:6;34859:93;;;34852:100;;34970:93;35059:3;35050:6;34970:93;;;34963:100;;35081:93;35170:3;35161:6;35081:93;;;35074:100;;35192:93;35281:3;35272:6;35192:93;;;35185:100;;35303:93;35392:3;35383:6;35303:93;;;35296:100;34840:581;-1:-1;;;;;;;34840:581;35428:7314;;38253:148;38397:3;38253:148;;;38246:155;;38419:148;38563:3;38419:148;;;38412:155;;38585:148;38729:3;38585:148;;;38578:155;;38751:148;38895:3;38751:148;;;38744:155;;38917:148;39061:3;38917:148;;;38910:155;;39083:148;39227:3;39083:148;;;39076:155;;39249:148;39393:3;39249:148;;;39242:155;;39415:148;39559:3;39415:148;;;39408:155;;39581:148;39725:3;39581:148;;;39574:155;;39747:148;39891:3;39747:148;;;39740:155;;39913:148;40057:3;39913:148;;;39906:155;;40079:148;40223:3;40079:148;;;40072:155;;40245:148;40389:3;40245:148;;;40238:155;;40411:148;40555:3;40411:148;;;40404:155;;40577:148;40721:3;40577:148;;;40570:155;;40743:148;40887:3;40743:148;;;40736:155;;40909:148;41053:3;40909:148;;;40902:155;;41075:148;41219:3;41075:148;;;41068:155;;41241:148;41385:3;41241:148;;;41234:155;;41407:148;41551:3;41407:148;;;41400:155;;41573:148;41717:3;41573:148;;;41566:155;;41739:148;41883:3;41739:148;;;41732:155;;41905:148;42049:3;41905:148;;;41898:155;;42071:148;42215:3;42071:148;;;42064:155;;42237:148;42381:3;42237:148;;;42230:155;;42403:148;42547:3;42403:148;;;42396:155;;42569:148;42713:3;42569:148;;42749:1013;;43054:75;43125:3;43116:6;43054:75;;;43151:2;43146:3;43142:12;43135:19;;43165:75;43236:3;43227:6;43165:75;;;43262:2;43257:3;43253:12;43246:19;;43283:121;43400:3;43391:6;43283:121;;;43276:128;;43415:75;43486:3;43477:6;43415:75;;;43512:2;43507:3;43503:12;43496:19;;43526:75;43597:3;43588:6;43526:75;;;43623:2;43618:3;43614:12;43607:19;;43637:75;43708:3;43699:6;43637:75;;;-1:-1;43734:2;43725:12;;43042:720;-1:-1;;;;;;43042:720;43769:522;;43944:75;44015:3;44006:6;43944:75;;;44041:2;44036:3;44032:12;44025:19;;44055:75;44126:3;44117:6;44055:75;;;44152:2;44147:3;44143:12;44136:19;;44166:75;44237:3;44228:6;44166:75;;;-1:-1;44263:2;44254:12;;43932:359;-1:-1;;;43932:359;44298:800;;44529:75;44600:3;44591:6;44529:75;;;44626:2;44621:3;44617:12;44610:19;;44640:75;44711:3;44702:6;44640:75;;;44737:2;44732:3;44728:12;44721:19;;44751:75;44822:3;44813:6;44751:75;;;44848:2;44843:3;44839:12;44832:19;;44862:75;44933:3;44924:6;44862:75;;;44959:2;44954:3;44950:12;44943:19;;44973:75;45044:3;45035:6;44973:75;;;-1:-1;45070:2;45061:12;;44517:581;-1:-1;;;;;44517:581;45105:213;45223:2;45208:18;;45237:71;45212:9;45281:6;45237:71;;45325:324;45471:2;45456:18;;45485:71;45460:9;45529:6;45485:71;;;45567:72;45635:2;45624:9;45620:18;45611:6;45567:72;;45656:324;45802:2;45787:18;;45816:71;45791:9;45860:6;45816:71;;;45898:72;45966:2;45955:9;45951:18;45942:6;45898:72;;45987:201;46099:2;46084:18;;46113:65;46088:9;46151:6;46113:65;;46195:213;46313:2;46298:18;;46327:71;46302:9;46371:6;46327:71;;46415:476;46613:2;46598:18;;46627:71;46602:9;46671:6;46627:71;;;46746:9;46740:4;46736:20;46731:2;46720:9;46716:18;46709:48;46771:110;46876:4;46867:6;46771:110;;46898:539;47096:3;47081:19;;47111:71;47085:9;47155:6;47111:71;;;47193:68;47257:2;47246:9;47242:18;47233:6;47193:68;;;47272:72;47340:2;47329:9;47325:18;47316:6;47272:72;;;47355;47423:2;47412:9;47408:18;47399:6;47355:72;;;47067:370;;;;;;;;47444:575;47660:3;47645:19;;47675:85;47649:9;47733:6;47675:85;;;47771:72;47839:2;47828:9;47824:18;47815:6;47771:72;;;47854;47922:2;47911:9;47907:18;47898:6;47854:72;;48026:293;48160:2;48174:47;;;48145:18;;48235:74;48145:18;48295:6;48235:74;;48634:407;48825:2;48839:47;;;48810:18;;48900:131;48810:18;48900:131;;49048:407;49239:2;49253:47;;;49224:18;;49314:131;49224:18;49314:131;;49462:407;49653:2;49667:47;;;49638:18;;49728:131;49638:18;49728:131;;49876:407;50067:2;50081:47;;;50052:18;;50142:131;50052:18;50142:131;;50290:407;50481:2;50495:47;;;50466:18;;50556:131;50466:18;50556:131;;50704:407;50895:2;50909:47;;;50880:18;;50970:131;50880:18;50970:131;;51118:407;51309:2;51323:47;;;51294:18;;51384:131;51294:18;51384:131;;51532:407;51723:2;51737:47;;;51708:18;;51798:131;51708:18;51798:131;;51946:407;52137:2;52151:47;;;52122:18;;52212:131;52122:18;52212:131;;52360:407;52551:2;52565:47;;;52536:18;;52626:131;52536:18;52626:131;;52774:407;52965:2;52979:47;;;52950:18;;53040:131;52950:18;53040:131;;53188:407;53379:2;53393:47;;;53364:18;;53454:131;53364:18;53454:131;;53602:407;53793:2;53807:47;;;53778:18;;53868:131;53778:18;53868:131;;54016:407;54207:2;54221:47;;;54192:18;;54282:131;54192:18;54282:131;;54430:680;54702:3;54717:47;;;54687:19;;54778:110;54687:19;54874:6;54778:110;;;54770:118;;54899:72;54967:2;54956:9;54952:18;54943:6;54899:72;;;54982:118;55096:2;55085:9;55081:18;55072:6;54982:118;;55337:256;55399:2;55393:9;55425:17;;;55500:18;55485:34;;55521:22;;;55482:62;55479:2;;;55557:1;55554;55547:12;55479:2;55573;55566:22;55377:216;;-1:-1;55377:216;55600:300;;55755:18;55747:6;55744:30;55741:2;;;55787:1;55784;55777:12;55741:2;-1:-1;55822:4;55810:17;;;55875:15;;55678:222;55907:317;;56046:18;56038:6;56035:30;56032:2;;;56078:1;56075;56068:12;56032:2;-1:-1;56209:4;56145;56122:17;;;;-1:-1;;56118:33;56199:15;;55969:255;56231:97;56315:3;56301:27;56335:147;56455:4;56446:14;;56403:79;56489:108;-1:-1;56583:4;;56561:36;56604:133;56703:12;;56674:63;57351:140;57482:3;57460:31;-1:-1;57460:31;57500:168;57608:19;;;57657:4;57648:14;;57601:67;58324:91;;58386:24;58404:5;58386:24;;58422:85;58488:13;58481:21;;58464:43;58593:105;;58669:24;58687:5;58669:24;;58705:121;-1:-1;;;;;58767:54;;58750:76;58912:81;58983:4;58972:16;;58955:38;59286:145;59367:6;59362:3;59357;59344:30;-1:-1;59423:1;59405:16;;59398:27;59337:94;59440:268;59505:1;59512:101;59526:6;59523:1;59520:13;59512:101;;;59593:11;;;59587:18;59574:11;;;59567:39;59548:2;59541:10;59512:101;;;59628:6;59625:1;59622:13;59619:2;;;-1:-1;;59693:1;59675:16;;59668:27;59489:219;59716:95;;59780:26;59800:5;59899:89;59963:20;59977:5;59963:20;;60076:97;60164:2;60144:14;-1:-1;;60140:28;;60124:49;60181:94;60255:2;60251:14;;60223:52;60283:117;60352:24;60370:5;60352:24;;;60345:5;60342:35;60332:2;;60391:1;60388;60381:12;60332:2;60326:74;;60407:111;60473:21;60488:5;60473:21;;60525:117;60594:24;60612:5;60594:24;;60649:145;60732:38;60764:5;60732:38;
Swarm Source
bzzr://a2abb4efe867fef9d1260029b16b5e4b8411d67b24e304ebe007220072d8e48e
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.