Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 218 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Exchange LBT2ERC... | 11631499 | 1499 days ago | IN | 0 ETH | 0.09444801 | ||||
Exchange LBT2ERC... | 11631462 | 1499 days ago | IN | 0 ETH | 0.08589794 | ||||
Exchange LBT2ERC... | 11616518 | 1501 days ago | IN | 0 ETH | 0.02982119 | ||||
Exchange LBT2ERC... | 11616510 | 1501 days ago | IN | 0 ETH | 0.0214284 | ||||
Exchange LBT2ERC... | 11615082 | 1501 days ago | IN | 0 ETH | 0.03223469 | ||||
Exchange LBT2ERC... | 11614810 | 1502 days ago | IN | 0 ETH | 0.03657868 | ||||
Exchange LBT2ERC... | 11614802 | 1502 days ago | IN | 0 ETH | 0.03483684 | ||||
Exchange ERC20To... | 11611181 | 1502 days ago | IN | 0 ETH | 0.02946204 | ||||
Exchange ERC20To... | 11610137 | 1502 days ago | IN | 0 ETH | 0.0167103 | ||||
Exchange ERC20To... | 11610135 | 1502 days ago | IN | 0 ETH | 0.01817915 | ||||
Exchange ERC20To... | 11610054 | 1502 days ago | IN | 0 ETH | 0.0233119 | ||||
Exchange ERC20To... | 11610022 | 1502 days ago | IN | 0 ETH | 0.01446163 | ||||
Exchange ERC20To... | 11610016 | 1502 days ago | IN | 0 ETH | 0.0167103 | ||||
Exchange ERC20To... | 11609883 | 1502 days ago | IN | 0 ETH | 0.0124345 | ||||
Exchange ERC20To... | 11608529 | 1502 days ago | IN | 0 ETH | 0.025789 | ||||
Exchange ERC20To... | 11607667 | 1503 days ago | IN | 0 ETH | 0.02215785 | ||||
Exchange LBT2ERC... | 11554422 | 1511 days ago | IN | 0 ETH | 0.02144486 | ||||
Exchange LBT2ERC... | 11553610 | 1511 days ago | IN | 0 ETH | 0.01391018 | ||||
Exchange LBT2ERC... | 11553569 | 1511 days ago | IN | 0 ETH | 0.01429657 | ||||
Exchange LBT2ERC... | 11553559 | 1511 days ago | IN | 0 ETH | 0.0191265 | ||||
Exchange LBT2ERC... | 11553417 | 1511 days ago | IN | 0 ETH | 0.01526256 | ||||
Exchange ERC20To... | 11538719 | 1513 days ago | IN | 0 ETH | 0.00886758 | ||||
Exchange ERC20To... | 11537699 | 1513 days ago | IN | 0 ETH | 0.00847217 | ||||
Exchange ERC20To... | 11537693 | 1513 days ago | IN | 0 ETH | 0.00969216 | ||||
Exchange ERC20To... | 11537692 | 1513 days ago | IN | 0 ETH | 0.00969216 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
DecentralizedOtcCollateralizedUsdc
Compiler Version
v0.6.6+commit.6c089d02
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-11-20 */ // File: contracts/util/TransferETHInterface.sol pragma solidity 0.6.6; interface TransferETHInterface { receive() external payable; event LogTransferETH(address indexed from, address indexed to, uint256 value); } // File: @openzeppelin/contracts/token/ERC20/IERC20.sol pragma solidity ^0.6.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ 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: contracts/bondToken/BondTokenInterface.sol pragma solidity 0.6.6; interface BondTokenInterface is IERC20 { event LogExpire(uint128 rateNumerator, uint128 rateDenominator, bool firstTime); function mint(address account, uint256 amount) external returns (bool success); function expire(uint128 rateNumerator, uint128 rateDenominator) external returns (bool firstTime); function simpleBurn(address account, uint256 amount) external returns (bool success); function burn(uint256 amount) external returns (bool success); function burnAll() external returns (uint256 amount); function getRate() external view returns (uint128 rateNumerator, uint128 rateDenominator); } // File: contracts/oracle/LatestPriceOracleInterface.sol pragma solidity 0.6.6; /** * @dev Interface of the price oracle. */ interface LatestPriceOracleInterface { /** * @dev Returns `true`if oracle is working. */ function isWorking() external returns (bool); /** * @dev Returns the last updated price. Decimals is 8. **/ function latestPrice() external returns (uint256); /** * @dev Returns the timestamp of the last updated price. */ function latestTimestamp() external returns (uint256); } // File: contracts/oracle/PriceOracleInterface.sol pragma solidity 0.6.6; /** * @dev Interface of the price oracle. */ interface PriceOracleInterface is LatestPriceOracleInterface { /** * @dev Returns the latest id. The id start from 1 and increments by 1. */ function latestId() external returns (uint256); /** * @dev Returns the historical price specified by `id`. Decimals is 8. */ function getPrice(uint256 id) external returns (uint256); /** * @dev Returns the timestamp of historical price specified by `id`. */ function getTimestamp(uint256 id) external returns (uint256); } // File: contracts/math/AdvancedMath.sol pragma solidity 0.6.6; abstract contract AdvancedMath { /** * @dev sqrt(2*PI) * 10^8 */ int256 internal constant SQRT_2PI_E8 = 250662827; int256 internal constant PI_E8 = 314159265; int256 internal constant E_E8 = 271828182; int256 internal constant INV_E_E8 = 36787944; // 1/e int256 internal constant LOG2_E8 = 30102999; int256 internal constant LOG3_E8 = 47712125; int256 internal constant p = 23164190; int256 internal constant b1 = 31938153; int256 internal constant b2 = -35656378; int256 internal constant b3 = 178147793; int256 internal constant b4 = -182125597; int256 internal constant b5 = 133027442; /** * @dev Calcurate an approximate value of the square root of x by Babylonian method. */ function _sqrt(int256 x) internal pure returns (int256 y) { require(x >= 0, "cannot calculate the square root of a negative number"); int256 z = (x + 1) / 2; y = x; while (z < y) { y = z; z = (x / z + z) / 2; } } /** * @dev Returns log(x) for any positive x. */ function _logTaylor(int256 inputE4) internal pure returns (int256 outputE4) { require(inputE4 > 1, "input should be positive number"); int256 inputE8 = inputE4 * 10**4; // input x for _logTayler1 is adjusted to 1/e < x < 1. while (inputE8 < INV_E_E8) { inputE8 = (inputE8 * E_E8) / 10**8; outputE4 -= 10**4; } while (inputE8 > 10**8) { inputE8 = (inputE8 * INV_E_E8) / 10**8; outputE4 += 10**4; } outputE4 += _logTaylor1(inputE8 / 10**4 - 10**4); } /**s * @notice Calculate an approximate value of the logarithm of input value by * Taylor expansion around 1. * @dev log(x + 1) = x - 1/2 x^2 + 1/3 x^3 - 1/4 x^4 + 1/5 x^5 * - 1/6 x^6 + 1/7 x^7 - 1/8 x^8 + ... */ function _logTaylor1(int256 inputE4) internal pure returns (int256 outputE4) { outputE4 = inputE4 - inputE4**2 / (2 * 10**4) + inputE4**3 / (3 * 10**8) - inputE4**4 / (4 * 10**12) + inputE4**5 / (5 * 10**16) - inputE4**6 / (6 * 10**20) + inputE4**7 / (7 * 10**24) - inputE4**8 / (8 * 10**28); } /** * @notice Calculate the cumulative distribution function of standard normal * distribution. * @dev Abramowitz and Stegun, Handbook of Mathematical Functions (1964) * http://people.math.sfu.ca/~cbm/aands/ */ function _calcPnorm(int256 inputE4) internal pure returns (int256 outputE8) { require(inputE4 < 440 * 10**4 && inputE4 > -440 * 10**4, "input is too large"); int256 _inputE4 = inputE4 > 0 ? inputE4 : inputE4 * (-1); int256 t = 10**16 / (10**8 + (p * _inputE4) / 10**4); int256 X2 = (inputE4 * inputE4) / 2; int256 exp2X2 = 10**8 + X2 + (X2**2 / (2 * 10**8)) + (X2**3 / (6 * 10**16)) + (X2**4 / (24 * 10**24)) + (X2**5 / (120 * 10**32)) + (X2**6 / (720 * 10**40)); int256 Z = (10**24 / exp2X2) / SQRT_2PI_E8; int256 y = (b5 * t) / 10**8; y = ((y + b4) * t) / 10**8; y = ((y + b3) * t) / 10**8; y = ((y + b2) * t) / 10**8; y = 10**8 - (Z * ((y + b1) * t)) / 10**16; return inputE4 > 0 ? y : 10**8 - y; } } // File: contracts/decentralizedOtc/CallOptionCalculator.sol pragma solidity 0.6.6; contract CallOptionCalculator is AdvancedMath { /** * @dev sqrt(365*86400) * 10^8 */ int256 internal constant SQRT_YEAR_E8 = 561569229926; int256 internal constant MIN_ND1_E8 = 0.0001 * 10**8; int256 internal constant MAX_ND1_E8 = 0.9999 * 10**8; function _calcLbtPrice( int256 etherPriceE4, int256 strikePriceE4, int256 nd1E8, int256 nd2E8 ) public pure returns (int256 lbtPriceE4) { int256 lowestPriceE4 = (etherPriceE4 > strikePriceE4) ? etherPriceE4 - strikePriceE4 : 0; // max(etherPriceE8 - strikePriceE8, 0) lbtPriceE4 = (etherPriceE4 * (nd1E8) - (strikePriceE4 * nd2E8)) / 10**8; // mutable if (lbtPriceE4 < lowestPriceE4) { lbtPriceE4 = lowestPriceE4; // max(lbtPriceE8, lowestPriceE8) } } function _calcLbtLeverage( uint256 etherPriceE4, uint256 lbtPriceE4, int256 nd1E8 ) public pure returns (uint256 lbtLeverageE4) { int256 modifiedNd1E8 = nd1E8 < MIN_ND1_E8 ? MIN_ND1_E8 : nd1E8 > MAX_ND1_E8 ? MAX_ND1_E8 : nd1E8; // clamp(MIN_ND1, nd1E4, MAX_ND1) return lbtPriceE4 != 0 ? (uint256(modifiedNd1E8) * (etherPriceE4)) / (lbtPriceE4) / 10**4 : 100 * 10**4; } /** * @dev * s := v * sqrt(t / (365 * 86400)) * d1 := log(S/K) / s + s / 2 * d2 := d1 - s * price := S * N(d1) - K * N(d2) */ function calcLbtPriceAndLeverage( int256 etherPriceE4, int256 strikePriceE4, int256 ethVolatilityE8, int256 untilMaturity ) public pure returns ( uint256 priceE4, uint256 leverageE4, int256 sigE8 ) { require(etherPriceE4 > 0, "the price of ETH should be positive"); require(ethVolatilityE8 > 0, "the volatility of ETH should be positive"); require(strikePriceE4 > 0, "the strike price should be positive"); require(untilMaturity >= 0, "LBT should not have expired"); require(untilMaturity <= 12 weeks, "the maturity of LBT should not be so distant"); int256 nd1E8; { int256 spotPerStrikeE4 = (etherPriceE4 * (10**4)) / strikePriceE4; sigE8 = (ethVolatilityE8 * (_sqrt(untilMaturity)) * (10**8)) / (SQRT_YEAR_E8); int256 logSigE4 = _logTaylor(spotPerStrikeE4); int256 d1E4 = ((logSigE4 * 10**8) / sigE8) + (sigE8 / (2 * 10**4)); nd1E8 = _calcPnorm(d1E4); int256 d2E4 = d1E4 - (sigE8 / 10**4); int256 nd2E8 = _calcPnorm(d2E4); if (nd1E8 > 0.0001 * 10**8 && nd2E8 > 0.0001 * 10**8) { int256 lbtPriceE4 = _calcLbtPrice(etherPriceE4, strikePriceE4, nd1E8, nd2E8); priceE4 = uint256(lbtPriceE4); } } leverageE4 = _calcLbtLeverage(uint256(etherPriceE4), priceE4, nd1E8); return (priceE4, leverageE4, sigE8); } } // File: contracts/util/TransferETH.sol pragma solidity 0.6.6; abstract contract TransferETH is TransferETHInterface { receive() external override payable { emit LogTransferETH(msg.sender, address(this), msg.value); } function _hasSufficientBalance(uint256 amount) internal view returns (bool ok) { address thisContract = address(this); return amount <= thisContract.balance; } /** * @notice transfer `amount` ETH to the `recipient` account with emitting log */ function _transferETH( address payable recipient, uint256 amount, string memory errorMessage ) internal { require(_hasSufficientBalance(amount), errorMessage); (bool success, ) = recipient.call{value: amount}(""); require(success, "transferring Ether failed"); emit LogTransferETH(address(this), recipient, amount); } function _transferETH(address payable recipient, uint256 amount) internal { _transferETH(recipient, amount, "TransferETH: transfer amount exceeds balance"); } } // File: @openzeppelin/contracts/math/SafeMath.sol pragma solidity ^0.6.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. */ 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. */ 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. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File: @openzeppelin/contracts/math/SignedSafeMath.sol pragma solidity ^0.6.0; /** * @title SignedSafeMath * @dev Signed math operations with safety checks that revert on error. */ library SignedSafeMath { int256 constant private _INT256_MIN = -2**255; /** * @dev Multiplies two signed integers, reverts on overflow. */ function mul(int256 a, int256 b) internal pure returns (int256) { // 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; } require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow"); int256 c = a * b; require(c / a == b, "SignedSafeMath: multiplication overflow"); return c; } /** * @dev Integer division of two signed integers truncating the quotient, reverts on division by zero. */ function div(int256 a, int256 b) internal pure returns (int256) { require(b != 0, "SignedSafeMath: division by zero"); require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow"); int256 c = a / b; return c; } /** * @dev Subtracts two signed integers, reverts on overflow. */ function sub(int256 a, int256 b) internal pure returns (int256) { int256 c = a - b; require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow"); return c; } /** * @dev Adds two signed integers, reverts on overflow. */ function add(int256 a, int256 b) internal pure returns (int256) { int256 c = a + b; require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow"); return c; } } // File: @openzeppelin/contracts/utils/SafeCast.sol pragma solidity ^0.6.0; /** * @dev Wrappers over Solidity's uintXX casting operators with added overflow * checks. * * Downcasting from uint256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such 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. * * Can be combined with {SafeMath} to extend it to smaller types, by performing * all math on `uint256` and then downcasting. */ library SafeCast { /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits. */ function toUint8(uint256 value) internal pure returns (uint8) { require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { require(value < 2**255, "SafeCast: value doesn't fit in an int256"); return int256(value); } } // File: contracts/math/UseSafeMath.sol pragma solidity ^0.6.0; /** * @notice ((a - 1) / b) + 1 = (a + b -1) / b * for example a.add(10**18 -1).div(10**18) = a.sub(1).div(10**18) + 1 */ library SafeMathDivRoundUp { using SafeMath for uint256; function divRoundUp( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { if (a == 0) { return 0; } require(b > 0, errorMessage); return ((a - 1) / b) + 1; } function divRoundUp(uint256 a, uint256 b) internal pure returns (uint256) { return divRoundUp(a, b, "SafeMathDivRoundUp: modulo by zero"); } } /** * @title UseSafeMath * @dev One can use SafeMath for not only uint256 but also uin64 or uint16, * and also can use SafeCast for uint256. * For example: * uint64 a = 1; * uint64 b = 2; * a = a.add(b).toUint64() // `a` become 3 as uint64 * In addition, one can use SignedSafeMath and SafeCast.toUint256(int256) for int256. * In the case of the operation to the uint64 value, one needs to cast the value into int256 in * advance to use `sub` as SignedSafeMath.sub not SafeMath.sub. * For example: * int256 a = 1; * uint64 b = 2; * int256 c = 3; * a = a.add(int256(b).sub(c)); // `a` becomes 0 as int256 * b = a.toUint256().toUint64(); // `b` becomes 0 as uint64 */ abstract contract UseSafeMath { using SafeMath for uint256; using SafeMathDivRoundUp for uint256; using SafeMath for uint64; using SafeMathDivRoundUp for uint64; using SafeMath for uint16; using SignedSafeMath for int256; using SafeCast for uint256; using SafeCast for int256; } // File: contracts/bondMaker/BondMakerInterface.sol pragma solidity 0.6.6; interface BondMakerInterface { event LogNewBond( bytes32 indexed bondID, address indexed bondTokenAddress, uint256 indexed maturity, bytes32 fnMapID ); event LogNewBondGroup( uint256 indexed bondGroupID, uint256 indexed maturity, uint64 indexed sbtStrikePrice, bytes32[] bondIDs ); event LogIssueNewBonds(uint256 indexed bondGroupID, address indexed issuer, uint256 amount); event LogReverseBondGroupToCollateral( uint256 indexed bondGroupID, address indexed owner, uint256 amount ); event LogExchangeEquivalentBonds( address indexed owner, uint256 indexed inputBondGroupID, uint256 indexed outputBondGroupID, uint256 amount ); event LogLiquidateBond(bytes32 indexed bondID, uint128 rateNumerator, uint128 rateDenominator); function registerNewBond(uint256 maturity, bytes calldata fnMap) external returns ( bytes32 bondID, address bondTokenAddress, bytes32 fnMapID ); function registerNewBondGroup(bytes32[] calldata bondIDList, uint256 maturity) external returns (uint256 bondGroupID); function reverseBondGroupToCollateral(uint256 bondGroupID, uint256 amount) external returns (bool success); function exchangeEquivalentBonds( uint256 inputBondGroupID, uint256 outputBondGroupID, uint256 amount, bytes32[] calldata exceptionBonds ) external returns (bool); function liquidateBond(uint256 bondGroupID, uint256 oracleHintID) external returns (uint256 totalPayment); function collateralAddress() external view returns (address); function oracleAddress() external view returns (address); function feeTaker() external view returns (address); function decimalsOfBond() external view returns (uint8); function decimalsOfOraclePrice() external view returns (uint8); function maturityScale() external view returns (uint256); function getBond(bytes32 bondID) external view returns ( address bondAddress, uint256 maturity, uint64 solidStrikePrice, bytes32 fnMapID ); function getFnMap(bytes32 fnMapID) external view returns (bytes memory fnMap); function getBondGroup(uint256 bondGroupID) external view returns (bytes32[] memory bondIDs, uint256 maturity); function generateFnMapID(bytes calldata fnMap) external view returns (bytes32 fnMapID); function generateBondID(uint256 maturity, bytes calldata fnMap) external view returns (bytes32 bondID); } // File: contracts/bondMaker/BondMakerCollateralizedErc20Interface.sol pragma solidity 0.6.6; interface BondMakerCollateralizedErc20Interface is BondMakerInterface { function issueNewBonds(uint256 bondGroupID) external returns (uint256 amount); } // File: contracts/util/Time.sol pragma solidity 0.6.6; abstract contract Time { function _getBlockTimestampSec() internal view returns (uint256 unixtimesec) { unixtimesec = now; // solium-disable-line security/no-block-members } } // File: @openzeppelin/contracts/GSN/Context.sol pragma solidity ^0.6.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract Context { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. constructor () internal { } function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } // File: @openzeppelin/contracts/utils/Address.sol pragma solidity ^0.6.2; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is 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. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // 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 != accountHash && codehash != 0x0); } /** * @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]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } } // File: @openzeppelin/contracts/token/ERC20/ERC20.sol pragma solidity ^0.6.0; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20MinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; using Address for address; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor (string memory name, string memory symbol) public { _name = name; _symbol = symbol; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } } // File: @openzeppelin/contracts/access/Ownable.sol pragma solidity ^0.6.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_owner == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } // File: contracts/bondToken/BondToken.sol pragma solidity 0.6.6; abstract contract BondToken is Ownable, BondTokenInterface, ERC20 { struct Frac128x128 { uint128 numerator; uint128 denominator; } Frac128x128 internal _rate; constructor( string memory name, string memory symbol, uint8 decimals ) public ERC20(name, symbol) { _setupDecimals(decimals); } function mint(address account, uint256 amount) public virtual override onlyOwner returns (bool success) { require(!_isExpired(), "this token contract has expired"); _mint(account, amount); return true; } function transfer(address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool success) { _transfer(msg.sender, recipient, amount); return true; } function transferFrom( address sender, address recipient, uint256 amount ) public override(ERC20, IERC20) returns (bool success) { _transfer(sender, recipient, amount); _approve( sender, msg.sender, allowance(sender, msg.sender).sub(amount, "ERC20: transfer amount exceeds allowance") ); return true; } /** * @dev Record the settlement price at maturity in the form of a fraction and let the bond * token expire. */ function expire(uint128 rateNumerator, uint128 rateDenominator) public override onlyOwner returns (bool isFirstTime) { isFirstTime = !_isExpired(); if (isFirstTime) { _setRate(Frac128x128(rateNumerator, rateDenominator)); } emit LogExpire(rateNumerator, rateDenominator, isFirstTime); } function simpleBurn(address from, uint256 amount) public override onlyOwner returns (bool) { if (amount > balanceOf(from)) { return false; } _burn(from, amount); return true; } function burn(uint256 amount) public override returns (bool success) { if (!_isExpired()) { return false; } _burn(msg.sender, amount); if (_rate.numerator != 0) { uint8 decimalsOfCollateral = _getCollateralDecimals(); uint256 withdrawAmount = _applyDecimalGap(amount, decimals(), decimalsOfCollateral) .mul(_rate.numerator) .div(_rate.denominator); _sendCollateralTo(msg.sender, withdrawAmount); } return true; } function burnAll() public override returns (uint256 amount) { amount = balanceOf(msg.sender); bool success = burn(amount); if (!success) { amount = 0; } } /** * @dev rateDenominator never be zero due to div() function, thus initial _rateDenominator is 0 * can be used for flag of non-expired; */ function _isExpired() internal view returns (bool) { return _rate.denominator != 0; } function getRate() public override view returns (uint128 rateNumerator, uint128 rateDenominator) { rateNumerator = _rate.numerator; rateDenominator = _rate.denominator; } function _setRate(Frac128x128 memory rate) internal { require( rate.denominator != 0, "system error: the exchange rate must be non-negative number" ); _rate = rate; } /** * @dev removes a decimal gap from rate. */ function _applyDecimalGap( uint256 baseAmount, uint8 decimalsOfBase, uint8 decimalsOfQuote ) internal pure returns (uint256 quoteAmount) { uint256 n; uint256 d; if (decimalsOfBase > decimalsOfQuote) { d = decimalsOfBase - decimalsOfQuote; } else if (decimalsOfBase < decimalsOfQuote) { n = decimalsOfQuote - decimalsOfBase; } // The consequent multiplication would overflow under extreme and non-blocking circumstances. require(n < 19 && d < 19, "decimal gap needs to be lower than 19"); quoteAmount = baseAmount.mul(10**n).div(10**d); } function _getCollateralDecimals() internal virtual view returns (uint8); function _sendCollateralTo(address receiver, uint256 amount) internal virtual; } // File: contracts/bondToken/BondTokenCollateralizedErc20.sol pragma solidity 0.6.6; contract BondTokenCollateralizedErc20 is BondToken { ERC20 internal immutable COLLATERALIZED_TOKEN; constructor( address collateralizedTokenAddress, string memory name, string memory symbol, uint8 decimals ) public BondToken(name, symbol, decimals) { COLLATERALIZED_TOKEN = ERC20(collateralizedTokenAddress); } function _getCollateralDecimals() internal override view returns (uint8) { return COLLATERALIZED_TOKEN.decimals(); } function _sendCollateralTo(address receiver, uint256 amount) internal override { COLLATERALIZED_TOKEN.transfer(receiver, amount); } } // File: contracts/bondToken/BondTokenCollateralizedEth.sol pragma solidity 0.6.6; contract BondTokenCollateralizedEth is BondToken, TransferETH { constructor( string memory name, string memory symbol, uint8 decimals ) public BondToken(name, symbol, decimals) {} function _getCollateralDecimals() internal override view returns (uint8) { return 18; } function _sendCollateralTo(address receiver, uint256 amount) internal override { _transferETH(payable(receiver), amount); } } // File: contracts/bondToken/BondTokenFactory.sol pragma solidity 0.6.6; contract BondTokenFactory { address private constant ETH = address(0); function createBondToken( address collateralizedTokenAddress, string calldata name, string calldata symbol, uint8 decimals ) external returns (address) { if (collateralizedTokenAddress == ETH) { BondTokenCollateralizedEth bond = new BondTokenCollateralizedEth( name, symbol, decimals ); bond.transferOwnership(msg.sender); return address(bond); } else { BondTokenCollateralizedErc20 bond = new BondTokenCollateralizedErc20( collateralizedTokenAddress, name, symbol, decimals ); bond.transferOwnership(msg.sender); return address(bond); } } } // File: contracts/util/Polyline.sol pragma solidity 0.6.6; contract Polyline is UseSafeMath { struct Point { uint64 x; // Value of the x-axis of the x-y plane uint64 y; // Value of the y-axis of the x-y plane } struct LineSegment { Point left; // The left end of the line definition range Point right; // The right end of the line definition range } /** * @notice Return the value of y corresponding to x on the given line. line in the form of * a rational number (numerator / denominator). * If you treat a line as a line segment instead of a line, you should run * includesDomain(line, x) to check whether x is included in the line's domain or not. * @dev To guarantee accuracy, the bit length of the denominator must be greater than or equal * to the bit length of x, and the bit length of the numerator must be greater than or equal * to the sum of the bit lengths of x and y. */ function _mapXtoY(LineSegment memory line, uint64 x) internal pure returns (uint128 numerator, uint64 denominator) { int256 x1 = int256(line.left.x); int256 y1 = int256(line.left.y); int256 x2 = int256(line.right.x); int256 y2 = int256(line.right.y); require(x2 > x1, "must be left.x < right.x"); denominator = uint64(x2 - x1); // Calculate y = ((x2 - x) * y1 + (x - x1) * y2) / (x2 - x1) // in the form of a fraction (numerator / denominator). int256 n = (x - x1) * y2 + (x2 - x) * y1; require(n >= 0, "underflow n"); require(n < 2**128, "system error: overflow n"); numerator = uint128(n); } /** * @notice Checking that a line segment is a valid format. */ function assertLineSegment(LineSegment memory segment) internal pure { uint64 x1 = segment.left.x; uint64 x2 = segment.right.x; require(x1 < x2, "must be left.x < right.x"); } /** * @notice Checking that a polyline is a valid format. */ function assertPolyline(LineSegment[] memory polyline) internal pure { uint256 numOfSegment = polyline.length; require(numOfSegment != 0, "polyline must not be empty array"); // About the first line segment. LineSegment memory firstSegment = polyline[0]; // The beginning of the first line segment's domain is 0. require( firstSegment.left.x == uint64(0), "the x coordinate of left end of the first segment must be 0" ); // The value of y when x is 0 is 0. require( firstSegment.left.y == uint64(0), "the y coordinate of left end of the first segment must be 0" ); // About the last line segment. LineSegment memory lastSegment = polyline[numOfSegment - 1]; // The slope of the last line segment should be between 0 and 1. int256 gradientNumerator = int256(lastSegment.right.y).sub(lastSegment.left.y); int256 gradientDenominator = int256(lastSegment.right.x).sub(lastSegment.left.x); require( gradientNumerator >= 0 && gradientNumerator <= gradientDenominator, "the gradient of last line segment must be non-negative, and equal to or less than 1" ); // Making sure that the first line segment is a correct format. assertLineSegment(firstSegment); // The end of the domain of a segment and the beginning of the domain of the adjacent // segment must coincide. for (uint256 i = 1; i < numOfSegment; i++) { LineSegment memory leftSegment = polyline[i - 1]; LineSegment memory rightSegment = polyline[i]; // Make sure that the i-th line segment is a correct format. assertLineSegment(rightSegment); // Checking that the x-coordinates are same. require( leftSegment.right.x == rightSegment.left.x, "given polyline has an undefined domain." ); // Checking that the y-coordinates are same. require( leftSegment.right.y == rightSegment.left.y, "given polyline is not a continuous function" ); } } /** * @notice zip a LineSegment structure to uint256 * @return zip uint256( 0 ... 0 | x1 | y1 | x2 | y2 ) */ function zipLineSegment(LineSegment memory segment) internal pure returns (uint256 zip) { uint256 x1U256 = uint256(segment.left.x) << (64 + 64 + 64); // uint64 uint256 y1U256 = uint256(segment.left.y) << (64 + 64); // uint64 uint256 x2U256 = uint256(segment.right.x) << 64; // uint64 uint256 y2U256 = uint256(segment.right.y); // uint64 zip = x1U256 | y1U256 | x2U256 | y2U256; } /** * @notice unzip uint256 to a LineSegment structure */ function unzipLineSegment(uint256 zip) internal pure returns (LineSegment memory) { uint64 x1 = uint64(zip >> (64 + 64 + 64)); uint64 y1 = uint64(zip >> (64 + 64)); uint64 x2 = uint64(zip >> 64); uint64 y2 = uint64(zip); return LineSegment({left: Point({x: x1, y: y1}), right: Point({x: x2, y: y2})}); } /** * @notice unzip the fnMap to uint256[]. */ function decodePolyline(bytes memory fnMap) internal pure returns (uint256[] memory) { return abi.decode(fnMap, (uint256[])); } } // File: contracts/oracle/OracleInterface.sol pragma solidity ^0.6.6; // Oracle referenced by OracleProxy must implement this interface. interface OracleInterface is PriceOracleInterface { function getVolatility() external returns (uint256); function lastCalculatedVolatility() external view returns (uint256); } // File: contracts/oracle/UseOracle.sol pragma solidity 0.6.6; abstract contract UseOracle { OracleInterface internal _oracleContract; constructor(address contractAddress) public { require(contractAddress != address(0), "contract should be non-zero address"); _oracleContract = OracleInterface(contractAddress); } /** * @notice Get the latest price (USD) and historical volatility using oracle. * @dev If the oracle is not working, `latestPrice()` reverts. * @return priceE8 (10^-8 USD) * @return volatilityE8 (10^-8) */ function _getOracleData() internal returns (uint256 priceE8, uint256 volatilityE8) { priceE8 = _oracleContract.latestPrice(); volatilityE8 = _oracleContract.lastCalculatedVolatility(); return (priceE8, volatilityE8); } /** * @notice Get the price of the oracle data with a minimum timestamp that does more than input value * when you know the ID you are looking for. * @param timestamp is the timestamp that you want to get price. * @param hintID is the ID of the oracle data you are looking for. * @return priceE8 (10^-8 USD) */ function _getPriceOn(uint256 timestamp, uint256 hintID) internal returns (uint256 priceE8) { uint256 latestID = _oracleContract.latestId(); require(latestID != 0, "system error: the ID of oracle data should not be zero"); require(hintID != 0, "the hint ID must not be zero"); uint256 id = hintID; if (hintID > latestID) { id = latestID; } require( _oracleContract.getTimestamp(id) > timestamp, "there is no price data after maturity" ); id--; while (id != 0) { if (_oracleContract.getTimestamp(id) <= timestamp) { break; } id--; } return _oracleContract.getPrice(id + 1); } } // File: contracts/bondTokenName/BondTokenNameInterface.sol pragma solidity ^0.6.6; /** * @title bond token name contract interface */ interface BondTokenNameInterface { function genBondTokenName( string calldata shortNamePrefix, string calldata longNamePrefix, uint256 maturity, uint256 solidStrikePriceE4 ) external pure returns (string memory shortName, string memory longName); function getBondTokenName( uint256 maturity, uint256 solidStrikePriceE4, uint256 rateLBTWorthlessE4 ) external pure returns (string memory shortName, string memory longName); } // File: contracts/bondTokenName/UseBondTokenName.sol pragma solidity 0.6.6; abstract contract UseBondTokenName { BondTokenNameInterface internal immutable _bondTokenNameContract; constructor(address contractAddress) public { require(contractAddress != address(0), "contract should be non-zero address"); _bondTokenNameContract = BondTokenNameInterface(contractAddress); } } // File: contracts/bondMaker/BondMaker.sol pragma solidity 0.6.6; abstract contract BondMaker is UseSafeMath, BondMakerInterface, Time, Polyline, UseOracle { uint8 internal immutable DECIMALS_OF_BOND; uint8 internal immutable DECIMALS_OF_ORACLE_PRICE; address internal immutable FEE_TAKER; uint256 internal immutable MATURITY_SCALE; uint256 public nextBondGroupID = 1; /** * @dev The contents in this internal storage variable can be seen by getBond function. */ struct BondInfo { uint256 maturity; BondTokenInterface contractInstance; uint64 strikePrice; bytes32 fnMapID; } mapping(bytes32 => BondInfo) internal _bonds; /** * @notice mapping fnMapID to polyline * @dev The contents in this internal storage variable can be seen by getFnMap function. */ mapping(bytes32 => LineSegment[]) internal _registeredFnMap; /** * @dev The contents in this internal storage variable can be seen by getBondGroup function. */ struct BondGroup { bytes32[] bondIDs; uint256 maturity; } mapping(uint256 => BondGroup) internal _bondGroupList; constructor( address oracleAddress, address feeTaker, uint256 maturityScale, uint8 decimalsOfBond, uint8 decimalsOfOraclePrice ) public UseOracle(oracleAddress) { require(decimalsOfBond < 19, "the decimals of bond must be less than 19"); DECIMALS_OF_BOND = decimalsOfBond; require(decimalsOfOraclePrice < 19, "the decimals of oracle price must be less than 19"); DECIMALS_OF_ORACLE_PRICE = decimalsOfOraclePrice; require(feeTaker != address(0), "the fee taker must be non-zero address"); FEE_TAKER = feeTaker; require(maturityScale != 0, "MATURITY_SCALE must be positive"); MATURITY_SCALE = maturityScale; } /** * @notice Create bond token contract. * The name of this bond token is its bond ID. * @dev To convert bytes32 to string, encode its bond ID at first, then convert to string. * The symbol of any bond token with bond ID is either SBT or LBT; * As SBT is a special case of bond token, any bond token which does not match to the form of * SBT is defined as LBT. */ function registerNewBond(uint256 maturity, bytes calldata fnMap) external virtual override returns ( bytes32, address, bytes32 ) { _assertBeforeMaturity(maturity); require(maturity < _getBlockTimestampSec() + 365 days, "the maturity is too far"); require( maturity % MATURITY_SCALE == 0, "the maturity must be the multiple of MATURITY_SCALE" ); bytes32 bondID = generateBondID(maturity, fnMap); // Check if the same form of bond is already registered. // Cannot detect if the bond is described in a different polyline while two are // mathematically equivalent. require( address(_bonds[bondID].contractInstance) == address(0), "the bond type has been already registered" ); // Register function mapping if necessary. bytes32 fnMapID = generateFnMapID(fnMap); uint64 sbtStrikePrice; if (_registeredFnMap[fnMapID].length == 0) { uint256[] memory polyline = decodePolyline(fnMap); for (uint256 i = 0; i < polyline.length; i++) { _registeredFnMap[fnMapID].push(unzipLineSegment(polyline[i])); } LineSegment[] memory segments = _registeredFnMap[fnMapID]; assertPolyline(segments); require(!_isBondWorthless(segments), "the bond is 0-value at any price"); sbtStrikePrice = _getSbtStrikePrice(segments); } else { LineSegment[] memory segments = _registeredFnMap[fnMapID]; sbtStrikePrice = _getSbtStrikePrice(segments); } BondTokenInterface bondTokenContract = _createNewBondToken(maturity, fnMap); // Set bond info to storage. _bonds[bondID] = BondInfo({ maturity: maturity, contractInstance: bondTokenContract, strikePrice: sbtStrikePrice, fnMapID: fnMapID }); emit LogNewBond(bondID, address(bondTokenContract), maturity, fnMapID); return (bondID, address(bondTokenContract), fnMapID); } function _assertBondGroup(bytes32[] memory bondIDs, uint256 maturity) internal view { require(bondIDs.length >= 2, "the bond group should consist of 2 or more bonds"); /** * @dev Count the number of the end points on x axis. In the case of a simple SBT/LBT split, * 3 for SBT plus 3 for LBT equals to 6. * In the case of SBT with the strike price 100, (x,y) = (0,0), (100,100), (200,100) defines * the form of SBT on the field. * In the case of LBT with the strike price 100, (x,y) = (0,0), (100,0), (200,100) defines * the form of LBT on the field. * Right hand side area of the last grid point is expanded on the last line to the infinity. * @param nextBreakPointIndex returns the number of unique points on x axis. * In the case of SBT and LBT with the strike price 100, x = 0,100,200 are the unique points * and the number is 3. */ uint256 numOfBreakPoints = 0; for (uint256 i = 0; i < bondIDs.length; i++) { BondInfo storage bond = _bonds[bondIDs[i]]; require(bond.maturity == maturity, "the maturity of the bonds must be same"); LineSegment[] storage polyline = _registeredFnMap[bond.fnMapID]; numOfBreakPoints = numOfBreakPoints.add(polyline.length); } uint256 nextBreakPointIndex = 0; uint64[] memory rateBreakPoints = new uint64[](numOfBreakPoints); for (uint256 i = 0; i < bondIDs.length; i++) { BondInfo storage bond = _bonds[bondIDs[i]]; LineSegment[] storage segments = _registeredFnMap[bond.fnMapID]; for (uint256 j = 0; j < segments.length; j++) { uint64 breakPoint = segments[j].right.x; bool ok = false; for (uint256 k = 0; k < nextBreakPointIndex; k++) { if (rateBreakPoints[k] == breakPoint) { ok = true; break; } } if (ok) { continue; } rateBreakPoints[nextBreakPointIndex] = breakPoint; nextBreakPointIndex++; } } for (uint256 k = 0; k < rateBreakPoints.length; k++) { uint64 rate = rateBreakPoints[k]; uint256 totalBondPriceN = 0; uint256 totalBondPriceD = 1; for (uint256 i = 0; i < bondIDs.length; i++) { BondInfo storage bond = _bonds[bondIDs[i]]; LineSegment[] storage segments = _registeredFnMap[bond.fnMapID]; (uint256 segmentIndex, bool ok) = _correspondSegment(segments, rate); require(ok, "invalid domain expression"); (uint128 n, uint64 d) = _mapXtoY(segments[segmentIndex], rate); if (n != 0) { // a/b + c/d = (ad+bc)/bd // totalBondPrice += (n / d); // N = D*n + N*d, D = D*d totalBondPriceN = totalBondPriceD.mul(n).add(totalBondPriceN.mul(d)); totalBondPriceD = totalBondPriceD.mul(d); } } /** * @dev Ensure that totalBondPrice (= totalBondPriceN / totalBondPriceD) is the same * with rate. Because we need 1 Ether to mint a unit of each bond token respectively, * the sum of cashflow (USD) per a unit of bond token is the same as USD/ETH * rate at maturity. */ require( totalBondPriceN == totalBondPriceD.mul(rate), "the total price at any rateBreakPoints should be the same value as the rate" ); } } /** * @notice Collect bondIDs that regenerate the collateral, and group them as a bond group. * Any bond is described as a set of linear functions(i.e. polyline), * so we can easily check if the set of bondIDs are well-formed by looking at all the end * points of the lines. */ function registerNewBondGroup(bytes32[] calldata bondIDs, uint256 maturity) external virtual override returns (uint256 bondGroupID) { _assertBondGroup(bondIDs, maturity); (, , uint64 sbtStrikePrice, ) = getBond(bondIDs[0]); require(sbtStrikePrice != 0, "the first bond must be SBT"); // Get and increment next bond group ID bondGroupID = nextBondGroupID; nextBondGroupID = nextBondGroupID.add(1); _bondGroupList[bondGroupID] = BondGroup(bondIDs, maturity); emit LogNewBondGroup(bondGroupID, maturity, sbtStrikePrice, bondIDs); return bondGroupID; } /** * @notice A user needs to issue a bond via BondGroup in order to guarantee that the total value * of bonds in the bond group equals to the token allowance except for about 0.2% fee (accurately 2/1002). * The fee send to Lien token contract when liquidateBond(). */ function _issueNewBonds(uint256 bondGroupID, uint256 collateralAmountWithFee) internal returns (uint256 bondAmount) { (bytes32[] memory bondIDs, uint256 maturity) = getBondGroup(bondGroupID); _assertNonEmptyBondGroup(bondIDs); _assertBeforeMaturity(maturity); uint256 fee = collateralAmountWithFee.mul(2).divRoundUp(1002); uint8 decimalsOfCollateral = _getCollateralDecimals(); bondAmount = _applyDecimalGap( collateralAmountWithFee.sub(fee), decimalsOfCollateral, DECIMALS_OF_BOND ); require(bondAmount != 0, "the minting amount must be non-zero"); for (uint256 i = 0; i < bondIDs.length; i++) { _mintBond(bondIDs[i], msg.sender, bondAmount); } emit LogIssueNewBonds(bondGroupID, msg.sender, bondAmount); } /** * @notice redeems collateral from the total set of bonds in the bondGroupID before maturity date. * @param bondGroupID is the bond group ID. * @param bondAmount is the redeemed bond amount (decimal: 8). */ function reverseBondGroupToCollateral(uint256 bondGroupID, uint256 bondAmount) external virtual override returns (bool) { (bytes32[] memory bondIDs, uint256 maturity) = getBondGroup(bondGroupID); _assertNonEmptyBondGroup(bondIDs); _assertBeforeMaturity(maturity); for (uint256 i = 0; i < bondIDs.length; i++) { _burnBond(bondIDs[i], msg.sender, bondAmount); } uint8 decimalsOfCollateral = _getCollateralDecimals(); uint256 collateralAmount = _applyDecimalGap( bondAmount, DECIMALS_OF_BOND, decimalsOfCollateral ); _sendCollateralTo(msg.sender, collateralAmount); emit LogReverseBondGroupToCollateral(bondGroupID, msg.sender, collateralAmount); return true; } /** * @notice Burns set of LBTs and mints equivalent set of LBTs that are not in the exception list. * @param inputBondGroupID is the BondGroupID of bonds which you want to burn. * @param outputBondGroupID is the BondGroupID of bonds which you want to mint. * @param exceptionBonds is the list of bondIDs that should be excluded in burn/mint process. */ function exchangeEquivalentBonds( uint256 inputBondGroupID, uint256 outputBondGroupID, uint256 amount, bytes32[] calldata exceptionBonds ) external virtual override returns (bool) { (bytes32[] memory inputIDs, uint256 inputMaturity) = getBondGroup(inputBondGroupID); _assertNonEmptyBondGroup(inputIDs); (bytes32[] memory outputIDs, uint256 outputMaturity) = getBondGroup(outputBondGroupID); _assertNonEmptyBondGroup(outputIDs); require(inputMaturity == outputMaturity, "cannot exchange bonds with different maturities"); _assertBeforeMaturity(inputMaturity); bool flag; uint256 exceptionCount; for (uint256 i = 0; i < inputIDs.length; i++) { // this flag control checks whether the bond is in the scope of burn/mint flag = true; for (uint256 j = 0; j < exceptionBonds.length; j++) { if (exceptionBonds[j] == inputIDs[i]) { flag = false; // this count checks if all the bondIDs in exceptionBonds are included both in inputBondGroupID and outputBondGroupID exceptionCount = exceptionCount.add(1); } } if (flag) { _burnBond(inputIDs[i], msg.sender, amount); } } require( exceptionBonds.length == exceptionCount, "All the exceptionBonds need to be included in input" ); for (uint256 i = 0; i < outputIDs.length; i++) { flag = true; for (uint256 j = 0; j < exceptionBonds.length; j++) { if (exceptionBonds[j] == outputIDs[i]) { flag = false; exceptionCount = exceptionCount.sub(1); } } if (flag) { _mintBond(outputIDs[i], msg.sender, amount); } } require( exceptionCount == 0, "All the exceptionBonds need to be included both in input and output" ); emit LogExchangeEquivalentBonds(msg.sender, inputBondGroupID, outputBondGroupID, amount); return true; } /** * @notice This function distributes the collateral to the bond token holders * after maturity date based on the oracle price. * @param bondGroupID is the target bond group ID. * @param oracleHintID is manually set to be smaller number than the oracle latestId * when the caller wants to save gas. */ function liquidateBond(uint256 bondGroupID, uint256 oracleHintID) external virtual override returns (uint256 totalPayment) { (bytes32[] memory bondIDs, uint256 maturity) = getBondGroup(bondGroupID); _assertNonEmptyBondGroup(bondIDs); require(_getBlockTimestampSec() >= maturity, "the bond has not expired yet"); uint256 price = _getPriceOn( maturity, (oracleHintID != 0) ? oracleHintID : _oracleContract.latestId() ); require(price != 0, "price should be non-zero value"); require(price < 2**64, "price should be less than 2^64"); for (uint256 i = 0; i < bondIDs.length; i++) { bytes32 bondID = bondIDs[i]; uint256 payment = _sendCollateralToBondTokenContract(bondID, uint64(price)); totalPayment = totalPayment.add(payment); } if (totalPayment != 0) { /// @dev collateral:fee = 1000:2 uint256 fee = totalPayment.mul(2).div(1000); _sendCollateralTo(payable(FEE_TAKER), fee); } } function collateralAddress() external override view returns (address) { return _collateralAddress(); } function oracleAddress() external override view returns (address) { return address(_oracleContract); } function feeTaker() external override view returns (address) { return FEE_TAKER; } function decimalsOfBond() external override view returns (uint8) { return DECIMALS_OF_BOND; } function decimalsOfOraclePrice() external override view returns (uint8) { return DECIMALS_OF_ORACLE_PRICE; } function maturityScale() external override view returns (uint256) { return MATURITY_SCALE; } /** * @notice Returns multiple information for the bondID. * @dev The decimals of strike price is the same as that of oracle price. */ function getBond(bytes32 bondID) public override view returns ( address bondTokenAddress, uint256 maturity, uint64 solidStrikePrice, bytes32 fnMapID ) { BondInfo memory bondInfo = _bonds[bondID]; bondTokenAddress = address(bondInfo.contractInstance); maturity = bondInfo.maturity; solidStrikePrice = bondInfo.strikePrice; fnMapID = bondInfo.fnMapID; } /** * @dev Returns polyline for the fnMapID. */ function getFnMap(bytes32 fnMapID) public override view returns (bytes memory fnMap) { LineSegment[] storage segments = _registeredFnMap[fnMapID]; uint256[] memory polyline = new uint256[](segments.length); for (uint256 i = 0; i < segments.length; i++) { polyline[i] = zipLineSegment(segments[i]); } return abi.encode(polyline); } /** * @dev Returns all the bondIDs and their maturity for the bondGroupID. */ function getBondGroup(uint256 bondGroupID) public override view returns (bytes32[] memory bondIDs, uint256 maturity) { require(bondGroupID < nextBondGroupID, "the bond group does not exist"); BondGroup memory bondGroup = _bondGroupList[bondGroupID]; bondIDs = bondGroup.bondIDs; maturity = bondGroup.maturity; } /** * @dev Returns keccak256 for the fnMap. */ function generateFnMapID(bytes memory fnMap) public override view returns (bytes32 fnMapID) { return keccak256(fnMap); } /** * @dev Returns a bond ID determined by this contract address, maturity and fnMap. */ function generateBondID(uint256 maturity, bytes memory fnMap) public override view returns (bytes32 bondID) { return keccak256(abi.encodePacked(address(this), maturity, fnMap)); } function _mintBond( bytes32 bondID, address account, uint256 amount ) internal { BondTokenInterface bondTokenContract = _bonds[bondID].contractInstance; _assertRegisteredBond(bondTokenContract); require(bondTokenContract.mint(account, amount), "failed to mint bond token"); } function _burnBond( bytes32 bondID, address account, uint256 amount ) internal { BondTokenInterface bondTokenContract = _bonds[bondID].contractInstance; _assertRegisteredBond(bondTokenContract); require(bondTokenContract.simpleBurn(account, amount), "failed to burn bond token"); } function _sendCollateralToBondTokenContract(bytes32 bondID, uint64 price) internal returns (uint256 collateralAmount) { BondTokenInterface bondTokenContract = _bonds[bondID].contractInstance; _assertRegisteredBond(bondTokenContract); LineSegment[] storage segments = _registeredFnMap[_bonds[bondID].fnMapID]; (uint256 segmentIndex, bool ok) = _correspondSegment(segments, price); assert(ok); // not found a segment whose price range include current price (uint128 n, uint64 _d) = _mapXtoY(segments[segmentIndex], price); // x = price, y = n / _d // uint64(-1) * uint64(-1) < uint128(-1) uint128 d = uint128(_d) * uint128(price); uint256 totalSupply = bondTokenContract.totalSupply(); bool expiredFlag = bondTokenContract.expire(n, d); // rateE0 = n / d = f(price) / price if (expiredFlag) { uint8 decimalsOfCollateral = _getCollateralDecimals(); collateralAmount = _applyDecimalGap(totalSupply, DECIMALS_OF_BOND, decimalsOfCollateral) .mul(n) .div(d); _sendCollateralTo(address(bondTokenContract), collateralAmount); emit LogLiquidateBond(bondID, n, d); } } /** * @dev removes a decimal gap from rate. */ function _applyDecimalGap( uint256 baseAmount, uint8 decimalsOfBase, uint8 decimalsOfQuote ) internal pure returns (uint256 quoteAmount) { uint256 n; uint256 d; if (decimalsOfBase > decimalsOfQuote) { d = decimalsOfBase - decimalsOfQuote; } else if (decimalsOfBase < decimalsOfQuote) { n = decimalsOfQuote - decimalsOfBase; } // The consequent multiplication would overflow under extreme and non-blocking circumstances. require(n < 19 && d < 19, "decimal gap needs to be lower than 19"); quoteAmount = baseAmount.mul(10**n).div(10**d); } function _assertRegisteredBond(BondTokenInterface bondTokenContract) internal pure { require(address(bondTokenContract) != address(0), "the bond is not registered"); } function _assertNonEmptyBondGroup(bytes32[] memory bondIDs) internal pure { require(bondIDs.length != 0, "the list of bond ID must be non-empty"); } function _assertBeforeMaturity(uint256 maturity) internal view { require(_getBlockTimestampSec() < maturity, "the maturity has already expired"); } function _isBondWorthless(LineSegment[] memory polyline) internal pure returns (bool) { for (uint256 i = 0; i < polyline.length; i++) { LineSegment memory segment = polyline[i]; if (segment.right.y != 0) { return false; } } return true; } /** * @dev Return the strike price only when the form of polyline matches to the definition of SBT. * Check if the form is SBT even when the polyline is in a verbose style. */ function _getSbtStrikePrice(LineSegment[] memory polyline) internal pure returns (uint64) { if (polyline.length == 0) { return 0; } uint64 strikePrice = polyline[0].right.x; if (strikePrice == 0) { return 0; } for (uint256 i = 0; i < polyline.length; i++) { LineSegment memory segment = polyline[i]; if (segment.right.y != strikePrice) { return 0; } } return uint64(strikePrice); } /** * @dev Only when the form of polyline matches to the definition of LBT, this function returns * the minimum collateral price (USD) that LBT is not worthless. * Check if the form is LBT even when the polyline is in a verbose style. */ function _getLbtStrikePrice(LineSegment[] memory polyline) internal pure returns (uint64) { if (polyline.length == 0) { return 0; } uint64 strikePrice = polyline[0].right.x; if (strikePrice == 0) { return 0; } for (uint256 i = 0; i < polyline.length; i++) { LineSegment memory segment = polyline[i]; if (segment.right.y.add(strikePrice) != segment.right.x) { return 0; } } return uint64(strikePrice); } /** * @dev In order to calculate y axis value for the corresponding x axis value, we need to find * the place of domain of x value on the polyline. * As the polyline is already checked to be correctly formed, we can simply look from the right * hand side of the polyline. */ function _correspondSegment(LineSegment[] memory segments, uint64 x) internal pure returns (uint256 i, bool ok) { i = segments.length; while (i > 0) { i--; if (segments[i].left.x <= x) { ok = true; break; } } } // function issueNewBonds(uint256 bondGroupID) external returns (uint256 bondAmount); function _createNewBondToken(uint256 maturity, bytes memory fnMap) internal virtual returns (BondTokenInterface); function _collateralAddress() internal virtual view returns (address); function _getCollateralDecimals() internal virtual view returns (uint8); function _sendCollateralTo(address receiver, uint256 amount) internal virtual; } // File: contracts/bondMaker/BondMakerCollateralizedEth.sol pragma solidity 0.6.6; contract BondMakerCollateralizedEth is BondMaker, UseBondTokenName, TransferETH { address private constant ETH = address(0); BondTokenFactory internal immutable BOND_TOKEN_FACTORY; constructor( address oracleAddress, address feeTaker, address bondTokenNameAddress, address bondTokenFactoryAddress, uint256 maturityScale ) public BondMaker(oracleAddress, feeTaker, maturityScale, 8, 8) UseBondTokenName(bondTokenNameAddress) { BOND_TOKEN_FACTORY = BondTokenFactory(bondTokenFactoryAddress); } function issueNewBonds(uint256 bondGroupID) public payable returns (uint256 bondAmount) { return _issueNewBonds(bondGroupID, msg.value); } function _createNewBondToken(uint256 maturity, bytes memory fnMap) internal override returns (BondTokenInterface) { (string memory symbol, string memory name) = _getBondTokenName(maturity, fnMap); address bondAddress = BOND_TOKEN_FACTORY.createBondToken( ETH, name, symbol, DECIMALS_OF_BOND ); return BondTokenInterface(bondAddress); } function _getBondTokenName(uint256 maturity, bytes memory fnMap) internal virtual view returns (string memory symbol, string memory name) { bytes32 fnMapID = generateFnMapID(fnMap); LineSegment[] memory segments = _registeredFnMap[fnMapID]; uint64 sbtStrikePrice = _getSbtStrikePrice(segments); uint64 lbtStrikePrice = _getLbtStrikePrice(segments); uint64 sbtStrikePriceE0 = sbtStrikePrice / (uint64(10)**DECIMALS_OF_ORACLE_PRICE); uint64 lbtStrikePriceE0 = lbtStrikePrice / (uint64(10)**DECIMALS_OF_ORACLE_PRICE); if (sbtStrikePrice != 0) { return _bondTokenNameContract.genBondTokenName("SBT", "SBT", maturity, sbtStrikePriceE0); } else if (lbtStrikePrice != 0) { return _bondTokenNameContract.genBondTokenName("LBT", "LBT", maturity, lbtStrikePriceE0); } else { return _bondTokenNameContract.genBondTokenName("IMT", "Immortal Option", maturity, 0); } } function _collateralAddress() internal override view returns (address) { return address(0); } function _getCollateralDecimals() internal override view returns (uint8) { return 18; } function _sendCollateralTo(address receiver, uint256 amount) internal override { _transferETH(payable(receiver), amount); } } // File: contracts/bondMaker/BondMakerCollateralizedEthInterface.sol pragma solidity 0.6.6; interface BondMakerCollateralizedEthInterface is BondMakerInterface { function issueNewBonds(uint256 bondGroupID) external payable returns (uint256 amount); } // File: contracts/bondMaker/UseBondMaker.sol pragma solidity 0.6.6; abstract contract UseBondMaker { BondMakerCollateralizedEthInterface internal _bondMakerContract; constructor(address contractAddress) public { require(contractAddress != address(0), "contract should be non-zero address"); _bondMakerContract = BondMakerCollateralizedEthInterface(payable(contractAddress)); } } // File: contracts/decentralizedOtc/DecentralizedOTC.sol pragma solidity 0.6.6; contract DecentralizedOTC is UseOracle, UseBondMaker, UseSafeMath, Time, CallOptionCalculator { uint256 internal constant MIN_EXCHANGE_RATE_E8 = 0.000001 * 10**8; uint256 internal constant MAX_EXCHANGE_RATE_E8 = 1000000 * 10**8; int256 internal constant MAX_SPREAD_E8 = 0.15 * 10**8; // 15% mapping(bytes32 => address) public deployer; /** * @notice ERC20pool is the amount of ERC20 deposit of a deployer. * @param ERC20Address is the target ERC20 token address. * @param spread is the fee base of the bid-ask spread. * @param isLBTSellPool is whether this pool is for the LBT sale or not. */ struct PoolInfo { ERC20 ERC20Address; int16 spread; bool isLBTSellPool; } mapping(bytes32 => PoolInfo) public poolMap; mapping(bytes32 => PriceOracleInterface) internal _erc20OracleMap; event LogERC20TokenLBTSwap( bytes32 indexed poolID, address indexed sender, uint256 indexed bondGroupID, uint256 volume, // decimal: 8 uint256 LBTAmount, // decimal: BondToken.decimals() uint256 ERC20Amount // decimal: ERC20.decimals() ); event LogLBTERC20TokenSwap( bytes32 indexed poolID, address indexed sender, uint256 indexed bondGroupID, uint256 volume, // decimal: 8 uint256 LBTAmount, // decimal: BondToken.decimals() uint256 ERC20Amount // decimal: ERC20.decimals() ); event LogCreateERC20Pool( address indexed deployer, address indexed ERC20Address, bytes32 indexed poolID, int16 spread, bool isLBTSellPool ); event LogDeleteERC20Pool(bytes32 indexed poolID); modifier isExistentPool(bytes32 erc20PoolID) { require(deployer[erc20PoolID] != address(0), "the pool does not exist"); _; } constructor(address bondMakerAddress, address oracleAddress) public UseOracle(oracleAddress) UseBondMaker(bondMakerAddress) { require( _bondMakerContract.decimalsOfOraclePrice() == 8, "the decimals of oracle price must be 8" ); require(_bondMakerContract.decimalsOfBond() == 8, "the decimals of bond token must be 8"); require( oracleAddress == _bondMakerContract.oracleAddress(), "the oracle address is differ" ); } /** * @notice providers set a pool and deposit to a pool. * If there is vesting(lockUp) setting, users of their pool transfer LBT to grants of the vesting ERC20 contract. */ function setPoolMap( address ERC20Address, int16 spread, bool isLBTSellPool ) external returns (bytes32 erc20PoolID) { erc20PoolID = keccak256(abi.encode(msg.sender, ERC20Address, spread, isLBTSellPool)); require(deployer[erc20PoolID] == address(0), "already registered"); require(msg.sender != address(0), "deployer must be non-zero address"); require(spread > -1000 && spread < 1000, "the range of fee base must be -999~999"); require(ERC20Address != address(0), "ERC20 address is 0x0"); poolMap[erc20PoolID] = PoolInfo(ERC20(ERC20Address), spread, isLBTSellPool); deployer[erc20PoolID] = msg.sender; emit LogCreateERC20Pool(msg.sender, ERC20Address, erc20PoolID, spread, isLBTSellPool); } /** * @notice providers must provide LBT price caluculator and ERC20 price oracle. */ function setProvider( bytes32 erc20PoolID, address oracleAddress, address ) external isExistentPool(erc20PoolID) { require(msg.sender == deployer[erc20PoolID], "only deployer is allowed to execute"); _erc20OracleMap[erc20PoolID] = PriceOracleInterface(oracleAddress); } /** * @dev (deprecated) Use getPoolInfo(poolID). */ function oracleInfo(bytes32 poolID) external view returns (address oracleAddress, address calculatorAddress) { oracleAddress = address(_erc20OracleMap[poolID]); calculatorAddress = address(0); } function getPoolInfo(bytes32 poolID) external view isExistentPool(poolID) returns ( address deployerAddress, address erc20Address, int16 feeBase, bool isLBTSellPool, address erc20OracleAddress ) { deployerAddress = deployer[poolID]; PoolInfo memory poolInfo = poolMap[poolID]; erc20Address = address(poolInfo.ERC20Address); feeBase = poolInfo.spread; isLBTSellPool = poolInfo.isLBTSellPool; erc20OracleAddress = address(_erc20OracleMap[poolID]); } function getOraclePrice(bytes32 erc20PoolID) external returns (uint256 priceE8) { return _getOraclePrice(erc20PoolID); } function _getOraclePrice(bytes32 erc20PoolID) internal isExistentPool(erc20PoolID) returns (uint256 priceE8) { PriceOracleInterface oracleContract = _erc20OracleMap[erc20PoolID]; require(address(oracleContract) != address(0), "invalid ERC20 price oracle"); return oracleContract.latestPrice(); } /** * @notice Returns the exchange rate included spread. */ function calcRateLBT2ERC20( bytes32 sbtID, bytes32 erc20PoolID, uint256 maturity ) external returns (uint256 rateLBT2ERC20E8) { (rateLBT2ERC20E8, , , ) = _calcRateLBT2ERC20(sbtID, erc20PoolID, maturity); } function _calcRateLBT2ERC20( bytes32 sbtID, bytes32 erc20PoolID, uint256 maturity ) internal returns ( uint256 rateLBT2ERC20E8, uint256 lbtPriceE8, uint256 erc20PriceE8, int256 spreadE8 ) { PoolInfo memory pool = poolMap[erc20PoolID]; (uint256 etherPriceE8, uint256 ethVolatilityE8) = _getOracleData(); (, , uint256 strikePriceE8, ) = _bondMakerContract.getBond(sbtID); erc20PriceE8 = _getOraclePrice(erc20PoolID); (lbtPriceE8, spreadE8) = _calcLbtPriceAndSpread( strikePriceE8, etherPriceE8, ethVolatilityE8, maturity, pool.spread * 10 // feeBaseE4 ); uint256 rateE8 = lbtPriceE8.mul(10**8).div( erc20PriceE8, "ERC20 oracle price must be non-zero" ); require(rateE8 > MIN_EXCHANGE_RATE_E8, "exchange rate is too small"); // require(rateE8 < MAX_EXCHANGE_RATE_E8, "exchange rate is too large"); if (pool.isLBTSellPool) { rateLBT2ERC20E8 = rateE8.mul(uint256(10**8 + spreadE8)) / (10**8); } else { rateLBT2ERC20E8 = rateE8.mul(uint256(10**8 - spreadE8)) / (10**8); } } /** * @dev Gets LBT data, and outputs the spread and the exchange rate excluding spread. */ function _calcLbtPriceAndSpread( uint256 strikePriceE8, uint256 etherPriceE8, uint256 ethVolatilityE8, uint256 maturity, int256 feeBaseE4 ) internal view returns (uint256 lbtPriceE8, int256 spreadE8) { uint256 untilMaturity = maturity.sub( _getBlockTimestampSec(), "LBT should not have expired" ); uint8 decimalsOfPrice = 0; // mutable { uint256 threshould = 1000000 * 10**8; while (threshould >= 10) { if (strikePriceE8 >= threshould) { break; } decimalsOfPrice++; threshould /= 10; } } // assert(decimalsOfPrice >= 0 && decimalsOfPrice <= 14); uint256 lbtLeverageE4; { uint256 etherPrice = _applyDecimalGap(etherPriceE8, 8, decimalsOfPrice); uint256 strikePrice = _applyDecimalGap(strikePriceE8, 8, decimalsOfPrice); uint256 lbtPrice; (lbtPrice, lbtLeverageE4, ) = calcLbtPriceAndLeverage( etherPrice.toInt256(), strikePrice.toInt256(), ethVolatilityE8.toInt256(), untilMaturity.toInt256() ); lbtPriceE8 = _applyDecimalGap(lbtPrice, decimalsOfPrice, 8); } uint256 volE8 = ethVolatilityE8 < 10**8 ? 10**8 : ethVolatilityE8 > 2 * 10**8 ? 2 * 10**8 : ethVolatilityE8; uint256 volTimesLevE4 = (volE8 * lbtLeverageE4) / 10**8; spreadE8 = feeBaseE4 * (feeBaseE4 < 0 || volTimesLevE4 < 10**4 ? 10**4 : volTimesLevE4).toInt256(); spreadE8 = spreadE8 > MAX_SPREAD_E8 ? MAX_SPREAD_E8 : spreadE8; } /** * @notice removes a decimal gap from rate. */ function _applyDecimalGap( uint256 baseAmount, ERC20 baseToken, ERC20 quoteToken ) private view returns (uint256) { uint8 decimalsOfBase = baseToken.decimals(); uint8 decimalsOfQuote = quoteToken.decimals(); return _applyDecimalGap(baseAmount, decimalsOfBase, decimalsOfQuote); } function _applyDecimalGap( uint256 amount, uint8 decimalsOfBase, uint8 decimalsOfQuote ) private pure returns (uint256) { uint256 n; uint256 d; if (decimalsOfBase > decimalsOfQuote) { d = decimalsOfBase - decimalsOfQuote; } else if (decimalsOfBase < decimalsOfQuote) { n = decimalsOfQuote - decimalsOfBase; } // The consequent multiplication would overflow under extreme and non-blocking circumstances. require(n < 19 && d < 19, "decimal gap needs to be lower than 19"); return amount.mul(10**n).div(10**d); } /** * @notice Before this function, approve is needed to be excuted. * Main function of this contract. Users exchange ERC20 tokens (like USDC Token) to LBT */ function exchangeERC20ToLBT( uint256 bondGroupID, bytes32 erc20PoolID, uint256 ERC20Amount, uint256 expectedAmount, uint256 range ) public returns (uint256 LBTAmount) { LBTAmount = _exchangeERC20ToLBT(bondGroupID, erc20PoolID, ERC20Amount); if (expectedAmount != 0) { require(LBTAmount.mul(1000 + range).div(1000) >= expectedAmount, "out of price range"); } } function _exchangeERC20ToLBT( uint256 bondGroupID, bytes32 erc20PoolID, uint256 ERC20Amount ) internal isExistentPool(erc20PoolID) returns (uint256 LBTAmount) { bytes32 sbtID; bytes32 lbtID; { (bytes32[] memory bonds, ) = _bondMakerContract.getBondGroup(bondGroupID); require(bonds.length == 2, "the bond group must include only 2 types of bond."); lbtID = bonds[1]; sbtID = bonds[0]; } ERC20 bondToken; uint256 maturity; { address contractAddress; (contractAddress, maturity, , ) = _bondMakerContract.getBond(lbtID); require(contractAddress != address(0), "the bond is not registered"); bondToken = ERC20(contractAddress); } ERC20 token; { PoolInfo memory pool = poolMap[erc20PoolID]; require(pool.isLBTSellPool, "This pool is for buying LBT"); token = pool.ERC20Address; } uint256 volumeE8; { (uint256 rateE8, , uint256 erc20PriceE8, ) = _calcRateLBT2ERC20( sbtID, erc20PoolID, maturity ); require(rateE8 != 0, "exchange rate included spread must be non-zero"); LBTAmount = _applyDecimalGap(ERC20Amount.mul(10**8), token, bondToken).div(rateE8); require(LBTAmount != 0, "must transfer non-zero LBT amount"); volumeE8 = erc20PriceE8.mul(ERC20Amount).div(10**uint256(token.decimals())); volumeE8 = _calcUsdVolume(volumeE8); } require( token.transferFrom(msg.sender, deployer[erc20PoolID], ERC20Amount), "fail to transfer ERC20 token" ); require( bondToken.transferFrom(deployer[erc20PoolID], msg.sender, LBTAmount), "fail to transfer LBT" ); emit LogERC20TokenLBTSwap( erc20PoolID, msg.sender, bondGroupID, volumeE8, LBTAmount, ERC20Amount ); } /** * @notice Before this function, approve is needed to be excuted. * Main function of this contract. Users exchange LBT to ERC20 tokens (like USDC Token) */ function exchangeLBT2ERC20( uint256 bondGroupID, bytes32 erc20PoolID, uint256 LBTAmount, uint256 expectedAmount, uint256 range ) public returns (uint256 ERC20Amount) { ERC20Amount = _exchangeLBT2ERC20(bondGroupID, erc20PoolID, LBTAmount); if (expectedAmount != 0) { require( ERC20Amount.mul(1000 + range).div(1000) >= expectedAmount, "out of price range" ); } } function _exchangeLBT2ERC20( uint256 bondGroupID, bytes32 erc20PoolID, uint256 LBTAmount ) internal isExistentPool(erc20PoolID) returns (uint256 ERC20Amount) { bytes32 lbtID; bytes32 sbtID; { (bytes32[] memory bonds, ) = _bondMakerContract.getBondGroup(bondGroupID); require(bonds.length == 2, "the bond group must include only 2 types of bond."); lbtID = bonds[1]; sbtID = bonds[0]; } ERC20 bondToken; uint256 maturity; { address contractAddress; (contractAddress, maturity, , ) = _bondMakerContract.getBond(lbtID); require(contractAddress != address(0), "the bond is not registered"); bondToken = ERC20(contractAddress); } ERC20 token; { PoolInfo memory pool = poolMap[erc20PoolID]; require(!pool.isLBTSellPool, "This pool is not for buying LBT"); token = pool.ERC20Address; } uint256 volumeE8; { (uint256 rateE8, uint256 lbtPriceE8, , ) = _calcRateLBT2ERC20( sbtID, erc20PoolID, maturity ); require(rateE8 != 0, "exchange rate included spread must be non-zero"); ERC20Amount = _applyDecimalGap(LBTAmount.mul(rateE8), bondToken, token).div(10**8); require(ERC20Amount != 0, "must transfer non-zero token amount"); volumeE8 = lbtPriceE8.mul(LBTAmount).div(10**uint256(bondToken.decimals())); volumeE8 = _calcUsdVolume(volumeE8); } require( token.transferFrom(deployer[erc20PoolID], msg.sender, ERC20Amount), "fail to transfer ERC20 token" ); require( bondToken.transferFrom(msg.sender, deployer[erc20PoolID], LBTAmount), "fail to transfer LBT" ); emit LogLBTERC20TokenSwap( erc20PoolID, msg.sender, bondGroupID, volumeE8, LBTAmount, ERC20Amount ); } function deletePoolAndProvider(bytes32 erc20PoolID) public isExistentPool(erc20PoolID) { require(deployer[erc20PoolID] == msg.sender, "this pool is not owned"); delete deployer[erc20PoolID]; delete poolMap[erc20PoolID]; delete _erc20OracleMap[erc20PoolID]; emit LogDeleteERC20Pool(erc20PoolID); } function bondMakerAddress() external view returns (address) { return address(_bondMakerContract); } /** * @dev Converts the unit of the strike price to USD. * Considering oracle, this function is non-payable. */ function _calcUsdVolume(uint256 volume) internal virtual returns (uint256) { return volume; } } // File: contracts/decentralizedOtc/DecentralizedOtcCollateralizedUsdc.sol pragma solidity 0.6.6; contract DecentralizedOtcCollateralizedUsdc is DecentralizedOTC { constructor(address ethBondMakerCollateralizedUsdcAddress, address ethPriceInverseOracleAddress) public DecentralizedOTC(ethBondMakerCollateralizedUsdcAddress, ethPriceInverseOracleAddress) {} /** * @dev Converts ETH to USD. */ function _calcUsdVolume(uint256 volume) internal override returns (uint256) { (uint256 ethPriceInverseE8, ) = _getOracleData(); return volume.mul(10**8) / ethPriceInverseE8; } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"ethBondMakerCollateralizedUsdcAddress","type":"address"},{"internalType":"address","name":"ethPriceInverseOracleAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"deployer","type":"address"},{"indexed":true,"internalType":"address","name":"ERC20Address","type":"address"},{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"},{"indexed":false,"internalType":"int16","name":"spread","type":"int16"},{"indexed":false,"internalType":"bool","name":"isLBTSellPool","type":"bool"}],"name":"LogCreateERC20Pool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"}],"name":"LogDeleteERC20Pool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint256","name":"bondGroupID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"volume","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"LBTAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ERC20Amount","type":"uint256"}],"name":"LogERC20TokenLBTSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolID","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint256","name":"bondGroupID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"volume","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"LBTAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ERC20Amount","type":"uint256"}],"name":"LogLBTERC20TokenSwap","type":"event"},{"inputs":[{"internalType":"uint256","name":"etherPriceE4","type":"uint256"},{"internalType":"uint256","name":"lbtPriceE4","type":"uint256"},{"internalType":"int256","name":"nd1E8","type":"int256"}],"name":"_calcLbtLeverage","outputs":[{"internalType":"uint256","name":"lbtLeverageE4","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"int256","name":"etherPriceE4","type":"int256"},{"internalType":"int256","name":"strikePriceE4","type":"int256"},{"internalType":"int256","name":"nd1E8","type":"int256"},{"internalType":"int256","name":"nd2E8","type":"int256"}],"name":"_calcLbtPrice","outputs":[{"internalType":"int256","name":"lbtPriceE4","type":"int256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"bondMakerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"etherPriceE4","type":"int256"},{"internalType":"int256","name":"strikePriceE4","type":"int256"},{"internalType":"int256","name":"ethVolatilityE8","type":"int256"},{"internalType":"int256","name":"untilMaturity","type":"int256"}],"name":"calcLbtPriceAndLeverage","outputs":[{"internalType":"uint256","name":"priceE4","type":"uint256"},{"internalType":"uint256","name":"leverageE4","type":"uint256"},{"internalType":"int256","name":"sigE8","type":"int256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"sbtID","type":"bytes32"},{"internalType":"bytes32","name":"erc20PoolID","type":"bytes32"},{"internalType":"uint256","name":"maturity","type":"uint256"}],"name":"calcRateLBT2ERC20","outputs":[{"internalType":"uint256","name":"rateLBT2ERC20E8","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"erc20PoolID","type":"bytes32"}],"name":"deletePoolAndProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"deployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bondGroupID","type":"uint256"},{"internalType":"bytes32","name":"erc20PoolID","type":"bytes32"},{"internalType":"uint256","name":"ERC20Amount","type":"uint256"},{"internalType":"uint256","name":"expectedAmount","type":"uint256"},{"internalType":"uint256","name":"range","type":"uint256"}],"name":"exchangeERC20ToLBT","outputs":[{"internalType":"uint256","name":"LBTAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bondGroupID","type":"uint256"},{"internalType":"bytes32","name":"erc20PoolID","type":"bytes32"},{"internalType":"uint256","name":"LBTAmount","type":"uint256"},{"internalType":"uint256","name":"expectedAmount","type":"uint256"},{"internalType":"uint256","name":"range","type":"uint256"}],"name":"exchangeLBT2ERC20","outputs":[{"internalType":"uint256","name":"ERC20Amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"erc20PoolID","type":"bytes32"}],"name":"getOraclePrice","outputs":[{"internalType":"uint256","name":"priceE8","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"name":"getPoolInfo","outputs":[{"internalType":"address","name":"deployerAddress","type":"address"},{"internalType":"address","name":"erc20Address","type":"address"},{"internalType":"int16","name":"feeBase","type":"int16"},{"internalType":"bool","name":"isLBTSellPool","type":"bool"},{"internalType":"address","name":"erc20OracleAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolID","type":"bytes32"}],"name":"oracleInfo","outputs":[{"internalType":"address","name":"oracleAddress","type":"address"},{"internalType":"address","name":"calculatorAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"poolMap","outputs":[{"internalType":"contract ERC20","name":"ERC20Address","type":"address"},{"internalType":"int16","name":"spread","type":"int16"},{"internalType":"bool","name":"isLBTSellPool","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ERC20Address","type":"address"},{"internalType":"int16","name":"spread","type":"int16"},{"internalType":"bool","name":"isLBTSellPool","type":"bool"}],"name":"setPoolMap","outputs":[{"internalType":"bytes32","name":"erc20PoolID","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"erc20PoolID","type":"bytes32"},{"internalType":"address","name":"oracleAddress","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"setProvider","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620035d2380380620035d2833981810160405260408110156200003757600080fd5b508051602090910151818181816001600160a01b038116620000a5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806200358b6023913960400191505060405180910390fd5b600080546001600160a01b0319166001600160a01b0392831617905581166200011a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806200358b6023913960400191505060405180910390fd5b600180546001600160a01b0319166001600160a01b039283161790819055604080517fd0d6153a0000000000000000000000000000000000000000000000000000000081529051919092169163d0d6153a916004808301926020929190829003018186803b1580156200018c57600080fd5b505afa158015620001a1573d6000803e3d6000fd5b505050506040513d6020811015620001b857600080fd5b505160ff1660081462000217576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180620035656026913960400191505060405180910390fd5b600160009054906101000a90046001600160a01b03166001600160a01b031663f08e2a336040518163ffffffff1660e01b815260040160206040518083038186803b1580156200026657600080fd5b505afa1580156200027b573d6000803e3d6000fd5b505050506040513d60208110156200029257600080fd5b505160ff16600814620002f1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180620035ae6024913960400191505060405180910390fd5b600160009054906101000a90046001600160a01b03166001600160a01b031663a89ae4ba6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200034057600080fd5b505afa15801562000355573d6000803e3d6000fd5b505050506040513d60208110156200036c57600080fd5b50516001600160a01b03828116911614620003e857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f746865206f7261636c6520616464726573732069732064696666657200000000604482015290519081900360640190fd5b5050505061316980620003fc6000396000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c8063541240c211610097578063a5761d6411610066578063a5761d64146103b1578063c72e47dc146103ce578063faceb3b51461041b578063fe74de2f1461044a576100f5565b8063541240c2146102c2578063816501c7146102eb57806390c2f87b1461032c5780639214554d14610361576100f5565b8063134c1abc116100d3578063134c1abc146101ef5780633796a8051461022a5780633bc714271461025f5780635392fb4e146102a3576100f5565b806309f2c019146100fa5780630b1a3554146101655780630defebeb14610196575b600080fd5b6101176004803603602081101561011057600080fd5b5035610467565b6040805173ffffffffffffffffffffffffffffffffffffffff96871681529486166020860152600193840b90930b848401529015156060840152909216608082015290519081900360a00190f35b61016d6105b8565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6101b3600480360360208110156101ac57600080fd5b50356105d4565b6040805173ffffffffffffffffffffffffffffffffffffffff9094168452600192830b90920b6020840152151582820152519081900360600190f35b6102186004803603606081101561020557600080fd5b5080359060208101359060400135610637565b60408051918252519081900360200190f35b610218600480360360a081101561024057600080fd5b5080359060208101359060408101359060608101359060800135610650565b6102186004803603606081101561027557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602081013560010b906040013515156106e6565b6102c0600480360360208110156102b957600080fd5b5035610a17565b005b610218600480360360608110156102d857600080fd5b5080359060208101359060400135610ba8565b6102c06004803603606081101561030157600080fd5b5080359073ffffffffffffffffffffffffffffffffffffffff60208201358116916040013516610c04565b610218600480360360a081101561034257600080fd5b5080359060208101359060408101359060608101359060800135610d33565b61037e6004803603602081101561037757600080fd5b5035610d40565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815291909216602082015281519081900390910190f35b610218600480360360208110156103c757600080fd5b5035610d68565b6103fd600480360360808110156103e457600080fd5b5080359060208101359060408101359060600135610d79565b60408051938452602084019290925282820152519081900360600190f35b6102186004803603608081101561043157600080fd5b5080359060208101359060408101359060600135610f92565b61016d6004803603602081101561046057600080fd5b5035610fcd565b6000818152600260205260408120548190819081908190869073ffffffffffffffffffffffffffffffffffffffff166104e7576040805162461bcd60e51b815260206004820152601760248201527f74686520706f6f6c20646f6573206e6f74206578697374000000000000000000604482015290519081900360640190fd5b60008781526002602052604090205473ffffffffffffffffffffffffffffffffffffffff169550610516612ea6565b50505060008581526003602090815260408083208151606081018352905473ffffffffffffffffffffffffffffffffffffffff808216808452740100000000000000000000000000000000000000008304600190810b810b900b84870181905276010000000000000000000000000000000000000000000090930460ff1615159385018490529a86526004909452919093205496989096929550911692509050565b60015473ffffffffffffffffffffffffffffffffffffffff1690565b60036020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000810460010b90760100000000000000000000000000000000000000000000900460ff1683565b6000610644848484610ff5565b50919695505050505050565b600061065d868686611264565b905082156106dd578261068a6103e861067e8486830163ffffffff611aca16565b9063ffffffff611b2a16565b10156106dd576040805162461bcd60e51b815260206004820152601260248201527f6f7574206f662070726963652072616e67650000000000000000000000000000604482015290519081900360640190fd5b95945050505050565b604080513360208083019190915273ffffffffffffffffffffffffffffffffffffffff80871683850152600186810b900b60608401528415156080808501919091528451808503909101815260a09093018452825192820192909220600081815260029092529290205416156107a3576040805162461bcd60e51b815260206004820152601260248201527f616c726561647920726567697374657265640000000000000000000000000000604482015290519081900360640190fd5b336107df5760405162461bcd60e51b81526004018080602001828103825260218152602001806130a56021913960400191505060405180910390fd5b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc188360010b13801561081557506103e88360010b125b6108505760405162461bcd60e51b8152600401808060200182810382526026815260200180612f656026913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84166108b8576040805162461bcd60e51b815260206004820152601460248201527f4552433230206164647265737320697320307830000000000000000000000000604482015290519081900360640190fd5b6040805160608101825273ffffffffffffffffffffffffffffffffffffffff808716808352600187810b602080860182815289151587890181815260008b8152600385528a812099518a54945192511515760100000000000000000000000000000000000000000000027fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff93890b61ffff1674010000000000000000000000000000000000000000027fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff92909b167fffffffffffffffffffffffff00000000000000000000000000000000000000009687161791909116999099179190911697909717909755600282529487902080549095163390811790955586519190920b8152908101939093528351859491937f28da1d6d2067c4645a98dd2864d916e009074ec474ca6eabfb5205502e65e09a92908290030190a49392505050565b600081815260026020526040902054819073ffffffffffffffffffffffffffffffffffffffff16610a8f576040805162461bcd60e51b815260206004820152601760248201527f74686520706f6f6c20646f6573206e6f74206578697374000000000000000000604482015290519081900360640190fd5b60008281526002602052604090205473ffffffffffffffffffffffffffffffffffffffff163314610b07576040805162461bcd60e51b815260206004820152601660248201527f7468697320706f6f6c206973206e6f74206f776e656400000000000000000000604482015290519081900360640190fd5b600082815260026020908152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081169091556003835281842080547fffffffffffffffffff0000000000000000000000000000000000000000000000169055600490925280832080549092169091555183917f724a716d65dc2323a35989a357a6ba80c85bebbb2e946555529efb6c1ef2cf9f91a25050565b6000806127108312610bd0576305f5b9f08313610bc55782610bcb565b6305f5b9f05b610bd4565b6127105b905083610be457620f42406106dd565b6127108486830281610bf257fe5b0481610bfa57fe5b0495945050505050565b600083815260026020526040902054839073ffffffffffffffffffffffffffffffffffffffff16610c7c576040805162461bcd60e51b815260206004820152601760248201527f74686520706f6f6c20646f6573206e6f74206578697374000000000000000000604482015290519081900360640190fd5b60008481526002602052604090205473ffffffffffffffffffffffffffffffffffffffff163314610cde5760405162461bcd60e51b81526004018080602001828103825260238152602001806130c66023913960400191505060405180910390fd5b505060009182526004602052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055565b600061065d868686611b6c565b60009081526004602052604081205473ffffffffffffffffffffffffffffffffffffffff1691565b6000610d738261238e565b92915050565b6000806000808713610dbc5760405162461bcd60e51b8152600401808060200182810382526023815260200180612eec6023913960400191505060405180910390fd5b60008513610dfb5760405162461bcd60e51b8152600401808060200182810382526028815260200180612f0f6028913960400191505060405180910390fd5b60008613610e3a5760405162461bcd60e51b81526004018080602001828103825260238152602001806130e96023913960400191505060405180910390fd5b6000841215610e90576040805162461bcd60e51b815260206004820152601b60248201527f4c42542073686f756c64206e6f74206861766520657870697265640000000000604482015290519081900360640190fd5b626ebe00841315610ed25760405162461bcd60e51b815260040180806020018281038252602c815260200180613035602c913960400191505060405180910390fd5b60008087896127100281610ee257fe5b0590506482c0226c66610ef4876124fb565b88026305f5e1000281610f0357fe5b0592506000610f118261256e565b90506000614e20850585836305f5e1000281610f2957fe5b05019050610f3681612631565b9350612710850581036000610f4a82612631565b905061271086138015610f5e575061271081135b15610f75576000610f718e8e8985610f92565b9950505b5050505050610f85888583610ba8565b9250509450945094915050565b600080848613610fa3576000610fa7565b8486035b90506305f5e1008584028786020305915080821215610fc4578091505b50949350505050565b60026020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b600080600080611003612ea6565b5060008681526003602090815260408083208151606081018352905473ffffffffffffffffffffffffffffffffffffffff81168252740100000000000000000000000000000000000000008104600190810b810b900b9382019390935276010000000000000000000000000000000000000000000090920460ff16151590820152908061108e61283f565b600154604080517f26d6c97b000000000000000000000000000000000000000000000000000000008152600481018f9052905193955091935060009273ffffffffffffffffffffffffffffffffffffffff909116916326d6c97b916024808301926080929190829003018186803b15801561110857600080fd5b505afa15801561111c573d6000803e3d6000fd5b505050506040513d608081101561113257600080fd5b506040015167ffffffffffffffff16905061114c8a61238e565b95506111658184848c8860200151600a0260010b612977565b809650819850505060006111ad87604051806060016040528060238152602001612f8b602391396111a08b6305f5e10063ffffffff611aca16565b919063ffffffff612ae916565b905060648111611204576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f20736d616c6c000000000000604482015290519081900360640190fd5b846040015115611234576305f5e1006112258288830163ffffffff611aca16565b8161122c57fe5b049850611256565b6305f5e10061124b8288830363ffffffff611aca16565b8161125257fe5b0498505b505050505093509350935093565b600082815260026020526040812054839073ffffffffffffffffffffffffffffffffffffffff166112dc576040805162461bcd60e51b815260206004820152601760248201527f74686520706f6f6c20646f6573206e6f74206578697374000000000000000000604482015290519081900360640190fd5b600154604080517ff2eefd80000000000000000000000000000000000000000000000000000000008152600481018890529051600092839260609273ffffffffffffffffffffffffffffffffffffffff9092169163f2eefd80916024808201928792909190829003018186803b15801561135557600080fd5b505afa158015611369573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160409081528110156113b057600080fd5b81019080805160405193929190846401000000008211156113d057600080fd5b9083019060208201858111156113e557600080fd5b825186602082028301116401000000008211171561140257600080fd5b82525081516020918201928201910280838360005b8381101561142f578181015183820152602001611417565b50505050919091016040525050825192935050600290911490506114845760405162461bcd60e51b81526004018080602001828103825260318152602001806130046031913960400191505060405180910390fd5b8060018151811061149157fe5b60200260200101519250806000815181106114a857fe5b60200260200101519150506000806000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166326d6c97b866040518263ffffffff1660e01b81526004018082815260200191505060806040518083038186803b15801561152b57600080fd5b505afa15801561153f573d6000803e3d6000fd5b505050506040513d608081101561155557600080fd5b5080516020909101519250905073ffffffffffffffffffffffffffffffffffffffff81166115ca576040805162461bcd60e51b815260206004820152601a60248201527f74686520626f6e64206973206e6f742072656769737465726564000000000000604482015290519081900360640190fd5b915060006115d6612ea6565b506000898152600360209081526040918290208251606081018452905473ffffffffffffffffffffffffffffffffffffffff81168252740100000000000000000000000000000000000000008104600190810b810b900b9282019290925276010000000000000000000000000000000000000000000090910460ff1615801592820192909252906116ae576040805162461bcd60e51b815260206004820152601f60248201527f5468697320706f6f6c206973206e6f7420666f7220627579696e67204c425400604482015290519081900360640190fd5b519050600080806116c0878d87610ff5565b50509150915081600014156117065760405162461bcd60e51b815260040180806020018281038252602e815260200180612f37602e913960400191505060405180910390fd5b6117286305f5e10061067e6117218e8663ffffffff611aca16565b8988612b81565b9950896117665760405162461bcd60e51b81526004018080602001828103825260238152602001806130826023913960400191505060405180910390fd5b6117f18673ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156117af57600080fd5b505afa1580156117c3573d6000803e3d6000fd5b505050506040513d60208110156117d957600080fd5b505160ff16600a0a61067e838e63ffffffff611aca16565b92506117fc83612ca5565b925050508173ffffffffffffffffffffffffffffffffffffffff166323b872dd600260008d815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16338b6040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b1580156118ee57600080fd5b505af1158015611902573d6000803e3d6000fd5b505050506040513d602081101561191857600080fd5b505161196b576040805162461bcd60e51b815260206004820152601c60248201527f6661696c20746f207472616e7366657220455243323020746f6b656e00000000604482015290519081900360640190fd5b60008a81526002602090815260408083205481517f23b872dd00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9182166024820152604481018e90529151908816936323b872dd93606480850194919392918390030190829087803b1580156119f857600080fd5b505af1158015611a0c573d6000803e3d6000fd5b505050506040513d6020811015611a2257600080fd5b5051611a75576040805162461bcd60e51b815260206004820152601460248201527f6661696c20746f207472616e73666572204c4254000000000000000000000000604482015290519081900360640190fd5b60408051828152602081018b90528082018a905290518c9133918d917f2ef7a8caf0ccf63fdd2c0138a6cc089e79fb22ca53ef02ad8d66a7a87f0876f4919081900360600190a4505050505050509392505050565b600082611ad957506000610d73565b82820282848281611ae657fe5b0414611b235760405162461bcd60e51b81526004018080602001828103825260218152602001806130616021913960400191505060405180910390fd5b9392505050565b6000611b2383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612ae9565b600082815260026020526040812054839073ffffffffffffffffffffffffffffffffffffffff16611be4576040805162461bcd60e51b815260206004820152601760248201527f74686520706f6f6c20646f6573206e6f74206578697374000000000000000000604482015290519081900360640190fd5b600154604080517ff2eefd80000000000000000000000000000000000000000000000000000000008152600481018890529051600092839260609273ffffffffffffffffffffffffffffffffffffffff9092169163f2eefd80916024808201928792909190829003018186803b158015611c5d57600080fd5b505afa158015611c71573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040908152811015611cb857600080fd5b8101908080516040519392919084640100000000821115611cd857600080fd5b908301906020820185811115611ced57600080fd5b8251866020820283011164010000000082111715611d0a57600080fd5b82525081516020918201928201910280838360005b83811015611d37578181015183820152602001611d1f565b5050505091909101604052505082519293505060029091149050611d8c5760405162461bcd60e51b81526004018080602001828103825260318152602001806130046031913960400191505060405180910390fd5b80600181518110611d9957fe5b6020026020010151915080600081518110611db057fe5b60200260200101519250506000806000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166326d6c97b856040518263ffffffff1660e01b81526004018082815260200191505060806040518083038186803b158015611e3357600080fd5b505afa158015611e47573d6000803e3d6000fd5b505050506040513d6080811015611e5d57600080fd5b5080516020909101519250905073ffffffffffffffffffffffffffffffffffffffff8116611ed2576040805162461bcd60e51b815260206004820152601a60248201527f74686520626f6e64206973206e6f742072656769737465726564000000000000604482015290519081900360640190fd5b91506000611ede612ea6565b506000898152600360209081526040918290208251606081018452905473ffffffffffffffffffffffffffffffffffffffff81168252740100000000000000000000000000000000000000008104600190810b810b900b9282019290925276010000000000000000000000000000000000000000000090910460ff16151591810182905290611fb4576040805162461bcd60e51b815260206004820152601b60248201527f5468697320706f6f6c20697320666f7220627579696e67204c42540000000000604482015290519081900360640190fd5b51905060008080611fc6888d87610ff5565b509250509150816000141561200c5760405162461bcd60e51b815260040180806020018281038252602e815260200180612f37602e913960400191505060405180910390fd5b61202e8261067e6120278e6305f5e10063ffffffff611aca16565b878a612b81565b99508961206c5760405162461bcd60e51b8152600401808060200182810382526021815260200180612fe36021913960400191505060405180910390fd5b6120b58473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156117af57600080fd5b92506120c083612ca5565b925050508173ffffffffffffffffffffffffffffffffffffffff166323b872dd33600260008e815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168c6040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b1580156121b257600080fd5b505af11580156121c6573d6000803e3d6000fd5b505050506040513d60208110156121dc57600080fd5b505161222f576040805162461bcd60e51b815260206004820152601c60248201527f6661696c20746f207472616e7366657220455243323020746f6b656e00000000604482015290519081900360640190fd5b60008a81526002602090815260408083205481517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152336024820152604481018d90529151908816936323b872dd93606480850194919392918390030190829087803b1580156122bc57600080fd5b505af11580156122d0573d6000803e3d6000fd5b505050506040513d60208110156122e657600080fd5b5051612339576040805162461bcd60e51b815260206004820152601460248201527f6661696c20746f207472616e73666572204c4254000000000000000000000000604482015290519081900360640190fd5b60408051828152602081018a90528082018b905290518c9133918d917fedaa6b09cf775df20048bc57896c1b841891baf226f9379143023ea272929a69919081900360600190a4505050505050509392505050565b600081815260026020526040812054829073ffffffffffffffffffffffffffffffffffffffff16612406576040805162461bcd60e51b815260206004820152601760248201527f74686520706f6f6c20646f6573206e6f74206578697374000000000000000000604482015290519081900360640190fd5b60008381526004602052604090205473ffffffffffffffffffffffffffffffffffffffff168061247d576040805162461bcd60e51b815260206004820152601a60248201527f696e76616c6964204552433230207072696365206f7261636c65000000000000604482015290519081900360640190fd5b8073ffffffffffffffffffffffffffffffffffffffff1663a3e6ba946040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156124c557600080fd5b505af11580156124d9573d6000803e3d6000fd5b505050506040513d60208110156124ef57600080fd5b50519250505b50919050565b60008082121561253c5760405162461bcd60e51b8152600401808060200182810382526035815260200180612fae6035913960400191505060405180910390fd5b5080600260018201055b818112156124f55780915060028182858161255d57fe5b05018161256657fe5b059050612546565b6000600182136125c5576040805162461bcd60e51b815260206004820152601f60248201527f696e7075742073686f756c6420626520706f736974697665206e756d62657200604482015290519081900360640190fd5b61271082025b63023156e88112156125f2576305f5e100631033c4d68202059050612710820391506125cb565b6305f5e100811315612619576305f5e10063023156e88202059050612710820191506125f2565b61262861271080830503612cd7565b90910192915050565b6000624323808212801561266457507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbcdc8082135b6126b5576040805162461bcd60e51b815260206004820152601260248201527f696e70757420697320746f6f206c617267650000000000000000000000000000604482015290519081900360640190fd5b60008083136126e657827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff026126e8565b825b90506000612710630161751e8302056305f5e10001662386f26fc100008161270c57fe5b059050600284800281900590630bebc20090820a05810166d529ae9e8600006003830a05016a13da329b633647180000006004830a05016e024fa54b36a2e6a9104478000000006005830a05017152a6e5f7f5748f5b12fb0220d000000000006006830a05016305f5e100016000630ef0cfab8269d3c21bcecceda10000008161279257fe5b058161279a57fe5b059050662386f26fc100006305f5e1006307edd67286028190057ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff524fbe3018602819005630a9e51d10186028190057ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffddfed460186028190056301e7566901860283029190910590036000881361283157806305f5e10003612833565b805b98975050505050505050565b60008054604080517fa3e6ba940000000000000000000000000000000000000000000000000000000081529051839273ffffffffffffffffffffffffffffffffffffffff169163a3e6ba9491600480830192602092919082900301818787803b1580156128ab57600080fd5b505af11580156128bf573d6000803e3d6000fd5b505050506040513d60208110156128d557600080fd5b5051600054604080517fd5480277000000000000000000000000000000000000000000000000000000008152905192945073ffffffffffffffffffffffffffffffffffffffff9091169163d548027791600480820192602092909190829003018186803b15801561294557600080fd5b505afa158015612959573d6000803e3d6000fd5b505050506040513d602081101561296f57600080fd5b505190509091565b60008060006129c9612987612d46565b60408051808201909152601b81527f4c42542073686f756c64206e6f74206861766520657870697265640000000000602082015287919063ffffffff612d4a16565b90506000655af3107a40005b600a81106129f957808a106129e9576129f9565b60019190910190600a90046129d5565b50600080612a098a600885612da4565b90506000612a198c600886612da4565b90506000612a49612a2984612e42565b612a3284612e42565b612a3b8e612e42565b612a448a612e42565b610d79565b5094509050612a5a81866008612da4565b975050505060006305f5e1008910612a8857630bebc2008911612a7d5788612a83565b630bebc2005b612a8e565b6305f5e1005b90506305f5e10082820204612abf6000891280612aac575061271082105b612ab65781612aba565b6127105b612e42565b8802955062e4e1c08613612ad35785612ad8565b62e4e1c05b955050505050509550959350505050565b60008183612b755760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612b3a578181015183820152602001612b22565b50505050905090810190601f168015612b675780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581610bfa57fe5b6000808373ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612bca57600080fd5b505afa158015612bde573d6000803e3d6000fd5b505050506040513d6020811015612bf457600080fd5b5051604080517f313ce567000000000000000000000000000000000000000000000000000000008152905191925060009173ffffffffffffffffffffffffffffffffffffffff86169163313ce567916004808301926020929190829003018186803b158015612c6257600080fd5b505afa158015612c76573d6000803e3d6000fd5b505050506040513d6020811015612c8c57600080fd5b50519050612c9b868383612da4565b9695505050505050565b600080612cb061283f565b50905080612cc8846305f5e10063ffffffff611aca16565b81612ccf57fe5b049392505050565b60006c01027e72f1f1281308800000006008830a056a05ca4ec2a79a7f670000006007840a05682086ac3510526000006006850a0566b1a2bc2ec500006005860a056503a3529440006004870a056311e1a3006003880a05614e206002890a0588030103010301039050919050565b4290565b60008184841115612d9c5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315612b3a578181015183820152602001612b22565b505050900390565b60008060008360ff168560ff161115612dc3575060ff83850316612dda565b8360ff168560ff161015612dda5784840360ff1691505b601382108015612dea5750601381105b612e255760405162461bcd60e51b8152600401808060200182810382526025815260200180612ec76025913960400191505060405180910390fd5b612c9b81600a0a61067e84600a0a89611aca90919063ffffffff16565b60007f80000000000000000000000000000000000000000000000000000000000000008210612ea25760405162461bcd60e51b815260040180806020018281038252602881526020018061310c6028913960400191505060405180910390fd5b5090565b60408051606081018252600080825260208201819052918101919091529056fe646563696d616c20676170206e6565647320746f206265206c6f776572207468616e203139746865207072696365206f66204554482073686f756c6420626520706f73697469766574686520766f6c6174696c697479206f66204554482073686f756c6420626520706f73697469766565786368616e6765207261746520696e636c7564656420737072656164206d757374206265206e6f6e2d7a65726f7468652072616e6765206f66206665652062617365206d757374206265202d3939397e3939394552433230206f7261636c65207072696365206d757374206265206e6f6e2d7a65726f63616e6e6f742063616c63756c617465207468652073717561726520726f6f74206f662061206e65676174697665206e756d6265726d757374207472616e73666572206e6f6e2d7a65726f204c425420616d6f756e7474686520626f6e642067726f7570206d75737420696e636c756465206f6e6c792032207479706573206f6620626f6e642e746865206d61747572697479206f66204c42542073686f756c64206e6f7420626520736f2064697374616e74536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f776d757374207472616e73666572206e6f6e2d7a65726f20746f6b656e20616d6f756e746465706c6f796572206d757374206265206e6f6e2d7a65726f20616464726573736f6e6c79206465706c6f79657220697320616c6c6f77656420746f206578656375746574686520737472696b652070726963652073686f756c6420626520706f73697469766553616665436173743a2076616c756520646f65736e27742066697420696e20616e20696e74323536a26469706673582212202e3d4a1c39fa98a24898ef6b0c7960e1db205a22000f8a37736342a96a5cc9d564736f6c6343000606003374686520646563696d616c73206f66206f7261636c65207072696365206d7573742062652038636f6e74726163742073686f756c64206265206e6f6e2d7a65726f206164647265737374686520646563696d616c73206f6620626f6e6420746f6b656e206d7573742062652038000000000000000000000000481d0c28ad5a3ec985bee820c7a99ec280b51d5f00000000000000000000000034e68a86930b2d2cdb3563479f765d30d6c8c710
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100f55760003560e01c8063541240c211610097578063a5761d6411610066578063a5761d64146103b1578063c72e47dc146103ce578063faceb3b51461041b578063fe74de2f1461044a576100f5565b8063541240c2146102c2578063816501c7146102eb57806390c2f87b1461032c5780639214554d14610361576100f5565b8063134c1abc116100d3578063134c1abc146101ef5780633796a8051461022a5780633bc714271461025f5780635392fb4e146102a3576100f5565b806309f2c019146100fa5780630b1a3554146101655780630defebeb14610196575b600080fd5b6101176004803603602081101561011057600080fd5b5035610467565b6040805173ffffffffffffffffffffffffffffffffffffffff96871681529486166020860152600193840b90930b848401529015156060840152909216608082015290519081900360a00190f35b61016d6105b8565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6101b3600480360360208110156101ac57600080fd5b50356105d4565b6040805173ffffffffffffffffffffffffffffffffffffffff9094168452600192830b90920b6020840152151582820152519081900360600190f35b6102186004803603606081101561020557600080fd5b5080359060208101359060400135610637565b60408051918252519081900360200190f35b610218600480360360a081101561024057600080fd5b5080359060208101359060408101359060608101359060800135610650565b6102186004803603606081101561027557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602081013560010b906040013515156106e6565b6102c0600480360360208110156102b957600080fd5b5035610a17565b005b610218600480360360608110156102d857600080fd5b5080359060208101359060400135610ba8565b6102c06004803603606081101561030157600080fd5b5080359073ffffffffffffffffffffffffffffffffffffffff60208201358116916040013516610c04565b610218600480360360a081101561034257600080fd5b5080359060208101359060408101359060608101359060800135610d33565b61037e6004803603602081101561037757600080fd5b5035610d40565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815291909216602082015281519081900390910190f35b610218600480360360208110156103c757600080fd5b5035610d68565b6103fd600480360360808110156103e457600080fd5b5080359060208101359060408101359060600135610d79565b60408051938452602084019290925282820152519081900360600190f35b6102186004803603608081101561043157600080fd5b5080359060208101359060408101359060600135610f92565b61016d6004803603602081101561046057600080fd5b5035610fcd565b6000818152600260205260408120548190819081908190869073ffffffffffffffffffffffffffffffffffffffff166104e7576040805162461bcd60e51b815260206004820152601760248201527f74686520706f6f6c20646f6573206e6f74206578697374000000000000000000604482015290519081900360640190fd5b60008781526002602052604090205473ffffffffffffffffffffffffffffffffffffffff169550610516612ea6565b50505060008581526003602090815260408083208151606081018352905473ffffffffffffffffffffffffffffffffffffffff808216808452740100000000000000000000000000000000000000008304600190810b810b900b84870181905276010000000000000000000000000000000000000000000090930460ff1615159385018490529a86526004909452919093205496989096929550911692509050565b60015473ffffffffffffffffffffffffffffffffffffffff1690565b60036020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000810460010b90760100000000000000000000000000000000000000000000900460ff1683565b6000610644848484610ff5565b50919695505050505050565b600061065d868686611264565b905082156106dd578261068a6103e861067e8486830163ffffffff611aca16565b9063ffffffff611b2a16565b10156106dd576040805162461bcd60e51b815260206004820152601260248201527f6f7574206f662070726963652072616e67650000000000000000000000000000604482015290519081900360640190fd5b95945050505050565b604080513360208083019190915273ffffffffffffffffffffffffffffffffffffffff80871683850152600186810b900b60608401528415156080808501919091528451808503909101815260a09093018452825192820192909220600081815260029092529290205416156107a3576040805162461bcd60e51b815260206004820152601260248201527f616c726561647920726567697374657265640000000000000000000000000000604482015290519081900360640190fd5b336107df5760405162461bcd60e51b81526004018080602001828103825260218152602001806130a56021913960400191505060405180910390fd5b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc188360010b13801561081557506103e88360010b125b6108505760405162461bcd60e51b8152600401808060200182810382526026815260200180612f656026913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84166108b8576040805162461bcd60e51b815260206004820152601460248201527f4552433230206164647265737320697320307830000000000000000000000000604482015290519081900360640190fd5b6040805160608101825273ffffffffffffffffffffffffffffffffffffffff808716808352600187810b602080860182815289151587890181815260008b8152600385528a812099518a54945192511515760100000000000000000000000000000000000000000000027fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff93890b61ffff1674010000000000000000000000000000000000000000027fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff92909b167fffffffffffffffffffffffff00000000000000000000000000000000000000009687161791909116999099179190911697909717909755600282529487902080549095163390811790955586519190920b8152908101939093528351859491937f28da1d6d2067c4645a98dd2864d916e009074ec474ca6eabfb5205502e65e09a92908290030190a49392505050565b600081815260026020526040902054819073ffffffffffffffffffffffffffffffffffffffff16610a8f576040805162461bcd60e51b815260206004820152601760248201527f74686520706f6f6c20646f6573206e6f74206578697374000000000000000000604482015290519081900360640190fd5b60008281526002602052604090205473ffffffffffffffffffffffffffffffffffffffff163314610b07576040805162461bcd60e51b815260206004820152601660248201527f7468697320706f6f6c206973206e6f74206f776e656400000000000000000000604482015290519081900360640190fd5b600082815260026020908152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081169091556003835281842080547fffffffffffffffffff0000000000000000000000000000000000000000000000169055600490925280832080549092169091555183917f724a716d65dc2323a35989a357a6ba80c85bebbb2e946555529efb6c1ef2cf9f91a25050565b6000806127108312610bd0576305f5b9f08313610bc55782610bcb565b6305f5b9f05b610bd4565b6127105b905083610be457620f42406106dd565b6127108486830281610bf257fe5b0481610bfa57fe5b0495945050505050565b600083815260026020526040902054839073ffffffffffffffffffffffffffffffffffffffff16610c7c576040805162461bcd60e51b815260206004820152601760248201527f74686520706f6f6c20646f6573206e6f74206578697374000000000000000000604482015290519081900360640190fd5b60008481526002602052604090205473ffffffffffffffffffffffffffffffffffffffff163314610cde5760405162461bcd60e51b81526004018080602001828103825260238152602001806130c66023913960400191505060405180910390fd5b505060009182526004602052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055565b600061065d868686611b6c565b60009081526004602052604081205473ffffffffffffffffffffffffffffffffffffffff1691565b6000610d738261238e565b92915050565b6000806000808713610dbc5760405162461bcd60e51b8152600401808060200182810382526023815260200180612eec6023913960400191505060405180910390fd5b60008513610dfb5760405162461bcd60e51b8152600401808060200182810382526028815260200180612f0f6028913960400191505060405180910390fd5b60008613610e3a5760405162461bcd60e51b81526004018080602001828103825260238152602001806130e96023913960400191505060405180910390fd5b6000841215610e90576040805162461bcd60e51b815260206004820152601b60248201527f4c42542073686f756c64206e6f74206861766520657870697265640000000000604482015290519081900360640190fd5b626ebe00841315610ed25760405162461bcd60e51b815260040180806020018281038252602c815260200180613035602c913960400191505060405180910390fd5b60008087896127100281610ee257fe5b0590506482c0226c66610ef4876124fb565b88026305f5e1000281610f0357fe5b0592506000610f118261256e565b90506000614e20850585836305f5e1000281610f2957fe5b05019050610f3681612631565b9350612710850581036000610f4a82612631565b905061271086138015610f5e575061271081135b15610f75576000610f718e8e8985610f92565b9950505b5050505050610f85888583610ba8565b9250509450945094915050565b600080848613610fa3576000610fa7565b8486035b90506305f5e1008584028786020305915080821215610fc4578091505b50949350505050565b60026020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b600080600080611003612ea6565b5060008681526003602090815260408083208151606081018352905473ffffffffffffffffffffffffffffffffffffffff81168252740100000000000000000000000000000000000000008104600190810b810b900b9382019390935276010000000000000000000000000000000000000000000090920460ff16151590820152908061108e61283f565b600154604080517f26d6c97b000000000000000000000000000000000000000000000000000000008152600481018f9052905193955091935060009273ffffffffffffffffffffffffffffffffffffffff909116916326d6c97b916024808301926080929190829003018186803b15801561110857600080fd5b505afa15801561111c573d6000803e3d6000fd5b505050506040513d608081101561113257600080fd5b506040015167ffffffffffffffff16905061114c8a61238e565b95506111658184848c8860200151600a0260010b612977565b809650819850505060006111ad87604051806060016040528060238152602001612f8b602391396111a08b6305f5e10063ffffffff611aca16565b919063ffffffff612ae916565b905060648111611204576040805162461bcd60e51b815260206004820152601a60248201527f65786368616e6765207261746520697320746f6f20736d616c6c000000000000604482015290519081900360640190fd5b846040015115611234576305f5e1006112258288830163ffffffff611aca16565b8161122c57fe5b049850611256565b6305f5e10061124b8288830363ffffffff611aca16565b8161125257fe5b0498505b505050505093509350935093565b600082815260026020526040812054839073ffffffffffffffffffffffffffffffffffffffff166112dc576040805162461bcd60e51b815260206004820152601760248201527f74686520706f6f6c20646f6573206e6f74206578697374000000000000000000604482015290519081900360640190fd5b600154604080517ff2eefd80000000000000000000000000000000000000000000000000000000008152600481018890529051600092839260609273ffffffffffffffffffffffffffffffffffffffff9092169163f2eefd80916024808201928792909190829003018186803b15801561135557600080fd5b505afa158015611369573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160409081528110156113b057600080fd5b81019080805160405193929190846401000000008211156113d057600080fd5b9083019060208201858111156113e557600080fd5b825186602082028301116401000000008211171561140257600080fd5b82525081516020918201928201910280838360005b8381101561142f578181015183820152602001611417565b50505050919091016040525050825192935050600290911490506114845760405162461bcd60e51b81526004018080602001828103825260318152602001806130046031913960400191505060405180910390fd5b8060018151811061149157fe5b60200260200101519250806000815181106114a857fe5b60200260200101519150506000806000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166326d6c97b866040518263ffffffff1660e01b81526004018082815260200191505060806040518083038186803b15801561152b57600080fd5b505afa15801561153f573d6000803e3d6000fd5b505050506040513d608081101561155557600080fd5b5080516020909101519250905073ffffffffffffffffffffffffffffffffffffffff81166115ca576040805162461bcd60e51b815260206004820152601a60248201527f74686520626f6e64206973206e6f742072656769737465726564000000000000604482015290519081900360640190fd5b915060006115d6612ea6565b506000898152600360209081526040918290208251606081018452905473ffffffffffffffffffffffffffffffffffffffff81168252740100000000000000000000000000000000000000008104600190810b810b900b9282019290925276010000000000000000000000000000000000000000000090910460ff1615801592820192909252906116ae576040805162461bcd60e51b815260206004820152601f60248201527f5468697320706f6f6c206973206e6f7420666f7220627579696e67204c425400604482015290519081900360640190fd5b519050600080806116c0878d87610ff5565b50509150915081600014156117065760405162461bcd60e51b815260040180806020018281038252602e815260200180612f37602e913960400191505060405180910390fd5b6117286305f5e10061067e6117218e8663ffffffff611aca16565b8988612b81565b9950896117665760405162461bcd60e51b81526004018080602001828103825260238152602001806130826023913960400191505060405180910390fd5b6117f18673ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156117af57600080fd5b505afa1580156117c3573d6000803e3d6000fd5b505050506040513d60208110156117d957600080fd5b505160ff16600a0a61067e838e63ffffffff611aca16565b92506117fc83612ca5565b925050508173ffffffffffffffffffffffffffffffffffffffff166323b872dd600260008d815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16338b6040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b1580156118ee57600080fd5b505af1158015611902573d6000803e3d6000fd5b505050506040513d602081101561191857600080fd5b505161196b576040805162461bcd60e51b815260206004820152601c60248201527f6661696c20746f207472616e7366657220455243323020746f6b656e00000000604482015290519081900360640190fd5b60008a81526002602090815260408083205481517f23b872dd00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9182166024820152604481018e90529151908816936323b872dd93606480850194919392918390030190829087803b1580156119f857600080fd5b505af1158015611a0c573d6000803e3d6000fd5b505050506040513d6020811015611a2257600080fd5b5051611a75576040805162461bcd60e51b815260206004820152601460248201527f6661696c20746f207472616e73666572204c4254000000000000000000000000604482015290519081900360640190fd5b60408051828152602081018b90528082018a905290518c9133918d917f2ef7a8caf0ccf63fdd2c0138a6cc089e79fb22ca53ef02ad8d66a7a87f0876f4919081900360600190a4505050505050509392505050565b600082611ad957506000610d73565b82820282848281611ae657fe5b0414611b235760405162461bcd60e51b81526004018080602001828103825260218152602001806130616021913960400191505060405180910390fd5b9392505050565b6000611b2383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612ae9565b600082815260026020526040812054839073ffffffffffffffffffffffffffffffffffffffff16611be4576040805162461bcd60e51b815260206004820152601760248201527f74686520706f6f6c20646f6573206e6f74206578697374000000000000000000604482015290519081900360640190fd5b600154604080517ff2eefd80000000000000000000000000000000000000000000000000000000008152600481018890529051600092839260609273ffffffffffffffffffffffffffffffffffffffff9092169163f2eefd80916024808201928792909190829003018186803b158015611c5d57600080fd5b505afa158015611c71573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040908152811015611cb857600080fd5b8101908080516040519392919084640100000000821115611cd857600080fd5b908301906020820185811115611ced57600080fd5b8251866020820283011164010000000082111715611d0a57600080fd5b82525081516020918201928201910280838360005b83811015611d37578181015183820152602001611d1f565b5050505091909101604052505082519293505060029091149050611d8c5760405162461bcd60e51b81526004018080602001828103825260318152602001806130046031913960400191505060405180910390fd5b80600181518110611d9957fe5b6020026020010151915080600081518110611db057fe5b60200260200101519250506000806000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166326d6c97b856040518263ffffffff1660e01b81526004018082815260200191505060806040518083038186803b158015611e3357600080fd5b505afa158015611e47573d6000803e3d6000fd5b505050506040513d6080811015611e5d57600080fd5b5080516020909101519250905073ffffffffffffffffffffffffffffffffffffffff8116611ed2576040805162461bcd60e51b815260206004820152601a60248201527f74686520626f6e64206973206e6f742072656769737465726564000000000000604482015290519081900360640190fd5b91506000611ede612ea6565b506000898152600360209081526040918290208251606081018452905473ffffffffffffffffffffffffffffffffffffffff81168252740100000000000000000000000000000000000000008104600190810b810b900b9282019290925276010000000000000000000000000000000000000000000090910460ff16151591810182905290611fb4576040805162461bcd60e51b815260206004820152601b60248201527f5468697320706f6f6c20697320666f7220627579696e67204c42540000000000604482015290519081900360640190fd5b51905060008080611fc6888d87610ff5565b509250509150816000141561200c5760405162461bcd60e51b815260040180806020018281038252602e815260200180612f37602e913960400191505060405180910390fd5b61202e8261067e6120278e6305f5e10063ffffffff611aca16565b878a612b81565b99508961206c5760405162461bcd60e51b8152600401808060200182810382526021815260200180612fe36021913960400191505060405180910390fd5b6120b58473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156117af57600080fd5b92506120c083612ca5565b925050508173ffffffffffffffffffffffffffffffffffffffff166323b872dd33600260008e815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168c6040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b1580156121b257600080fd5b505af11580156121c6573d6000803e3d6000fd5b505050506040513d60208110156121dc57600080fd5b505161222f576040805162461bcd60e51b815260206004820152601c60248201527f6661696c20746f207472616e7366657220455243323020746f6b656e00000000604482015290519081900360640190fd5b60008a81526002602090815260408083205481517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152336024820152604481018d90529151908816936323b872dd93606480850194919392918390030190829087803b1580156122bc57600080fd5b505af11580156122d0573d6000803e3d6000fd5b505050506040513d60208110156122e657600080fd5b5051612339576040805162461bcd60e51b815260206004820152601460248201527f6661696c20746f207472616e73666572204c4254000000000000000000000000604482015290519081900360640190fd5b60408051828152602081018a90528082018b905290518c9133918d917fedaa6b09cf775df20048bc57896c1b841891baf226f9379143023ea272929a69919081900360600190a4505050505050509392505050565b600081815260026020526040812054829073ffffffffffffffffffffffffffffffffffffffff16612406576040805162461bcd60e51b815260206004820152601760248201527f74686520706f6f6c20646f6573206e6f74206578697374000000000000000000604482015290519081900360640190fd5b60008381526004602052604090205473ffffffffffffffffffffffffffffffffffffffff168061247d576040805162461bcd60e51b815260206004820152601a60248201527f696e76616c6964204552433230207072696365206f7261636c65000000000000604482015290519081900360640190fd5b8073ffffffffffffffffffffffffffffffffffffffff1663a3e6ba946040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156124c557600080fd5b505af11580156124d9573d6000803e3d6000fd5b505050506040513d60208110156124ef57600080fd5b50519250505b50919050565b60008082121561253c5760405162461bcd60e51b8152600401808060200182810382526035815260200180612fae6035913960400191505060405180910390fd5b5080600260018201055b818112156124f55780915060028182858161255d57fe5b05018161256657fe5b059050612546565b6000600182136125c5576040805162461bcd60e51b815260206004820152601f60248201527f696e7075742073686f756c6420626520706f736974697665206e756d62657200604482015290519081900360640190fd5b61271082025b63023156e88112156125f2576305f5e100631033c4d68202059050612710820391506125cb565b6305f5e100811315612619576305f5e10063023156e88202059050612710820191506125f2565b61262861271080830503612cd7565b90910192915050565b6000624323808212801561266457507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbcdc8082135b6126b5576040805162461bcd60e51b815260206004820152601260248201527f696e70757420697320746f6f206c617267650000000000000000000000000000604482015290519081900360640190fd5b60008083136126e657827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff026126e8565b825b90506000612710630161751e8302056305f5e10001662386f26fc100008161270c57fe5b059050600284800281900590630bebc20090820a05810166d529ae9e8600006003830a05016a13da329b633647180000006004830a05016e024fa54b36a2e6a9104478000000006005830a05017152a6e5f7f5748f5b12fb0220d000000000006006830a05016305f5e100016000630ef0cfab8269d3c21bcecceda10000008161279257fe5b058161279a57fe5b059050662386f26fc100006305f5e1006307edd67286028190057ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff524fbe3018602819005630a9e51d10186028190057ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffddfed460186028190056301e7566901860283029190910590036000881361283157806305f5e10003612833565b805b98975050505050505050565b60008054604080517fa3e6ba940000000000000000000000000000000000000000000000000000000081529051839273ffffffffffffffffffffffffffffffffffffffff169163a3e6ba9491600480830192602092919082900301818787803b1580156128ab57600080fd5b505af11580156128bf573d6000803e3d6000fd5b505050506040513d60208110156128d557600080fd5b5051600054604080517fd5480277000000000000000000000000000000000000000000000000000000008152905192945073ffffffffffffffffffffffffffffffffffffffff9091169163d548027791600480820192602092909190829003018186803b15801561294557600080fd5b505afa158015612959573d6000803e3d6000fd5b505050506040513d602081101561296f57600080fd5b505190509091565b60008060006129c9612987612d46565b60408051808201909152601b81527f4c42542073686f756c64206e6f74206861766520657870697265640000000000602082015287919063ffffffff612d4a16565b90506000655af3107a40005b600a81106129f957808a106129e9576129f9565b60019190910190600a90046129d5565b50600080612a098a600885612da4565b90506000612a198c600886612da4565b90506000612a49612a2984612e42565b612a3284612e42565b612a3b8e612e42565b612a448a612e42565b610d79565b5094509050612a5a81866008612da4565b975050505060006305f5e1008910612a8857630bebc2008911612a7d5788612a83565b630bebc2005b612a8e565b6305f5e1005b90506305f5e10082820204612abf6000891280612aac575061271082105b612ab65781612aba565b6127105b612e42565b8802955062e4e1c08613612ad35785612ad8565b62e4e1c05b955050505050509550959350505050565b60008183612b755760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612b3a578181015183820152602001612b22565b50505050905090810190601f168015612b675780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581610bfa57fe5b6000808373ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612bca57600080fd5b505afa158015612bde573d6000803e3d6000fd5b505050506040513d6020811015612bf457600080fd5b5051604080517f313ce567000000000000000000000000000000000000000000000000000000008152905191925060009173ffffffffffffffffffffffffffffffffffffffff86169163313ce567916004808301926020929190829003018186803b158015612c6257600080fd5b505afa158015612c76573d6000803e3d6000fd5b505050506040513d6020811015612c8c57600080fd5b50519050612c9b868383612da4565b9695505050505050565b600080612cb061283f565b50905080612cc8846305f5e10063ffffffff611aca16565b81612ccf57fe5b049392505050565b60006c01027e72f1f1281308800000006008830a056a05ca4ec2a79a7f670000006007840a05682086ac3510526000006006850a0566b1a2bc2ec500006005860a056503a3529440006004870a056311e1a3006003880a05614e206002890a0588030103010301039050919050565b4290565b60008184841115612d9c5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315612b3a578181015183820152602001612b22565b505050900390565b60008060008360ff168560ff161115612dc3575060ff83850316612dda565b8360ff168560ff161015612dda5784840360ff1691505b601382108015612dea5750601381105b612e255760405162461bcd60e51b8152600401808060200182810382526025815260200180612ec76025913960400191505060405180910390fd5b612c9b81600a0a61067e84600a0a89611aca90919063ffffffff16565b60007f80000000000000000000000000000000000000000000000000000000000000008210612ea25760405162461bcd60e51b815260040180806020018281038252602881526020018061310c6028913960400191505060405180910390fd5b5090565b60408051606081018252600080825260208201819052918101919091529056fe646563696d616c20676170206e6565647320746f206265206c6f776572207468616e203139746865207072696365206f66204554482073686f756c6420626520706f73697469766574686520766f6c6174696c697479206f66204554482073686f756c6420626520706f73697469766565786368616e6765207261746520696e636c7564656420737072656164206d757374206265206e6f6e2d7a65726f7468652072616e6765206f66206665652062617365206d757374206265202d3939397e3939394552433230206f7261636c65207072696365206d757374206265206e6f6e2d7a65726f63616e6e6f742063616c63756c617465207468652073717561726520726f6f74206f662061206e65676174697665206e756d6265726d757374207472616e73666572206e6f6e2d7a65726f204c425420616d6f756e7474686520626f6e642067726f7570206d75737420696e636c756465206f6e6c792032207479706573206f6620626f6e642e746865206d61747572697479206f66204c42542073686f756c64206e6f7420626520736f2064697374616e74536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f776d757374207472616e73666572206e6f6e2d7a65726f20746f6b656e20616d6f756e746465706c6f796572206d757374206265206e6f6e2d7a65726f20616464726573736f6e6c79206465706c6f79657220697320616c6c6f77656420746f206578656375746574686520737472696b652070726963652073686f756c6420626520706f73697469766553616665436173743a2076616c756520646f65736e27742066697420696e20616e20696e74323536a26469706673582212202e3d4a1c39fa98a24898ef6b0c7960e1db205a22000f8a37736342a96a5cc9d564736f6c63430006060033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000481d0c28ad5a3ec985bee820c7a99ec280b51d5f00000000000000000000000034e68a86930b2d2cdb3563479f765d30d6c8c710
-----Decoded View---------------
Arg [0] : ethBondMakerCollateralizedUsdcAddress (address): 0x481d0C28Ad5A3ec985bEE820C7a99EC280B51D5f
Arg [1] : ethPriceInverseOracleAddress (address): 0x34e68a86930b2d2cdB3563479f765d30d6C8c710
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000481d0c28ad5a3ec985bee820c7a99ec280b51d5f
Arg [1] : 00000000000000000000000034e68a86930b2d2cdb3563479f765d30d6c8c710
Deployed Bytecode Sourcemap
108206:547:0:-:0;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;108206:547:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12:1:-1;9;2:12;95821:621:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;95821:621:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;107728:113;;;:::i;:::-;;;;;;;;;;;;;;;;;;;92348:43;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;92348:43:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;97036:251;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;97036:251:0;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;104661:503;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;104661:503:0;;;;;;;;;;;;;;;;;;;;;;:::i;94250:802::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;94250:802:0;;;;;;;;;;;;;;;;;;:::i;107372:348::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;107372:348:0;;:::i;:::-;;9703:496;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;9703:496:0;;;;;;;;;;;;:::i;95163:324::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;95163:324:0;;;;;;;;;;;;;;;;:::i;101823:454::-;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;101823:454:0;;;;;;;;;;;;;;;;;;;;;;:::i;95564:249::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;95564:249:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;96450:134;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;96450:134:0;;:::i;10374:1579::-;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;10374:1579:0;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;9149:546;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;9149:546:0;;;;;;;;;;;;;;;;;:::i;91893:43::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;91893:43:0;;:::i;95821:621::-;95954:23;93404:21;;;:8;:21;;;;;;95954:23;;;;;;;;95914:6;;93404:35;:21;93396:71;;;;;-1:-1:-1;;;93396:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;96160:16:::1;::::0;;;:8:::1;:16;::::0;;;;;::::1;;::::0;-1:-1:-1;96187:24:0::1;;:::i;:::-;-1:-1:-1::0;;;96214:15:0::1;::::0;;;:7:::1;:15;::::0;;;;;;;96187:42;;::::1;::::0;::::1;::::0;;;;::::1;::::0;;::::1;::::0;;;;;::::1;::::0;;;::::1;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;;;;;;::::1;;;;;::::0;;;;;;96410:23;;;:15:::1;:23:::0;;;;;;;;95821:621;;96187:42;;;;-1:-1:-1;96410:23:0;::::1;::::0;-1:-1:-1;95821:621:0;-1:-1:-1;95821:621:0:o;107728:113::-;107814:18;;;;107728:113;:::o;92348:43::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;97036:251::-;97169:23;97231:48;97250:5;97257:11;97270:8;97231:18;:48::i;:::-;-1:-1:-1;97205:74:0;;97036:251;-1:-1:-1;;;;;;97036:251:0:o;104661:503::-;104856:19;104902:55;104921:11;104934;104947:9;104902:18;:55::i;:::-;104888:69;-1:-1:-1;104972:19:0;;104968:189;;105077:14;105034:39;105068:4;105034:29;:11;105050:12;;;105034:29;:15;:29;:::i;:::-;:33;:39;:33;:39;:::i;:::-;:57;;105008:137;;;;;-1:-1:-1;;;105008:137:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;104661:503;;;;;;;:::o;94250:802::-;94434:59;;;94445:10;94434:59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;94434:59:0;;;;;;94424:70;;;;;;;;;94378:19;94513:21;;;:8;:21;;;;;;;;:35;94505:66;;;;;-1:-1:-1;;;94505:66:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;94590:10;94582:70;;;;-1:-1:-1;;;94582:70:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;94680:5;94671:6;:14;;;:31;;;;;94698:4;94689:6;:13;;;94671:31;94663:82;;;;-1:-1:-1;;;94663:82:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;94764:26;;;94756:59;;;;;-1:-1:-1;;;94756:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;94851:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;94828:20:0;;;:7;:20;;;;;:75;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;94914:8;:21;;;;;;:34;;;;;94938:10;94914:34;;;;;;94964:80;;;;;;;;;;;;;;;;;94836:11;;94851:52;;94964:80;;;;;;;;;94250:802;;;;;:::o;107372:348::-;93437:1;93404:21;;;:8;:21;;;;;;107446:11;;93404:35;:21;93396:71;;;;;-1:-1:-1;;;93396:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;107478:21:::1;::::0;;;:8:::1;:21;::::0;;;;;:35:::1;:21;107503:10;107478:35;107470:70;;;::::0;;-1:-1:-1;;;107470:70:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;107558:21;::::0;;;:8:::1;:21;::::0;;;;;;;107551:28;;;;;::::1;::::0;;;107597:7:::1;:20:::0;;;;;107590:27;;;;;;107635:15:::1;:28:::0;;;;;;107628:35;;;;::::1;::::0;;;107681:31;107567:11;;107681:31:::1;::::0;::::1;107372:348:::0;;:::o;9703:496::-;9840:21;9874:20;9067:14;9897:5;:18;:99;;9126:14;9931:5;:18;:65;;9991:5;9931:65;;;9126:14;9931:65;9897:99;;;9067:14;9897:99;9874:122;-1:-1:-1;10061:15:0;:130;;10180:11;10061:130;;;10155:5;10141:10;10123:12;10105:13;10097:39;10096:56;;;;;;:64;;;;;;10041:150;9703:496;-1:-1:-1;;;;;9703:496:0:o;95163:324::-;93437:1;93404:21;;;:8;:21;;;;;;95295:11;;93404:35;:21;93396:71;;;;;-1:-1:-1;;;93396:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;95341:21:::1;::::0;;;:8:::1;:21;::::0;;;;;::::1;;95327:10;:35;95319:83;;;;-1:-1:-1::0;;;95319:83:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;95413:28:0::1;::::0;;;:15:::1;:28;::::0;;;;;:66;;;::::1;;::::0;;::::1;::::0;;;::::1;::::0;;95163:324::o;101823:454::-;102021:17;102063:58;102083:11;102096;102109;102063:19;:58::i;95564:249::-;95650:21;95740:23;;;:15;:23;;;;;;;;;95564:249::o;96450:134::-;96513:15;96548:28;96564:11;96548:15;:28::i;:::-;96541:35;96450:134;-1:-1:-1;;96450:134:0:o;10374:1579::-;10601:15;10631:18;10664:12;10727:1;10712:12;:16;10704:64;;;;-1:-1:-1;;;10704:64:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10805:1;10787:15;:19;10779:72;;;;-1:-1:-1;;;10779:72:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10886:1;10870:13;:17;10862:65;;;;-1:-1:-1;;;10862:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10963:1;10946:13;:18;;10938:58;;;;;-1:-1:-1;;;10938:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;11032:8;11015:13;:25;;11007:82;;;;-1:-1:-1;;;11007:82:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11102:12;11140:22;11192:13;11166:12;11182:5;11166:22;11165:40;;;;;;11140:65;;9008:12;11248:20;11254:13;11248:5;:20::i;:::-;11229:15;:40;11273:5;11229:50;11228:69;;;;;;11220:77;;11314:15;11332:27;11343:15;11332:10;:27::i;:::-;11314:45;-1:-1:-1;11374:11:0;11429:9;11420:5;:19;11410:5;11390:8;11401:5;11390:16;11389:26;;;;;;11388:52;11374:66;;11463:16;11474:4;11463:10;:16::i;:::-;11455:24;-1:-1:-1;11526:5:0;11518:13;;11510:22;;11496:11;11562:16;11510:22;11562:10;:16::i;:::-;11547:31;;11605:14;11597:5;:22;:48;;;;;11631:14;11623:5;:22;11597:48;11593:213;;;11666:17;11686:56;11700:12;11714:13;11729:5;11736;11686:13;:56::i;:::-;11666:76;-1:-1:-1;;11593:213:0;10374:1579;;;;;11842:55;11867:12;11882:7;11891:5;11842:16;:55::i;:::-;11829:68;-1:-1:-1;;10374:1579:0;;;;;;;;:::o;9149:546::-;9307:17;9337:20;9376:13;9361:12;:28;9360:65;;9424:1;9360:65;;;9408:13;9393:12;:28;9360:65;9337:88;-1:-1:-1;9542:5:0;9516:21;;;9490:22;;;:48;9489:58;9476:71;;9586:13;9573:10;:26;9569:119;;;9629:13;9616:26;;9569:119;9149:546;;;;;;;:::o;91893:43::-;;;;;;;;;;;;;;;:::o;97295:1326::-;97461:23;97499:18;97532:20;97567:15;97610:20;;:::i;:::-;-1:-1:-1;97633:20:0;;;;:7;:20;;;;;;;;97610:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;97633:20;97714:16;:14;:16::i;:::-;97773:18;;:33;;;;;;;;;;;;;;97664:66;;-1:-1:-1;97664:66:0;;-1:-1:-1;97746:21:0;;97773:18;;;;;:26;;:33;;;;;;;;;;;;;;:18;:33;;;2:2:-1;;;;27:1;24;17:12;2:2;97773:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;97773:33:0;;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;97773:33:0;;;97741:65;;;-1:-1:-1;97832:28:0;97848:11;97832:15;:28::i;:::-;97817:43;;97898:185;97935:13;97963:12;97990:15;98020:8;98043:4;:11;;;98057:2;98043:16;97898:185;;:22;:185::i;:::-;97873:210;;;;;;;;98094:14;98111:115;98151:12;98111:115;;;;;;;;;;;;;;;;;:21;:10;98126:5;98111:21;:14;:21;:::i;:::-;:25;:115;;:25;:115;:::i;:::-;98094:132;;91728:16;98245:6;:29;98237:68;;;;;-1:-1:-1;;;98237:68:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;98404:4;:18;;;98400:214;;;98498:5;98457:37;:6;98476:16;;;98457:37;:10;:37;:::i;:::-;:47;;;;;;98439:65;;98400:214;;;98596:5;98555:37;:6;98574:16;;;98555:37;:10;:37;:::i;:::-;:47;;;;;;98537:65;;98400:214;97295:1326;;;;;;;;;;;;:::o;105172:2192::-;105341:19;93404:21;;;:8;:21;;;;;;105319:11;;93404:35;:21;93396:71;;;;;-1:-1:-1;;;93396:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;105465:18:::1;::::0;:44:::1;::::0;;;;;::::1;::::0;::::1;::::0;;;;;105373:13:::1;::::0;;;105437:22:::1;::::0;105465:18:::1;::::0;;::::1;::::0;:31:::1;::::0;:44;;;;;105373:13;;105465:44;;;;;;;;:18;:44;::::1;;2:2:-1::0;::::1;;;27:1;24::::0;17:12:::1;2:2;105465:44:0;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;105465:44:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;105465:44:0;80:15:-1::0;;::::1;97:9:::0;76:31:::1;65:43:::0;::::1;120:4;113:20:::0;;;7:11;::::1;4:2;;;31:1;28::::0;21:12:::1;4:2;105465:44:0;;;;;;;;;;;;;19:11:-1;14:3;11:20;8:2;;;44:1;41::::0;34:12:::1;8:2;62:21:::0;;::::1;::::0;123:4:::1;114:14:::0;::::1;138:31:::0;;::::1;135:2;;;182:1;179::::0;172:12:::1;135:2;219:3;213:10;331:9;325:2;311:12;307:21;289:16;285:44;282:59;261:11;247:12;244:29;233:116;230:2;;;362:1;359::::0;352:12:::1;230:2;373:25:::0;;-1:-1;105465:44:0;;421:4:-1::1;412:14:::0;;::::1;::::0;105465:44:0;::::1;::::0;::::1;::::0;412:14:-1;105465:44:0;23:1:-1::1;8:100;33:3;30:1;27:10;8:100;;;90:11:::0;;::::1;84:18:::0;71:11;;::::1;64:39:::0;52:2:::1;45:10;8:100;;;-1:-1:::0;;;;105465:44:0;;;::::1;;::::0;-1:-1:-1;;105532:12:0;;105436:73;;-1:-1:-1;;105548:1:0::1;105532:17:::0;;::::1;::::0;-1:-1:-1;105524:79:0::1;;;;-1:-1:-1::0;;;105524:79:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;105626:5;105632:1;105626:8;;;;;;;;;;;;;;105618:16;;105657:5;105663:1;105657:8;;;;;;;;;;;;;;105649:16;;93478:1;105689:15;105715:16:::0;105757:23:::1;105829:18;;;;;;;;;;;:26;;;105856:5;105829:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24::::0;17:12:::1;2:2;105829:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;105829:33:0;;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29::::0;22:12:::1;4:2;-1:-1:::0;105829:33:0;;::::1;::::0;;::::1;::::0;;-1:-1:-1;105829:33:0;-1:-1:-1;105885:29:0::1;::::0;::::1;105877:68;;;::::0;;-1:-1:-1;;;105877:68:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;105978:15:::0;-1:-1:-1;106018:11:0::1;106055:20;;:::i;:::-;-1:-1:-1::0;106078:20:0::1;::::0;;;:7:::1;:20;::::0;;;;;;;;106055:43;;::::1;::::0;::::1;::::0;;;;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;::::1;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;;;;;;;::::1;;;;::::0;::::1;::::0;;;;;;;;106113:63:::1;;;::::0;;-1:-1:-1;;;106113:63:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;106199:17:::0;;-1:-1:-1;106199:17:0::1;::::0;;106325:114:::1;106362:5:::0;106386:11;106416:8;106325:18:::1;:114::i;:::-;106282:157;;;;;;106462:6;106472:1;106462:11;;106454:70;;;;-1:-1:-1::0;;;106454:70:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;106553:68;106615:5;106553:57;106570:21;:9:::0;106584:6;106570:21:::1;:13;:21;:::i;:::-;106593:9;106604:5;106553:16;:57::i;:68::-;106539:82:::0;-1:-1:-1;106644:16:0;106636:64:::1;;;;-1:-1:-1::0;;;106636:64:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;106726;106768:9;:18;;;:20;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24::::0;17:12:::1;2:2;106768:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;106768:20:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::1;4:2;-1:-1:::0;106768:20:0;106760:29:::1;;106756:2;:33;106726:25;:10:::0;106741:9;106726:25:::1;:14;:25;:::i;:64::-;106715:75;;106816:24;106831:8;106816:14;:24::i;:::-;106805:35;;93478:1;;106886:5;:18;;;106905:8;:21;106914:11;106905:21;;;;;;;;;;;;;;;;;;;;;106928:10;106940:11;106886:66;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24::::0;17:12:::1;2:2;106886:66:0;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;106886:66:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::1;4:2;-1:-1:::0;106886:66:0;106864:144:::1;;;::::0;;-1:-1:-1;;;106864:144:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;107076:21;::::0;;;:8:::1;:21;::::0;;;;;;;;107041:68;;;;;107064:10:::1;107041:68;::::0;::::1;::::0;:22:::1;107076:21:::0;;::::1;107041:68:::0;;;;;;;;;;;;:22;;::::1;::::0;::::1;::::0;:68;;;;;107076:21;;107041:68;;;;;;;;;:22;:68;::::1;;2:2:-1::0;::::1;;;27:1;24::::0;17:12:::1;2:2;107041:68:0;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;107041:68:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::1;4:2;-1:-1:::0;107041:68:0;107019:138:::1;;;::::0;;-1:-1:-1;;;107019:138:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;107175:181;::::0;;;;;::::1;::::0;::::1;::::0;;;;;;;;;;;107261:11;;107236:10:::1;::::0;107210:11;;107175:181:::1;::::0;;;;;;;;::::1;93478:1;;;;;;105172:2192:::0;;;;;;:::o;15325:471::-;15383:7;15628:6;15624:47;;-1:-1:-1;15658:1:0;15651:8;;15624:47;15695:5;;;15699:1;15695;:5;:1;15719:5;;;;;:10;15711:56;;;;-1:-1:-1;;;15711:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15787:1;15325:471;-1:-1:-1;;;15325:471:0:o;16264:132::-;16322:7;16349:39;16353:1;16356;16349:39;;;;;;;;;;;;;;;;;:3;:39::i;102285:2186::-;102457:17;93404:21;;;:8;:21;;;;;;102435:11;;93404:35;:21;93396:71;;;;;-1:-1:-1;;;93396:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;102579:18:::1;::::0;:44:::1;::::0;;;;;::::1;::::0;::::1;::::0;;;;;102487:13:::1;::::0;;;102551:22:::1;::::0;102579:18:::1;::::0;;::::1;::::0;:31:::1;::::0;:44;;;;;102487:13;;102579:44;;;;;;;;:18;:44;::::1;;2:2:-1::0;::::1;;;27:1;24::::0;17:12:::1;2:2;102579:44:0;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;102579:44:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;102579:44:0;80:15:-1::0;;::::1;97:9:::0;76:31:::1;65:43:::0;::::1;120:4;113:20:::0;;;7:11;::::1;4:2;;;31:1;28::::0;21:12:::1;4:2;102579:44:0;;;;;;;;;;;;;19:11:-1;14:3;11:20;8:2;;;44:1;41::::0;34:12:::1;8:2;62:21:::0;;::::1;::::0;123:4:::1;114:14:::0;::::1;138:31:::0;;::::1;135:2;;;182:1;179::::0;172:12:::1;135:2;219:3;213:10;331:9;325:2;311:12;307:21;289:16;285:44;282:59;261:11;247:12;244:29;233:116;230:2;;;362:1;359::::0;352:12:::1;230:2;373:25:::0;;-1:-1;102579:44:0;;421:4:-1::1;412:14:::0;;::::1;::::0;102579:44:0;::::1;::::0;::::1;::::0;412:14:-1;102579:44:0;23:1:-1::1;8:100;33:3;30:1;27:10;8:100;;;90:11:::0;;::::1;84:18:::0;71:11;;::::1;64:39:::0;52:2:::1;45:10;8:100;;;-1:-1:::0;;;;102579:44:0;;;::::1;;::::0;-1:-1:-1;;102646:12:0;;102550:73;;-1:-1:-1;;102662:1:0::1;102646:17:::0;;::::1;::::0;-1:-1:-1;102638:79:0::1;;;;-1:-1:-1::0;;;102638:79:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;102740:5;102746:1;102740:8;;;;;;;;;;;;;;102732:16;;102771:5;102777:1;102771:8;;;;;;;;;;;;;;102763:16;;93478:1;102803:15;102829:16:::0;102871:23:::1;102943:18;;;;;;;;;;;:26;;;102970:5;102943:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24::::0;17:12:::1;2:2;102943:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;102943:33:0;;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29::::0;22:12:::1;4:2;-1:-1:::0;102943:33:0;;::::1;::::0;;::::1;::::0;;-1:-1:-1;102943:33:0;-1:-1:-1;102999:29:0::1;::::0;::::1;102991:68;;;::::0;;-1:-1:-1;;;102991:68:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;103092:15:::0;-1:-1:-1;103132:11:0::1;103169:20;;:::i;:::-;-1:-1:-1::0;103192:20:0::1;::::0;;;:7:::1;:20;::::0;;;;;;;;103169:43;;::::1;::::0;::::1;::::0;;;;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;::::1;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;;;;;;;::::1;;;;;::::0;;;;;;;103227:58:::1;;;::::0;;-1:-1:-1;;;103227:58:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;103308:17:::0;;-1:-1:-1;103308:17:0::1;::::0;;103436:114:::1;103473:5:::0;103497:11;103527:8;103436:18:::1;:114::i;:::-;103391:159;;;;;;103573:6;103583:1;103573:11;;103565:70;;;;-1:-1:-1::0;;;103565:70:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;103662;103725:6:::0;103662:58:::1;103679:22;:11:::0;103695:5:::1;103679:22;:15;:22;:::i;:::-;103703:5;103710:9;103662:16;:58::i;:70::-;103650:82:::0;-1:-1:-1;103755:14:0;103747:60:::1;;;;-1:-1:-1::0;;;103747:60:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;103833:64;103879:5;:14;;;:16;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24::::0;17:12:::1;103833:64:0;103822:75;;103923:24;103938:8;103923:14;:24::i;:::-;103912:35;;93478:1;;103993:5;:18;;;104012:10;104024:8;:21;104033:11;104024:21;;;;;;;;;;;;;;;;;;;;;104047:11;103993:66;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24::::0;17:12:::1;2:2;103993:66:0;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;103993:66:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::1;4:2;-1:-1:::0;103993:66:0;103971:144:::1;;;::::0;;-1:-1:-1;;;103971:144:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;104171:21;::::0;;;:8:::1;:21;::::0;;;;;;;;104148:68;;;;;:22:::1;104171:21:::0;;::::1;104148:68;::::0;::::1;::::0;104194:10:::1;104148:68:::0;;;;;;;;;;;;:22;;::::1;::::0;::::1;::::0;:68;;;;;104171:21;;104148:68;;;;;;;;;:22;:68;::::1;;2:2:-1::0;::::1;;;27:1;24::::0;17:12:::1;2:2;104148:68:0;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;104148:68:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::1;4:2;-1:-1:::0;104148:68:0;104126:138:::1;;;::::0;;-1:-1:-1;;;104126:138:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;104282:181;::::0;;;;;::::1;::::0;::::1;::::0;;;;;;;;;;;104368:11;;104343:10:::1;::::0;104317:11;;104282:181:::1;::::0;;;;;;;;::::1;93478:1;;;;;;102285:2186:::0;;;;;;:::o;96592:359::-;96711:15;93404:21;;;:8;:21;;;;;;96680:11;;93404:35;:21;93396:71;;;;;-1:-1:-1;;;93396:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;96744:35:::1;96782:28:::0;;;:15:::1;:28;::::0;;;;;::::1;;96829:37:::0;96821:76:::1;;;::::0;;-1:-1:-1;;;96821:76:0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;96915:14;:26;;;:28;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24::::0;17:12:::1;2:2;96915:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;96915:28:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::1;4:2;-1:-1:::0;96915:28:0;;-1:-1:-1;;93478:1:0::1;96592:359:::0;;;;:::o;5896:288::-;5944:8;5978:1;5973;:6;;5965:72;;;;-1:-1:-1;;;5965:72:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6060:5:0;6069:1;6064;6060:5;;6059:11;6097:80;6108:1;6104;:5;6097:80;;;6130:1;6126:5;;6164:1;6159;6155;6151;:5;;;;;;:9;6150:15;;;;;;6146:19;;6097:80;;6258:577;6317:15;6363:1;6353:7;:11;6345:55;;;;;-1:-1:-1;;;6345:55:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;6438:5;6428:15;;6518:120;5388:8;6525:7;:18;6518:120;;;6589:5;5336:9;6571:14;;6570:24;6560:34;;6621:5;6609:17;;;;6518:120;;;6665:5;6655:7;:15;6648:121;;;6720:5;5388:8;6698:18;;6697:28;6687:38;;6752:5;6740:17;;;;6648:121;;;6791:36;6821:5;;6803:7;:15;:23;6791:11;:36::i;:::-;6779:48;;;;6258:577;-1:-1:-1;;6258:577:0:o;7868:892::-;7927:15;7973:11;7963:7;:21;:47;;;;;7998:12;7988:7;:22;7963:47;7955:78;;;;;-1:-1:-1;;;7955:78:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;8044:15;8072:1;8062:7;:11;:38;;8086:7;8097:2;8086:14;8062:38;;;8076:7;8062:38;8044:56;-1:-1:-1;8111:8:0;8157:5;5541:8;8141:12;;8140:22;8132:5;:30;8122:6;:41;;;;;;;-1:-1:-1;8208:1:0;8187:17;;;8186:23;;;;8285:9;8276:5;;;:19;8236:60;;8322:10;8317:1;8313:5;;:20;8236:98;8360:11;8355:1;8351:5;;:21;8236:137;8399:12;8394:1;8390:5;;:22;8236:177;8439:12;8434:1;8430:5;;:22;8236:217;:5;:217;8174:9;5239;8236:217;8476:6;8236:217;8476:15;;;;;8475:31;;;;;;;-1:-1:-1;8701:6:0;8539:5;5770:9;8529:6;;8528:16;;;5723:10;8561:6;8560:12;;8559:22;;;5677:9;8598:6;8597:12;;8596:22;;;5631:9;8635:6;8634:12;;8633:22;;;5586:8;8685:6;8684:12;;8679:18;;8678:29;;;;8670:37;;8517:8;8725:11;;:27;;8751:1;8743:5;:9;8725:27;;;8739:1;8725:27;8718:34;7868:892;-1:-1:-1;;;;;;;;7868:892:0:o;60290:252::-;60334:15;60394;;:29;;;;;;;;60334:15;;60394;;;:27;;:29;;;;;;;;;;;;;;60334:15;60394;:29;;;2:2:-1;;;;27:1;24;17:12;2:2;60394:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;60394:29:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;60394:29:0;60449:15;;:42;;;;;;;;60394:29;;-1:-1:-1;60449:15:0;;;;;:40;;:42;;;;;60394:29;;60449:42;;;;;;;;:15;:42;;;2:2:-1;;;;27:1;24;17:12;2:2;60449:42:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;60449:42:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;60449:42:0;;-1:-1:-1;60290:252:0;;:::o;98738:1821::-;98951:18;98971:15;98999:21;99023:105;99050:23;:21;:23::i;:::-;99023:105;;;;;;;;;;;;;;;;;:8;;:105;;:12;:105;:::i;:::-;98999:129;-1:-1:-1;99141:21:0;99224:15;99254:211;99275:2;99261:10;:16;99254:211;;99319:10;99302:13;:27;99298:81;;99354:5;;99298:81;99397:17;;;;;;99447:2;99433:16;;99254:211;;;98738:1821;99555:21;99602:18;99623:50;99640:12;99654:1;99657:15;99623:16;:50::i;:::-;99602:71;;99688:19;99710:51;99727:13;99742:1;99745:15;99710:16;:51::i;:::-;99688:73;;99776:16;99837:207;99879:21;:10;:19;:21::i;:::-;99919:22;:11;:20;:22::i;:::-;99960:26;:15;:24;:26::i;:::-;100005:24;:13;:22;:24::i;:::-;99837:23;:207::i;:::-;-1:-1:-1;99807:237:0;-1:-1:-1;99807:237:0;-1:-1:-1;100074:46:0;99807:237;100101:15;100118:1;100074:16;:46::i;:::-;100061:59;;98738:1821;;;100144:13;100178:5;100160:15;:23;:117;;100212:9;100194:15;:27;:83;;100262:15;100194:83;;;100237:9;100194:83;100160:117;;;100186:5;100160:117;100144:133;-1:-1:-1;100338:5:0;100313:21;;;100312:31;100403:75;100288:21;100404:13;;;:38;;;100437:5;100421:13;:21;100404:38;:62;;100453:13;100404:62;;;100445:5;100404:62;100403:73;:75::i;:::-;100378:9;:100;100354:124;;91865:12;100500:8;:24;:51;;100543:8;100500:51;;;91865:12;100500:51;100489:62;;98738:1821;;;;;;;;;;;;;:::o;16884:345::-;16970:7;17072:12;17065:5;17057:28;;;;-1:-1:-1;;;17057:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;17057:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;17096:9;17112:1;17108;:5;;;;100634:343;100771:7;100791:20;100814:9;:18;;;:20;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;100814:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;100814:20:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;100814:20:0;100869:21;;;;;;;;100814:20;;-1:-1:-1;100845:21:0;;100869:19;;;;;;:21;;;;;100814:20;;100869:21;;;;;;;:19;:21;;;2:2:-1;;;;27:1;24;17:12;2:2;100869:21:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;100869:21:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;100869:21:0;;-1:-1:-1;100908:61:0;100925:10;100937:14;100869:21;100908:16;:61::i;:::-;100901:68;100634:343;-1:-1:-1;;;;;;100634:343:0:o;108552:198::-;108619:7;108640:25;108671:16;:14;:16::i;:::-;-1:-1:-1;108639:48:0;-1:-1:-1;108639:48:0;108705:17;:6;108716:5;108705:17;:10;:17;:::i;:::-;:37;;;;;;;108552:198;-1:-1:-1;;;108552:198:0:o;7111:503::-;7171:15;7595:10;7577:1;7568:10;;:38;7541:10;7523:1;7514:10;;:38;7487:10;7469:1;7460:10;;:38;7433:10;7415:1;7406:10;;:38;7379:10;7361:1;7352:10;;:38;7326:9;7308:1;7299:10;;:37;7273:9;7255:1;7246:10;;:37;7223:7;:60;:113;:167;:221;:275;:329;:383;7199:407;;7111:503;;;:::o;29378:162::-;29480:3;;29378:162::o;14882:192::-;14968:7;15004:12;14996:6;;;;14988:29;;;;-1:-1:-1;;;14988:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;14988:29:0;-1:-1:-1;;;15040:5:0;;;14882:192::o;100985:648::-;101128:7;101148:9;101168;101211:15;101194:32;;:14;:32;;;101190:208;;;-1:-1:-1;101243:36:0;101247:32;;;101243:36;101190:208;;;101318:15;101301:32;;:14;:32;;;101297:101;;;101372:14;101354:15;:32;101350:36;;;;101297:101;101525:2;101521:1;:6;:16;;;;;101535:2;101531:1;:6;101521:16;101513:66;;;;-1:-1:-1;;;101513:66:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;101597:28;101623:1;101619:2;:5;101597:17;101612:1;101608:2;:5;101597:6;:10;;:17;;;;:::i;24126:181::-;24182:6;24217;24209:5;:14;24201:67;;;;-1:-1:-1;;;24201:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;24293:5:0;24126:181::o;108206:547::-;;;;;;;;;-1:-1:-1;108206:547:0;;;;;;;;;;;;;;;;;:::o
Swarm Source
ipfs://2e3d4a1c39fa98a24898ef6b0c7960e1db205a22000f8a37736342a96a5cc9d5
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.