Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Name:
OptionPricingLinearV2_1
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 0 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; // Libraries import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import {BlackScholes} from "./external/BlackScholes.sol"; import {ABDKMathQuad} from "./external/ABDKMathQuad.sol"; // Contracts import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; // Interfaces import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract OptionPricingLinearV2_1 is Ownable { using SafeMath for uint256; // The % of the price of asset which is the minimum option price possible in 1e8 precision uint256 public minOptionPricePercentage; // The decimal precision for volatility calculation uint256 public constant VOLATILITY_PRECISION = 1e4; // xSYK token address address public xSyk; // Time to expiry => volatility mapping(uint256 => uint256) public ttlToVol; // TTL => The offset for volatility calculation in 1e4 precision mapping(uint256 => uint256) public volatilityOffsets; // TTL => The multiplier for volatility calculation in 1e4 precision mapping(uint256 => uint256) public volatilityMultipliers; // IV Setter addresses mapping(address => bool) public ivSetter; // xSYK Balances for each tier uint256[] public xSykBalances; // Discount for each tier uint256[] public discounts; error NotIVSetter(); event UpdatedIVs(address sender, uint256[] ttls, uint256[] ttlIVs); constructor(uint256 _minOptionPricePercentage, address _xSyk) { minOptionPricePercentage = _minOptionPricePercentage; xSyk = _xSyk; ivSetter[msg.sender] = true; } /*---- GOVERNANCE FUNCTIONS ----*/ /// @notice Updates the IV setter /// @param _setter Address of the setter /// @param _status Status to set /// @dev Only the owner of the contract can call this function function updateIVSetter(address _setter, bool _status) external onlyOwner { ivSetter[_setter] = _status; } /// @notice Updates the implied volatility (IV) for the given time to expirations (TTLs). /// @param _ttls The TTLs to update the IV for. /// @param _ttlIVs The new IVs for the given TTLs. /// @dev Only the IV SETTER can call this function. function updateIVs(uint256[] calldata _ttls, uint256[] calldata _ttlIVs) external { if (!ivSetter[msg.sender]) revert NotIVSetter(); for (uint256 i; i < _ttls.length; i++) { ttlToVol[_ttls[i]] = _ttlIVs[i]; } emit UpdatedIVs(msg.sender, _ttls, _ttlIVs); } /// @notice updates the offset for volatility calculation /// @param _volatilityOffsets the new offset /// @param _ttls The TTLs to update the volatility offset for. /// @return whether offset was updated function updateVolatilityOffset(uint256[] calldata _volatilityOffsets, uint256[] calldata _ttls) external onlyOwner returns (bool) { uint256 volatilityOffsetsLength = _volatilityOffsets.length; for (uint256 i; i < volatilityOffsetsLength;) { volatilityOffsets[_ttls[i]] = _volatilityOffsets[i]; unchecked { ++i; } } return true; } /// @notice updates the multiplier for volatility calculation /// @param _volatilityMultipliers the new multiplier /// @param _ttls The TTLs to update the volatility multiplier for. /// @return whether multiplier was updated function updateVolatilityMultiplier(uint256[] calldata _volatilityMultipliers, uint256[] calldata _ttls) external onlyOwner returns (bool) { for (uint256 i = 0; i < _volatilityMultipliers.length; i++) { volatilityMultipliers[_ttls[i]] = _volatilityMultipliers[i]; } return true; } /// @notice updates % of the price of asset which is the minimum option price possible /// @param _minOptionPricePercentage the new % /// @return whether % was updated function updateMinOptionPricePercentage(uint256 _minOptionPricePercentage) external onlyOwner returns (bool) { minOptionPricePercentage = _minOptionPricePercentage; return true; } /// @notice sets the xSYK balances and discounts for each tier /// @param _xSykBalances the xSYK balances /// @param _discounts the discounts /// @return whether the balances and discounts were set function setXSykBalancesAndDiscounts(uint256[] calldata _xSykBalances, uint256[] calldata _discounts) external onlyOwner returns (bool) { xSykBalances = _xSykBalances; discounts = _discounts; return true; } /*---- VIEWS ----*/ /// @notice computes the option price (with liquidity multiplier) /// @param isPut is put option /// @param expiry expiry timestamp /// @param strike strike price /// @param lastPrice current price function getOptionPrice(bool isPut, uint256 expiry, uint256 strike, uint256 lastPrice) external view returns (uint256) { uint256 timeToExpiry = expiry.sub(block.timestamp).div(864); uint256 volatility = ttlToVol[expiry - block.timestamp]; if (volatility == 0) revert(); volatility = getVolatility(strike, lastPrice, volatility, expiry - block.timestamp); uint256 optionPrice = BlackScholes.calculate(isPut ? 1 : 0, lastPrice, strike, timeToExpiry, 0, volatility) // 0 - Put, 1 - Call // Number of days to expiry mul by 100 .div(BlackScholes.DIVISOR); uint256 minOptionPrice = lastPrice.mul(minOptionPricePercentage).div(1e10); if (minOptionPrice > optionPrice) { return minOptionPrice; } return optionPrice; } /// @notice computes the option price (with liquidity multiplier) /// @param isPut is put option /// @param ttl time to live for the option /// @param strike strike price /// @param lastPrice current price function getOptionPriceViaTTL(bool isPut, uint256 ttl, uint256 strike, uint256 lastPrice) external view returns (uint256) { uint256 timeToExpiry = ttl.div(864); uint256 volatility = ttlToVol[ttl]; if (volatility == 0) revert(); volatility = getVolatility(strike, lastPrice, volatility, ttl); uint256 optionPrice = BlackScholes.calculate(isPut ? 1 : 0, lastPrice, strike, timeToExpiry, 0, volatility) // 0 - Put, 1 - Call // Number of days to expiry mul by 100 .div(BlackScholes.DIVISOR); uint256 minOptionPrice = lastPrice.mul(minOptionPricePercentage).div(1e10); if (minOptionPrice > optionPrice) { return minOptionPrice; } return optionPrice; } /// @notice computes the volatility for a strike /// @param strike strike price /// @param lastPrice current price /// @param volatility volatility function getVolatility(uint256 strike, uint256 lastPrice, uint256 volatility, uint256 ttl) public view returns (uint256) { uint256 percentageDifference = strike.mul(1e2).mul(VOLATILITY_PRECISION).div(lastPrice); // 1e4 in percentage precision (1e6 is 100%) if (strike > lastPrice) { percentageDifference = percentageDifference.sub(1e6); } else { percentageDifference = uint256(1e6).sub(percentageDifference); } uint256 scaleFactor = volatilityOffsets[ttl] + (percentageDifference.mul(volatilityMultipliers[ttl]).div(VOLATILITY_PRECISION)); volatility = volatility.mul(scaleFactor).div(VOLATILITY_PRECISION); address userAddress = tx.origin; uint256 tiers = xSykBalances.length; uint256 userDiscount = 0; if (tiers != 0) { for (uint256 i; i < tiers;) { uint256 balance = IERC20(xSyk).balanceOf(userAddress); if (balance >= xSykBalances[i]) { userDiscount = discounts[i]; } else { break; } unchecked { ++i; } } } volatility = volatility.mul(1e4 - userDiscount).div(1e4); return volatility; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol) pragma solidity ^0.8.0; // CAUTION // This version of SafeMath should only be used with Solidity 0.8 or later, // because it relies on the compiler's built in overflow checks. /** * @dev Wrappers over Solidity's arithmetic operations. * * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler * now has built in overflow checking. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // 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 (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @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) { return a + b; } /** * @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 a - b; } /** * @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) { return a * b; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting 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 a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b <= a, errorMessage); return a - b; } } /** * @dev Returns the integer division of two unsigned integers, reverting 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) { unchecked { require(b > 0, errorMessage); return a / b; } } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * 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) { unchecked { require(b > 0, errorMessage); return a % b; } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; // Libraries import {ABDKMathQuad} from "./ABDKMathQuad.sol"; /// @title Black-Scholes option pricing formula and supporting statistical functions /// @author Dopex /// @notice This library implements the Black-Scholes model to price options. /// See - https://en.wikipedia.org/wiki/Black%E2%80%93Scholes_model /// @dev Implements the following implementation - https://cseweb.ucsd.edu/~goguen/courses/130/SayBlackScholes.html /// Uses the ABDKMathQuad(https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMathQuad.md) /// library to make precise calculations. It uses a DIVISOR (1e16) for maintaining precision in constants. library BlackScholes { uint8 internal constant OPTION_TYPE_CALL = 0; uint8 internal constant OPTION_TYPE_PUT = 1; uint256 internal constant DIVISOR = 10 ** 16; /** * @notice The function that uses the Black-Scholes equation to calculate the option price * See http://en.wikipedia.org/wiki/Black%E2%80%93Scholes_model#Black-Scholes_formula * NOTE: The different parts of the equation are broken down to separate functions as using * ABDKMathQuad makes small equations verbose. * @param optionType Type of option - 0 = call, 1 = put * @param price Stock price * @param strike Strike price * @param timeToExpiry Time to expiry in days * @param riskFreeRate Risk-free rate * @param volatility Volatility on the asset * @return Option price based on the Black-Scholes model */ function calculate( uint8 optionType, uint256 price, uint256 strike, uint256 timeToExpiry, uint256 riskFreeRate, uint256 volatility ) internal pure returns (uint256) { bytes16 S = ABDKMathQuad.fromUInt(price); bytes16 X = ABDKMathQuad.fromUInt(strike); bytes16 T = ABDKMathQuad.div( ABDKMathQuad.fromUInt(timeToExpiry), ABDKMathQuad.fromUInt(36500) // 365 * 10 ^ DAYS_PRECISION ); bytes16 r = ABDKMathQuad.div( ABDKMathQuad.fromUInt(riskFreeRate), ABDKMathQuad.fromUInt(10000) ); bytes16 v = ABDKMathQuad.div( ABDKMathQuad.fromUInt(volatility), ABDKMathQuad.fromUInt(100) ); bytes16 d1 = ABDKMathQuad.div( ABDKMathQuad.add( ABDKMathQuad.ln(ABDKMathQuad.div(S, X)), ABDKMathQuad.mul( ABDKMathQuad.add( r, ABDKMathQuad.mul( v, ABDKMathQuad.div(v, ABDKMathQuad.fromUInt(2)) ) ), T ) ), ABDKMathQuad.mul(v, ABDKMathQuad.sqrt(T)) ); bytes16 d2 = ABDKMathQuad.sub( d1, ABDKMathQuad.mul(v, ABDKMathQuad.sqrt(T)) ); if (optionType == OPTION_TYPE_CALL) { return ABDKMathQuad.toUInt( ABDKMathQuad.mul( _calculateCallTimeDecay(S, d1, X, r, T, d2), ABDKMathQuad.fromUInt(DIVISOR) ) ); } else if (optionType == OPTION_TYPE_PUT) { return ABDKMathQuad.toUInt( ABDKMathQuad.mul( _calculatePutTimeDecay(X, r, T, d2, S, d1), ABDKMathQuad.fromUInt(DIVISOR) ) ); } else return 0; } /// @dev Function to caluclate the call time decay /// From the implementation page(https://cseweb.ucsd.edu/~goguen/courses/130/SayBlackScholes.html); part of the equation /// ( S * CND(d1)-X * Math.exp(-r * T) * CND(d2) ); function _calculateCallTimeDecay( bytes16 S, bytes16 d1, bytes16 X, bytes16 r, bytes16 T, bytes16 d2 ) internal pure returns (bytes16) { return ABDKMathQuad.sub( ABDKMathQuad.mul(S, CND(d1)), ABDKMathQuad.mul( ABDKMathQuad.mul( X, ABDKMathQuad.exp( ABDKMathQuad.mul(ABDKMathQuad.neg(r), T) ) ), CND(d2) ) ); } /// @dev Function to caluclate the put time decay /// From the implementation page(https://cseweb.ucsd.edu/~goguen/courses/130/SayBlackScholes.html); part of the equation - /// ( X * Math.exp(-r * T) * CND(-d2) - S * CND(-d1) ); function _calculatePutTimeDecay( bytes16 X, bytes16 r, bytes16 T, bytes16 d2, bytes16 S, bytes16 d1 ) internal pure returns (bytes16) { bytes16 price_part1 = ABDKMathQuad.mul( ABDKMathQuad.mul( X, ABDKMathQuad.exp(ABDKMathQuad.mul(ABDKMathQuad.neg(r), T)) ), CND(ABDKMathQuad.neg(d2)) ); bytes16 price_part2 = ABDKMathQuad.mul(S, CND(ABDKMathQuad.neg(d1))); bytes16 price = ABDKMathQuad.sub(price_part1, price_part2); return price; } /** * @notice Normal cumulative distribution function. * See http://en.wikipedia.org/wiki/Normal_distribution#Cumulative_distribution_function * From the implementation page(https://cseweb.ucsd.edu/~goguen/courses/130/SayBlackScholes.html); part of the equation - * "k = 1 / (1 + .2316419 * x); return ( 1 - Math.exp(-x * x / 2)/ Math.sqrt(2*Math.PI) * k * (.31938153 + k * (-.356563782 + k * (1.781477937 + k * (-1.821255978 + k * 1.330274429)))) );" * NOTE: The different parts of the equation are broken down to separate functions as using * ABDKMathQuad makes small equations verbose. */ function CND(bytes16 x) internal pure returns (bytes16) { if (ABDKMathQuad.toInt(x) < 0) { return ( ABDKMathQuad.sub( ABDKMathQuad.fromUInt(1), CND(ABDKMathQuad.neg(x)) ) ); } else { bytes16 k = ABDKMathQuad.div( ABDKMathQuad.fromUInt(1), ABDKMathQuad.add( ABDKMathQuad.fromUInt(1), ABDKMathQuad.mul( ABDKMathQuad.div( ABDKMathQuad.fromUInt(2316419000000000), ABDKMathQuad.fromUInt(DIVISOR) ), x ) ) ); bytes16 CND_part2 = _getCNDPart2(k, x); return ABDKMathQuad.sub(ABDKMathQuad.fromUInt(1), CND_part2); } } function _getCNDPart2( bytes16 k, bytes16 x ) internal pure returns (bytes16) { return ABDKMathQuad.mul(_getCNDPart2_1(x), _getCNDPart2_2(k)); } function _getCNDPart2_1(bytes16 x) internal pure returns (bytes16) { return ABDKMathQuad.div( ABDKMathQuad.exp( ABDKMathQuad.mul( ABDKMathQuad.neg(x), ABDKMathQuad.div(x, ABDKMathQuad.fromUInt(2)) ) ), ABDKMathQuad.sqrt( ABDKMathQuad.mul( ABDKMathQuad.fromUInt(2), ABDKMathQuad.div( ABDKMathQuad.fromUInt(31415926530000000), ABDKMathQuad.fromUInt(DIVISOR) ) ) ) ); } function _getCNDPart2_2(bytes16 k) internal pure returns (bytes16) { return ABDKMathQuad.mul( ABDKMathQuad.add( ABDKMathQuad.div( ABDKMathQuad.fromUInt(3193815300000000), ABDKMathQuad.fromUInt(DIVISOR) ), ABDKMathQuad.mul( k, ABDKMathQuad.add( ABDKMathQuad.neg( ABDKMathQuad.div( ABDKMathQuad.fromUInt(3565637820000000), ABDKMathQuad.fromUInt(DIVISOR) ) ), ABDKMathQuad.mul( k, ABDKMathQuad.add( ABDKMathQuad.div( ABDKMathQuad.fromUInt( 17814779370000000 ), ABDKMathQuad.fromUInt(DIVISOR) ), _getCNDPart2_2_1(k) ) ) ) ) ), k ); } function _getCNDPart2_2_1(bytes16 k) internal pure returns (bytes16) { return ABDKMathQuad.mul( k, ABDKMathQuad.add( ABDKMathQuad.neg( ABDKMathQuad.div( ABDKMathQuad.fromUInt(18212559780000000), ABDKMathQuad.fromUInt(DIVISOR) ) ), ABDKMathQuad.mul( k, ABDKMathQuad.div( ABDKMathQuad.fromUInt(13302744290000000), ABDKMathQuad.fromUInt(DIVISOR) ) ) ) ); } }
// SPDX-License-Identifier: BSD-4-Clause /* * ABDK Math Quad Smart Contract Library. Copyright © 2019 by ABDK Consulting. * Author: Mikhail Vladimirov <[email protected]> */ pragma solidity ^0.8.13; /** * Smart contract library of mathematical functions operating with IEEE 754 * quadruple-precision binary floating-point numbers (quadruple precision * numbers). As long as quadruple precision numbers are 16-bytes long, they are * represented by bytes16 type. */ library ABDKMathQuad { /* * 0. */ bytes16 private constant POSITIVE_ZERO = 0x00000000000000000000000000000000; /* * -0. */ bytes16 private constant NEGATIVE_ZERO = 0x80000000000000000000000000000000; /* * +Infinity. */ bytes16 private constant POSITIVE_INFINITY = 0x7FFF0000000000000000000000000000; /* * -Infinity. */ bytes16 private constant NEGATIVE_INFINITY = 0xFFFF0000000000000000000000000000; /* * Canonical NaN value. */ bytes16 private constant NaN = 0x7FFF8000000000000000000000000000; /** * Convert signed 256-bit integer number into quadruple precision number. * * @param x signed 256-bit integer number * @return quadruple precision number */ function fromInt(int256 x) internal pure returns (bytes16) { unchecked { if (x == 0) return bytes16(0); else { // We rely on overflow behavior here uint256 result = uint256(x > 0 ? x : -x); uint256 msb = mostSignificantBit(result); if (msb < 112) result <<= 112 - msb; else if (msb > 112) result >>= msb - 112; result = (result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | ((16383 + msb) << 112); if (x < 0) result |= 0x80000000000000000000000000000000; return bytes16(uint128(result)); } } } /** * Convert quadruple precision number into signed 256-bit integer number * rounding towards zero. Revert on overflow. * * @param x quadruple precision number * @return signed 256-bit integer number */ function toInt(bytes16 x) internal pure returns (int256) { unchecked { uint256 exponent = (uint128(x) >> 112) & 0x7FFF; require(exponent <= 16638); // Overflow if (exponent < 16383) return 0; // Underflow uint256 result = (uint256(uint128(x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | 0x10000000000000000000000000000; if (exponent < 16495) result >>= 16495 - exponent; else if (exponent > 16495) result <<= exponent - 16495; if (uint128(x) >= 0x80000000000000000000000000000000) { // Negative require( result <= 0x8000000000000000000000000000000000000000000000000000000000000000 ); return -int256(result); // We rely on overflow behavior here } else { require( result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ); return int256(result); } } } /** * Convert unsigned 256-bit integer number into quadruple precision number. * * @param x unsigned 256-bit integer number * @return quadruple precision number */ function fromUInt(uint256 x) internal pure returns (bytes16) { unchecked { if (x == 0) return bytes16(0); else { uint256 result = x; uint256 msb = mostSignificantBit(result); if (msb < 112) result <<= 112 - msb; else if (msb > 112) result >>= msb - 112; result = (result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | ((16383 + msb) << 112); return bytes16(uint128(result)); } } } /** * Convert quadruple precision number into unsigned 256-bit integer number * rounding towards zero. Revert on underflow. Note, that negative floating * point numbers in range (-1.0 .. 0.0) may be converted to unsigned integer * without error, because they are rounded to zero. * * @param x quadruple precision number * @return unsigned 256-bit integer number */ function toUInt(bytes16 x) internal pure returns (uint256) { unchecked { uint256 exponent = (uint128(x) >> 112) & 0x7FFF; if (exponent < 16383) return 0; // Underflow require(uint128(x) < 0x80000000000000000000000000000000); // Negative require(exponent <= 16638); // Overflow uint256 result = (uint256(uint128(x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | 0x10000000000000000000000000000; if (exponent < 16495) result >>= 16495 - exponent; else if (exponent > 16495) result <<= exponent - 16495; return result; } } /** * Convert signed 128.128 bit fixed point number into quadruple precision * number. * * @param x signed 128.128 bit fixed point number * @return quadruple precision number */ function from128x128(int256 x) internal pure returns (bytes16) { unchecked { if (x == 0) return bytes16(0); else { // We rely on overflow behavior here uint256 result = uint256(x > 0 ? x : -x); uint256 msb = mostSignificantBit(result); if (msb < 112) result <<= 112 - msb; else if (msb > 112) result >>= msb - 112; result = (result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | ((16255 + msb) << 112); if (x < 0) result |= 0x80000000000000000000000000000000; return bytes16(uint128(result)); } } } /** * Convert quadruple precision number into signed 128.128 bit fixed point * number. Revert on overflow. * * @param x quadruple precision number * @return signed 128.128 bit fixed point number */ function to128x128(bytes16 x) internal pure returns (int256) { unchecked { uint256 exponent = (uint128(x) >> 112) & 0x7FFF; require(exponent <= 16510); // Overflow if (exponent < 16255) return 0; // Underflow uint256 result = (uint256(uint128(x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | 0x10000000000000000000000000000; if (exponent < 16367) result >>= 16367 - exponent; else if (exponent > 16367) result <<= exponent - 16367; if (uint128(x) >= 0x80000000000000000000000000000000) { // Negative require( result <= 0x8000000000000000000000000000000000000000000000000000000000000000 ); return -int256(result); // We rely on overflow behavior here } else { require( result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ); return int256(result); } } } /** * Convert signed 64.64 bit fixed point number into quadruple precision * number. * * @param x signed 64.64 bit fixed point number * @return quadruple precision number */ function from64x64(int128 x) internal pure returns (bytes16) { unchecked { if (x == 0) return bytes16(0); else { // We rely on overflow behavior here uint256 result = uint128(x > 0 ? x : -x); uint256 msb = mostSignificantBit(result); if (msb < 112) result <<= 112 - msb; else if (msb > 112) result >>= msb - 112; result = (result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | ((16319 + msb) << 112); if (x < 0) result |= 0x80000000000000000000000000000000; return bytes16(uint128(result)); } } } /** * Convert quadruple precision number into signed 64.64 bit fixed point * number. Revert on overflow. * * @param x quadruple precision number * @return signed 64.64 bit fixed point number */ function to64x64(bytes16 x) internal pure returns (int128) { unchecked { uint256 exponent = (uint128(x) >> 112) & 0x7FFF; require(exponent <= 16446); // Overflow if (exponent < 16319) return 0; // Underflow uint256 result = (uint256(uint128(x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | 0x10000000000000000000000000000; if (exponent < 16431) result >>= 16431 - exponent; else if (exponent > 16431) result <<= exponent - 16431; if (uint128(x) >= 0x80000000000000000000000000000000) { // Negative require(result <= 0x80000000000000000000000000000000); return -int128(int256(result)); // We rely on overflow behavior here } else { require(result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return int128(int256(result)); } } } /** * Convert octuple precision number into quadruple precision number. * * @param x octuple precision number * @return quadruple precision number */ function fromOctuple(bytes32 x) internal pure returns (bytes16) { unchecked { bool negative = x & 0x8000000000000000000000000000000000000000000000000000000000000000 > 0; uint256 exponent = (uint256(x) >> 236) & 0x7FFFF; uint256 significand = uint256(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (exponent == 0x7FFFF) { if (significand > 0) return NaN; else return negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY; } if (exponent > 278526) return negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY; else if (exponent < 245649) return negative ? NEGATIVE_ZERO : POSITIVE_ZERO; else if (exponent < 245761) { significand = (significand | 0x100000000000000000000000000000000000000000000000000000000000) >> (245885 - exponent); exponent = 0; } else { significand >>= 124; exponent -= 245760; } uint128 result = uint128(significand | (exponent << 112)); if (negative) result |= 0x80000000000000000000000000000000; return bytes16(result); } } /** * Convert quadruple precision number into octuple precision number. * * @param x quadruple precision number * @return octuple precision number */ function toOctuple(bytes16 x) internal pure returns (bytes32) { unchecked { uint256 exponent = (uint128(x) >> 112) & 0x7FFF; uint256 result = uint128(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (exponent == 0x7FFF) exponent = 0x7FFFF; // Infinity or NaN else if (exponent == 0) { if (result > 0) { uint256 msb = mostSignificantBit(result); result = (result << (236 - msb)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; exponent = 245649 + msb; } } else { result <<= 124; exponent += 245760; } result |= exponent << 236; if (uint128(x) >= 0x80000000000000000000000000000000) result |= 0x8000000000000000000000000000000000000000000000000000000000000000; return bytes32(result); } } /** * Convert double precision number into quadruple precision number. * * @param x double precision number * @return quadruple precision number */ function fromDouble(bytes8 x) internal pure returns (bytes16) { unchecked { uint256 exponent = (uint64(x) >> 52) & 0x7FF; uint256 result = uint64(x) & 0xFFFFFFFFFFFFF; if (exponent == 0x7FF) exponent = 0x7FFF; // Infinity or NaN else if (exponent == 0) { if (result > 0) { uint256 msb = mostSignificantBit(result); result = (result << (112 - msb)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; exponent = 15309 + msb; } } else { result <<= 60; exponent += 15360; } result |= exponent << 112; if (x & 0x8000000000000000 > 0) result |= 0x80000000000000000000000000000000; return bytes16(uint128(result)); } } /** * Convert quadruple precision number into double precision number. * * @param x quadruple precision number * @return double precision number */ function toDouble(bytes16 x) internal pure returns (bytes8) { unchecked { bool negative = uint128(x) >= 0x80000000000000000000000000000000; uint256 exponent = (uint128(x) >> 112) & 0x7FFF; uint256 significand = uint128(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (exponent == 0x7FFF) { if (significand > 0) return 0x7FF8000000000000; // NaN else return negative ? bytes8(0xFFF0000000000000) // -Infinity : bytes8(0x7FF0000000000000); // Infinity } if (exponent > 17406) return negative ? bytes8(0xFFF0000000000000) // -Infinity : bytes8(0x7FF0000000000000); // Infinity else if (exponent < 15309) return negative ? bytes8(0x8000000000000000) // -0 : bytes8(0x0000000000000000); // 0 else if (exponent < 15361) { significand = (significand | 0x10000000000000000000000000000) >> (15421 - exponent); exponent = 0; } else { significand >>= 60; exponent -= 15360; } uint64 result = uint64(significand | (exponent << 52)); if (negative) result |= 0x8000000000000000; return bytes8(result); } } /** * Test whether given quadruple precision number is NaN. * * @param x quadruple precision number * @return true if x is NaN, false otherwise */ function isNaN(bytes16 x) internal pure returns (bool) { unchecked { return uint128(x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF > 0x7FFF0000000000000000000000000000; } } /** * Test whether given quadruple precision number is positive or negative * infinity. * * @param x quadruple precision number * @return true if x is positive or negative infinity, false otherwise */ function isInfinity(bytes16 x) internal pure returns (bool) { unchecked { return uint128(x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x7FFF0000000000000000000000000000; } } /** * Calculate sign of x, i.e. -1 if x is negative, 0 if x if zero, and 1 if x * is positive. Note that sign (-0) is zero. Revert if x is NaN. * * @param x quadruple precision number * @return sign of x */ function sign(bytes16 x) internal pure returns (int8) { unchecked { uint128 absoluteX = uint128(x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; require(absoluteX <= 0x7FFF0000000000000000000000000000); // Not NaN if (absoluteX == 0) return 0; else if (uint128(x) >= 0x80000000000000000000000000000000) return -1; else return 1; } } /** * Calculate sign (x - y). Revert if either argument is NaN, or both * arguments are infinities of the same sign. * * @param x quadruple precision number * @param y quadruple precision number * @return sign (x - y) */ function cmp(bytes16 x, bytes16 y) internal pure returns (int8) { unchecked { uint128 absoluteX = uint128(x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; require(absoluteX <= 0x7FFF0000000000000000000000000000); // Not NaN uint128 absoluteY = uint128(y) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; require(absoluteY <= 0x7FFF0000000000000000000000000000); // Not NaN // Not infinities of the same sign require(x != y || absoluteX < 0x7FFF0000000000000000000000000000); if (x == y) return 0; else { bool negativeX = uint128(x) >= 0x80000000000000000000000000000000; bool negativeY = uint128(y) >= 0x80000000000000000000000000000000; if (negativeX) { if (negativeY) return absoluteX > absoluteY ? -1 : int8(1); else return -1; } else { if (negativeY) return 1; else return absoluteX > absoluteY ? int8(1) : -1; } } } } /** * Test whether x equals y. NaN, infinity, and -infinity are not equal to * anything. * * @param x quadruple precision number * @param y quadruple precision number * @return true if x equals to y, false otherwise */ function eq(bytes16 x, bytes16 y) internal pure returns (bool) { unchecked { if (x == y) { return uint128(x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF < 0x7FFF0000000000000000000000000000; } else return false; } } /** * Calculate x + y. Special values behave in the following way: * * NaN + x = NaN for any x. * Infinity + x = Infinity for any finite x. * -Infinity + x = -Infinity for any finite x. * Infinity + Infinity = Infinity. * -Infinity + -Infinity = -Infinity. * Infinity + -Infinity = -Infinity + Infinity = NaN. * * @param x quadruple precision number * @param y quadruple precision number * @return quadruple precision number */ function add(bytes16 x, bytes16 y) internal pure returns (bytes16) { unchecked { uint256 xExponent = (uint128(x) >> 112) & 0x7FFF; uint256 yExponent = (uint128(y) >> 112) & 0x7FFF; if (xExponent == 0x7FFF) { if (yExponent == 0x7FFF) { if (x == y) return x; else return NaN; } else return x; } else if (yExponent == 0x7FFF) return y; else { bool xSign = uint128(x) >= 0x80000000000000000000000000000000; uint256 xSignifier = uint128(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0) xExponent = 1; else xSignifier |= 0x10000000000000000000000000000; bool ySign = uint128(y) >= 0x80000000000000000000000000000000; uint256 ySignifier = uint128(y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (yExponent == 0) yExponent = 1; else ySignifier |= 0x10000000000000000000000000000; if (xSignifier == 0) return y == NEGATIVE_ZERO ? POSITIVE_ZERO : y; else if (ySignifier == 0) return x == NEGATIVE_ZERO ? POSITIVE_ZERO : x; else { int256 delta = int256(xExponent) - int256(yExponent); if (xSign == ySign) { if (delta > 112) return x; else if (delta > 0) ySignifier >>= uint256(delta); else if (delta < -112) return y; else if (delta < 0) { xSignifier >>= uint256(-delta); xExponent = yExponent; } xSignifier += ySignifier; if (xSignifier >= 0x20000000000000000000000000000) { xSignifier >>= 1; xExponent += 1; } if (xExponent == 0x7FFF) return xSign ? NEGATIVE_INFINITY : POSITIVE_INFINITY; else { if (xSignifier < 0x10000000000000000000000000000) xExponent = 0; else xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; return bytes16( uint128( ( xSign ? 0x80000000000000000000000000000000 : 0 ) | (xExponent << 112) | xSignifier ) ); } } else { if (delta > 0) { xSignifier <<= 1; xExponent -= 1; } else if (delta < 0) { ySignifier <<= 1; xExponent = yExponent - 1; } if (delta > 112) ySignifier = 1; else if (delta > 1) ySignifier = ((ySignifier - 1) >> uint256(delta - 1)) + 1; else if (delta < -112) xSignifier = 1; else if (delta < -1) xSignifier = ((xSignifier - 1) >> uint256(-delta - 1)) + 1; if (xSignifier >= ySignifier) xSignifier -= ySignifier; else { xSignifier = ySignifier - xSignifier; xSign = ySign; } if (xSignifier == 0) return POSITIVE_ZERO; uint256 msb = mostSignificantBit(xSignifier); if (msb == 113) { xSignifier = (xSignifier >> 1) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; xExponent += 1; } else if (msb < 112) { uint256 shift = 112 - msb; if (xExponent > shift) { xSignifier = (xSignifier << shift) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; xExponent -= shift; } else { xSignifier <<= xExponent - 1; xExponent = 0; } } else xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0x7FFF) return xSign ? NEGATIVE_INFINITY : POSITIVE_INFINITY; else return bytes16( uint128( ( xSign ? 0x80000000000000000000000000000000 : 0 ) | (xExponent << 112) | xSignifier ) ); } } } } } /** * Calculate x - y. Special values behave in the following way: * * NaN - x = NaN for any x. * Infinity - x = Infinity for any finite x. * -Infinity - x = -Infinity for any finite x. * Infinity - -Infinity = Infinity. * -Infinity - Infinity = -Infinity. * Infinity - Infinity = -Infinity - -Infinity = NaN. * * @param x quadruple precision number * @param y quadruple precision number * @return quadruple precision number */ function sub(bytes16 x, bytes16 y) internal pure returns (bytes16) { unchecked { return add(x, y ^ 0x80000000000000000000000000000000); } } /** * Calculate x * y. Special values behave in the following way: * * NaN * x = NaN for any x. * Infinity * x = Infinity for any finite positive x. * Infinity * x = -Infinity for any finite negative x. * -Infinity * x = -Infinity for any finite positive x. * -Infinity * x = Infinity for any finite negative x. * Infinity * 0 = NaN. * -Infinity * 0 = NaN. * Infinity * Infinity = Infinity. * Infinity * -Infinity = -Infinity. * -Infinity * Infinity = -Infinity. * -Infinity * -Infinity = Infinity. * * @param x quadruple precision number * @param y quadruple precision number * @return quadruple precision number */ function mul(bytes16 x, bytes16 y) internal pure returns (bytes16) { unchecked { uint256 xExponent = (uint128(x) >> 112) & 0x7FFF; uint256 yExponent = (uint128(y) >> 112) & 0x7FFF; if (xExponent == 0x7FFF) { if (yExponent == 0x7FFF) { if (x == y) return x ^ (y & 0x80000000000000000000000000000000); else if (x ^ y == 0x80000000000000000000000000000000) return x | y; else return NaN; } else { if (y & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN; else return x ^ (y & 0x80000000000000000000000000000000); } } else if (yExponent == 0x7FFF) { if (x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN; else return y ^ (x & 0x80000000000000000000000000000000); } else { uint256 xSignifier = uint128(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0) xExponent = 1; else xSignifier |= 0x10000000000000000000000000000; uint256 ySignifier = uint128(y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (yExponent == 0) yExponent = 1; else ySignifier |= 0x10000000000000000000000000000; xSignifier *= ySignifier; if (xSignifier == 0) return (x ^ y) & 0x80000000000000000000000000000000 > 0 ? NEGATIVE_ZERO : POSITIVE_ZERO; xExponent += yExponent; uint256 msb = xSignifier >= 0x200000000000000000000000000000000000000000000000000000000 ? 225 : xSignifier >= 0x100000000000000000000000000000000000000000000000000000000 ? 224 : mostSignificantBit(xSignifier); if (xExponent + msb < 16496) { // Underflow xExponent = 0; xSignifier = 0; } else if (xExponent + msb < 16608) { // Subnormal if (xExponent < 16496) xSignifier >>= 16496 - xExponent; else if (xExponent > 16496) xSignifier <<= xExponent - 16496; xExponent = 0; } else if (xExponent + msb > 49373) { xExponent = 0x7FFF; xSignifier = 0; } else { if (msb > 112) xSignifier >>= msb - 112; else if (msb < 112) xSignifier <<= 112 - msb; xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; xExponent = xExponent + msb - 16607; } return bytes16( uint128( uint128( (x ^ y) & 0x80000000000000000000000000000000 ) | (xExponent << 112) | xSignifier ) ); } } } /** * Calculate x / y. Special values behave in the following way: * * NaN / x = NaN for any x. * x / NaN = NaN for any x. * Infinity / x = Infinity for any finite non-negative x. * Infinity / x = -Infinity for any finite negative x including -0. * -Infinity / x = -Infinity for any finite non-negative x. * -Infinity / x = Infinity for any finite negative x including -0. * x / Infinity = 0 for any finite non-negative x. * x / -Infinity = -0 for any finite non-negative x. * x / Infinity = -0 for any finite non-negative x including -0. * x / -Infinity = 0 for any finite non-negative x including -0. * * Infinity / Infinity = NaN. * Infinity / -Infinity = -NaN. * -Infinity / Infinity = -NaN. * -Infinity / -Infinity = NaN. * * Division by zero behaves in the following way: * * x / 0 = Infinity for any finite positive x. * x / -0 = -Infinity for any finite positive x. * x / 0 = -Infinity for any finite negative x. * x / -0 = Infinity for any finite negative x. * 0 / 0 = NaN. * 0 / -0 = NaN. * -0 / 0 = NaN. * -0 / -0 = NaN. * * @param x quadruple precision number * @param y quadruple precision number * @return quadruple precision number */ function div(bytes16 x, bytes16 y) internal pure returns (bytes16) { unchecked { uint256 xExponent = (uint128(x) >> 112) & 0x7FFF; uint256 yExponent = (uint128(y) >> 112) & 0x7FFF; if (xExponent == 0x7FFF) { if (yExponent == 0x7FFF) return NaN; else return x ^ (y & 0x80000000000000000000000000000000); } else if (yExponent == 0x7FFF) { if (y & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFF != 0) return NaN; else return POSITIVE_ZERO | ((x ^ y) & 0x80000000000000000000000000000000); } else if (y & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) { if (x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN; else return POSITIVE_INFINITY | ((x ^ y) & 0x80000000000000000000000000000000); } else { uint256 ySignifier = uint128(y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (yExponent == 0) yExponent = 1; else ySignifier |= 0x10000000000000000000000000000; uint256 xSignifier = uint128(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0) { if (xSignifier != 0) { uint256 shift = 226 - mostSignificantBit(xSignifier); xSignifier <<= shift; xExponent = 1; yExponent += shift - 114; } } else { xSignifier = (xSignifier | 0x10000000000000000000000000000) << 114; } xSignifier = xSignifier / ySignifier; if (xSignifier == 0) return (x ^ y) & 0x80000000000000000000000000000000 > 0 ? NEGATIVE_ZERO : POSITIVE_ZERO; assert(xSignifier >= 0x1000000000000000000000000000); uint256 msb = xSignifier >= 0x80000000000000000000000000000 ? mostSignificantBit(xSignifier) : xSignifier >= 0x40000000000000000000000000000 ? 114 : xSignifier >= 0x20000000000000000000000000000 ? 113 : 112; if (xExponent + msb > yExponent + 16497) { // Overflow xExponent = 0x7FFF; xSignifier = 0; } else if (xExponent + msb + 16380 < yExponent) { // Underflow xExponent = 0; xSignifier = 0; } else if (xExponent + msb + 16268 < yExponent) { // Subnormal if (xExponent + 16380 > yExponent) xSignifier <<= xExponent + 16380 - yExponent; else if (xExponent + 16380 < yExponent) xSignifier >>= yExponent - xExponent - 16380; xExponent = 0; } else { // Normal if (msb > 112) xSignifier >>= msb - 112; xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; xExponent = xExponent + msb + 16269 - yExponent; } return bytes16( uint128( uint128( (x ^ y) & 0x80000000000000000000000000000000 ) | (xExponent << 112) | xSignifier ) ); } } } /** * Calculate -x. * * @param x quadruple precision number * @return quadruple precision number */ function neg(bytes16 x) internal pure returns (bytes16) { unchecked { return x ^ 0x80000000000000000000000000000000; } } /** * Calculate |x|. * * @param x quadruple precision number * @return quadruple precision number */ function abs(bytes16 x) internal pure returns (bytes16) { unchecked { return x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; } } /** * Calculate square root of x. Return NaN on negative x excluding -0. * * @param x quadruple precision number * @return quadruple precision number */ function sqrt(bytes16 x) internal pure returns (bytes16) { unchecked { if (uint128(x) > 0x80000000000000000000000000000000) return NaN; else { uint256 xExponent = (uint128(x) >> 112) & 0x7FFF; if (xExponent == 0x7FFF) return x; else { uint256 xSignifier = uint128(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0) xExponent = 1; else xSignifier |= 0x10000000000000000000000000000; if (xSignifier == 0) return POSITIVE_ZERO; bool oddExponent = xExponent & 0x1 == 0; xExponent = (xExponent + 16383) >> 1; if (oddExponent) { if (xSignifier >= 0x10000000000000000000000000000) xSignifier <<= 113; else { uint256 msb = mostSignificantBit(xSignifier); uint256 shift = (226 - msb) & 0xFE; xSignifier <<= shift; xExponent -= (shift - 112) >> 1; } } else { if (xSignifier >= 0x10000000000000000000000000000) xSignifier <<= 112; else { uint256 msb = mostSignificantBit(xSignifier); uint256 shift = (225 - msb) & 0xFE; xSignifier <<= shift; xExponent -= (shift - 112) >> 1; } } uint256 r = 0x10000000000000000000000000000; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; // Seven iterations should be enough uint256 r1 = xSignifier / r; if (r1 < r) r = r1; return bytes16( uint128( (xExponent << 112) | (r & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) ) ); } } } } /** * Calculate binary logarithm of x. Return NaN on negative x excluding -0. * * @param x quadruple precision number * @return quadruple precision number */ function log_2(bytes16 x) internal pure returns (bytes16) { unchecked { if (uint128(x) > 0x80000000000000000000000000000000) return NaN; else if (x == 0x3FFF0000000000000000000000000000) return POSITIVE_ZERO; else { uint256 xExponent = (uint128(x) >> 112) & 0x7FFF; if (xExponent == 0x7FFF) return x; else { uint256 xSignifier = uint128(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0) xExponent = 1; else xSignifier |= 0x10000000000000000000000000000; if (xSignifier == 0) return NEGATIVE_INFINITY; bool resultNegative; uint256 resultExponent = 16495; uint256 resultSignifier; if (xExponent >= 0x3FFF) { resultNegative = false; resultSignifier = xExponent - 0x3FFF; xSignifier <<= 15; } else { resultNegative = true; if (xSignifier >= 0x10000000000000000000000000000) { resultSignifier = 0x3FFE - xExponent; xSignifier <<= 15; } else { uint256 msb = mostSignificantBit(xSignifier); resultSignifier = 16493 - msb; xSignifier <<= 127 - msb; } } if (xSignifier == 0x80000000000000000000000000000000) { if (resultNegative) resultSignifier += 1; uint256 shift = 112 - mostSignificantBit(resultSignifier); resultSignifier <<= shift; resultExponent -= shift; } else { uint256 bb = resultNegative ? 1 : 0; while ( resultSignifier < 0x10000000000000000000000000000 ) { resultSignifier <<= 1; resultExponent -= 1; xSignifier *= xSignifier; uint256 b = xSignifier >> 255; resultSignifier += b ^ bb; xSignifier >>= 127 + b; } } return bytes16( uint128( ( resultNegative ? 0x80000000000000000000000000000000 : 0 ) | (resultExponent << 112) | (resultSignifier & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF) ) ); } } } } /** * Calculate natural logarithm of x. Return NaN on negative x excluding -0. * * @param x quadruple precision number * @return quadruple precision number */ function ln(bytes16 x) internal pure returns (bytes16) { unchecked { return mul(log_2(x), 0x3FFE62E42FEFA39EF35793C7673007E5); } } /** * Calculate 2^x. * * @param x quadruple precision number * @return quadruple precision number */ function pow_2(bytes16 x) internal pure returns (bytes16) { unchecked { bool xNegative = uint128(x) > 0x80000000000000000000000000000000; uint256 xExponent = (uint128(x) >> 112) & 0x7FFF; uint256 xSignifier = uint128(x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0x7FFF && xSignifier != 0) return NaN; else if (xExponent > 16397) return xNegative ? POSITIVE_ZERO : POSITIVE_INFINITY; else if (xExponent < 16255) return 0x3FFF0000000000000000000000000000; else { if (xExponent == 0) xExponent = 1; else xSignifier |= 0x10000000000000000000000000000; if (xExponent > 16367) xSignifier <<= xExponent - 16367; else if (xExponent < 16367) xSignifier >>= 16367 - xExponent; if ( xNegative && xSignifier > 0x406E00000000000000000000000000000000 ) return POSITIVE_ZERO; if ( !xNegative && xSignifier > 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ) return POSITIVE_INFINITY; uint256 resultExponent = xSignifier >> 128; xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xNegative && xSignifier != 0) { xSignifier = ~xSignifier; resultExponent += 1; } uint256 resultSignifier = 0x80000000000000000000000000000000; if (xSignifier & 0x80000000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x16A09E667F3BCC908B2FB1366EA957D3E) >> 128; if (xSignifier & 0x40000000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1306FE0A31B7152DE8D5A46305C85EDEC) >> 128; if (xSignifier & 0x20000000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1172B83C7D517ADCDF7C8C50EB14A791F) >> 128; if (xSignifier & 0x10000000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10B5586CF9890F6298B92B71842A98363) >> 128; if (xSignifier & 0x8000000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1059B0D31585743AE7C548EB68CA417FD) >> 128; if (xSignifier & 0x4000000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x102C9A3E778060EE6F7CACA4F7A29BDE8) >> 128; if (xSignifier & 0x2000000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10163DA9FB33356D84A66AE336DCDFA3F) >> 128; if (xSignifier & 0x1000000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100B1AFA5ABCBED6129AB13EC11DC9543) >> 128; if (xSignifier & 0x800000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10058C86DA1C09EA1FF19D294CF2F679B) >> 128; if (xSignifier & 0x400000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1002C605E2E8CEC506D21BFC89A23A00F) >> 128; if (xSignifier & 0x200000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100162F3904051FA128BCA9C55C31E5DF) >> 128; if (xSignifier & 0x100000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000B175EFFDC76BA38E31671CA939725) >> 128; if (xSignifier & 0x80000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100058BA01FB9F96D6CACD4B180917C3D) >> 128; if (xSignifier & 0x40000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10002C5CC37DA9491D0985C348C68E7B3) >> 128; if (xSignifier & 0x20000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000162E525EE054754457D5995292026) >> 128; if (xSignifier & 0x10000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000B17255775C040618BF4A4ADE83FC) >> 128; if (xSignifier & 0x8000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB) >> 128; if (xSignifier & 0x4000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9) >> 128; if (xSignifier & 0x2000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000162E43F4F831060E02D839A9D16D) >> 128; if (xSignifier & 0x1000000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000B1721BCFC99D9F890EA06911763) >> 128; if (xSignifier & 0x800000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000058B90CF1E6D97F9CA14DBCC1628) >> 128; if (xSignifier & 0x400000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000002C5C863B73F016468F6BAC5CA2B) >> 128; if (xSignifier & 0x200000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000162E430E5A18F6119E3C02282A5) >> 128; if (xSignifier & 0x100000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000B1721835514B86E6D96EFD1BFE) >> 128; if (xSignifier & 0x80000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000058B90C0B48C6BE5DF846C5B2EF) >> 128; if (xSignifier & 0x40000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000002C5C8601CC6B9E94213C72737A) >> 128; if (xSignifier & 0x20000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000162E42FFF037DF38AA2B219F06) >> 128; if (xSignifier & 0x10000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000B17217FBA9C739AA5819F44F9) >> 128; if (xSignifier & 0x8000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000058B90BFCDEE5ACD3C1CEDC823) >> 128; if (xSignifier & 0x4000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000002C5C85FE31F35A6A30DA1BE50) >> 128; if (xSignifier & 0x2000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000162E42FF0999CE3541B9FFFCF) >> 128; if (xSignifier & 0x1000000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000B17217F80F4EF5AADDA45554) >> 128; if (xSignifier & 0x800000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000058B90BFBF8479BD5A81B51AD) >> 128; if (xSignifier & 0x400000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000002C5C85FDF84BD62AE30A74CC) >> 128; if (xSignifier & 0x200000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000162E42FEFB2FED257559BDAA) >> 128; if (xSignifier & 0x100000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000B17217F7D5A7716BBA4A9AE) >> 128; if (xSignifier & 0x80000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000058B90BFBE9DDBAC5E109CCE) >> 128; if (xSignifier & 0x40000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000002C5C85FDF4B15DE6F17EB0D) >> 128; if (xSignifier & 0x20000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000162E42FEFA494F1478FDE05) >> 128; if (xSignifier & 0x10000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000B17217F7D20CF927C8E94C) >> 128; if (xSignifier & 0x8000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000058B90BFBE8F71CB4E4B33D) >> 128; if (xSignifier & 0x4000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000002C5C85FDF477B662B26945) >> 128; if (xSignifier & 0x2000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000162E42FEFA3AE53369388C) >> 128; if (xSignifier & 0x1000000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000B17217F7D1D351A389D40) >> 128; if (xSignifier & 0x800000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000058B90BFBE8E8B2D3D4EDE) >> 128; if (xSignifier & 0x400000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000002C5C85FDF4741BEA6E77E) >> 128; if (xSignifier & 0x200000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000162E42FEFA39FE95583C2) >> 128; if (xSignifier & 0x100000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000B17217F7D1CFB72B45E1) >> 128; if (xSignifier & 0x80000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000058B90BFBE8E7CC35C3F0) >> 128; if (xSignifier & 0x40000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000002C5C85FDF473E242EA38) >> 128; if (xSignifier & 0x20000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000162E42FEFA39F02B772C) >> 128; if (xSignifier & 0x10000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000B17217F7D1CF7D83C1A) >> 128; if (xSignifier & 0x8000000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000058B90BFBE8E7BDCBE2E) >> 128; if (xSignifier & 0x4000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000002C5C85FDF473DEA871F) >> 128; if (xSignifier & 0x2000000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000162E42FEFA39EF44D91) >> 128; if (xSignifier & 0x1000000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000B17217F7D1CF79E949) >> 128; if (xSignifier & 0x800000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000058B90BFBE8E7BCE544) >> 128; if (xSignifier & 0x400000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000002C5C85FDF473DE6ECA) >> 128; if (xSignifier & 0x200000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000162E42FEFA39EF366F) >> 128; if (xSignifier & 0x100000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000B17217F7D1CF79AFA) >> 128; if (xSignifier & 0x80000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000058B90BFBE8E7BCD6D) >> 128; if (xSignifier & 0x40000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000002C5C85FDF473DE6B2) >> 128; if (xSignifier & 0x20000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000162E42FEFA39EF358) >> 128; if (xSignifier & 0x10000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000B17217F7D1CF79AB) >> 128; if (xSignifier & 0x8000000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000058B90BFBE8E7BCD5) >> 128; if (xSignifier & 0x4000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000002C5C85FDF473DE6A) >> 128; if (xSignifier & 0x2000000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000162E42FEFA39EF34) >> 128; if (xSignifier & 0x1000000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000B17217F7D1CF799) >> 128; if (xSignifier & 0x800000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000058B90BFBE8E7BCC) >> 128; if (xSignifier & 0x400000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000002C5C85FDF473DE5) >> 128; if (xSignifier & 0x200000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000162E42FEFA39EF2) >> 128; if (xSignifier & 0x100000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000B17217F7D1CF78) >> 128; if (xSignifier & 0x80000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000058B90BFBE8E7BB) >> 128; if (xSignifier & 0x40000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000002C5C85FDF473DD) >> 128; if (xSignifier & 0x20000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000162E42FEFA39EE) >> 128; if (xSignifier & 0x10000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000B17217F7D1CF6) >> 128; if (xSignifier & 0x8000000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000058B90BFBE8E7A) >> 128; if (xSignifier & 0x4000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000002C5C85FDF473C) >> 128; if (xSignifier & 0x2000000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000162E42FEFA39D) >> 128; if (xSignifier & 0x1000000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000B17217F7D1CE) >> 128; if (xSignifier & 0x800000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000058B90BFBE8E6) >> 128; if (xSignifier & 0x400000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000002C5C85FDF472) >> 128; if (xSignifier & 0x200000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000162E42FEFA38) >> 128; if (xSignifier & 0x100000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000B17217F7D1B) >> 128; if (xSignifier & 0x80000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000058B90BFBE8D) >> 128; if (xSignifier & 0x40000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000002C5C85FDF46) >> 128; if (xSignifier & 0x20000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000162E42FEFA2) >> 128; if (xSignifier & 0x10000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000B17217F7D0) >> 128; if (xSignifier & 0x8000000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000058B90BFBE7) >> 128; if (xSignifier & 0x4000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000002C5C85FDF3) >> 128; if (xSignifier & 0x2000000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000162E42FEF9) >> 128; if (xSignifier & 0x1000000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000B17217F7C) >> 128; if (xSignifier & 0x800000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000058B90BFBD) >> 128; if (xSignifier & 0x400000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000002C5C85FDE) >> 128; if (xSignifier & 0x200000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000162E42FEE) >> 128; if (xSignifier & 0x100000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000B17217F6) >> 128; if (xSignifier & 0x80000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000058B90BFA) >> 128; if (xSignifier & 0x40000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000002C5C85FC) >> 128; if (xSignifier & 0x20000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000162E42FD) >> 128; if (xSignifier & 0x10000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000B17217E) >> 128; if (xSignifier & 0x8000000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000058B90BE) >> 128; if (xSignifier & 0x4000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000002C5C85E) >> 128; if (xSignifier & 0x2000000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000162E42E) >> 128; if (xSignifier & 0x1000000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000B17216) >> 128; if (xSignifier & 0x800000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000058B90A) >> 128; if (xSignifier & 0x400000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000002C5C84) >> 128; if (xSignifier & 0x200000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000162E41) >> 128; if (xSignifier & 0x100000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000000B1720) >> 128; if (xSignifier & 0x80000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000058B8F) >> 128; if (xSignifier & 0x40000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000002C5C7) >> 128; if (xSignifier & 0x20000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000000162E3) >> 128; if (xSignifier & 0x10000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000000B171) >> 128; if (xSignifier & 0x8000 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000000058B8) >> 128; if (xSignifier & 0x4000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000002C5B) >> 128; if (xSignifier & 0x2000 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000000162D) >> 128; if (xSignifier & 0x1000 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000000B16) >> 128; if (xSignifier & 0x800 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000000058A) >> 128; if (xSignifier & 0x400 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000000002C4) >> 128; if (xSignifier & 0x200 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000000161) >> 128; if (xSignifier & 0x100 > 0) resultSignifier = (resultSignifier * 0x1000000000000000000000000000000B0) >> 128; if (xSignifier & 0x80 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000000057) >> 128; if (xSignifier & 0x40 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000000002B) >> 128; if (xSignifier & 0x20 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000000015) >> 128; if (xSignifier & 0x10 > 0) resultSignifier = (resultSignifier * 0x10000000000000000000000000000000A) >> 128; if (xSignifier & 0x8 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000000004) >> 128; if (xSignifier & 0x4 > 0) resultSignifier = (resultSignifier * 0x100000000000000000000000000000001) >> 128; if (!xNegative) { resultSignifier = (resultSignifier >> 15) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; resultExponent += 0x3FFF; } else if (resultExponent <= 0x3FFE) { resultSignifier = (resultSignifier >> 15) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; resultExponent = 0x3FFF - resultExponent; } else { resultSignifier = resultSignifier >> (resultExponent - 16367); resultExponent = 0; } return bytes16(uint128((resultExponent << 112) | resultSignifier)); } } } /** * Calculate e^x. * * @param x quadruple precision number * @return quadruple precision number */ function exp(bytes16 x) internal pure returns (bytes16) { unchecked { return pow_2(mul(x, 0x3FFF71547652B82FE1777D0FFDA0D23A)); } } /** * Get index of the most significant non-zero bit in binary representation of * x. Reverts if x is zero. * * @return index of the most significant non-zero bit in binary representation * of x */ function mostSignificantBit(uint256 x) private pure returns (uint256) { unchecked { require(x > 0); uint256 result = 0; if (x >= 0x100000000000000000000000000000000) { x >>= 128; result += 128; } if (x >= 0x10000000000000000) { x >>= 64; result += 64; } if (x >= 0x100000000) { x >>= 32; result += 32; } if (x >= 0x10000) { x >>= 16; result += 16; } if (x >= 0x100) { x >>= 8; result += 8; } if (x >= 0x10) { x >>= 4; result += 4; } if (x >= 0x4) { x >>= 2; result += 2; } if (x >= 0x2) result += 1; // No need to shift x anymore return result; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @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. */ abstract 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() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(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"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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); /** * @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 `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.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 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. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin/=lib/openzeppelin-contracts/contracts/", "@openzeppelin/=lib/openzeppelin-contracts/", "v3-core/=lib/v3-core/", "v3-periphery/=lib/v3-periphery/contracts/", "@uniswap/v3-core/=lib/v3-core/", "base64-sol/=lib/openzeppelin-contracts/contracts/utils/", "BokkyPooBahsDateTimeLibrary/=lib/BokkyPooBahsDateTimeLibrary/" ], "optimizer": { "enabled": true, "runs": 0 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"uint256","name":"_minOptionPricePercentage","type":"uint256"},{"internalType":"address","name":"_xSyk","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"NotIVSetter","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ttls","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"ttlIVs","type":"uint256[]"}],"name":"UpdatedIVs","type":"event"},{"inputs":[],"name":"VOLATILITY_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"discounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"isPut","type":"bool"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"strike","type":"uint256"},{"internalType":"uint256","name":"lastPrice","type":"uint256"}],"name":"getOptionPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"isPut","type":"bool"},{"internalType":"uint256","name":"ttl","type":"uint256"},{"internalType":"uint256","name":"strike","type":"uint256"},{"internalType":"uint256","name":"lastPrice","type":"uint256"}],"name":"getOptionPriceViaTTL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"strike","type":"uint256"},{"internalType":"uint256","name":"lastPrice","type":"uint256"},{"internalType":"uint256","name":"volatility","type":"uint256"},{"internalType":"uint256","name":"ttl","type":"uint256"}],"name":"getVolatility","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"ivSetter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minOptionPricePercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_xSykBalances","type":"uint256[]"},{"internalType":"uint256[]","name":"_discounts","type":"uint256[]"}],"name":"setXSykBalancesAndDiscounts","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ttlToVol","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_setter","type":"address"},{"internalType":"bool","name":"_status","type":"bool"}],"name":"updateIVSetter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_ttls","type":"uint256[]"},{"internalType":"uint256[]","name":"_ttlIVs","type":"uint256[]"}],"name":"updateIVs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minOptionPricePercentage","type":"uint256"}],"name":"updateMinOptionPricePercentage","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_volatilityMultipliers","type":"uint256[]"},{"internalType":"uint256[]","name":"_ttls","type":"uint256[]"}],"name":"updateVolatilityMultiplier","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_volatilityOffsets","type":"uint256[]"},{"internalType":"uint256[]","name":"_ttls","type":"uint256[]"}],"name":"updateVolatilityOffset","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"volatilityMultipliers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"volatilityOffsets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"xSyk","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"xSykBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620031e5380380620031e58339810160408190526200003491620000d4565b6200003f3362000084565b6001918255600280546001600160a01b0319166001600160a01b0392909216919091179055336000908152600660205260409020805460ff1916909117905562000113565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008060408385031215620000e857600080fd5b825160208401519092506001600160a01b03811681146200010857600080fd5b809150509250929050565b6130c280620001236000396000f3fe608060405234801561001057600080fd5b50600436106101075760003560e01c8063016d47b51461010c57806307c91935146101215780631ce2a6881461014757806325b2a93b1461015a5780632ae0d14114610163578063326611f814610176578063427ec698146101995780634a95155c146101b95780635b7f6d77146101cc578063715018a6146101df578063717a1dec146101e75780637b0bfdbb146102075780637c90d3c71461021a5780638da5cb5b14610223578063aaa534da14610238578063b12ce0b41461024b578063bae6a6901461026b578063cf24eb241461027e578063d1dfc6b314610291578063d5f1b2ce146102a4578063f2fde38b146102c7575b600080fd5b61011f61011a366004612da0565b6102da565b005b61013461012f366004612e0b565b6103b6565b6040519081526020015b60405180910390f35b610134610155366004612e34565b6103d7565b61013460015481565b61011f610171366004612e84565b610487565b610189610184366004612e0b565b6104ba565b604051901515815260200161013e565b6101346101a7366004612e0b565b60046020526000908152604090205481565b6101896101c7366004612da0565b6104d0565b6101346101da366004612e34565b6104ff565b61011f610551565b6101346101f5366004612e0b565b60056020526000908152604090205481565b610189610215366004612da0565b610565565b61013461271081565b61022b6105d5565b60405161013e9190612eb7565b610134610246366004612ecb565b6105e4565b610134610259366004612e0b565b60036020526000908152604090205481565b610134610279366004612e0b565b61078e565b60025461022b906001600160a01b031681565b61018961029f366004612da0565b61079e565b6101896102b2366004612efd565b60066020526000908152604090205460ff1681565b61011f6102d5366004612efd565b610812565b3360009081526006602052604090205460ff1661030a5760405163f25c884f60e01b815260040160405180910390fd5b60005b838110156103705782828281811061032757610327612f18565b905060200201356003600087878581811061034457610344612f18565b90506020020135815260200190815260200160002081905550808061036890612f44565b91505061030d565b507f95805653338d965e92ffa53d6faff39c28f90a2e8a5166c48e94ca9a919f424533858585856040516103a8959493929190612f93565b60405180910390a150505050565b600781815481106103c657600080fd5b600091825260209091200154905081565b6000806103e685610360610890565b60008681526003602052604081205491925081900361040457600080fd5b610410858583896105e4565b90506000610442662386f26fc1000061043c8a61042e576000610431565b60015b888a886000896108a5565b90610890565b905060006104646402540be40061043c600154896109f690919063ffffffff16565b90508181111561047957935061047f92505050565b50925050505b949350505050565b61048f610a02565b6001600160a01b03919091166000908152600660205260409020805460ff1916911515919091179055565b60006104c4610a02565b5060018181555b919050565b60006104da610a02565b6104e660078686612cf5565b506104f360088484612cf5565b50600195945050505050565b60008061051261036061043c8742610a61565b905060006003816105234289612fd7565b81526020019081526020016000205490508060000361054157600080fd5b610410858583610246428b612fd7565b610559610a02565b6105636000610a6d565b565b600061056f610a02565b60005b848110156104f35785858281811061058c5761058c612f18565b90506020020135600560008686858181106105a9576105a9612f18565b9050602002013581526020019081526020016000208190555080806105cd90612f44565b915050610572565b6000546001600160a01b031690565b6000806106028561043c6127106105fc8a60646109f6565b906109f6565b9050848611156106205761061981620f4240610a61565b9050610630565b61062d620f424082610a61565b90505b600083815260056020526040812054610652906127109061043c9085906109f6565b60008581526004602052604090205461066b9190612fee565b905061067d61271061043c87846109f6565b6007549095503290600081156107665760005b82811015610764576002546040516370a0823160e01b81526000916001600160a01b0316906370a08231906106c9908890600401612eb7565b602060405180830381865afa1580156106e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061070a9190613006565b90506007828154811061071f5761071f612f18565b90600052602060002001548110610755576008828154811061074357610743612f18565b9060005260206000200154925061075b565b50610764565b50600101610690565b505b61078061271061043c6107798483612fd7565b8b906109f6565b9a9950505050505050505050565b600881815481106103c657600080fd5b60006107a8610a02565b8360005b81811015610805578686828181106107c6576107c6612f18565b90506020020135600460008787858181106107e3576107e3612f18565b60209081029290920135835250810191909152604001600020556001016107ac565b5060019695505050505050565b61081a610a02565b6001600160a01b0381166108845760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b61088d81610a6d565b50565b600061089c8284613035565b90505b92915050565b6000806108b187610abd565b905060006108be87610abd565b905060006108de6108ce88610abd565b6108d9618e94610abd565b610b24565b905060006108f96108ee88610abd565b6108d9612710610abd565b9050600061091361090988610abd565b6108d96064610abd565b9050600061096561095861092f61092a8989610b24565b610de4565b61094d6109528761094d886109488a6108d96002610abd565b610e07565b611070565b88610e07565b6108d9846109488861143a565b9050600061097f8261097a856109488961143a565b611613565b905060ff8e166109c0576109b26109ad61099d89858a898b88611625565b610948662386f26fc10000610abd565b61166c565b9750505050505050506109ec565b60001960ff8f16016109e0576109b26109ad61099d888789868d896116f0565b60009750505050505050505b9695505050505050565b600061089c8284613057565b33610a0b6105d5565b6001600160a01b0316146105635760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161087b565b600061089c8284612fd7565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600081600003610acf57506000919050565b816000610adb82611742565b90506070811015610af4578060700382901b9150610b07565b6070811115610b07576070810382901c91505b613fff0160701b6001600160701b03919091161760801b92915050565b6000617fff60f084811c8216919084901c811690829003610b695780617fff03610b58575061ffff60ef1b915061089f9050565b505050600160ff1b8116821861089f565b80617fff03610ba557600160801b600160f01b03841615610b94575061ffff60ef1b915061089f9050565b505050808218600160ff1b1661089f565b600160801b600160ff1b038416600003610bf557600160801b600160ff1b038516600003610bdd575061ffff60ef1b915061089f9050565b505050808218600160ff1b16617fff60f01b1761089f565b6001600160701b03608085901c166000829003610c155760019150610c1c565b600160701b175b6001600160701b03608087901c166000849003610c5f578015610c5a576000610c4482611742565b6001955060e20393840160711901939190911b90505b610c69565b600160701b1760721b5b818181610c7857610c7861301f565b04905080600003610ca857600160ff1b87871816610c97576000610c9d565b600160ff1b5b94505050505061089f565b6001606c1b811015610cbc57610cbc613076565b6000600160731b821015610cfb57600160721b821015610cf057600160711b821015610ce9576070610cf3565b6071610cf3565b60725b60ff16610d04565b610d0482611742565b905083614071018186011115610d2257617fff945060009150610db5565b83818601613ffc011015610d3d576000945060009150610db5565b83818601613f8c011015610d8a578385613ffc011115610d68578385613ffc010382901b9150610d81565b8385613ffc011015610d8157613ffc8585030382901c91505b60009450610db5565b6070811115610d9d576070810382901c91505b6001600160701b038216915083818601613f8d010394505b81607086901b888a186001607f1b60801b1660801c6001600160801b0316171760801b9550505050505061089f565b600061089f610df2836117df565b6f3ffe62e42fefa39ef35793c7673007e560801b5b6000617fff60f084811c8216919084901c811690829003610ea65780617fff03610e82576001600160801b031980851690861603610e5057505050600160ff1b8116821861089f565b6001600160801b031985851816600160ff1b03610e725750505081811761089f565b5061ffff60ef1b915061089f9050565b600160801b600160ff1b038416600003610b58575061ffff60ef1b915061089f9050565b80617fff03610ee457600160801b600160ff1b038516600003610ed3575061ffff60ef1b915061089f9050565b505050600160ff1b8216811861089f565b6001600160701b03608086901c166000839003610f045760019250610f0b565b600160701b175b6001600160701b03608086901c166000839003610f2b5760019250610f32565b600160701b175b808202915081600003610f5357600160ff1b87871816610c97576000610c9d565b928201926000600160e11b831015610f8657600160e01b831015610f7f57610f7a83611742565b610f89565b60e0610f89565b60e15b90506140708186011015610fa4576000945060009250611041565b6140e08186011015610fe757614070851015610fc957846140700383901c9250610fde565b614070851115610fde57614070850383901b92505b60009450611041565b61c0dd818601111561100157617fff945060009250611041565b6070811115611018576070810383901c925061102b565b607081101561102b578060700383901b92505b6001600160701b03831692506140df8186010394505b82607086901b888a186001607f1b60801b1660801c6001600160801b0316171760801b9550505050505061089f565b6000617fff60f084811c8216919084901c8116908290036110bc5780617fff036110b2576001600160801b031980851690861603610e7257849250505061089f565b849250505061089f565b80617fff036110cf57839250505061089f565b6001607f1b608086901c90811015906001600160701b031660008490036110f95760019350611100565b600160701b175b6001607f1b608087901c90811015906001600160701b0316600085900361112a5760019450611131565b600160701b175b82600003611164576001600160801b03198816600160ff1b146111545787611157565b60005b965050505050505061089f565b80600003611187576001600160801b03198916600160ff1b146111545788611157565b848603821515851515036112905760708113156111ad578997505050505050505061089f565b60008113156111bf5790811c906111ee565b606f198112156111d8578897505050505050505061089f565b60008112156111ee578060000384901c93508596505b92810192600160711b8410611209576001968701969390931c925b86617fff0361123a578461122257617fff60f01b61122c565b6001600160f01b03195b97505050505050505061089f565b600160701b84101561124f576000965061125c565b6001600160701b03841693505b83607088901b8661126e576000611274565b6001607f1b5b6001600160801b0316171760801b97505050505050505061089f565b60008113156112ab57600184901b93506001870396506112c2565b60008112156112c257600182901b91506001860396505b60708113156112d45760019150611321565b60018113156112f1576001810360018303901c6001019150611321565b606f198112156113045760019350611321565b600019811215611321576001816000030360018503901c60010193505b81841061133257818403935061133b565b83820393508294505b8360000361135457506000965061089f95505050505050565b600061135f85611742565b90508060710361138457600185901c6001600160701b031694506001880197506113d3565b60708110156113c6576070819003808911156113b3578086901b6001600160701b0316955080890398506113c0565b600098600019019590951b945b506113d3565b6001600160701b03851694505b87617fff0361140557856113ec57617fff60f01b6113f6565b6001600160f01b03195b9850505050505050505061089f565b84607089901b8761141757600061141d565b6001607f1b5b6001600160801b0316171760801b9850505050505050505061089f565b60006001607f1b608083901c1115611458575061ffff60ef1b919050565b617fff60f083901c811690819003611471575090919050565b6001600160701b03608084901c1660008290036114915760019150611498565b600160701b175b806000036114aa575060009392505050565b613fff8201600190811c92161580156114fc57600160701b82106114d457607182901b9150611537565b60006114df83611742565b60e20360fe16606f19810160011c909403939290921b9150611537565b600160701b821061151357607082901b9150611537565b600061151e83611742565b60e10360fe16606f19810160011c909403939290921b91505b600160701b80830401600190811c908184816115555761155561301f565b048201901c9050600181848161156d5761156d61301f565b048201901c905060018184816115855761158561301f565b048201901c9050600181848161159d5761159d61301f565b048201901c905060018184816115b5576115b561301f565b048201901c905060018184816115cd576115cd61301f565b048201901c905060008184816115e5576115e561301f565b049050818110156115f4578091505b816001600160701b0316607086901b1760801b95505050505050919050565b600061089c83600160ff1b8418611070565b60006116616116378861094889611997565b61097a6116588861094861165361164d8b611a27565b8a610e07565b611a30565b61094886611997565b979650505050505050565b6000617fff60f083901c16613fff81101561168a5750600092915050565b6001607f1b608084901c1061169e57600080fd5b6140fe8111156116ad57600080fd5b600160701b6001600160701b03608085901c161761406f8210156116d75761406f8290031c6116e9565b61406f8211156116e95761406e1982011b5b9392505050565b60008061172061170f896109486116536117098c611a27565b8b610e07565b61094861171b88611a27565b611997565b905060006117348561094861171b87611a27565b905060006107808383611613565b600080821161175057600080fd5b6000600160801b831061176557608092831c92015b600160401b831061177857604092831c92015b600160201b831061178b57602092831c92015b62010000831061179d57601092831c92015b61010083106117ae57600892831c92015b601083106117be57600492831c92015b600483106117ce57600292831c92015b6002831061089f5760010192915050565b60006001607f1b608083901c11156117fd575061ffff60ef1b919050565b6001600160801b03198216613fff60f01b0361181b57506000919050565b617fff60f083901c811690819003611834575090919050565b6001600160701b03608084901c166000829003611854576001915061185b565b600160701b175b8060000361187457506001600160f01b03199392505050565b600061406f81613fff851061189a5750600f9290921b9160009150613ffe1984016118d9565b60019250600160701b84106118bc5784613ffe039050600f84901b93506118d9565b60006118c785611742565b607f8190039590951b9461406d039150505b836001607f1b0361190f5782156118ee576001015b60006118f982611742565b60700390508082901b915080830392505061195d565b60008361191d576000611920565b60015b60ff1690505b600160701b82101561195b5793800260ff81901c607f81019190911c94600019939093019260019290921b9082180190611926565b505b806001600160701b0316607083901b8461197857600061197e565b6001607f1b5b6001600160801b0316171760801b979650505050505050565b6000806119a383611a57565b12156119c25761089f6119b66001610abd565b61097a61171b85611a27565b6000611a046119d16001610abd565b6108d96119de6001610abd565b61094d6109526119f466083ac553a55e00610abd565b6108d9662386f26fc10000610abd565b90506000611a128285611afe565b905061047f611a216001610abd565b82611613565b600160ff1b1890565b600061089f611a52836f1fffb8aa3b295c17f0bbbe87fed0691d60811b610e07565b611b15565b6000617fff60f083901c166140fe811115611a7157600080fd5b613fff811015611a845750600092915050565b600160701b6001600160701b03608085901c161761406f821015611aae5761406f8290031c611ac0565b61406f821115611ac05761406e1982011b5b6001607f1b608085901c10611aea57600160ff1b811115611ae057600080fd5b6000039392505050565b6001600160ff1b038111156116e957600080fd5b600061089c611b0c83612c0f565b61094885612c59565b60006001607f1b608083901c90811190617fff60f085901c8116916001600160701b03169082148015611b4757508015155b15611b5b575061ffff60ef1b949350505050565b61400d821115611b815782611b7557617fff60f01b611b78565b60005b95945050505050565b613f7f821015611b9a5750613fff60f01b949350505050565b81600003611bab5760019150611bb2565b600160701b175b613fef821115611bc857613fee1982011b611bda565b613fef821015611bda57613fef8290031c5b828015611beb575061203760811b81115b15611bfb57506000949350505050565b82158015611c0f575060016001608e1b0381115b15611c235750617fff60f01b949350505050565b6001600160801b0381169060801c838015611c3d57508115155b15611c49579019906001015b6001607f1b82811615611c6d5770016a09e667f3bcc908b2fb1366ea957d3e0260801c5b6001607e1b831615611c90577001306fe0a31b7152de8d5a46305c85edec0260801c5b6001607d1b831615611cb3577001172b83c7d517adcdf7c8c50eb14a791f0260801c5b6001607c1b831615611cd65770010b5586cf9890f6298b92b71842a983630260801c5b6001607b1b831615611cf9577001059b0d31585743ae7c548eb68ca417fd0260801c5b6001607a1b831615611d1c57700102c9a3e778060ee6f7caca4f7a29bde80260801c5b600160791b831615611d3f5770010163da9fb33356d84a66ae336dcdfa3f0260801c5b600160781b831615611d6257700100b1afa5abcbed6129ab13ec11dc95430260801c5b600160771b831615611d855770010058c86da1c09ea1ff19d294cf2f679b0260801c5b600160761b831615611da8577001002c605e2e8cec506d21bfc89a23a00f0260801c5b600160751b831615611dcb57700100162f3904051fa128bca9c55c31e5df0260801c5b600160741b831615611dee577001000b175effdc76ba38e31671ca9397250260801c5b600160731b831615611e1157700100058ba01fb9f96d6cacd4b180917c3d0260801c5b600160721b831615611e345770010002c5cc37da9491d0985c348c68e7b30260801c5b600160711b831615611e57577001000162e525ee054754457d59952920260260801c5b600160701b831615611e7a5770010000b17255775c040618bf4a4ade83fc0260801c5b6001606f1b831615611e9d577001000058b91b5bc9ae2eed81e9b7d4cfab0260801c5b6001606e1b831615611ec057700100002c5c89d5ec6ca4d7c8acc017b7c90260801c5b6001606d1b831615611ee35770010000162e43f4f831060e02d839a9d16d0260801c5b6001606c1b831615611f0657700100000b1721bcfc99d9f890ea069117630260801c5b6001606b1b831615611f295770010000058b90cf1e6d97f9ca14dbcc16280260801c5b6001606a1b831615611f4c577001000002c5c863b73f016468f6bac5ca2b0260801c5b600160691b831615611f6f57700100000162e430e5a18f6119e3c02282a50260801c5b600160681b831615611f92577001000000b1721835514b86e6d96efd1bfe0260801c5b600160671b831615611fb557700100000058b90c0b48c6be5df846c5b2ef0260801c5b600160661b831615611fd85770010000002c5c8601cc6b9e94213c72737a0260801c5b600160651b831615611ffb577001000000162e42fff037df38aa2b219f060260801c5b600160641b83161561201e5770010000000b17217fba9c739aa5819f44f90260801c5b600160631b831615612041577001000000058b90bfcdee5acd3c1cedc8230260801c5b600160621b83161561206457700100000002c5c85fe31f35a6a30da1be500260801c5b600160611b8316156120875770010000000162e42ff0999ce3541b9fffcf0260801c5b600160601b8316156120aa57700100000000b17217f80f4ef5aadda455540260801c5b6001605f1b8316156120cd5770010000000058b90bfbf8479bd5a81b51ad0260801c5b6001605e1b8316156120f0577001000000002c5c85fdf84bd62ae30a74cc0260801c5b6001605d1b83161561211357700100000000162e42fefb2fed257559bdaa0260801c5b6001605c1b831615612136577001000000000b17217f7d5a7716bba4a9ae0260801c5b6001605b1b83161561215957700100000000058b90bfbe9ddbac5e109cce0260801c5b6001605a1b83161561217c5770010000000002c5c85fdf4b15de6f17eb0d0260801c5b600160591b83161561219f577001000000000162e42fefa494f1478fde050260801c5b600160581b8316156121c25770010000000000b17217f7d20cf927c8e94c0260801c5b600160571b8316156121e5577001000000000058b90bfbe8f71cb4e4b33d0260801c5b600160561b83161561220857700100000000002c5c85fdf477b662b269450260801c5b600160551b83161561222b5770010000000000162e42fefa3ae53369388c0260801c5b600160541b83161561224e57700100000000000b17217f7d1d351a389d400260801c5b600160531b8316156122715770010000000000058b90bfbe8e8b2d3d4ede0260801c5b600160521b831615612294577001000000000002c5c85fdf4741bea6e77e0260801c5b600160511b8316156122b757700100000000000162e42fefa39fe95583c20260801c5b600160501b8316156122d95769b17217f7d1cfb72b45e1600160801b010260801c5b6001604f1b8316156122fb576958b90bfbe8e7cc35c3f0600160801b010260801c5b6001604e1b83161561231d57692c5c85fdf473e242ea38600160801b010260801c5b6001604d1b83161561233f5769162e42fefa39f02b772c600160801b010260801c5b6001604c1b83161561236157690b17217f7d1cf7d83c1a600160801b010260801c5b6001604b1b8316156123835769058b90bfbe8e7bdcbe2e600160801b010260801c5b6001604a1b8316156123a5576902c5c85fdf473dea871f600160801b010260801c5b600160491b8316156123c757690162e42fefa39ef44d91600160801b010260801c5b600160481b8316156123e85768b17217f7d1cf79e949600160801b010260801c5b600160471b831615612409576858b90bfbe8e7bce544600160801b010260801c5b600160461b83161561242a57682c5c85fdf473de6eca600160801b010260801c5b600160451b83161561244b5768162e42fefa39ef366f600160801b010260801c5b600160441b83161561246c57680b17217f7d1cf79afa600160801b010260801c5b600160431b83161561248d5768058b90bfbe8e7bcd6d600160801b010260801c5b600160421b8316156124ae576802c5c85fdf473de6b2600160801b010260801c5b600160411b8316156124cf57680162e42fefa39ef358600160801b010260801c5b600160401b8316156124ef5767b17217f7d1cf79ab600160801b010260801c5b6001603f1b83161561250f576758b90bfbe8e7bcd5600160801b010260801c5b6001603e1b83161561252f57672c5c85fdf473de6a600160801b010260801c5b6001603d1b83161561254f5767162e42fefa39ef34600160801b010260801c5b6001603c1b83161561256f57670b17217f7d1cf799600160801b010260801c5b6001603b1b83161561258f5767058b90bfbe8e7bcc600160801b010260801c5b6001603a1b8316156125af576702c5c85fdf473de5600160801b010260801c5b600160391b8316156125cf57670162e42fefa39ef2600160801b010260801c5b600160381b8316156125ee5766b17217f7d1cf78600160801b010260801c5b600160371b83161561260d576658b90bfbe8e7bb600160801b010260801c5b600160361b83161561262c57662c5c85fdf473dd600160801b010260801c5b600160351b83161561264b5766162e42fefa39ee600160801b010260801c5b600160341b83161561266a57660b17217f7d1cf6600160801b010260801c5b600160331b8316156126895766058b90bfbe8e7a600160801b010260801c5b600160321b8316156126a8576602c5c85fdf473c600160801b010260801c5b600160311b8316156126c757660162e42fefa39d600160801b010260801c5b600160301b8316156126e55765b17217f7d1ce600160801b010260801c5b6001602f1b831615612703576558b90bfbe8e6600160801b010260801c5b6001602e1b83161561272157652c5c85fdf472600160801b010260801c5b6001602d1b83161561273f5765162e42fefa38600160801b010260801c5b6001602c1b83161561275d57650b17217f7d1b600160801b010260801c5b6001602b1b83161561277b5765058b90bfbe8d600160801b010260801c5b6001602a1b831615612799576502c5c85fdf46600160801b010260801c5b600160291b8316156127b757650162e42fefa2600160801b010260801c5b600160281b8316156127d45764b17217f7d0600160801b010260801c5b600160271b8316156127f1576458b90bfbe7600160801b010260801c5b600160261b83161561280e57642c5c85fdf3600160801b010260801c5b600160251b83161561282b5764162e42fef9600160801b010260801c5b600160241b83161561284857640b17217f7c600160801b010260801c5b600160231b8316156128655764058b90bfbd600160801b010260801c5b600160221b831615612882576402c5c85fde600160801b010260801c5b600160211b83161561289f57640162e42fee600160801b010260801c5b600160201b8316156128bb5763b17217f6600160801b010260801c5b63800000008316156128d7576358b90bfa600160801b010260801c5b63400000008316156128f357632c5c85fc600160801b010260801c5b632000000083161561290f5763162e42fd600160801b010260801c5b631000000083161561292b57630b17217e600160801b010260801c5b63080000008316156129475763058b90be600160801b010260801c5b6304000000831615612963576302c5c85e600160801b010260801c5b630200000083161561297f57630162e42e600160801b010260801c5b630100000083161561299a5762b17216600160801b010260801c5b628000008316156129b4576258b90a600160801b010260801c5b624000008316156129ce57622c5c84600160801b010260801c5b622000008316156129e85762162e41600160801b010260801c5b62100000831615612a0257620b1720600160801b010260801c5b62080000831615612a1c5762058b8f600160801b010260801c5b62040000831615612a36576202c5c7600160801b010260801c5b62020000831615612a5057620162e3600160801b010260801c5b62010000831615612a695761b171600160801b010260801c5b618000831615612a81576158b8600160801b010260801c5b614000831615612a9957612c5b600160801b010260801c5b612000831615612ab15761162d600160801b010260801c5b611000831615612ac957610b16600160801b010260801c5b610800831615612ae15761058a600160801b010260801c5b610400831615612af9576102c4600160801b010260801c5b610200831615612b1157610161600160801b010260801c5b610100831615612b285760b0600160801b010260801c5b6080831615612b3e576057600160801b010260801c5b6040831615612b5457602b600160801b010260801c5b6020831615612b6a576015600160801b010260801c5b6010831615612b8057600a600160801b010260801c5b6008831615612b96576004600160801b010260801c5b6004831615612bac576001600160801b010260801c5b84612bcd57600f81901c6001600160701b03169050613fff82019150612bfc565b613ffe8211612bf257600f81901c6001600160701b0316905081613fff039150612bfc565b600091613fee19011c5b60709190911b1760801b95945050505050565b600061089f612c31611653612c2385611a27565b610948866108d96002610abd565b6108d9612c54612c416002610abd565b6109486119f4666f9c9e651c4480610abd565b61143a565b600061089f612cb9612c746119f4660b58c2126f4900610abd565b61094d85610948612c96612c916119f4660caaedbfa8a700610abd565b611a27565b61094d89610948612cb06119f4663f4a728c19ce80610abd565b61094d8d612cbf565b83610e07565b600061089f82610948612cde612c916119f46640b43a04233100610abd565b61094d866109486119f4662f42c683f17c80610abd565b828054828255906000526020600020908101928215612d30579160200282015b82811115612d30578235825591602001919060010190612d15565b50612d3c929150612d40565b5090565b5b80821115612d3c5760008155600101612d41565b60008083601f840112612d6757600080fd5b5081356001600160401b03811115612d7e57600080fd5b6020830191508360208260051b8501011115612d9957600080fd5b9250929050565b60008060008060408587031215612db657600080fd5b84356001600160401b0380821115612dcd57600080fd5b612dd988838901612d55565b90965094506020870135915080821115612df257600080fd5b50612dff87828801612d55565b95989497509550505050565b600060208284031215612e1d57600080fd5b5035919050565b803580151581146104cb57600080fd5b60008060008060808587031215612e4a57600080fd5b612e5385612e24565b966020860135965060408601359560600135945092505050565b80356001600160a01b03811681146104cb57600080fd5b60008060408385031215612e9757600080fd5b612ea083612e6d565b9150612eae60208401612e24565b90509250929050565b6001600160a01b0391909116815260200190565b60008060008060808587031215612ee157600080fd5b5050823594602084013594506040840135936060013592509050565b600060208284031215612f0f57600080fd5b61089c82612e6d565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612f5657612f56612f2e565b5060010190565b81835260006001600160fb1b03831115612f7657600080fd5b8260051b8083602087013760009401602001938452509192915050565b6001600160a01b0386168152606060208201819052600090612fb89083018688612f5d565b8281036040840152612fcb818587612f5d565b98975050505050505050565b600082821015612fe957612fe9612f2e565b500390565b6000821982111561300157613001612f2e565b500190565b60006020828403121561301857600080fd5b5051919050565b634e487b7160e01b600052601260045260246000fd5b60008261305257634e487b7160e01b600052601260045260246000fd5b500490565b600081600019048311821515161561307157613071612f2e565b500290565b634e487b7160e01b600052600160045260246000fdfea264697066735822122064bc6f460f65931cebf50c2a6e57d0d2cc0fa236481e9dcc45f2a93d0038f0cb64736f6c634300080f0033000000000000000000000000000000000000000000000000000000000098968000000000000000000000000050e04e222fc1be96e94e86acf1136cb0e97e1d40
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101075760003560e01c8063016d47b51461010c57806307c91935146101215780631ce2a6881461014757806325b2a93b1461015a5780632ae0d14114610163578063326611f814610176578063427ec698146101995780634a95155c146101b95780635b7f6d77146101cc578063715018a6146101df578063717a1dec146101e75780637b0bfdbb146102075780637c90d3c71461021a5780638da5cb5b14610223578063aaa534da14610238578063b12ce0b41461024b578063bae6a6901461026b578063cf24eb241461027e578063d1dfc6b314610291578063d5f1b2ce146102a4578063f2fde38b146102c7575b600080fd5b61011f61011a366004612da0565b6102da565b005b61013461012f366004612e0b565b6103b6565b6040519081526020015b60405180910390f35b610134610155366004612e34565b6103d7565b61013460015481565b61011f610171366004612e84565b610487565b610189610184366004612e0b565b6104ba565b604051901515815260200161013e565b6101346101a7366004612e0b565b60046020526000908152604090205481565b6101896101c7366004612da0565b6104d0565b6101346101da366004612e34565b6104ff565b61011f610551565b6101346101f5366004612e0b565b60056020526000908152604090205481565b610189610215366004612da0565b610565565b61013461271081565b61022b6105d5565b60405161013e9190612eb7565b610134610246366004612ecb565b6105e4565b610134610259366004612e0b565b60036020526000908152604090205481565b610134610279366004612e0b565b61078e565b60025461022b906001600160a01b031681565b61018961029f366004612da0565b61079e565b6101896102b2366004612efd565b60066020526000908152604090205460ff1681565b61011f6102d5366004612efd565b610812565b3360009081526006602052604090205460ff1661030a5760405163f25c884f60e01b815260040160405180910390fd5b60005b838110156103705782828281811061032757610327612f18565b905060200201356003600087878581811061034457610344612f18565b90506020020135815260200190815260200160002081905550808061036890612f44565b91505061030d565b507f95805653338d965e92ffa53d6faff39c28f90a2e8a5166c48e94ca9a919f424533858585856040516103a8959493929190612f93565b60405180910390a150505050565b600781815481106103c657600080fd5b600091825260209091200154905081565b6000806103e685610360610890565b60008681526003602052604081205491925081900361040457600080fd5b610410858583896105e4565b90506000610442662386f26fc1000061043c8a61042e576000610431565b60015b888a886000896108a5565b90610890565b905060006104646402540be40061043c600154896109f690919063ffffffff16565b90508181111561047957935061047f92505050565b50925050505b949350505050565b61048f610a02565b6001600160a01b03919091166000908152600660205260409020805460ff1916911515919091179055565b60006104c4610a02565b5060018181555b919050565b60006104da610a02565b6104e660078686612cf5565b506104f360088484612cf5565b50600195945050505050565b60008061051261036061043c8742610a61565b905060006003816105234289612fd7565b81526020019081526020016000205490508060000361054157600080fd5b610410858583610246428b612fd7565b610559610a02565b6105636000610a6d565b565b600061056f610a02565b60005b848110156104f35785858281811061058c5761058c612f18565b90506020020135600560008686858181106105a9576105a9612f18565b9050602002013581526020019081526020016000208190555080806105cd90612f44565b915050610572565b6000546001600160a01b031690565b6000806106028561043c6127106105fc8a60646109f6565b906109f6565b9050848611156106205761061981620f4240610a61565b9050610630565b61062d620f424082610a61565b90505b600083815260056020526040812054610652906127109061043c9085906109f6565b60008581526004602052604090205461066b9190612fee565b905061067d61271061043c87846109f6565b6007549095503290600081156107665760005b82811015610764576002546040516370a0823160e01b81526000916001600160a01b0316906370a08231906106c9908890600401612eb7565b602060405180830381865afa1580156106e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061070a9190613006565b90506007828154811061071f5761071f612f18565b90600052602060002001548110610755576008828154811061074357610743612f18565b9060005260206000200154925061075b565b50610764565b50600101610690565b505b61078061271061043c6107798483612fd7565b8b906109f6565b9a9950505050505050505050565b600881815481106103c657600080fd5b60006107a8610a02565b8360005b81811015610805578686828181106107c6576107c6612f18565b90506020020135600460008787858181106107e3576107e3612f18565b60209081029290920135835250810191909152604001600020556001016107ac565b5060019695505050505050565b61081a610a02565b6001600160a01b0381166108845760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b61088d81610a6d565b50565b600061089c8284613035565b90505b92915050565b6000806108b187610abd565b905060006108be87610abd565b905060006108de6108ce88610abd565b6108d9618e94610abd565b610b24565b905060006108f96108ee88610abd565b6108d9612710610abd565b9050600061091361090988610abd565b6108d96064610abd565b9050600061096561095861092f61092a8989610b24565b610de4565b61094d6109528761094d886109488a6108d96002610abd565b610e07565b611070565b88610e07565b6108d9846109488861143a565b9050600061097f8261097a856109488961143a565b611613565b905060ff8e166109c0576109b26109ad61099d89858a898b88611625565b610948662386f26fc10000610abd565b61166c565b9750505050505050506109ec565b60001960ff8f16016109e0576109b26109ad61099d888789868d896116f0565b60009750505050505050505b9695505050505050565b600061089c8284613057565b33610a0b6105d5565b6001600160a01b0316146105635760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161087b565b600061089c8284612fd7565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600081600003610acf57506000919050565b816000610adb82611742565b90506070811015610af4578060700382901b9150610b07565b6070811115610b07576070810382901c91505b613fff0160701b6001600160701b03919091161760801b92915050565b6000617fff60f084811c8216919084901c811690829003610b695780617fff03610b58575061ffff60ef1b915061089f9050565b505050600160ff1b8116821861089f565b80617fff03610ba557600160801b600160f01b03841615610b94575061ffff60ef1b915061089f9050565b505050808218600160ff1b1661089f565b600160801b600160ff1b038416600003610bf557600160801b600160ff1b038516600003610bdd575061ffff60ef1b915061089f9050565b505050808218600160ff1b16617fff60f01b1761089f565b6001600160701b03608085901c166000829003610c155760019150610c1c565b600160701b175b6001600160701b03608087901c166000849003610c5f578015610c5a576000610c4482611742565b6001955060e20393840160711901939190911b90505b610c69565b600160701b1760721b5b818181610c7857610c7861301f565b04905080600003610ca857600160ff1b87871816610c97576000610c9d565b600160ff1b5b94505050505061089f565b6001606c1b811015610cbc57610cbc613076565b6000600160731b821015610cfb57600160721b821015610cf057600160711b821015610ce9576070610cf3565b6071610cf3565b60725b60ff16610d04565b610d0482611742565b905083614071018186011115610d2257617fff945060009150610db5565b83818601613ffc011015610d3d576000945060009150610db5565b83818601613f8c011015610d8a578385613ffc011115610d68578385613ffc010382901b9150610d81565b8385613ffc011015610d8157613ffc8585030382901c91505b60009450610db5565b6070811115610d9d576070810382901c91505b6001600160701b038216915083818601613f8d010394505b81607086901b888a186001607f1b60801b1660801c6001600160801b0316171760801b9550505050505061089f565b600061089f610df2836117df565b6f3ffe62e42fefa39ef35793c7673007e560801b5b6000617fff60f084811c8216919084901c811690829003610ea65780617fff03610e82576001600160801b031980851690861603610e5057505050600160ff1b8116821861089f565b6001600160801b031985851816600160ff1b03610e725750505081811761089f565b5061ffff60ef1b915061089f9050565b600160801b600160ff1b038416600003610b58575061ffff60ef1b915061089f9050565b80617fff03610ee457600160801b600160ff1b038516600003610ed3575061ffff60ef1b915061089f9050565b505050600160ff1b8216811861089f565b6001600160701b03608086901c166000839003610f045760019250610f0b565b600160701b175b6001600160701b03608086901c166000839003610f2b5760019250610f32565b600160701b175b808202915081600003610f5357600160ff1b87871816610c97576000610c9d565b928201926000600160e11b831015610f8657600160e01b831015610f7f57610f7a83611742565b610f89565b60e0610f89565b60e15b90506140708186011015610fa4576000945060009250611041565b6140e08186011015610fe757614070851015610fc957846140700383901c9250610fde565b614070851115610fde57614070850383901b92505b60009450611041565b61c0dd818601111561100157617fff945060009250611041565b6070811115611018576070810383901c925061102b565b607081101561102b578060700383901b92505b6001600160701b03831692506140df8186010394505b82607086901b888a186001607f1b60801b1660801c6001600160801b0316171760801b9550505050505061089f565b6000617fff60f084811c8216919084901c8116908290036110bc5780617fff036110b2576001600160801b031980851690861603610e7257849250505061089f565b849250505061089f565b80617fff036110cf57839250505061089f565b6001607f1b608086901c90811015906001600160701b031660008490036110f95760019350611100565b600160701b175b6001607f1b608087901c90811015906001600160701b0316600085900361112a5760019450611131565b600160701b175b82600003611164576001600160801b03198816600160ff1b146111545787611157565b60005b965050505050505061089f565b80600003611187576001600160801b03198916600160ff1b146111545788611157565b848603821515851515036112905760708113156111ad578997505050505050505061089f565b60008113156111bf5790811c906111ee565b606f198112156111d8578897505050505050505061089f565b60008112156111ee578060000384901c93508596505b92810192600160711b8410611209576001968701969390931c925b86617fff0361123a578461122257617fff60f01b61122c565b6001600160f01b03195b97505050505050505061089f565b600160701b84101561124f576000965061125c565b6001600160701b03841693505b83607088901b8661126e576000611274565b6001607f1b5b6001600160801b0316171760801b97505050505050505061089f565b60008113156112ab57600184901b93506001870396506112c2565b60008112156112c257600182901b91506001860396505b60708113156112d45760019150611321565b60018113156112f1576001810360018303901c6001019150611321565b606f198112156113045760019350611321565b600019811215611321576001816000030360018503901c60010193505b81841061133257818403935061133b565b83820393508294505b8360000361135457506000965061089f95505050505050565b600061135f85611742565b90508060710361138457600185901c6001600160701b031694506001880197506113d3565b60708110156113c6576070819003808911156113b3578086901b6001600160701b0316955080890398506113c0565b600098600019019590951b945b506113d3565b6001600160701b03851694505b87617fff0361140557856113ec57617fff60f01b6113f6565b6001600160f01b03195b9850505050505050505061089f565b84607089901b8761141757600061141d565b6001607f1b5b6001600160801b0316171760801b9850505050505050505061089f565b60006001607f1b608083901c1115611458575061ffff60ef1b919050565b617fff60f083901c811690819003611471575090919050565b6001600160701b03608084901c1660008290036114915760019150611498565b600160701b175b806000036114aa575060009392505050565b613fff8201600190811c92161580156114fc57600160701b82106114d457607182901b9150611537565b60006114df83611742565b60e20360fe16606f19810160011c909403939290921b9150611537565b600160701b821061151357607082901b9150611537565b600061151e83611742565b60e10360fe16606f19810160011c909403939290921b91505b600160701b80830401600190811c908184816115555761155561301f565b048201901c9050600181848161156d5761156d61301f565b048201901c905060018184816115855761158561301f565b048201901c9050600181848161159d5761159d61301f565b048201901c905060018184816115b5576115b561301f565b048201901c905060018184816115cd576115cd61301f565b048201901c905060008184816115e5576115e561301f565b049050818110156115f4578091505b816001600160701b0316607086901b1760801b95505050505050919050565b600061089c83600160ff1b8418611070565b60006116616116378861094889611997565b61097a6116588861094861165361164d8b611a27565b8a610e07565b611a30565b61094886611997565b979650505050505050565b6000617fff60f083901c16613fff81101561168a5750600092915050565b6001607f1b608084901c1061169e57600080fd5b6140fe8111156116ad57600080fd5b600160701b6001600160701b03608085901c161761406f8210156116d75761406f8290031c6116e9565b61406f8211156116e95761406e1982011b5b9392505050565b60008061172061170f896109486116536117098c611a27565b8b610e07565b61094861171b88611a27565b611997565b905060006117348561094861171b87611a27565b905060006107808383611613565b600080821161175057600080fd5b6000600160801b831061176557608092831c92015b600160401b831061177857604092831c92015b600160201b831061178b57602092831c92015b62010000831061179d57601092831c92015b61010083106117ae57600892831c92015b601083106117be57600492831c92015b600483106117ce57600292831c92015b6002831061089f5760010192915050565b60006001607f1b608083901c11156117fd575061ffff60ef1b919050565b6001600160801b03198216613fff60f01b0361181b57506000919050565b617fff60f083901c811690819003611834575090919050565b6001600160701b03608084901c166000829003611854576001915061185b565b600160701b175b8060000361187457506001600160f01b03199392505050565b600061406f81613fff851061189a5750600f9290921b9160009150613ffe1984016118d9565b60019250600160701b84106118bc5784613ffe039050600f84901b93506118d9565b60006118c785611742565b607f8190039590951b9461406d039150505b836001607f1b0361190f5782156118ee576001015b60006118f982611742565b60700390508082901b915080830392505061195d565b60008361191d576000611920565b60015b60ff1690505b600160701b82101561195b5793800260ff81901c607f81019190911c94600019939093019260019290921b9082180190611926565b505b806001600160701b0316607083901b8461197857600061197e565b6001607f1b5b6001600160801b0316171760801b979650505050505050565b6000806119a383611a57565b12156119c25761089f6119b66001610abd565b61097a61171b85611a27565b6000611a046119d16001610abd565b6108d96119de6001610abd565b61094d6109526119f466083ac553a55e00610abd565b6108d9662386f26fc10000610abd565b90506000611a128285611afe565b905061047f611a216001610abd565b82611613565b600160ff1b1890565b600061089f611a52836f1fffb8aa3b295c17f0bbbe87fed0691d60811b610e07565b611b15565b6000617fff60f083901c166140fe811115611a7157600080fd5b613fff811015611a845750600092915050565b600160701b6001600160701b03608085901c161761406f821015611aae5761406f8290031c611ac0565b61406f821115611ac05761406e1982011b5b6001607f1b608085901c10611aea57600160ff1b811115611ae057600080fd5b6000039392505050565b6001600160ff1b038111156116e957600080fd5b600061089c611b0c83612c0f565b61094885612c59565b60006001607f1b608083901c90811190617fff60f085901c8116916001600160701b03169082148015611b4757508015155b15611b5b575061ffff60ef1b949350505050565b61400d821115611b815782611b7557617fff60f01b611b78565b60005b95945050505050565b613f7f821015611b9a5750613fff60f01b949350505050565b81600003611bab5760019150611bb2565b600160701b175b613fef821115611bc857613fee1982011b611bda565b613fef821015611bda57613fef8290031c5b828015611beb575061203760811b81115b15611bfb57506000949350505050565b82158015611c0f575060016001608e1b0381115b15611c235750617fff60f01b949350505050565b6001600160801b0381169060801c838015611c3d57508115155b15611c49579019906001015b6001607f1b82811615611c6d5770016a09e667f3bcc908b2fb1366ea957d3e0260801c5b6001607e1b831615611c90577001306fe0a31b7152de8d5a46305c85edec0260801c5b6001607d1b831615611cb3577001172b83c7d517adcdf7c8c50eb14a791f0260801c5b6001607c1b831615611cd65770010b5586cf9890f6298b92b71842a983630260801c5b6001607b1b831615611cf9577001059b0d31585743ae7c548eb68ca417fd0260801c5b6001607a1b831615611d1c57700102c9a3e778060ee6f7caca4f7a29bde80260801c5b600160791b831615611d3f5770010163da9fb33356d84a66ae336dcdfa3f0260801c5b600160781b831615611d6257700100b1afa5abcbed6129ab13ec11dc95430260801c5b600160771b831615611d855770010058c86da1c09ea1ff19d294cf2f679b0260801c5b600160761b831615611da8577001002c605e2e8cec506d21bfc89a23a00f0260801c5b600160751b831615611dcb57700100162f3904051fa128bca9c55c31e5df0260801c5b600160741b831615611dee577001000b175effdc76ba38e31671ca9397250260801c5b600160731b831615611e1157700100058ba01fb9f96d6cacd4b180917c3d0260801c5b600160721b831615611e345770010002c5cc37da9491d0985c348c68e7b30260801c5b600160711b831615611e57577001000162e525ee054754457d59952920260260801c5b600160701b831615611e7a5770010000b17255775c040618bf4a4ade83fc0260801c5b6001606f1b831615611e9d577001000058b91b5bc9ae2eed81e9b7d4cfab0260801c5b6001606e1b831615611ec057700100002c5c89d5ec6ca4d7c8acc017b7c90260801c5b6001606d1b831615611ee35770010000162e43f4f831060e02d839a9d16d0260801c5b6001606c1b831615611f0657700100000b1721bcfc99d9f890ea069117630260801c5b6001606b1b831615611f295770010000058b90cf1e6d97f9ca14dbcc16280260801c5b6001606a1b831615611f4c577001000002c5c863b73f016468f6bac5ca2b0260801c5b600160691b831615611f6f57700100000162e430e5a18f6119e3c02282a50260801c5b600160681b831615611f92577001000000b1721835514b86e6d96efd1bfe0260801c5b600160671b831615611fb557700100000058b90c0b48c6be5df846c5b2ef0260801c5b600160661b831615611fd85770010000002c5c8601cc6b9e94213c72737a0260801c5b600160651b831615611ffb577001000000162e42fff037df38aa2b219f060260801c5b600160641b83161561201e5770010000000b17217fba9c739aa5819f44f90260801c5b600160631b831615612041577001000000058b90bfcdee5acd3c1cedc8230260801c5b600160621b83161561206457700100000002c5c85fe31f35a6a30da1be500260801c5b600160611b8316156120875770010000000162e42ff0999ce3541b9fffcf0260801c5b600160601b8316156120aa57700100000000b17217f80f4ef5aadda455540260801c5b6001605f1b8316156120cd5770010000000058b90bfbf8479bd5a81b51ad0260801c5b6001605e1b8316156120f0577001000000002c5c85fdf84bd62ae30a74cc0260801c5b6001605d1b83161561211357700100000000162e42fefb2fed257559bdaa0260801c5b6001605c1b831615612136577001000000000b17217f7d5a7716bba4a9ae0260801c5b6001605b1b83161561215957700100000000058b90bfbe9ddbac5e109cce0260801c5b6001605a1b83161561217c5770010000000002c5c85fdf4b15de6f17eb0d0260801c5b600160591b83161561219f577001000000000162e42fefa494f1478fde050260801c5b600160581b8316156121c25770010000000000b17217f7d20cf927c8e94c0260801c5b600160571b8316156121e5577001000000000058b90bfbe8f71cb4e4b33d0260801c5b600160561b83161561220857700100000000002c5c85fdf477b662b269450260801c5b600160551b83161561222b5770010000000000162e42fefa3ae53369388c0260801c5b600160541b83161561224e57700100000000000b17217f7d1d351a389d400260801c5b600160531b8316156122715770010000000000058b90bfbe8e8b2d3d4ede0260801c5b600160521b831615612294577001000000000002c5c85fdf4741bea6e77e0260801c5b600160511b8316156122b757700100000000000162e42fefa39fe95583c20260801c5b600160501b8316156122d95769b17217f7d1cfb72b45e1600160801b010260801c5b6001604f1b8316156122fb576958b90bfbe8e7cc35c3f0600160801b010260801c5b6001604e1b83161561231d57692c5c85fdf473e242ea38600160801b010260801c5b6001604d1b83161561233f5769162e42fefa39f02b772c600160801b010260801c5b6001604c1b83161561236157690b17217f7d1cf7d83c1a600160801b010260801c5b6001604b1b8316156123835769058b90bfbe8e7bdcbe2e600160801b010260801c5b6001604a1b8316156123a5576902c5c85fdf473dea871f600160801b010260801c5b600160491b8316156123c757690162e42fefa39ef44d91600160801b010260801c5b600160481b8316156123e85768b17217f7d1cf79e949600160801b010260801c5b600160471b831615612409576858b90bfbe8e7bce544600160801b010260801c5b600160461b83161561242a57682c5c85fdf473de6eca600160801b010260801c5b600160451b83161561244b5768162e42fefa39ef366f600160801b010260801c5b600160441b83161561246c57680b17217f7d1cf79afa600160801b010260801c5b600160431b83161561248d5768058b90bfbe8e7bcd6d600160801b010260801c5b600160421b8316156124ae576802c5c85fdf473de6b2600160801b010260801c5b600160411b8316156124cf57680162e42fefa39ef358600160801b010260801c5b600160401b8316156124ef5767b17217f7d1cf79ab600160801b010260801c5b6001603f1b83161561250f576758b90bfbe8e7bcd5600160801b010260801c5b6001603e1b83161561252f57672c5c85fdf473de6a600160801b010260801c5b6001603d1b83161561254f5767162e42fefa39ef34600160801b010260801c5b6001603c1b83161561256f57670b17217f7d1cf799600160801b010260801c5b6001603b1b83161561258f5767058b90bfbe8e7bcc600160801b010260801c5b6001603a1b8316156125af576702c5c85fdf473de5600160801b010260801c5b600160391b8316156125cf57670162e42fefa39ef2600160801b010260801c5b600160381b8316156125ee5766b17217f7d1cf78600160801b010260801c5b600160371b83161561260d576658b90bfbe8e7bb600160801b010260801c5b600160361b83161561262c57662c5c85fdf473dd600160801b010260801c5b600160351b83161561264b5766162e42fefa39ee600160801b010260801c5b600160341b83161561266a57660b17217f7d1cf6600160801b010260801c5b600160331b8316156126895766058b90bfbe8e7a600160801b010260801c5b600160321b8316156126a8576602c5c85fdf473c600160801b010260801c5b600160311b8316156126c757660162e42fefa39d600160801b010260801c5b600160301b8316156126e55765b17217f7d1ce600160801b010260801c5b6001602f1b831615612703576558b90bfbe8e6600160801b010260801c5b6001602e1b83161561272157652c5c85fdf472600160801b010260801c5b6001602d1b83161561273f5765162e42fefa38600160801b010260801c5b6001602c1b83161561275d57650b17217f7d1b600160801b010260801c5b6001602b1b83161561277b5765058b90bfbe8d600160801b010260801c5b6001602a1b831615612799576502c5c85fdf46600160801b010260801c5b600160291b8316156127b757650162e42fefa2600160801b010260801c5b600160281b8316156127d45764b17217f7d0600160801b010260801c5b600160271b8316156127f1576458b90bfbe7600160801b010260801c5b600160261b83161561280e57642c5c85fdf3600160801b010260801c5b600160251b83161561282b5764162e42fef9600160801b010260801c5b600160241b83161561284857640b17217f7c600160801b010260801c5b600160231b8316156128655764058b90bfbd600160801b010260801c5b600160221b831615612882576402c5c85fde600160801b010260801c5b600160211b83161561289f57640162e42fee600160801b010260801c5b600160201b8316156128bb5763b17217f6600160801b010260801c5b63800000008316156128d7576358b90bfa600160801b010260801c5b63400000008316156128f357632c5c85fc600160801b010260801c5b632000000083161561290f5763162e42fd600160801b010260801c5b631000000083161561292b57630b17217e600160801b010260801c5b63080000008316156129475763058b90be600160801b010260801c5b6304000000831615612963576302c5c85e600160801b010260801c5b630200000083161561297f57630162e42e600160801b010260801c5b630100000083161561299a5762b17216600160801b010260801c5b628000008316156129b4576258b90a600160801b010260801c5b624000008316156129ce57622c5c84600160801b010260801c5b622000008316156129e85762162e41600160801b010260801c5b62100000831615612a0257620b1720600160801b010260801c5b62080000831615612a1c5762058b8f600160801b010260801c5b62040000831615612a36576202c5c7600160801b010260801c5b62020000831615612a5057620162e3600160801b010260801c5b62010000831615612a695761b171600160801b010260801c5b618000831615612a81576158b8600160801b010260801c5b614000831615612a9957612c5b600160801b010260801c5b612000831615612ab15761162d600160801b010260801c5b611000831615612ac957610b16600160801b010260801c5b610800831615612ae15761058a600160801b010260801c5b610400831615612af9576102c4600160801b010260801c5b610200831615612b1157610161600160801b010260801c5b610100831615612b285760b0600160801b010260801c5b6080831615612b3e576057600160801b010260801c5b6040831615612b5457602b600160801b010260801c5b6020831615612b6a576015600160801b010260801c5b6010831615612b8057600a600160801b010260801c5b6008831615612b96576004600160801b010260801c5b6004831615612bac576001600160801b010260801c5b84612bcd57600f81901c6001600160701b03169050613fff82019150612bfc565b613ffe8211612bf257600f81901c6001600160701b0316905081613fff039150612bfc565b600091613fee19011c5b60709190911b1760801b95945050505050565b600061089f612c31611653612c2385611a27565b610948866108d96002610abd565b6108d9612c54612c416002610abd565b6109486119f4666f9c9e651c4480610abd565b61143a565b600061089f612cb9612c746119f4660b58c2126f4900610abd565b61094d85610948612c96612c916119f4660caaedbfa8a700610abd565b611a27565b61094d89610948612cb06119f4663f4a728c19ce80610abd565b61094d8d612cbf565b83610e07565b600061089f82610948612cde612c916119f46640b43a04233100610abd565b61094d866109486119f4662f42c683f17c80610abd565b828054828255906000526020600020908101928215612d30579160200282015b82811115612d30578235825591602001919060010190612d15565b50612d3c929150612d40565b5090565b5b80821115612d3c5760008155600101612d41565b60008083601f840112612d6757600080fd5b5081356001600160401b03811115612d7e57600080fd5b6020830191508360208260051b8501011115612d9957600080fd5b9250929050565b60008060008060408587031215612db657600080fd5b84356001600160401b0380821115612dcd57600080fd5b612dd988838901612d55565b90965094506020870135915080821115612df257600080fd5b50612dff87828801612d55565b95989497509550505050565b600060208284031215612e1d57600080fd5b5035919050565b803580151581146104cb57600080fd5b60008060008060808587031215612e4a57600080fd5b612e5385612e24565b966020860135965060408601359560600135945092505050565b80356001600160a01b03811681146104cb57600080fd5b60008060408385031215612e9757600080fd5b612ea083612e6d565b9150612eae60208401612e24565b90509250929050565b6001600160a01b0391909116815260200190565b60008060008060808587031215612ee157600080fd5b5050823594602084013594506040840135936060013592509050565b600060208284031215612f0f57600080fd5b61089c82612e6d565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612f5657612f56612f2e565b5060010190565b81835260006001600160fb1b03831115612f7657600080fd5b8260051b8083602087013760009401602001938452509192915050565b6001600160a01b0386168152606060208201819052600090612fb89083018688612f5d565b8281036040840152612fcb818587612f5d565b98975050505050505050565b600082821015612fe957612fe9612f2e565b500390565b6000821982111561300157613001612f2e565b500190565b60006020828403121561301857600080fd5b5051919050565b634e487b7160e01b600052601260045260246000fd5b60008261305257634e487b7160e01b600052601260045260246000fd5b500490565b600081600019048311821515161561307157613071612f2e565b500290565b634e487b7160e01b600052600160045260246000fdfea264697066735822122064bc6f460f65931cebf50c2a6e57d0d2cc0fa236481e9dcc45f2a93d0038f0cb64736f6c634300080f0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000098968000000000000000000000000050e04e222fc1be96e94e86acf1136cb0e97e1d40
-----Decoded View---------------
Arg [0] : _minOptionPricePercentage (uint256): 10000000
Arg [1] : _xSyk (address): 0x50E04E222Fc1be96E94E86AcF1136cB0E97E1d40
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000989680
Arg [1] : 00000000000000000000000050e04e222fc1be96e94e86acf1136cb0e97e1d40
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.