My Name Tag:
Not Available
Txn Hash | Method |
Block
|
From
|
To
|
Value | [Txn Fee] | |||
---|---|---|---|---|---|---|---|---|---|
0x6679bd9e451fe9c113ee69244310b67dbdbf051bca31ed0a4ad80551187b0fcc | 0x61020060 | 3304826 | 855 days 18 hrs ago | 0xc7f8d87734ab2cbf70030ac8aa82abfe3e8126cb | IN | Create: PoolIO | 0 ETH | 0.201665162647 ETH |
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
PoolIO
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 // For further clarification please see https://license.premia.legal pragma solidity ^0.8.0; import {EnumerableSet} from "@solidstate/contracts/utils/EnumerableSet.sol"; import {ABDKMath64x64} from "abdk-libraries-solidity/ABDKMath64x64.sol"; import {IPoolIO} from "./IPoolIO.sol"; import {PoolSwap} from "./PoolSwap.sol"; import {PoolStorage} from "./PoolStorage.sol"; import {IPremiaMining} from "../mining/IPremiaMining.sol"; /** * @title Premia option pool * @dev deployed standalone and referenced by PoolProxy */ contract PoolIO is IPoolIO, PoolSwap { using ABDKMath64x64 for int128; using EnumerableSet for EnumerableSet.AddressSet; using EnumerableSet for EnumerableSet.UintSet; using PoolStorage for PoolStorage.Layout; constructor( address ivolOracle, address weth, address premiaMining, address feeReceiver, address feeDiscountAddress, int128 fee64x64, address uniswapV2Factory, address sushiswapFactory ) PoolSwap( ivolOracle, weth, premiaMining, feeReceiver, feeDiscountAddress, fee64x64, uniswapV2Factory, sushiswapFactory ) {} /** * @notice set timestamp after which reinvestment is disabled * @param timestamp timestamp to begin divestment * @param isCallPool whether we set divestment timestamp for the call pool or put pool */ function setDivestmentTimestamp(uint64 timestamp, bool isCallPool) external override { PoolStorage.Layout storage l = PoolStorage.layout(); require( timestamp >= l.depositedAt[msg.sender][isCallPool] + (1 days), "liq lock 1d" ); l.divestmentTimestamps[msg.sender][isCallPool] = timestamp; } /** * @notice deposit underlying currency, underwriting calls of that currency with respect to base currency * @param amount quantity of underlying currency to deposit * @param isCallPool whether to deposit underlying in the call pool or base in the put pool */ function deposit(uint256 amount, bool isCallPool) external payable override { _deposit(amount, isCallPool, false); } /** * @notice deposit underlying currency, underwriting calls of that currency with respect to base currency * @param amount quantity of underlying currency to deposit * @param isCallPool whether to deposit underlying in the call pool or base in the put pool * @param skipWethDeposit if false, will not try to deposit weth from attach eth */ function _deposit( uint256 amount, bool isCallPool, bool skipWethDeposit ) internal { PoolStorage.Layout storage l = PoolStorage.layout(); // Reset gradual divestment timestamp delete l.divestmentTimestamps[msg.sender][isCallPool]; uint256 cap = _getPoolCapAmount(l, isCallPool); require( l.totalTVL[isCallPool] + amount <= cap, "pool deposit cap reached" ); _processPendingDeposits(l, isCallPool); l.depositedAt[msg.sender][isCallPool] = block.timestamp; _addUserTVL(l, msg.sender, isCallPool, amount); _pullFrom( msg.sender, _getPoolToken(isCallPool), amount, skipWethDeposit ); _addToDepositQueue(msg.sender, amount, isCallPool); emit Deposit(msg.sender, isCallPool, amount); } /** * @notice deposit underlying currency, underwriting calls of that currency with respect to base currency * @param amount quantity of underlying currency to deposit * @param isCallPool whether to deposit underlying in the call pool or base in the put pool * @param amountOut amount out of tokens requested. If 0, we will swap exact amount necessary to pay the quote * @param amountInMax amount in max of tokens * @param path swap path * @param isSushi whether we use sushi or uniV2 for the swap */ function swapAndDeposit( uint256 amount, bool isCallPool, uint256 amountOut, uint256 amountInMax, address[] calldata path, bool isSushi ) external payable override { // If value is passed, amountInMax must be 0, as the value wont be used // If amountInMax is not 0, user wants to do a swap from an ERC20, and therefore no value should be attached require( msg.value == 0 || amountInMax == 0, "value and amountInMax passed" ); // If no amountOut has been passed, we swap the exact deposit amount specified if (amountOut == 0) { amountOut = amount; } if (msg.value > 0) { _swapETHForExactTokens(amountOut, path, isSushi); } else { _swapTokensForExactTokens(amountOut, amountInMax, path, isSushi); } _deposit(amount, isCallPool, true); } /** * @notice redeem pool share tokens for underlying asset * @param amount quantity of share tokens to redeem * @param isCallPool whether to deposit underlying in the call pool or base in the put pool */ function withdraw(uint256 amount, bool isCallPool) public override { PoolStorage.Layout storage l = PoolStorage.layout(); uint256 toWithdraw = amount; _processPendingDeposits(l, isCallPool); uint256 depositedAt = l.depositedAt[msg.sender][isCallPool]; require(depositedAt + (1 days) < block.timestamp, "liq lock 1d"); int128 oldLiquidity64x64 = l.totalFreeLiquiditySupply64x64(isCallPool); { uint256 reservedLiqTokenId = _getReservedLiquidityTokenId( isCallPool ); uint256 reservedLiquidity = _balanceOf( msg.sender, reservedLiqTokenId ); if (reservedLiquidity > 0) { uint256 reservedLiqToWithdraw; if (reservedLiquidity < toWithdraw) { reservedLiqToWithdraw = reservedLiquidity; } else { reservedLiqToWithdraw = toWithdraw; } toWithdraw -= reservedLiqToWithdraw; // burn reserved liquidity tokens from sender _burn(msg.sender, reservedLiqTokenId, reservedLiqToWithdraw); } } if (toWithdraw > 0) { // burn free liquidity tokens from sender _burn(msg.sender, _getFreeLiquidityTokenId(isCallPool), toWithdraw); int128 newLiquidity64x64 = l.totalFreeLiquiditySupply64x64( isCallPool ); _setCLevel(l, oldLiquidity64x64, newLiquidity64x64, isCallPool); } _subUserTVL(l, msg.sender, isCallPool, amount); _pushTo(msg.sender, _getPoolToken(isCallPool), amount); emit Withdrawal(msg.sender, isCallPool, depositedAt, amount); } /** * @notice reassign short position to new underwriter * @param tokenId ERC1155 token id (long or short) * @param contractSize quantity of option contract tokens to reassign * @return baseCost quantity of tokens required to reassign short position * @return feeCost quantity of tokens required to pay fees * @return amountOut quantity of liquidity freed and transferred to owner */ function reassign(uint256 tokenId, uint256 contractSize) external override returns ( uint256 baseCost, uint256 feeCost, uint256 amountOut ) { PoolStorage.Layout storage l = PoolStorage.layout(); int128 newPrice64x64 = _update(l); ( PoolStorage.TokenType tokenType, uint64 maturity, int128 strike64x64 ) = PoolStorage.parseTokenId(tokenId); bool isCall = tokenType == PoolStorage.TokenType.SHORT_CALL || tokenType == PoolStorage.TokenType.LONG_CALL; (baseCost, feeCost, amountOut) = _reassign( l, msg.sender, maturity, strike64x64, isCall, contractSize, newPrice64x64 ); _pushTo(msg.sender, _getPoolToken(isCall), amountOut); } /** * @notice reassign set of short position to new underwriter * @param tokenIds array of ERC1155 token ids (long or short) * @param contractSizes array of quantities of option contract tokens to reassign * @return baseCosts quantities of tokens required to reassign each short position * @return feeCosts quantities of tokens required to pay fees * @return amountOutCall quantity of call pool liquidity freed and transferred to owner * @return amountOutPut quantity of put pool liquidity freed and transferred to owner */ function reassignBatch( uint256[] calldata tokenIds, uint256[] calldata contractSizes ) public override returns ( uint256[] memory baseCosts, uint256[] memory feeCosts, uint256 amountOutCall, uint256 amountOutPut ) { require(tokenIds.length == contractSizes.length, "diff array length"); PoolStorage.Layout storage l = PoolStorage.layout(); int128 newPrice64x64 = _update(l); baseCosts = new uint256[](tokenIds.length); feeCosts = new uint256[](tokenIds.length); for (uint256 i; i < tokenIds.length; i++) { ( PoolStorage.TokenType tokenType, uint64 maturity, int128 strike64x64 ) = PoolStorage.parseTokenId(tokenIds[i]); bool isCall = tokenType == PoolStorage.TokenType.SHORT_CALL || tokenType == PoolStorage.TokenType.LONG_CALL; uint256 amountOut; uint256 contractSize = contractSizes[i]; (baseCosts[i], feeCosts[i], amountOut) = _reassign( l, msg.sender, maturity, strike64x64, isCall, contractSize, newPrice64x64 ); if (isCall) { amountOutCall += amountOut; } else { amountOutPut += amountOut; } } _pushTo(msg.sender, _getPoolToken(true), amountOutCall); _pushTo(msg.sender, _getPoolToken(false), amountOutPut); } /** * @notice withdraw all free liquidity and reassign set of short position to new underwriter * @param isCallPool true for call, false for put * @param tokenIds array of ERC1155 token ids (long or short) * @param contractSizes array of quantities of option contract tokens to reassign * @return baseCosts quantities of tokens required to reassign each short position * @return feeCosts quantities of tokens required to pay fees * @return amountOutCall quantity of call pool liquidity freed and transferred to owner * @return amountOutPut quantity of put pool liquidity freed and transferred to owner */ function withdrawAllAndReassignBatch( bool isCallPool, uint256[] calldata tokenIds, uint256[] calldata contractSizes ) external override returns ( uint256[] memory baseCosts, uint256[] memory feeCosts, uint256 amountOutCall, uint256 amountOutPut ) { uint256 balance = _balanceOf( msg.sender, _getFreeLiquidityTokenId(isCallPool) ); if (balance > 0) { withdraw(balance, isCallPool); } (baseCosts, feeCosts, amountOutCall, amountOutPut) = reassignBatch( tokenIds, contractSizes ); } /** * @notice transfer accumulated fees to the fee receiver * @return amountOutCall quantity of underlying tokens transferred * @return amountOutPut quantity of base tokens transferred */ function withdrawFees() external override returns (uint256 amountOutCall, uint256 amountOutPut) { amountOutCall = _withdrawFees(true); amountOutPut = _withdrawFees(false); _pushTo(FEE_RECEIVER_ADDRESS, _getPoolToken(true), amountOutCall); _pushTo(FEE_RECEIVER_ADDRESS, _getPoolToken(false), amountOutPut); } /** * @notice burn corresponding long and short option tokens and withdraw collateral * @param tokenId ERC1155 token id (long or short) * @param contractSize quantity of option contract tokens to annihilate */ function annihilate(uint256 tokenId, uint256 contractSize) external override { ( PoolStorage.TokenType tokenType, uint64 maturity, int128 strike64x64 ) = PoolStorage.parseTokenId(tokenId); bool isCall = tokenType == PoolStorage.TokenType.SHORT_CALL || tokenType == PoolStorage.TokenType.LONG_CALL; _annihilate(msg.sender, maturity, strike64x64, isCall, contractSize); _pushTo( msg.sender, _getPoolToken(isCall), isCall ? contractSize : PoolStorage.layout().fromUnderlyingToBaseDecimals( strike64x64.mulu(contractSize) ) ); } function claimRewards(bool isCallPool) external override { claimRewards(msg.sender, isCallPool); } function claimRewards(address account, bool isCallPool) public override { PoolStorage.Layout storage l = PoolStorage.layout(); uint256 userTVL = l.userTVL[account][isCallPool]; uint256 totalTVL = l.totalTVL[isCallPool]; IPremiaMining(PREMIA_MINING_ADDRESS).claim( account, address(this), isCallPool, userTVL, userTVL, totalTVL ); } function updateMiningPools() external override { PoolStorage.Layout storage l = PoolStorage.layout(); IPremiaMining(PREMIA_MINING_ADDRESS).updatePool( address(this), true, l.totalTVL[true] ); IPremiaMining(PREMIA_MINING_ADDRESS).updatePool( address(this), false, l.totalTVL[false] ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title Set implementation with enumeration functions * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license) */ library EnumerableSet { struct Set { bytes32[] _values; // 1-indexed to allow 0 to signify nonexistence mapping(bytes32 => uint256) _indexes; } struct Bytes32Set { Set _inner; } struct AddressSet { Set _inner; } struct UintSet { Set _inner; } function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } function indexOf(Bytes32Set storage set, bytes32 value) internal view returns (uint256) { return _indexOf(set._inner, value); } function indexOf(AddressSet storage set, address value) internal view returns (uint256) { return _indexOf(set._inner, bytes32(uint256(uint160(value)))); } function indexOf(UintSet storage set, uint256 value) internal view returns (uint256) { return _indexOf(set._inner, bytes32(value)); } function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } function _at(Set storage set, uint256 index) private view returns (bytes32) { require( set._values.length > index, 'EnumerableSet: index out of bounds' ); return set._values[index]; } function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } function _indexOf(Set storage set, bytes32 value) private view returns (uint256) { unchecked { return set._indexes[value] - 1; } } function _length(Set storage set) private view returns (uint256) { return set._values.length; } function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); set._indexes[value] = set._values.length; return true; } else { return false; } } function _remove(Set storage set, bytes32 value) private returns (bool) { uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { uint256 index = valueIndex - 1; bytes32 last = set._values[set._values.length - 1]; // move last value to now-vacant index set._values[index] = last; set._indexes[last] = index + 1; // clear last index set._values.pop(); delete set._indexes[value]; return true; } else { return false; } } }
// SPDX-License-Identifier: BSD-4-Clause /* * ABDK Math 64.64 Smart Contract Library. Copyright © 2019 by ABDK Consulting. * Author: Mikhail Vladimirov <[email protected]> */ pragma solidity ^0.8.0; /** * Smart contract library of mathematical functions operating with signed * 64.64-bit fixed point numbers. Signed 64.64-bit fixed point number is * basically a simple fraction whose numerator is signed 128-bit integer and * denominator is 2^64. As long as denominator is always the same, there is no * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are * represented by int128 type holding only the numerator. */ library ABDKMath64x64 { /* * Minimum value signed 64.64-bit fixed point number may have. */ int128 private constant MIN_64x64 = -0x80000000000000000000000000000000; /* * Maximum value signed 64.64-bit fixed point number may have. */ int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; /** * Convert signed 256-bit integer number into signed 64.64-bit fixed point * number. Revert on overflow. * * @param x signed 256-bit integer number * @return signed 64.64-bit fixed point number */ function fromInt (int256 x) internal pure returns (int128) { unchecked { require (x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF); return int128 (x << 64); } } /** * Convert signed 64.64 fixed point number into signed 64-bit integer number * rounding down. * * @param x signed 64.64-bit fixed point number * @return signed 64-bit integer number */ function toInt (int128 x) internal pure returns (int64) { unchecked { return int64 (x >> 64); } } /** * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point * number. Revert on overflow. * * @param x unsigned 256-bit integer number * @return signed 64.64-bit fixed point number */ function fromUInt (uint256 x) internal pure returns (int128) { unchecked { require (x <= 0x7FFFFFFFFFFFFFFF); return int128 (int256 (x << 64)); } } /** * Convert signed 64.64 fixed point number into unsigned 64-bit integer * number rounding down. Revert on underflow. * * @param x signed 64.64-bit fixed point number * @return unsigned 64-bit integer number */ function toUInt (int128 x) internal pure returns (uint64) { unchecked { require (x >= 0); return uint64 (uint128 (x >> 64)); } } /** * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point * number rounding down. Revert on overflow. * * @param x signed 128.128-bin fixed point number * @return signed 64.64-bit fixed point number */ function from128x128 (int256 x) internal pure returns (int128) { unchecked { int256 result = x >> 64; require (result >= MIN_64x64 && result <= MAX_64x64); return int128 (result); } } /** * Convert signed 64.64 fixed point number into signed 128.128 fixed point * number. * * @param x signed 64.64-bit fixed point number * @return signed 128.128 fixed point number */ function to128x128 (int128 x) internal pure returns (int256) { unchecked { return int256 (x) << 64; } } /** * Calculate x + y. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function add (int128 x, int128 y) internal pure returns (int128) { unchecked { int256 result = int256(x) + y; require (result >= MIN_64x64 && result <= MAX_64x64); return int128 (result); } } /** * Calculate x - y. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function sub (int128 x, int128 y) internal pure returns (int128) { unchecked { int256 result = int256(x) - y; require (result >= MIN_64x64 && result <= MAX_64x64); return int128 (result); } } /** * Calculate x * y rounding down. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function mul (int128 x, int128 y) internal pure returns (int128) { unchecked { int256 result = int256(x) * y >> 64; require (result >= MIN_64x64 && result <= MAX_64x64); return int128 (result); } } /** * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point * number and y is signed 256-bit integer number. Revert on overflow. * * @param x signed 64.64 fixed point number * @param y signed 256-bit integer number * @return signed 256-bit integer number */ function muli (int128 x, int256 y) internal pure returns (int256) { unchecked { if (x == MIN_64x64) { require (y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF && y <= 0x1000000000000000000000000000000000000000000000000); return -y << 63; } else { bool negativeResult = false; if (x < 0) { x = -x; negativeResult = true; } if (y < 0) { y = -y; // We rely on overflow behavior here negativeResult = !negativeResult; } uint256 absoluteResult = mulu (x, uint256 (y)); if (negativeResult) { require (absoluteResult <= 0x8000000000000000000000000000000000000000000000000000000000000000); return -int256 (absoluteResult); // We rely on overflow behavior here } else { require (absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return int256 (absoluteResult); } } } } /** * Calculate x * y rounding down, where x is signed 64.64 fixed point number * and y is unsigned 256-bit integer number. Revert on overflow. * * @param x signed 64.64 fixed point number * @param y unsigned 256-bit integer number * @return unsigned 256-bit integer number */ function mulu (int128 x, uint256 y) internal pure returns (uint256) { unchecked { if (y == 0) return 0; require (x >= 0); uint256 lo = (uint256 (int256 (x)) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64; uint256 hi = uint256 (int256 (x)) * (y >> 128); require (hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); hi <<= 64; require (hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo); return hi + lo; } } /** * Calculate x / y rounding towards zero. Revert on overflow or when y is * zero. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function div (int128 x, int128 y) internal pure returns (int128) { unchecked { require (y != 0); int256 result = (int256 (x) << 64) / y; require (result >= MIN_64x64 && result <= MAX_64x64); return int128 (result); } } /** * Calculate x / y rounding towards zero, where x and y are signed 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x signed 256-bit integer number * @param y signed 256-bit integer number * @return signed 64.64-bit fixed point number */ function divi (int256 x, int256 y) internal pure returns (int128) { unchecked { require (y != 0); bool negativeResult = false; if (x < 0) { x = -x; // We rely on overflow behavior here negativeResult = true; } if (y < 0) { y = -y; // We rely on overflow behavior here negativeResult = !negativeResult; } uint128 absoluteResult = divuu (uint256 (x), uint256 (y)); if (negativeResult) { require (absoluteResult <= 0x80000000000000000000000000000000); return -int128 (absoluteResult); // We rely on overflow behavior here } else { require (absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return int128 (absoluteResult); // We rely on overflow behavior here } } } /** * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x unsigned 256-bit integer number * @param y unsigned 256-bit integer number * @return signed 64.64-bit fixed point number */ function divu (uint256 x, uint256 y) internal pure returns (int128) { unchecked { require (y != 0); uint128 result = divuu (x, y); require (result <= uint128 (MAX_64x64)); return int128 (result); } } /** * Calculate -x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function neg (int128 x) internal pure returns (int128) { unchecked { require (x != MIN_64x64); return -x; } } /** * Calculate |x|. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function abs (int128 x) internal pure returns (int128) { unchecked { require (x != MIN_64x64); return x < 0 ? -x : x; } } /** * Calculate 1 / x rounding towards zero. Revert on overflow or when x is * zero. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function inv (int128 x) internal pure returns (int128) { unchecked { require (x != 0); int256 result = int256 (0x100000000000000000000000000000000) / x; require (result >= MIN_64x64 && result <= MAX_64x64); return int128 (result); } } /** * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function avg (int128 x, int128 y) internal pure returns (int128) { unchecked { return int128 ((int256 (x) + int256 (y)) >> 1); } } /** * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down. * Revert on overflow or in case x * y is negative. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function gavg (int128 x, int128 y) internal pure returns (int128) { unchecked { int256 m = int256 (x) * int256 (y); require (m >= 0); require (m < 0x4000000000000000000000000000000000000000000000000000000000000000); return int128 (sqrtu (uint256 (m))); } } /** * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number * and y is unsigned 256-bit integer number. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y uint256 value * @return signed 64.64-bit fixed point number */ function pow (int128 x, uint256 y) internal pure returns (int128) { unchecked { bool negative = x < 0 && y & 1 == 1; uint256 absX = uint128 (x < 0 ? -x : x); uint256 absResult; absResult = 0x100000000000000000000000000000000; if (absX <= 0x10000000000000000) { absX <<= 63; while (y != 0) { if (y & 0x1 != 0) { absResult = absResult * absX >> 127; } absX = absX * absX >> 127; if (y & 0x2 != 0) { absResult = absResult * absX >> 127; } absX = absX * absX >> 127; if (y & 0x4 != 0) { absResult = absResult * absX >> 127; } absX = absX * absX >> 127; if (y & 0x8 != 0) { absResult = absResult * absX >> 127; } absX = absX * absX >> 127; y >>= 4; } absResult >>= 64; } else { uint256 absXShift = 63; if (absX < 0x1000000000000000000000000) { absX <<= 32; absXShift -= 32; } if (absX < 0x10000000000000000000000000000) { absX <<= 16; absXShift -= 16; } if (absX < 0x1000000000000000000000000000000) { absX <<= 8; absXShift -= 8; } if (absX < 0x10000000000000000000000000000000) { absX <<= 4; absXShift -= 4; } if (absX < 0x40000000000000000000000000000000) { absX <<= 2; absXShift -= 2; } if (absX < 0x80000000000000000000000000000000) { absX <<= 1; absXShift -= 1; } uint256 resultShift = 0; while (y != 0) { require (absXShift < 64); if (y & 0x1 != 0) { absResult = absResult * absX >> 127; resultShift += absXShift; if (absResult > 0x100000000000000000000000000000000) { absResult >>= 1; resultShift += 1; } } absX = absX * absX >> 127; absXShift <<= 1; if (absX >= 0x100000000000000000000000000000000) { absX >>= 1; absXShift += 1; } y >>= 1; } require (resultShift < 64); absResult >>= 64 - resultShift; } int256 result = negative ? -int256 (absResult) : int256 (absResult); require (result >= MIN_64x64 && result <= MAX_64x64); return int128 (result); } } /** * Calculate sqrt (x) rounding down. Revert if x < 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function sqrt (int128 x) internal pure returns (int128) { unchecked { require (x >= 0); return int128 (sqrtu (uint256 (int256 (x)) << 64)); } } /** * Calculate binary logarithm of x. Revert if x <= 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function log_2 (int128 x) internal pure returns (int128) { unchecked { require (x > 0); int256 msb = 0; int256 xc = x; if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; } if (xc >= 0x100000000) { xc >>= 32; msb += 32; } if (xc >= 0x10000) { xc >>= 16; msb += 16; } if (xc >= 0x100) { xc >>= 8; msb += 8; } if (xc >= 0x10) { xc >>= 4; msb += 4; } if (xc >= 0x4) { xc >>= 2; msb += 2; } if (xc >= 0x2) msb += 1; // No need to shift xc anymore int256 result = msb - 64 << 64; uint256 ux = uint256 (int256 (x)) << uint256 (127 - msb); for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) { ux *= ux; uint256 b = ux >> 255; ux >>= 127 + b; result += bit * int256 (b); } return int128 (result); } } /** * Calculate natural logarithm of x. Revert if x <= 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function ln (int128 x) internal pure returns (int128) { unchecked { require (x > 0); return int128 (int256 ( uint256 (int256 (log_2 (x))) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF >> 128)); } } /** * Calculate binary exponent of x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function exp_2 (int128 x) internal pure returns (int128) { unchecked { require (x < 0x400000000000000000); // Overflow if (x < -0x400000000000000000) return 0; // Underflow uint256 result = 0x80000000000000000000000000000000; if (x & 0x8000000000000000 > 0) result = result * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128; if (x & 0x4000000000000000 > 0) result = result * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128; if (x & 0x2000000000000000 > 0) result = result * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128; if (x & 0x1000000000000000 > 0) result = result * 0x10B5586CF9890F6298B92B71842A98363 >> 128; if (x & 0x800000000000000 > 0) result = result * 0x1059B0D31585743AE7C548EB68CA417FD >> 128; if (x & 0x400000000000000 > 0) result = result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128; if (x & 0x200000000000000 > 0) result = result * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128; if (x & 0x100000000000000 > 0) result = result * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128; if (x & 0x80000000000000 > 0) result = result * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128; if (x & 0x40000000000000 > 0) result = result * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128; if (x & 0x20000000000000 > 0) result = result * 0x100162F3904051FA128BCA9C55C31E5DF >> 128; if (x & 0x10000000000000 > 0) result = result * 0x1000B175EFFDC76BA38E31671CA939725 >> 128; if (x & 0x8000000000000 > 0) result = result * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128; if (x & 0x4000000000000 > 0) result = result * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128; if (x & 0x2000000000000 > 0) result = result * 0x1000162E525EE054754457D5995292026 >> 128; if (x & 0x1000000000000 > 0) result = result * 0x10000B17255775C040618BF4A4ADE83FC >> 128; if (x & 0x800000000000 > 0) result = result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128; if (x & 0x400000000000 > 0) result = result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128; if (x & 0x200000000000 > 0) result = result * 0x10000162E43F4F831060E02D839A9D16D >> 128; if (x & 0x100000000000 > 0) result = result * 0x100000B1721BCFC99D9F890EA06911763 >> 128; if (x & 0x80000000000 > 0) result = result * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128; if (x & 0x40000000000 > 0) result = result * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128; if (x & 0x20000000000 > 0) result = result * 0x100000162E430E5A18F6119E3C02282A5 >> 128; if (x & 0x10000000000 > 0) result = result * 0x1000000B1721835514B86E6D96EFD1BFE >> 128; if (x & 0x8000000000 > 0) result = result * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128; if (x & 0x4000000000 > 0) result = result * 0x10000002C5C8601CC6B9E94213C72737A >> 128; if (x & 0x2000000000 > 0) result = result * 0x1000000162E42FFF037DF38AA2B219F06 >> 128; if (x & 0x1000000000 > 0) result = result * 0x10000000B17217FBA9C739AA5819F44F9 >> 128; if (x & 0x800000000 > 0) result = result * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128; if (x & 0x400000000 > 0) result = result * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128; if (x & 0x200000000 > 0) result = result * 0x10000000162E42FF0999CE3541B9FFFCF >> 128; if (x & 0x100000000 > 0) result = result * 0x100000000B17217F80F4EF5AADDA45554 >> 128; if (x & 0x80000000 > 0) result = result * 0x10000000058B90BFBF8479BD5A81B51AD >> 128; if (x & 0x40000000 > 0) result = result * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128; if (x & 0x20000000 > 0) result = result * 0x100000000162E42FEFB2FED257559BDAA >> 128; if (x & 0x10000000 > 0) result = result * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128; if (x & 0x8000000 > 0) result = result * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128; if (x & 0x4000000 > 0) result = result * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128; if (x & 0x2000000 > 0) result = result * 0x1000000000162E42FEFA494F1478FDE05 >> 128; if (x & 0x1000000 > 0) result = result * 0x10000000000B17217F7D20CF927C8E94C >> 128; if (x & 0x800000 > 0) result = result * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128; if (x & 0x400000 > 0) result = result * 0x100000000002C5C85FDF477B662B26945 >> 128; if (x & 0x200000 > 0) result = result * 0x10000000000162E42FEFA3AE53369388C >> 128; if (x & 0x100000 > 0) result = result * 0x100000000000B17217F7D1D351A389D40 >> 128; if (x & 0x80000 > 0) result = result * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128; if (x & 0x40000 > 0) result = result * 0x1000000000002C5C85FDF4741BEA6E77E >> 128; if (x & 0x20000 > 0) result = result * 0x100000000000162E42FEFA39FE95583C2 >> 128; if (x & 0x10000 > 0) result = result * 0x1000000000000B17217F7D1CFB72B45E1 >> 128; if (x & 0x8000 > 0) result = result * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128; if (x & 0x4000 > 0) result = result * 0x10000000000002C5C85FDF473E242EA38 >> 128; if (x & 0x2000 > 0) result = result * 0x1000000000000162E42FEFA39F02B772C >> 128; if (x & 0x1000 > 0) result = result * 0x10000000000000B17217F7D1CF7D83C1A >> 128; if (x & 0x800 > 0) result = result * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128; if (x & 0x400 > 0) result = result * 0x100000000000002C5C85FDF473DEA871F >> 128; if (x & 0x200 > 0) result = result * 0x10000000000000162E42FEFA39EF44D91 >> 128; if (x & 0x100 > 0) result = result * 0x100000000000000B17217F7D1CF79E949 >> 128; if (x & 0x80 > 0) result = result * 0x10000000000000058B90BFBE8E7BCE544 >> 128; if (x & 0x40 > 0) result = result * 0x1000000000000002C5C85FDF473DE6ECA >> 128; if (x & 0x20 > 0) result = result * 0x100000000000000162E42FEFA39EF366F >> 128; if (x & 0x10 > 0) result = result * 0x1000000000000000B17217F7D1CF79AFA >> 128; if (x & 0x8 > 0) result = result * 0x100000000000000058B90BFBE8E7BCD6D >> 128; if (x & 0x4 > 0) result = result * 0x10000000000000002C5C85FDF473DE6B2 >> 128; if (x & 0x2 > 0) result = result * 0x1000000000000000162E42FEFA39EF358 >> 128; if (x & 0x1 > 0) result = result * 0x10000000000000000B17217F7D1CF79AB >> 128; result >>= uint256 (int256 (63 - (x >> 64))); require (result <= uint256 (int256 (MAX_64x64))); return int128 (int256 (result)); } } /** * Calculate natural exponent of x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function exp (int128 x) internal pure returns (int128) { unchecked { require (x < 0x400000000000000000); // Overflow if (x < -0x400000000000000000) return 0; // Underflow return exp_2 ( int128 (int256 (x) * 0x171547652B82FE1777D0FFDA0D23A7D12 >> 128)); } } /** * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x unsigned 256-bit integer number * @param y unsigned 256-bit integer number * @return unsigned 64.64-bit fixed point number */ function divuu (uint256 x, uint256 y) private pure returns (uint128) { unchecked { require (y != 0); uint256 result; if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) result = (x << 64) / y; else { uint256 msb = 192; uint256 xc = x >> 192; if (xc >= 0x100000000) { xc >>= 32; msb += 32; } if (xc >= 0x10000) { xc >>= 16; msb += 16; } if (xc >= 0x100) { xc >>= 8; msb += 8; } if (xc >= 0x10) { xc >>= 4; msb += 4; } if (xc >= 0x4) { xc >>= 2; msb += 2; } if (xc >= 0x2) msb += 1; // No need to shift xc anymore result = (x << 255 - msb) / ((y - 1 >> msb - 191) + 1); require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); uint256 hi = result * (y >> 128); uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); uint256 xh = x >> 192; uint256 xl = x << 64; if (xl < lo) xh -= 1; xl -= lo; // We rely on overflow behavior here lo = hi << 128; if (xl < lo) xh -= 1; xl -= lo; // We rely on overflow behavior here assert (xh == hi >> 128); result += xl / y; } require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return uint128 (result); } } /** * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer * number. * * @param x unsigned 256-bit integer number * @return unsigned 128-bit integer number */ function sqrtu (uint256 x) private pure returns (uint128) { unchecked { if (x == 0) return 0; else { uint256 xx = x; uint256 r = 1; if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; } if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; } if (xx >= 0x100000000) { xx >>= 32; r <<= 16; } if (xx >= 0x10000) { xx >>= 16; r <<= 8; } if (xx >= 0x100) { xx >>= 8; r <<= 4; } if (xx >= 0x10) { xx >>= 4; r <<= 2; } if (xx >= 0x8) { r <<= 1; } r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; // Seven iterations should be enough uint256 r1 = x / r; return uint128 (r < r1 ? r : r1); } } } }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.8.0; interface IPoolIO { function setDivestmentTimestamp(uint64 timestamp, bool isCallPool) external; function deposit(uint256 amount, bool isCallPool) external payable; function swapAndDeposit( uint256 amount, bool isCallPool, uint256 amountOut, uint256 amountInMax, address[] calldata path, bool isSushi ) external payable; function withdraw(uint256 amount, bool isCallPool) external; function reassign(uint256 tokenId, uint256 contractSize) external returns ( uint256 baseCost, uint256 feeCost, uint256 amountOut ); function reassignBatch( uint256[] calldata tokenIds, uint256[] calldata contractSizes ) external returns ( uint256[] memory baseCosts, uint256[] memory feeCosts, uint256 amountOutCall, uint256 amountOutPut ); function withdrawAllAndReassignBatch( bool isCallPool, uint256[] calldata tokenIds, uint256[] calldata contractSizes ) external returns ( uint256[] memory baseCosts, uint256[] memory feeCosts, uint256 amountOutCall, uint256 amountOutPut ); function withdrawFees() external returns (uint256 amountOutCall, uint256 amountOutPut); function annihilate(uint256 tokenId, uint256 contractSize) external; function claimRewards(bool isCallPool) external; function claimRewards(address account, bool isCallPool) external; function updateMiningPools() external; }
// SPDX-License-Identifier: BUSL-1.1 // For further clarification please see https://license.premia.legal pragma solidity ^0.8.0; import {PoolStorage} from "./PoolStorage.sol"; import {IWETH} from "@solidstate/contracts/utils/IWETH.sol"; import {IUniswapV2Pair} from "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol"; import {SafeERC20} from "@solidstate/contracts/utils/SafeERC20.sol"; import {IERC20} from "@solidstate/contracts/token/ERC20/IERC20.sol"; import {ABDKMath64x64} from "abdk-libraries-solidity/ABDKMath64x64.sol"; import {PoolInternal} from "./PoolInternal.sol"; /** * @title Premia option pool * @dev deployed standalone and referenced by PoolProxy */ abstract contract PoolSwap is PoolInternal { using SafeERC20 for IERC20; using ABDKMath64x64 for int128; using PoolStorage for PoolStorage.Layout; address internal immutable UNISWAP_V2_FACTORY; address internal immutable SUSHISWAP_FACTORY; constructor( address ivolOracle, address weth, address premiaMining, address feeReceiver, address feeDiscountAddress, int128 fee64x64, address uniswapV2Factory, address sushiswapFactory ) PoolInternal( ivolOracle, weth, premiaMining, feeReceiver, feeDiscountAddress, fee64x64 ) { UNISWAP_V2_FACTORY = uniswapV2Factory; SUSHISWAP_FACTORY = sushiswapFactory; } // calculates the CREATE2 address for a pair without making any external calls function _pairFor( address factory, address tokenA, address tokenB, bool isSushi ) internal pure returns (address pair) { (address token0, address token1) = _sortTokens(tokenA, tokenB); pair = address( uint160( uint256( keccak256( abi.encodePacked( hex"ff", factory, keccak256(abi.encodePacked(token0, token1)), isSushi ? hex"e18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303" : hex"96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f" // init code hash ) ) ) ) ); } // returns sorted token addresses, used to handle return values from pairs sorted in this order function _sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { require(tokenA != tokenB, "UniswapV2Library: IDENTICAL_ADDRESSES"); (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), "UniswapV2Library: ZERO_ADDRESS"); } // performs chained getAmountIn calculations on any number of pairs function _getAmountsIn( address factory, uint256 amountOut, address[] memory path, bool isSushi ) internal view returns (uint256[] memory amounts) { require(path.length >= 2, "UniswapV2Library: INVALID_PATH"); amounts = new uint256[](path.length); amounts[amounts.length - 1] = amountOut; for (uint256 i = path.length - 1; i > 0; i--) { (uint256 reserveIn, uint256 reserveOut) = _getReserves( factory, path[i - 1], path[i], isSushi ); amounts[i - 1] = _getAmountIn(amounts[i], reserveIn, reserveOut); } } // fetches and sorts the reserves for a pair function _getReserves( address factory, address tokenA, address tokenB, bool isSushi ) internal view returns (uint256 reserveA, uint256 reserveB) { (address token0, ) = _sortTokens(tokenA, tokenB); (uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair( _pairFor(factory, tokenA, tokenB, isSushi) ).getReserves(); (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); } // given an output amount of an asset and pair reserves, returns a required input amount of the other asset function _getAmountIn( uint256 amountOut, uint256 reserveIn, uint256 reserveOut ) internal pure returns (uint256 amountIn) { require(amountOut > 0, "UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT"); require( reserveIn > 0 && reserveOut > 0, "UniswapV2Library: INSUFFICIENT_LIQUIDITY" ); uint256 numerator = reserveIn * amountOut * 1000; uint256 denominator = (reserveOut - amountOut) * 997; amountIn = (numerator / denominator) + 1; } // requires the initial amount to have already been sent to the first pair function _swap( uint256[] memory amounts, address[] memory path, address _to, bool isSushi ) internal { for (uint256 i; i < path.length - 1; i++) { (address input, address output) = (path[i], path[i + 1]); (address token0, ) = _sortTokens(input, output); uint256 amountOut = amounts[i + 1]; (uint256 amount0Out, uint256 amount1Out) = input == token0 ? (uint256(0), amountOut) : (amountOut, uint256(0)); address to = i < path.length - 2 ? _pairFor( isSushi ? SUSHISWAP_FACTORY : UNISWAP_V2_FACTORY, output, path[i + 2], isSushi ) : _to; IUniswapV2Pair( _pairFor( isSushi ? SUSHISWAP_FACTORY : UNISWAP_V2_FACTORY, input, output, isSushi ) ).swap(amount0Out, amount1Out, to, new bytes(0)); } } function _swapTokensForExactTokens( uint256 amountOut, uint256 amountInMax, address[] calldata path, bool isSushi ) internal returns (uint256[] memory amounts) { amounts = _getAmountsIn( isSushi ? SUSHISWAP_FACTORY : UNISWAP_V2_FACTORY, amountOut, path, isSushi ); require( amounts[0] <= amountInMax, "UniswapV2Router: EXCESSIVE_INPUT_AMOUNT" ); IERC20(path[0]).safeTransferFrom( msg.sender, _pairFor( isSushi ? SUSHISWAP_FACTORY : UNISWAP_V2_FACTORY, path[0], path[1], isSushi ), amounts[0] ); _swap(amounts, path, msg.sender, isSushi); } function _swapETHForExactTokens( uint256 amountOut, address[] calldata path, bool isSushi ) internal returns (uint256[] memory amounts) { require(path[0] == WETH_ADDRESS, "UniswapV2Router: INVALID_PATH"); amounts = _getAmountsIn( isSushi ? SUSHISWAP_FACTORY : UNISWAP_V2_FACTORY, amountOut, path, isSushi ); require( amounts[0] <= msg.value, "UniswapV2Router: EXCESSIVE_INPUT_AMOUNT" ); IWETH(WETH_ADDRESS).deposit{value: amounts[0]}(); assert( IWETH(WETH_ADDRESS).transfer( _pairFor( isSushi ? SUSHISWAP_FACTORY : UNISWAP_V2_FACTORY, path[0], path[1], isSushi ), amounts[0] ) ); _swap(amounts, path, msg.sender, isSushi); // refund dust eth, if any if (msg.value > amounts[0]) { (bool success, ) = payable(msg.sender).call{ value: msg.value - amounts[0] }(new bytes(0)); require( success, "TransferHelper::safeTransferETH: ETH transfer failed" ); } } }
// SPDX-License-Identifier: BUSL-1.1 // For further clarification please see https://license.premia.legal pragma solidity ^0.8.0; import {AggregatorInterface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorInterface.sol"; import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; import {EnumerableSet, ERC1155EnumerableStorage} from "@solidstate/contracts/token/ERC1155/enumerable/ERC1155EnumerableStorage.sol"; import {ABDKMath64x64} from "abdk-libraries-solidity/ABDKMath64x64.sol"; import {ABDKMath64x64Token} from "../libraries/ABDKMath64x64Token.sol"; import {OptionMath} from "../libraries/OptionMath.sol"; library PoolStorage { using ABDKMath64x64 for int128; using PoolStorage for PoolStorage.Layout; enum TokenType { UNDERLYING_FREE_LIQ, BASE_FREE_LIQ, UNDERLYING_RESERVED_LIQ, BASE_RESERVED_LIQ, LONG_CALL, SHORT_CALL, LONG_PUT, SHORT_PUT } struct PoolSettings { address underlying; address base; address underlyingOracle; address baseOracle; } struct QuoteArgsInternal { address feePayer; // address of the fee payer uint64 maturity; // timestamp of option maturity int128 strike64x64; // 64x64 fixed point representation of strike price int128 spot64x64; // 64x64 fixed point representation of spot price uint256 contractSize; // size of option contract bool isCall; // true for call, false for put } struct QuoteResultInternal { int128 baseCost64x64; // 64x64 fixed point representation of option cost denominated in underlying currency (without fee) int128 feeCost64x64; // 64x64 fixed point representation of option fee cost denominated in underlying currency for call, or base currency for put int128 cLevel64x64; // 64x64 fixed point representation of C-Level of Pool after purchase int128 slippageCoefficient64x64; // 64x64 fixed point representation of slippage coefficient for given order size } struct BatchData { uint256 eta; uint256 totalPendingDeposits; } bytes32 internal constant STORAGE_SLOT = keccak256("premia.contracts.storage.Pool"); uint256 private constant C_DECAY_BUFFER = 12 hours; uint256 private constant C_DECAY_INTERVAL = 4 hours; struct Layout { // ERC20 token addresses address base; address underlying; // AggregatorV3Interface oracle addresses address baseOracle; address underlyingOracle; // token metadata uint8 underlyingDecimals; uint8 baseDecimals; // minimum amounts uint256 baseMinimum; uint256 underlyingMinimum; // deposit caps uint256 basePoolCap; uint256 underlyingPoolCap; // market state int128 _deprecated_steepness64x64; int128 cLevelBase64x64; int128 cLevelUnderlying64x64; uint256 cLevelBaseUpdatedAt; uint256 cLevelUnderlyingUpdatedAt; uint256 updatedAt; // User -> isCall -> depositedAt mapping(address => mapping(bool => uint256)) depositedAt; mapping(address => mapping(bool => uint256)) divestmentTimestamps; // doubly linked list of free liquidity intervals // isCall -> User -> User mapping(bool => mapping(address => address)) liquidityQueueAscending; mapping(bool => mapping(address => address)) liquidityQueueDescending; // minimum resolution price bucket => price mapping(uint256 => int128) bucketPrices64x64; // sequence id (minimum resolution price bucket / 256) => price update sequence mapping(uint256 => uint256) priceUpdateSequences; // isCall -> batch data mapping(bool => BatchData) nextDeposits; // user -> batch timestamp -> isCall -> pending amount mapping(address => mapping(uint256 => mapping(bool => uint256))) pendingDeposits; EnumerableSet.UintSet tokenIds; // user -> isCallPool -> total value locked of user (Used for liquidity mining) mapping(address => mapping(bool => uint256)) userTVL; // isCallPool -> total value locked mapping(bool => uint256) totalTVL; // steepness values int128 steepnessBase64x64; int128 steepnessUnderlying64x64; } function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } /** * @notice calculate ERC1155 token id for given option parameters * @param tokenType TokenType enum * @param maturity timestamp of option maturity * @param strike64x64 64x64 fixed point representation of strike price * @return tokenId token id */ function formatTokenId( TokenType tokenType, uint64 maturity, int128 strike64x64 ) internal pure returns (uint256 tokenId) { tokenId = (uint256(tokenType) << 248) + (uint256(maturity) << 128) + uint256(int256(strike64x64)); } /** * @notice derive option maturity and strike price from ERC1155 token id * @param tokenId token id * @return tokenType TokenType enum * @return maturity timestamp of option maturity * @return strike64x64 option strike price */ function parseTokenId(uint256 tokenId) internal pure returns ( TokenType tokenType, uint64 maturity, int128 strike64x64 ) { assembly { tokenType := shr(248, tokenId) maturity := shr(128, tokenId) strike64x64 := tokenId } } function getTokenDecimals(Layout storage l, bool isCall) internal view returns (uint8 decimals) { decimals = isCall ? l.underlyingDecimals : l.baseDecimals; } /** * @notice get the total supply of free liquidity tokens, minus pending deposits * @param l storage layout struct * @param isCall whether query is for call or put pool * @return 64x64 fixed point representation of total free liquidity */ function totalFreeLiquiditySupply64x64(Layout storage l, bool isCall) internal view returns (int128) { uint256 tokenId = formatTokenId( isCall ? TokenType.UNDERLYING_FREE_LIQ : TokenType.BASE_FREE_LIQ, 0, 0 ); return ABDKMath64x64Token.fromDecimals( ERC1155EnumerableStorage.layout().totalSupply[tokenId] - l.nextDeposits[isCall].totalPendingDeposits, l.getTokenDecimals(isCall) ); } function getReinvestmentStatus( Layout storage l, address account, bool isCallPool ) internal view returns (bool) { uint256 timestamp = l.divestmentTimestamps[account][isCallPool]; return timestamp == 0 || timestamp > block.timestamp; } function addUnderwriter( Layout storage l, address account, bool isCallPool ) internal { require(account != address(0)); mapping(address => address) storage asc = l.liquidityQueueAscending[ isCallPool ]; mapping(address => address) storage desc = l.liquidityQueueDescending[ isCallPool ]; if (_isInQueue(account, asc, desc)) return; address last = desc[address(0)]; asc[last] = account; desc[account] = last; desc[address(0)] = account; } function removeUnderwriter( Layout storage l, address account, bool isCallPool ) internal { require(account != address(0)); mapping(address => address) storage asc = l.liquidityQueueAscending[ isCallPool ]; mapping(address => address) storage desc = l.liquidityQueueDescending[ isCallPool ]; if (!_isInQueue(account, asc, desc)) return; address prev = desc[account]; address next = asc[account]; asc[prev] = next; desc[next] = prev; delete asc[account]; delete desc[account]; } function isInQueue( Layout storage l, address account, bool isCallPool ) internal view returns (bool) { mapping(address => address) storage asc = l.liquidityQueueAscending[ isCallPool ]; mapping(address => address) storage desc = l.liquidityQueueDescending[ isCallPool ]; return _isInQueue(account, asc, desc); } function _isInQueue( address account, mapping(address => address) storage asc, mapping(address => address) storage desc ) private view returns (bool) { return asc[account] != address(0) || desc[address(0)] == account; } /** * @notice get current C-Level, without accounting for pending adjustments * @param l storage layout struct * @param isCall whether query is for call or put pool * @return cLevel64x64 64x64 fixed point representation of C-Level */ function getRawCLevel64x64(Layout storage l, bool isCall) internal view returns (int128 cLevel64x64) { cLevel64x64 = isCall ? l.cLevelUnderlying64x64 : l.cLevelBase64x64; } /** * @notice get current C-Level, accounting for unrealized decay * @param l storage layout struct * @param isCall whether query is for call or put pool * @return cLevel64x64 64x64 fixed point representation of C-Level */ function getDecayAdjustedCLevel64x64(Layout storage l, bool isCall) internal view returns (int128 cLevel64x64) { // get raw C-Level from storage cLevel64x64 = l.getRawCLevel64x64(isCall); // account for C-Level decay cLevel64x64 = l.applyCLevelDecayAdjustment(cLevel64x64, isCall); } /** * @notice calculate updated C-Level, accounting for unrealized decay * @param l storage layout struct * @param oldCLevel64x64 64x64 fixed point representation pool C-Level before accounting for decay * @param isCall whether query is for call or put pool * @return cLevel64x64 64x64 fixed point representation of C-Level of Pool after accounting for decay */ function applyCLevelDecayAdjustment( Layout storage l, int128 oldCLevel64x64, bool isCall ) internal view returns (int128 cLevel64x64) { uint256 timeElapsed = block.timestamp - (isCall ? l.cLevelUnderlyingUpdatedAt : l.cLevelBaseUpdatedAt); // do not apply C decay if less than 24 hours have elapsed if (timeElapsed > C_DECAY_BUFFER) { timeElapsed -= C_DECAY_BUFFER; } else { return oldCLevel64x64; } int128 timeIntervalsElapsed64x64 = ABDKMath64x64.divu( timeElapsed, C_DECAY_INTERVAL ); uint256 tokenId = formatTokenId( isCall ? TokenType.UNDERLYING_FREE_LIQ : TokenType.BASE_FREE_LIQ, 0, 0 ); uint256 tvl = l.totalTVL[isCall]; int128 utilization = ABDKMath64x64.divu( tvl - (ERC1155EnumerableStorage.layout().totalSupply[tokenId] - l.nextDeposits[isCall].totalPendingDeposits), tvl ); return OptionMath.calculateCLevelDecay( OptionMath.CalculateCLevelDecayArgs( timeIntervalsElapsed64x64, oldCLevel64x64, utilization, 0xb333333333333333, // 0.7 0xe666666666666666, // 0.9 0x10000000000000000, // 1.0 0x10000000000000000, // 1.0 0xe666666666666666, // 0.9 0x56fc2a2c515da32ea // 2e ) ); } /** * @notice calculate updated C-Level, accounting for pending deposits * @param l storage layout struct * @param oldCLevel64x64 64x64 fixed point representation pool C-Level before accounting for liquidity change * @param oldLiquidity64x64 64x64 fixed point representation of previous liquidity * @param isCall whether to update C-Level for call or put pool * @return cLevel64x64 64x64 fixed point representation of C-Level * @return liquidity64x64 64x64 fixed point representation of new liquidity amount */ function applyCLevelPendingDepositAdjustment( Layout storage l, int128 oldCLevel64x64, int128 oldLiquidity64x64, bool isCall ) internal view returns (int128 cLevel64x64, int128 liquidity64x64) { PoolStorage.BatchData storage batchData = l.nextDeposits[isCall]; int128 pendingDeposits64x64; if ( batchData.totalPendingDeposits > 0 && batchData.eta != 0 && block.timestamp >= batchData.eta ) { pendingDeposits64x64 = ABDKMath64x64Token.fromDecimals( batchData.totalPendingDeposits, l.getTokenDecimals(isCall) ); liquidity64x64 = oldLiquidity64x64.add(pendingDeposits64x64); cLevel64x64 = l.applyCLevelLiquidityChangeAdjustment( oldCLevel64x64, oldLiquidity64x64, liquidity64x64, isCall ); } else { cLevel64x64 = oldCLevel64x64; liquidity64x64 = oldLiquidity64x64; } } /** * @notice calculate updated C-Level, accounting for change in liquidity * @param l storage layout struct * @param oldCLevel64x64 64x64 fixed point representation pool C-Level before accounting for liquidity change * @param oldLiquidity64x64 64x64 fixed point representation of previous liquidity * @param newLiquidity64x64 64x64 fixed point representation of current liquidity * @param isCallPool whether to update C-Level for call or put pool * @return cLevel64x64 64x64 fixed point representation of C-Level */ function applyCLevelLiquidityChangeAdjustment( Layout storage l, int128 oldCLevel64x64, int128 oldLiquidity64x64, int128 newLiquidity64x64, bool isCallPool ) internal view returns (int128 cLevel64x64) { int128 steepness64x64 = isCallPool ? l.steepnessUnderlying64x64 : l.steepnessBase64x64; // fallback to deprecated storage value if side-specific value is not set if (steepness64x64 == 0) steepness64x64 = l._deprecated_steepness64x64; cLevel64x64 = OptionMath.calculateCLevel( oldCLevel64x64, oldLiquidity64x64, newLiquidity64x64, steepness64x64 ); if (cLevel64x64 < 0xb333333333333333) { cLevel64x64 = int128(0xb333333333333333); // 64x64 fixed point representation of 0.7 } } /** * @notice set C-Level to arbitrary pre-calculated value * @param cLevel64x64 new C-Level of pool * @param isCallPool whether to update C-Level for call or put pool */ function setCLevel( Layout storage l, int128 cLevel64x64, bool isCallPool ) internal { if (isCallPool) { l.cLevelUnderlying64x64 = cLevel64x64; l.cLevelUnderlyingUpdatedAt = block.timestamp; } else { l.cLevelBase64x64 = cLevel64x64; l.cLevelBaseUpdatedAt = block.timestamp; } } function setOracles( Layout storage l, address baseOracle, address underlyingOracle ) internal { require( AggregatorV3Interface(baseOracle).decimals() == AggregatorV3Interface(underlyingOracle).decimals(), "Pool: oracle decimals must match" ); l.baseOracle = baseOracle; l.underlyingOracle = underlyingOracle; } function fetchPriceUpdate(Layout storage l) internal view returns (int128 price64x64) { int256 priceUnderlying = AggregatorInterface(l.underlyingOracle) .latestAnswer(); int256 priceBase = AggregatorInterface(l.baseOracle).latestAnswer(); return ABDKMath64x64.divi(priceUnderlying, priceBase); } /** * @notice set price update for hourly bucket corresponding to given timestamp * @param l storage layout struct * @param timestamp timestamp to update * @param price64x64 64x64 fixed point representation of price */ function setPriceUpdate( Layout storage l, uint256 timestamp, int128 price64x64 ) internal { uint256 bucket = timestamp / (1 hours); l.bucketPrices64x64[bucket] = price64x64; l.priceUpdateSequences[bucket >> 8] += 1 << (255 - (bucket & 255)); } /** * @notice get price update for hourly bucket corresponding to given timestamp * @param l storage layout struct * @param timestamp timestamp to query * @return 64x64 fixed point representation of price */ function getPriceUpdate(Layout storage l, uint256 timestamp) internal view returns (int128) { return l.bucketPrices64x64[timestamp / (1 hours)]; } /** * @notice get first price update available following given timestamp * @param l storage layout struct * @param timestamp timestamp to query * @return 64x64 fixed point representation of price */ function getPriceUpdateAfter(Layout storage l, uint256 timestamp) internal view returns (int128) { // price updates are grouped into hourly buckets uint256 bucket = timestamp / (1 hours); // divide by 256 to get the index of the relevant price update sequence uint256 sequenceId = bucket >> 8; // get position within sequence relevant to current price update uint256 offset = bucket & 255; // shift to skip buckets from earlier in sequence uint256 sequence = (l.priceUpdateSequences[sequenceId] << offset) >> offset; // iterate through future sequences until a price update is found // sequence corresponding to current timestamp used as upper bound uint256 currentPriceUpdateSequenceId = block.timestamp / (256 hours); while (sequence == 0 && sequenceId <= currentPriceUpdateSequenceId) { sequence = l.priceUpdateSequences[++sequenceId]; } // if no price update is found (sequence == 0) function will return 0 // this should never occur, as each relevant external function triggers a price update // the most significant bit of the sequence corresponds to the offset of the relevant bucket uint256 msb; for (uint256 i = 128; i > 0; i >>= 1) { if (sequence >> i > 0) { msb += i; sequence >>= i; } } return l.bucketPrices64x64[((sequenceId + 1) << 8) - msb - 1]; } function fromBaseToUnderlyingDecimals(Layout storage l, uint256 value) internal view returns (uint256) { int128 valueFixed64x64 = ABDKMath64x64Token.fromDecimals( value, l.baseDecimals ); return ABDKMath64x64Token.toDecimals( valueFixed64x64, l.underlyingDecimals ); } function fromUnderlyingToBaseDecimals(Layout storage l, uint256 value) internal view returns (uint256) { int128 valueFixed64x64 = ABDKMath64x64Token.fromDecimals( value, l.underlyingDecimals ); return ABDKMath64x64Token.toDecimals(valueFixed64x64, l.baseDecimals); } }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.8.0; import {PremiaMiningStorage} from "./PremiaMiningStorage.sol"; interface IPremiaMining { function addPremiaRewards(uint256 _amount) external; function premiaRewardsAvailable() external view returns (uint256); function getTotalAllocationPoints() external view returns (uint256); function getPoolInfo(address pool, bool isCallPool) external view returns (PremiaMiningStorage.PoolInfo memory); function getPremiaPerYear() external view returns (uint256); function addPool(address _pool, uint256 _allocPoints) external; function setPoolAllocPoints( address[] memory _pools, uint256[] memory _allocPoints ) external; function pendingPremia( address _pool, bool _isCallPool, address _user ) external view returns (uint256); function updatePool( address _pool, bool _isCallPool, uint256 _totalTVL ) external; function allocatePending( address _user, address _pool, bool _isCallPool, uint256 _userTVLOld, uint256 _userTVLNew, uint256 _totalTVL ) external; function claim( address _user, address _pool, bool _isCallPool, uint256 _userTVLOld, uint256 _userTVLNew, uint256 _totalTVL ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC20 } from '../token/ERC20/IERC20.sol'; import { IERC20Metadata } from '../token/ERC20/metadata/IERC20Metadata.sol'; /** * @title WETH (Wrapped ETH) interface */ interface IWETH is IERC20, IERC20Metadata { /** * @notice convert ETH to WETH */ function deposit() external payable; /** * @notice convert WETH to ETH * @dev if caller is a contract, it should have a fallback or receive function * @param amount quantity of WETH to convert, denominated in wei */ function withdraw(uint256 amount) external; }
pragma solidity >=0.5.0; interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; function skim(address to) external; function sync() external; function initialize(address, address) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC20 } from '../token/ERC20/IERC20.sol'; import { AddressUtils } from './AddressUtils.sol'; /** * @title Safe ERC20 interaction library * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts/ (MIT license) */ library SafeERC20 { using AddressUtils for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn( token, abi.encodeWithSelector(token.transfer.selector, to, value) ); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn( token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value) ); } /** * @dev safeApprove (like approve) should only be called when setting an initial allowance or when resetting it to zero; otherwise prefer safeIncreaseAllowance and safeDecreaseAllowance */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { require( (value == 0) || (token.allowance(address(this), spender) == 0), 'SafeERC20: approve from non-zero to non-zero allowance' ); _callOptionalReturn( token, abi.encodeWithSelector(token.approve.selector, spender, value) ); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn( token, abi.encodeWithSelector( token.approve.selector, spender, newAllowance ) ); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require( oldAllowance >= value, 'SafeERC20: decreased allowance below zero' ); uint256 newAllowance = oldAllowance - value; _callOptionalReturn( token, abi.encodeWithSelector( token.approve.selector, spender, newAllowance ) ); } } /** * @notice send transaction data and check validity of return value, if present * @param token ERC20 token interface * @param data transaction data */ function _callOptionalReturn(IERC20 token, bytes memory data) private { bytes memory returndata = address(token).functionCall( data, 'SafeERC20: low-level call failed' ); if (returndata.length > 0) { require( abi.decode(returndata, (bool)), 'SafeERC20: ERC20 operation did not succeed' ); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC20Internal } from './IERC20Internal.sol'; /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ interface IERC20 is IERC20Internal { /** * @notice query the total minted token supply * @return token supply */ function totalSupply() external view returns (uint256); /** * @notice query the token balance of given account * @param account address to query * @return token balance */ function balanceOf(address account) external view returns (uint256); /** * @notice query the allowance granted from given holder to given spender * @param holder approver of allowance * @param spender recipient of allowance * @return token allowance */ function allowance(address holder, address spender) external view returns (uint256); /** * @notice grant approval to spender to spend tokens * @dev prefer ERC20Extended functions to avoid transaction-ordering vulnerability (see https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729) * @param spender recipient of allowance * @param amount quantity of tokens approved for spending * @return success status (always true; otherwise function should revert) */ function approve(address spender, uint256 amount) external returns (bool); /** * @notice transfer tokens to given recipient * @param recipient beneficiary of token transfer * @param amount quantity of tokens to transfer * @return success status (always true; otherwise function should revert) */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @notice transfer tokens to given recipient on behalf of given holder * @param holder holder of tokens prior to transfer * @param recipient beneficiary of token transfer * @param amount quantity of tokens to transfer * @return success status (always true; otherwise function should revert) */ function transferFrom( address holder, address recipient, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: BUSL-1.1 // For further clarification please see https://license.premia.legal pragma solidity ^0.8.0; import {IERC173} from "@solidstate/contracts/access/IERC173.sol"; import {OwnableStorage} from "@solidstate/contracts/access/OwnableStorage.sol"; import {IERC20} from "@solidstate/contracts/token/ERC20/IERC20.sol"; import {ERC1155EnumerableInternal, ERC1155EnumerableStorage, EnumerableSet} from "@solidstate/contracts/token/ERC1155/enumerable/ERC1155Enumerable.sol"; import {IWETH} from "@solidstate/contracts/utils/IWETH.sol"; import {PoolStorage} from "./PoolStorage.sol"; import {ABDKMath64x64} from "abdk-libraries-solidity/ABDKMath64x64.sol"; import {ABDKMath64x64Token} from "../libraries/ABDKMath64x64Token.sol"; import {OptionMath} from "../libraries/OptionMath.sol"; import {IFeeDiscount} from "../staking/IFeeDiscount.sol"; import {IPoolEvents} from "./IPoolEvents.sol"; import {IPremiaMining} from "../mining/IPremiaMining.sol"; import {IVolatilitySurfaceOracle} from "../oracle/IVolatilitySurfaceOracle.sol"; /** * @title Premia option pool * @dev deployed standalone and referenced by PoolProxy */ contract PoolInternal is IPoolEvents, ERC1155EnumerableInternal { using ABDKMath64x64 for int128; using EnumerableSet for EnumerableSet.AddressSet; using EnumerableSet for EnumerableSet.UintSet; using PoolStorage for PoolStorage.Layout; address internal immutable WETH_ADDRESS; address internal immutable PREMIA_MINING_ADDRESS; address internal immutable FEE_RECEIVER_ADDRESS; address internal immutable FEE_DISCOUNT_ADDRESS; address internal immutable IVOL_ORACLE_ADDRESS; int128 internal immutable FEE_64x64; uint256 internal immutable UNDERLYING_FREE_LIQ_TOKEN_ID; uint256 internal immutable BASE_FREE_LIQ_TOKEN_ID; uint256 internal immutable UNDERLYING_RESERVED_LIQ_TOKEN_ID; uint256 internal immutable BASE_RESERVED_LIQ_TOKEN_ID; uint256 internal constant INVERSE_BASIS_POINT = 1e4; uint256 internal constant BATCHING_PERIOD = 260; // Minimum APY for capital locked up to underwrite options. // The quote will return a minimum price corresponding to this APY int128 internal constant MIN_APY_64x64 = 0x4ccccccccccccccd; // 0.3 constructor( address ivolOracle, address weth, address premiaMining, address feeReceiver, address feeDiscountAddress, int128 fee64x64 ) { IVOL_ORACLE_ADDRESS = ivolOracle; WETH_ADDRESS = weth; PREMIA_MINING_ADDRESS = premiaMining; FEE_RECEIVER_ADDRESS = feeReceiver; // PremiaFeeDiscount contract address FEE_DISCOUNT_ADDRESS = feeDiscountAddress; FEE_64x64 = fee64x64; UNDERLYING_FREE_LIQ_TOKEN_ID = PoolStorage.formatTokenId( PoolStorage.TokenType.UNDERLYING_FREE_LIQ, 0, 0 ); BASE_FREE_LIQ_TOKEN_ID = PoolStorage.formatTokenId( PoolStorage.TokenType.BASE_FREE_LIQ, 0, 0 ); UNDERLYING_RESERVED_LIQ_TOKEN_ID = PoolStorage.formatTokenId( PoolStorage.TokenType.UNDERLYING_RESERVED_LIQ, 0, 0 ); BASE_RESERVED_LIQ_TOKEN_ID = PoolStorage.formatTokenId( PoolStorage.TokenType.BASE_RESERVED_LIQ, 0, 0 ); } modifier onlyProtocolOwner() { require( msg.sender == IERC173(OwnableStorage.layout().owner).owner(), "Not protocol owner" ); _; } function _getFeeDiscount(address feePayer) internal view returns (uint256 discount) { if (FEE_DISCOUNT_ADDRESS != address(0)) { discount = IFeeDiscount(FEE_DISCOUNT_ADDRESS).getDiscount(feePayer); } } function _getFeeWithDiscount(address feePayer, uint256 fee) internal view returns (uint256) { uint256 discount = _getFeeDiscount(feePayer); return fee - ((fee * discount) / INVERSE_BASIS_POINT); } function _withdrawFees(bool isCall) internal returns (uint256 amount) { uint256 tokenId = _getReservedLiquidityTokenId(isCall); amount = _balanceOf(FEE_RECEIVER_ADDRESS, tokenId); if (amount > 0) { _burn(FEE_RECEIVER_ADDRESS, tokenId, amount); emit FeeWithdrawal(isCall, amount); } } /** * @notice calculate price of option contract * @param args structured quote arguments * @return result quote result */ function _quote(PoolStorage.QuoteArgsInternal memory args) internal view returns (PoolStorage.QuoteResultInternal memory result) { require( args.strike64x64 > 0 && args.spot64x64 > 0 && args.maturity > 0, "invalid args" ); PoolStorage.Layout storage l = PoolStorage.layout(); int128 contractSize64x64 = ABDKMath64x64Token.fromDecimals( args.contractSize, l.underlyingDecimals ); bool isCall = args.isCall; (int128 adjustedCLevel64x64, int128 oldLiquidity64x64) = l .applyCLevelPendingDepositAdjustment( l.getDecayAdjustedCLevel64x64(isCall), l.totalFreeLiquiditySupply64x64(isCall), isCall ); require(oldLiquidity64x64 > 0, "no liq"); int128 timeToMaturity64x64 = ABDKMath64x64.divu( args.maturity - block.timestamp, 365 days ); int128 annualizedVolatility64x64 = IVolatilitySurfaceOracle( IVOL_ORACLE_ADDRESS ).getAnnualizedVolatility64x64( l.base, l.underlying, args.spot64x64, args.strike64x64, timeToMaturity64x64, isCall ); require(annualizedVolatility64x64 > 0, "vol = 0"); ( int128 price64x64, int128 cLevel64x64, int128 slippageCoefficient64x64 ) = OptionMath.quotePrice( OptionMath.QuoteArgs( annualizedVolatility64x64.mul(annualizedVolatility64x64), args.strike64x64, args.spot64x64, timeToMaturity64x64, adjustedCLevel64x64, oldLiquidity64x64, oldLiquidity64x64.sub(contractSize64x64), 0x10000000000000000, // 64x64 fixed point representation of 1 MIN_APY_64x64, isCall ) ); result.baseCost64x64 = isCall ? price64x64.mul(contractSize64x64).div(args.spot64x64) : price64x64.mul(contractSize64x64); result.feeCost64x64 = result.baseCost64x64.mul(FEE_64x64); result.cLevel64x64 = cLevel64x64; result.slippageCoefficient64x64 = slippageCoefficient64x64; int128 discount = ABDKMath64x64.divu( _getFeeDiscount(args.feePayer), INVERSE_BASIS_POINT ); result.feeCost64x64 -= result.feeCost64x64.mul(discount); } /** * @notice burn corresponding long and short option tokens * @param account holder of tokens to annihilate * @param maturity timestamp of option maturity * @param strike64x64 64x64 fixed point representation of strike price * @param isCall true for call, false for put * @param contractSize quantity of option contract tokens to annihilate */ function _annihilate( address account, uint64 maturity, int128 strike64x64, bool isCall, uint256 contractSize ) internal { uint256 longTokenId = PoolStorage.formatTokenId( _getTokenType(isCall, true), maturity, strike64x64 ); uint256 shortTokenId = PoolStorage.formatTokenId( _getTokenType(isCall, false), maturity, strike64x64 ); _burn(account, longTokenId, contractSize); _burn(account, shortTokenId, contractSize); emit Annihilate(shortTokenId, contractSize); } /** * @notice purchase call option * @param l storage layout struct * @param account recipient of purchased option * @param maturity timestamp of option maturity * @param strike64x64 64x64 fixed point representation of strike price * @param isCall true for call, false for put * @param contractSize size of option contract * @param newPrice64x64 64x64 fixed point representation of current spot price * @return baseCost quantity of tokens required to purchase long position * @return feeCost quantity of tokens required to pay fees */ function _purchase( PoolStorage.Layout storage l, address account, uint64 maturity, int128 strike64x64, bool isCall, uint256 contractSize, int128 newPrice64x64 ) internal returns (uint256 baseCost, uint256 feeCost) { require(maturity > block.timestamp, "expired"); require(contractSize >= l.underlyingMinimum, "too small"); { uint256 size = isCall ? contractSize : l.fromUnderlyingToBaseDecimals( strike64x64.mulu(contractSize) ); require( size <= ERC1155EnumerableStorage.layout().totalSupply[ _getFreeLiquidityTokenId(isCall) ] - l.nextDeposits[isCall].totalPendingDeposits, "insuf liq" ); } PoolStorage.QuoteResultInternal memory quote = _quote( PoolStorage.QuoteArgsInternal( account, maturity, strike64x64, newPrice64x64, contractSize, isCall ) ); baseCost = ABDKMath64x64Token.toDecimals( quote.baseCost64x64, l.getTokenDecimals(isCall) ); feeCost = ABDKMath64x64Token.toDecimals( quote.feeCost64x64, l.getTokenDecimals(isCall) ); uint256 longTokenId = PoolStorage.formatTokenId( _getTokenType(isCall, true), maturity, strike64x64 ); uint256 shortTokenId = PoolStorage.formatTokenId( _getTokenType(isCall, false), maturity, strike64x64 ); // mint long option token for buyer _mint(account, longTokenId, contractSize); int128 oldLiquidity64x64 = l.totalFreeLiquiditySupply64x64(isCall); // burn free liquidity tokens from other underwriters _mintShortTokenLoop( l, account, contractSize, baseCost, shortTokenId, isCall ); int128 newLiquidity64x64 = l.totalFreeLiquiditySupply64x64(isCall); _setCLevel(l, oldLiquidity64x64, newLiquidity64x64, isCall); // mint reserved liquidity tokens for fee receiver _mint( FEE_RECEIVER_ADDRESS, _getReservedLiquidityTokenId(isCall), feeCost ); emit Purchase( account, longTokenId, contractSize, baseCost, feeCost, newPrice64x64 ); } /** * @notice reassign short position to new underwriter * @param l storage layout struct * @param account holder of positions to be reassigned * @param maturity timestamp of option maturity * @param strike64x64 64x64 fixed point representation of strike price * @param isCall true for call, false for put * @param contractSize quantity of option contract tokens to reassign * @param newPrice64x64 64x64 fixed point representation of current spot price * @return baseCost quantity of tokens required to reassign short position * @return feeCost quantity of tokens required to pay fees * @return amountOut quantity of liquidity freed */ function _reassign( PoolStorage.Layout storage l, address account, uint64 maturity, int128 strike64x64, bool isCall, uint256 contractSize, int128 newPrice64x64 ) internal returns ( uint256 baseCost, uint256 feeCost, uint256 amountOut ) { (baseCost, feeCost) = _purchase( l, account, maturity, strike64x64, isCall, contractSize, newPrice64x64 ); _annihilate(account, maturity, strike64x64, isCall, contractSize); uint256 annihilateAmount = isCall ? contractSize : l.fromUnderlyingToBaseDecimals(strike64x64.mulu(contractSize)); amountOut = annihilateAmount - baseCost - feeCost; } /** * @notice exercise call option on behalf of holder * @dev used for processing of expired options if passed holder is zero address * @param holder owner of long option tokens to exercise * @param longTokenId long option token id * @param contractSize quantity of tokens to exercise */ function _exercise( address holder, uint256 longTokenId, uint256 contractSize ) internal { uint64 maturity; int128 strike64x64; bool isCall; bool onlyExpired = holder == address(0); { PoolStorage.TokenType tokenType; (tokenType, maturity, strike64x64) = PoolStorage.parseTokenId( longTokenId ); require( tokenType == PoolStorage.TokenType.LONG_CALL || tokenType == PoolStorage.TokenType.LONG_PUT, "invalid type" ); require(!onlyExpired || maturity < block.timestamp, "not expired"); isCall = tokenType == PoolStorage.TokenType.LONG_CALL; } PoolStorage.Layout storage l = PoolStorage.layout(); int128 spot64x64 = _update(l); if (maturity < block.timestamp) { spot64x64 = l.getPriceUpdateAfter(maturity); } require( onlyExpired || ( isCall ? (spot64x64 > strike64x64) : (spot64x64 < strike64x64) ), "not ITM" ); uint256 exerciseValue; // option has a non-zero exercise value if (isCall) { if (spot64x64 > strike64x64) { exerciseValue = spot64x64.sub(strike64x64).div(spot64x64).mulu( contractSize ); } } else { if (spot64x64 < strike64x64) { exerciseValue = l.fromUnderlyingToBaseDecimals( strike64x64.sub(spot64x64).mulu(contractSize) ); } } uint256 totalFee; if (onlyExpired) { totalFee += _burnLongTokenLoop( contractSize, exerciseValue, longTokenId, isCall ); } else { // burn long option tokens from sender _burn(holder, longTokenId, contractSize); if (exerciseValue > 0) { uint256 fee = _getFeeWithDiscount( holder, FEE_64x64.mulu(exerciseValue) ); totalFee += fee; _pushTo(holder, _getPoolToken(isCall), exerciseValue - fee); emit Exercise( holder, longTokenId, contractSize, exerciseValue, fee ); } } totalFee += _burnShortTokenLoop( contractSize, exerciseValue, PoolStorage.formatTokenId( _getTokenType(isCall, false), maturity, strike64x64 ), isCall ); _mint( FEE_RECEIVER_ADDRESS, _getReservedLiquidityTokenId(isCall), totalFee ); } function _mintShortTokenLoop( PoolStorage.Layout storage l, address buyer, uint256 contractSize, uint256 premium, uint256 shortTokenId, bool isCall ) internal { uint256 freeLiqTokenId = _getFreeLiquidityTokenId(isCall); (, , int128 strike64x64) = PoolStorage.parseTokenId(shortTokenId); uint256 toPay = isCall ? contractSize : l.fromUnderlyingToBaseDecimals(strike64x64.mulu(contractSize)); while (toPay > 0) { address underwriter = l.liquidityQueueAscending[isCall][address(0)]; uint256 balance = _balanceOf(underwriter, freeLiqTokenId); // If dust left, we remove underwriter and skip to next if (balance < _getMinimumAmount(l, isCall)) { l.removeUnderwriter(underwriter, isCall); continue; } if (!l.getReinvestmentStatus(underwriter, isCall)) { _burn(underwriter, freeLiqTokenId, balance); _mint( underwriter, _getReservedLiquidityTokenId(isCall), balance ); _subUserTVL(l, underwriter, isCall, balance); continue; } // amount of liquidity provided by underwriter, accounting for reinvested premium uint256 intervalContractSize = ((balance - l.pendingDeposits[underwriter][l.nextDeposits[isCall].eta][ isCall ]) * (toPay + premium)) / toPay; if (intervalContractSize == 0) continue; if (intervalContractSize > toPay) intervalContractSize = toPay; // amount of premium paid to underwriter uint256 intervalPremium = (premium * intervalContractSize) / toPay; premium -= intervalPremium; toPay -= intervalContractSize; _addUserTVL(l, underwriter, isCall, intervalPremium); // burn free liquidity tokens from underwriter _burn( underwriter, freeLiqTokenId, intervalContractSize - intervalPremium ); if (isCall == false) { // For PUT, conversion to contract amount is done here (Prior to this line, it is token amount) intervalContractSize = l.fromBaseToUnderlyingDecimals( strike64x64.inv().mulu(intervalContractSize) ); } // mint short option tokens for underwriter // toPay == 0 ? contractSize : intervalContractSize : To prevent minting less than amount, // because of rounding (Can happen for put, because of fixed point precision) _mint( underwriter, shortTokenId, toPay == 0 ? contractSize : intervalContractSize ); emit Underwrite( underwriter, buyer, shortTokenId, toPay == 0 ? contractSize : intervalContractSize, intervalPremium, false ); contractSize -= intervalContractSize; } } function _burnLongTokenLoop( uint256 contractSize, uint256 exerciseValue, uint256 longTokenId, bool isCall ) internal returns (uint256 totalFee) { EnumerableSet.AddressSet storage holders = ERC1155EnumerableStorage .layout() .accountsByToken[longTokenId]; while (contractSize > 0) { address longTokenHolder = holders.at(holders.length() - 1); uint256 intervalContractSize = _balanceOf( longTokenHolder, longTokenId ); if (intervalContractSize > contractSize) intervalContractSize = contractSize; uint256 intervalExerciseValue; uint256 fee; if (exerciseValue > 0) { intervalExerciseValue = (exerciseValue * intervalContractSize) / contractSize; fee = _getFeeWithDiscount( longTokenHolder, FEE_64x64.mulu(intervalExerciseValue) ); totalFee += fee; exerciseValue -= intervalExerciseValue; _pushTo( longTokenHolder, _getPoolToken(isCall), intervalExerciseValue - fee ); } contractSize -= intervalContractSize; emit Exercise( longTokenHolder, longTokenId, intervalContractSize, intervalExerciseValue - fee, fee ); _burn(longTokenHolder, longTokenId, intervalContractSize); } } function _burnShortTokenLoop( uint256 contractSize, uint256 exerciseValue, uint256 shortTokenId, bool isCall ) internal returns (uint256 totalFee) { EnumerableSet.AddressSet storage underwriters = ERC1155EnumerableStorage .layout() .accountsByToken[shortTokenId]; (, , int128 strike64x64) = PoolStorage.parseTokenId(shortTokenId); while (contractSize > 0) { address underwriter = underwriters.at(underwriters.length() - 1); // amount of liquidity provided by underwriter uint256 intervalContractSize = _balanceOf( underwriter, shortTokenId ); if (intervalContractSize > contractSize) intervalContractSize = contractSize; // amount of value claimed by buyer uint256 intervalExerciseValue = (exerciseValue * intervalContractSize) / contractSize; exerciseValue -= intervalExerciseValue; contractSize -= intervalContractSize; uint256 freeLiq = isCall ? intervalContractSize - intervalExerciseValue : PoolStorage.layout().fromUnderlyingToBaseDecimals( strike64x64.mulu(intervalContractSize) ) - intervalExerciseValue; uint256 fee = _getFeeWithDiscount( underwriter, FEE_64x64.mulu(freeLiq) ); totalFee += fee; uint256 tvlToSubtract = intervalExerciseValue; // mint free liquidity tokens for underwriter if ( PoolStorage.layout().getReinvestmentStatus(underwriter, isCall) ) { _addToDepositQueue(underwriter, freeLiq - fee, isCall); tvlToSubtract += fee; } else { _mint( underwriter, _getReservedLiquidityTokenId(isCall), freeLiq - fee ); tvlToSubtract += freeLiq; } _subUserTVL( PoolStorage.layout(), underwriter, isCall, tvlToSubtract ); // burn short option tokens from underwriter _burn(underwriter, shortTokenId, intervalContractSize); emit AssignExercise( underwriter, shortTokenId, freeLiq - fee, intervalContractSize, fee ); } } function _addToDepositQueue( address account, uint256 amount, bool isCallPool ) internal { PoolStorage.Layout storage l = PoolStorage.layout(); _mint(account, _getFreeLiquidityTokenId(isCallPool), amount); uint256 nextBatch = (block.timestamp / BATCHING_PERIOD) * BATCHING_PERIOD + BATCHING_PERIOD; l.pendingDeposits[account][nextBatch][isCallPool] += amount; PoolStorage.BatchData storage batchData = l.nextDeposits[isCallPool]; batchData.totalPendingDeposits += amount; batchData.eta = nextBatch; } function _processPendingDeposits(PoolStorage.Layout storage l, bool isCall) internal { PoolStorage.BatchData storage data = l.nextDeposits[isCall]; if (data.eta == 0 || block.timestamp < data.eta) return; int128 oldLiquidity64x64 = l.totalFreeLiquiditySupply64x64(isCall); _setCLevel( l, oldLiquidity64x64, oldLiquidity64x64.add( ABDKMath64x64Token.fromDecimals( data.totalPendingDeposits, l.getTokenDecimals(isCall) ) ), isCall ); delete l.nextDeposits[isCall]; } function _getFreeLiquidityTokenId(bool isCall) internal view returns (uint256 freeLiqTokenId) { freeLiqTokenId = isCall ? UNDERLYING_FREE_LIQ_TOKEN_ID : BASE_FREE_LIQ_TOKEN_ID; } function _getReservedLiquidityTokenId(bool isCall) internal view returns (uint256 reservedLiqTokenId) { reservedLiqTokenId = isCall ? UNDERLYING_RESERVED_LIQ_TOKEN_ID : BASE_RESERVED_LIQ_TOKEN_ID; } function _getPoolToken(bool isCall) internal view returns (address token) { token = isCall ? PoolStorage.layout().underlying : PoolStorage.layout().base; } function _getTokenType(bool isCall, bool isLong) internal pure returns (PoolStorage.TokenType tokenType) { if (isCall) { tokenType = isLong ? PoolStorage.TokenType.LONG_CALL : PoolStorage.TokenType.SHORT_CALL; } else { tokenType = isLong ? PoolStorage.TokenType.LONG_PUT : PoolStorage.TokenType.SHORT_PUT; } } function _getMinimumAmount(PoolStorage.Layout storage l, bool isCall) internal view returns (uint256 minimumAmount) { minimumAmount = isCall ? l.underlyingMinimum : l.baseMinimum; } function _getPoolCapAmount(PoolStorage.Layout storage l, bool isCall) internal view returns (uint256 poolCapAmount) { poolCapAmount = isCall ? l.underlyingPoolCap : l.basePoolCap; } function _setCLevel( PoolStorage.Layout storage l, int128 oldLiquidity64x64, int128 newLiquidity64x64, bool isCallPool ) internal { int128 oldCLevel64x64 = l.getDecayAdjustedCLevel64x64(isCallPool); int128 cLevel64x64 = l.applyCLevelLiquidityChangeAdjustment( oldCLevel64x64, oldLiquidity64x64, newLiquidity64x64, isCallPool ); l.setCLevel(cLevel64x64, isCallPool); emit UpdateCLevel( isCallPool, cLevel64x64, oldLiquidity64x64, newLiquidity64x64 ); } /** * @notice calculate and store updated market state * @param l storage layout struct * @return newPrice64x64 64x64 fixed point representation of current spot price */ function _update(PoolStorage.Layout storage l) internal returns (int128 newPrice64x64) { if (l.updatedAt == block.timestamp) { return (l.getPriceUpdate(block.timestamp)); } newPrice64x64 = l.fetchPriceUpdate(); if (l.getPriceUpdate(block.timestamp) == 0) { l.setPriceUpdate(block.timestamp, newPrice64x64); } l.updatedAt = block.timestamp; _processPendingDeposits(l, true); _processPendingDeposits(l, false); } /** * @notice transfer ERC20 tokens to message sender * @param token ERC20 token address * @param amount quantity of token to transfer */ function _pushTo( address to, address token, uint256 amount ) internal { if (amount == 0) return; require(IERC20(token).transfer(to, amount), "ERC20 transfer failed"); } /** * @notice transfer ERC20 tokens from message sender * @param from address from which tokens are pulled from * @param token ERC20 token address * @param amount quantity of token to transfer * @param skipWethDeposit if false, will not try to deposit weth from attach eth */ function _pullFrom( address from, address token, uint256 amount, bool skipWethDeposit ) internal { if (!skipWethDeposit) { if (token == WETH_ADDRESS) { if (msg.value > 0) { if (msg.value > amount) { IWETH(WETH_ADDRESS).deposit{value: amount}(); (bool success, ) = payable(msg.sender).call{ value: msg.value - amount }(""); require(success, "ETH refund failed"); amount = 0; } else { unchecked { amount -= msg.value; } IWETH(WETH_ADDRESS).deposit{value: msg.value}(); } } } else { require(msg.value == 0, "not WETH deposit"); } } if (amount > 0) { require( IERC20(token).transferFrom(from, address(this), amount), "ERC20 transfer failed" ); } } function _mint( address account, uint256 tokenId, uint256 amount ) internal { _mint(account, tokenId, amount, ""); } function _addUserTVL( PoolStorage.Layout storage l, address user, bool isCallPool, uint256 amount ) internal { uint256 userTVL = l.userTVL[user][isCallPool]; uint256 totalTVL = l.totalTVL[isCallPool]; IPremiaMining(PREMIA_MINING_ADDRESS).allocatePending( user, address(this), isCallPool, userTVL, userTVL + amount, totalTVL ); l.userTVL[user][isCallPool] = userTVL + amount; l.totalTVL[isCallPool] = totalTVL + amount; } function _subUserTVL( PoolStorage.Layout storage l, address user, bool isCallPool, uint256 amount ) internal { uint256 userTVL = l.userTVL[user][isCallPool]; uint256 totalTVL = l.totalTVL[isCallPool]; IPremiaMining(PREMIA_MINING_ADDRESS).allocatePending( user, address(this), isCallPool, userTVL, userTVL - amount, totalTVL ); l.userTVL[user][isCallPool] = userTVL - amount; l.totalTVL[isCallPool] = totalTVL - amount; } /** * @notice ERC1155 hook: track eligible underwriters * @param operator transaction sender * @param from token sender * @param to token receiver * @param ids token ids transferred * @param amounts token quantities transferred * @param data data payload */ function _beforeTokenTransfer( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual override { super._beforeTokenTransfer(operator, from, to, ids, amounts, data); PoolStorage.Layout storage l = PoolStorage.layout(); for (uint256 i; i < ids.length; i++) { uint256 id = ids[i]; uint256 amount = amounts[i]; if (amount == 0) continue; if (from == address(0)) { l.tokenIds.add(id); } if ( to == address(0) && ERC1155EnumerableStorage.layout().totalSupply[id] == 0 ) { l.tokenIds.remove(id); } // prevent transfer of free and reserved liquidity during waiting period if ( id == UNDERLYING_FREE_LIQ_TOKEN_ID || id == BASE_FREE_LIQ_TOKEN_ID || id == UNDERLYING_RESERVED_LIQ_TOKEN_ID || id == BASE_RESERVED_LIQ_TOKEN_ID ) { if (from != address(0) && to != address(0)) { bool isCallPool = id == UNDERLYING_FREE_LIQ_TOKEN_ID || id == UNDERLYING_RESERVED_LIQ_TOKEN_ID; require( l.depositedAt[from][isCallPool] + (1 days) < block.timestamp, "liq lock 1d" ); } } if ( id == UNDERLYING_FREE_LIQ_TOKEN_ID || id == BASE_FREE_LIQ_TOKEN_ID ) { bool isCallPool = id == UNDERLYING_FREE_LIQ_TOKEN_ID; uint256 minimum = _getMinimumAmount(l, isCallPool); if (from != address(0)) { uint256 balance = _balanceOf(from, id); if (balance > minimum && balance <= amount + minimum) { require( balance - l.pendingDeposits[from][ l.nextDeposits[isCallPool].eta ][isCallPool] >= amount, "Insuf balance" ); l.removeUnderwriter(from, isCallPool); } if (to != address(0)) { _subUserTVL(l, from, isCallPool, amounts[i]); _addUserTVL(l, to, isCallPool, amounts[i]); } } if (to != address(0)) { uint256 balance = _balanceOf(to, id); if (balance <= minimum && balance + amount > minimum) { l.addUnderwriter(to, isCallPool); } } } // Update userTVL on SHORT options transfers ( PoolStorage.TokenType tokenType, , int128 strike64x64 ) = PoolStorage.parseTokenId(id); if ( (from != address(0) && to != address(0)) && (tokenType == PoolStorage.TokenType.SHORT_CALL || tokenType == PoolStorage.TokenType.SHORT_PUT) ) { bool isCall = tokenType == PoolStorage.TokenType.SHORT_CALL; uint256 collateral = isCall ? amount : l.fromUnderlyingToBaseDecimals(strike64x64.mulu(amount)); _subUserTVL(l, from, isCall, collateral); _addUserTVL(l, to, isCall, collateral); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface AggregatorInterface { function latestAnswer() external view returns ( int256 ); function latestTimestamp() external view returns ( uint256 ); function latestRound() external view returns ( uint256 ); function getAnswer( uint256 roundId ) external view returns ( int256 ); function getTimestamp( uint256 roundId ) external view returns ( uint256 ); event AnswerUpdated( int256 indexed current, uint256 indexed roundId, uint256 updatedAt ); event NewRound( uint256 indexed roundId, address indexed startedBy, uint256 startedAt ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface AggregatorV3Interface { function decimals() external view returns ( uint8 ); function description() external view returns ( string memory ); function version() external view returns ( uint256 ); // getRoundData and latestRoundData should both raise "No data present" // if they do not have data to report, instead of returning unset values // which could be misinterpreted as actual reported values. function getRoundData( uint80 _roundId ) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { EnumerableSet } from '../../../utils/EnumerableSet.sol'; library ERC1155EnumerableStorage { struct Layout { mapping(uint256 => uint256) totalSupply; mapping(uint256 => EnumerableSet.AddressSet) accountsByToken; mapping(address => EnumerableSet.UintSet) tokensByAccount; } bytes32 internal constant STORAGE_SLOT = keccak256('solidstate.contracts.storage.ERC1155Enumerable'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: BUSL-1.1 // For further clarification please see https://license.premia.legal pragma solidity ^0.8.0; import {ABDKMath64x64} from "abdk-libraries-solidity/ABDKMath64x64.sol"; library ABDKMath64x64Token { using ABDKMath64x64 for int128; /** * @notice convert 64x64 fixed point representation of token amount to decimal * @param value64x64 64x64 fixed point representation of token amount * @param decimals token display decimals * @return value decimal representation of token amount */ function toDecimals(int128 value64x64, uint8 decimals) internal pure returns (uint256 value) { value = value64x64.mulu(10**decimals); } /** * @notice convert decimal representation of token amount to 64x64 fixed point * @param value decimal representation of token amount * @param decimals token display decimals * @return value64x64 64x64 fixed point representation of token amount */ function fromDecimals(uint256 value, uint8 decimals) internal pure returns (int128 value64x64) { value64x64 = ABDKMath64x64.divu(value, 10**decimals); } /** * @notice convert 64x64 fixed point representation of token amount to wei (18 decimals) * @param value64x64 64x64 fixed point representation of token amount * @return value wei representation of token amount */ function toWei(int128 value64x64) internal pure returns (uint256 value) { value = toDecimals(value64x64, 18); } /** * @notice convert wei representation (18 decimals) of token amount to 64x64 fixed point * @param value wei representation of token amount * @return value64x64 64x64 fixed point representation of token amount */ function fromWei(uint256 value) internal pure returns (int128 value64x64) { value64x64 = fromDecimals(value, 18); } }
// SPDX-License-Identifier: BUSL-1.1 // For further clarification please see https://license.premia.legal pragma solidity ^0.8.0; import {ABDKMath64x64} from "abdk-libraries-solidity/ABDKMath64x64.sol"; library OptionMath { using ABDKMath64x64 for int128; struct QuoteArgs { int128 varianceAnnualized64x64; // 64x64 fixed point representation of annualized variance int128 strike64x64; // 64x64 fixed point representation of strike price int128 spot64x64; // 64x64 fixed point representation of spot price int128 timeToMaturity64x64; // 64x64 fixed point representation of duration of option contract (in years) int128 oldCLevel64x64; // 64x64 fixed point representation of C-Level of Pool before purchase int128 oldPoolState; // 64x64 fixed point representation of current state of the pool int128 newPoolState; // 64x64 fixed point representation of state of the pool after trade int128 steepness64x64; // 64x64 fixed point representation of Pool state delta multiplier int128 minAPY64x64; // 64x64 fixed point representation of minimum APY for capital locked up to underwrite options bool isCall; // whether to price "call" or "put" option } struct CalculateCLevelDecayArgs { int128 timeIntervalsElapsed64x64; // 64x64 fixed point representation of quantity of discrete arbitrary intervals elapsed since last update int128 oldCLevel64x64; // 64x64 fixed point representation of C-Level prior to accounting for decay int128 utilization64x64; // 64x64 fixed point representation of pool capital utilization rate int128 utilizationLowerBound64x64; int128 utilizationUpperBound64x64; int128 cLevelLowerBound64x64; int128 cLevelUpperBound64x64; int128 cConvergenceULowerBound64x64; int128 cConvergenceUUpperBound64x64; } // 64x64 fixed point integer constants int128 internal constant ONE_64x64 = 0x10000000000000000; int128 internal constant THREE_64x64 = 0x30000000000000000; // 64x64 fixed point constants used in Choudhury’s approximation of the Black-Scholes CDF int128 private constant CDF_CONST_0 = 0x09109f285df452394; // 2260 / 3989 int128 private constant CDF_CONST_1 = 0x19abac0ea1da65036; // 6400 / 3989 int128 private constant CDF_CONST_2 = 0x0d3c84b78b749bd6b; // 3300 / 3989 /** * @notice recalculate C-Level based on change in liquidity * @param initialCLevel64x64 64x64 fixed point representation of C-Level of Pool before update * @param oldPoolState64x64 64x64 fixed point representation of liquidity in pool before update * @param newPoolState64x64 64x64 fixed point representation of liquidity in pool after update * @param steepness64x64 64x64 fixed point representation of steepness coefficient * @return 64x64 fixed point representation of new C-Level */ function calculateCLevel( int128 initialCLevel64x64, int128 oldPoolState64x64, int128 newPoolState64x64, int128 steepness64x64 ) external pure returns (int128) { return newPoolState64x64 .sub(oldPoolState64x64) .div( oldPoolState64x64 > newPoolState64x64 ? oldPoolState64x64 : newPoolState64x64 ) .mul(steepness64x64) .neg() .exp() .mul(initialCLevel64x64); } /** * @notice calculate the price of an option using the Premia Finance model * @param args arguments of quotePrice * @return premiaPrice64x64 64x64 fixed point representation of Premia option price * @return cLevel64x64 64x64 fixed point representation of C-Level of Pool after purchase */ function quotePrice(QuoteArgs memory args) external pure returns ( int128 premiaPrice64x64, int128 cLevel64x64, int128 slippageCoefficient64x64 ) { int128 deltaPoolState64x64 = args .newPoolState .sub(args.oldPoolState) .div(args.oldPoolState) .mul(args.steepness64x64); int128 tradingDelta64x64 = deltaPoolState64x64.neg().exp(); int128 blackScholesPrice64x64 = _blackScholesPrice( args.varianceAnnualized64x64, args.strike64x64, args.spot64x64, args.timeToMaturity64x64, args.isCall ); cLevel64x64 = tradingDelta64x64.mul(args.oldCLevel64x64); slippageCoefficient64x64 = ONE_64x64.sub(tradingDelta64x64).div( deltaPoolState64x64 ); premiaPrice64x64 = blackScholesPrice64x64.mul(cLevel64x64).mul( slippageCoefficient64x64 ); int128 intrinsicValue64x64; if (args.isCall && args.strike64x64 < args.spot64x64) { intrinsicValue64x64 = args.spot64x64.sub(args.strike64x64); } else if (!args.isCall && args.strike64x64 > args.spot64x64) { intrinsicValue64x64 = args.strike64x64.sub(args.spot64x64); } int128 collateralValue64x64 = args.isCall ? args.spot64x64 : args.strike64x64; int128 minPrice64x64 = intrinsicValue64x64.add( collateralValue64x64.mul(args.minAPY64x64).mul( args.timeToMaturity64x64 ) ); if (minPrice64x64 > premiaPrice64x64) { premiaPrice64x64 = minPrice64x64; } } /** * @notice calculate the decay of C-Level based on heat diffusion function * @param args structured CalculateCLevelDecayArgs * @return cLevelDecayed64x64 C-Level after accounting for decay */ function calculateCLevelDecay(CalculateCLevelDecayArgs memory args) external pure returns (int128 cLevelDecayed64x64) { int128 convFHighU64x64 = (args.utilization64x64 >= args.utilizationUpperBound64x64 && args.oldCLevel64x64 <= args.cLevelLowerBound64x64) ? ONE_64x64 : int128(0); int128 convFLowU64x64 = (args.utilization64x64 <= args.utilizationLowerBound64x64 && args.oldCLevel64x64 >= args.cLevelUpperBound64x64) ? ONE_64x64 : int128(0); cLevelDecayed64x64 = args .oldCLevel64x64 .sub(args.cConvergenceULowerBound64x64.mul(convFLowU64x64)) .sub(args.cConvergenceUUpperBound64x64.mul(convFHighU64x64)) .mul( convFLowU64x64 .mul(ONE_64x64.sub(args.utilization64x64)) .add(convFHighU64x64.mul(args.utilization64x64)) .mul(args.timeIntervalsElapsed64x64) .neg() .exp() ) .add( args.cConvergenceULowerBound64x64.mul(convFLowU64x64).add( args.cConvergenceUUpperBound64x64.mul(convFHighU64x64) ) ); } /** * @notice calculate the exponential decay coefficient for a given interval * @param oldTimestamp timestamp of previous update * @param newTimestamp current timestamp * @return 64x64 fixed point representation of exponential decay coefficient */ function _decay(uint256 oldTimestamp, uint256 newTimestamp) internal pure returns (int128) { return ONE_64x64.sub( (-ABDKMath64x64.divu(newTimestamp - oldTimestamp, 7 days)).exp() ); } /** * @notice calculate Choudhury’s approximation of the Black-Scholes CDF * @param input64x64 64x64 fixed point representation of random variable * @return 64x64 fixed point representation of the approximated CDF of x */ function _N(int128 input64x64) internal pure returns (int128) { // squaring via mul is cheaper than via pow int128 inputSquared64x64 = input64x64.mul(input64x64); int128 value64x64 = (-inputSquared64x64 >> 1).exp().div( CDF_CONST_0.add(CDF_CONST_1.mul(input64x64.abs())).add( CDF_CONST_2.mul(inputSquared64x64.add(THREE_64x64).sqrt()) ) ); return input64x64 > 0 ? ONE_64x64.sub(value64x64) : value64x64; } /** * @notice calculate the price of an option using the Black-Scholes model * @param varianceAnnualized64x64 64x64 fixed point representation of annualized variance * @param strike64x64 64x64 fixed point representation of strike price * @param spot64x64 64x64 fixed point representation of spot price * @param timeToMaturity64x64 64x64 fixed point representation of duration of option contract (in years) * @param isCall whether to price "call" or "put" option * @return 64x64 fixed point representation of Black-Scholes option price */ function _blackScholesPrice( int128 varianceAnnualized64x64, int128 strike64x64, int128 spot64x64, int128 timeToMaturity64x64, bool isCall ) internal pure returns (int128) { int128 cumulativeVariance64x64 = timeToMaturity64x64.mul( varianceAnnualized64x64 ); int128 cumulativeVarianceSqrt64x64 = cumulativeVariance64x64.sqrt(); int128 d1_64x64 = spot64x64 .div(strike64x64) .ln() .add(cumulativeVariance64x64 >> 1) .div(cumulativeVarianceSqrt64x64); int128 d2_64x64 = d1_64x64.sub(cumulativeVarianceSqrt64x64); if (isCall) { return spot64x64.mul(_N(d1_64x64)).sub(strike64x64.mul(_N(d2_64x64))); } else { return -spot64x64.mul(_N(-d1_64x64)).sub( strike64x64.mul(_N(-d2_64x64)) ); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title ERC20 metadata interface */ interface IERC20Metadata { /** * @notice return token name * @return token name */ function name() external view returns (string memory); /** * @notice return token symbol * @return token symbol */ function symbol() external view returns (string memory); /** * @notice return token decimals, generally used only for display purposes * @return token decimals */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title Partial ERC20 interface needed by internal functions */ interface IERC20Internal { event Transfer(address indexed from, address indexed to, uint256 value); event Approval( address indexed owner, address indexed spender, uint256 value ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library AddressUtils { function toString(address account) internal pure returns (string memory) { bytes32 value = bytes32(uint256(uint160(account))); bytes memory alphabet = '0123456789abcdef'; bytes memory chars = new bytes(42); chars[0] = '0'; chars[1] = 'x'; for (uint256 i = 0; i < 20; i++) { chars[2 + i * 2] = alphabet[uint8(value[i + 12] >> 4)]; chars[3 + i * 2] = alphabet[uint8(value[i + 12] & 0x0f)]; } return string(chars); } function isContract(address account) internal view returns (bool) { uint256 size; assembly { size := extcodesize(account) } return size > 0; } function sendValue(address payable account, uint256 amount) internal { (bool success, ) = account.call{ value: amount }(''); require(success, 'AddressUtils: failed to send value'); } function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, 'AddressUtils: failed low-level call'); } function functionCall( address target, bytes memory data, string memory error ) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, error); } function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue( target, data, value, 'AddressUtils: failed low-level call with value' ); } function functionCallWithValue( address target, bytes memory data, uint256 value, string memory error ) internal returns (bytes memory) { require( address(this).balance >= value, 'AddressUtils: insufficient balance for call' ); return _functionCallWithValue(target, data, value, error); } function _functionCallWithValue( address target, bytes memory data, uint256 value, string memory error ) private returns (bytes memory) { require( isContract(target), 'AddressUtils: function call to non-contract' ); (bool success, bytes memory returnData) = target.call{ value: value }( data ); if (success) { return returnData; } else if (returnData.length > 0) { assembly { let returnData_size := mload(returnData) revert(add(32, returnData), returnData_size) } } else { revert(error); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title Contract ownership standard interface * @dev see https://eips.ethereum.org/EIPS/eip-173 */ interface IERC173 { event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); /** * @notice get the ERC173 contract owner * @return conract owner */ function owner() external view returns (address); /** * @notice transfer contract ownership to new account * @param account address of new owner */ function transferOwnership(address account) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library OwnableStorage { struct Layout { address owner; } bytes32 internal constant STORAGE_SLOT = keccak256('solidstate.contracts.storage.Ownable'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } function setOwner(Layout storage l, address owner) internal { l.owner = owner; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { EnumerableSet } from '../../../utils/EnumerableSet.sol'; import { ERC1155Base, ERC1155BaseInternal } from '../base/ERC1155Base.sol'; import { IERC1155Enumerable } from './IERC1155Enumerable.sol'; import { ERC1155EnumerableInternal, ERC1155EnumerableStorage } from './ERC1155EnumerableInternal.sol'; /** * @title ERC1155 implementation including enumerable and aggregate functions */ abstract contract ERC1155Enumerable is IERC1155Enumerable, ERC1155Base, ERC1155EnumerableInternal { using EnumerableSet for EnumerableSet.AddressSet; using EnumerableSet for EnumerableSet.UintSet; /** * @inheritdoc IERC1155Enumerable */ function totalSupply(uint256 id) public view virtual override returns (uint256) { return ERC1155EnumerableStorage.layout().totalSupply[id]; } /** * @inheritdoc IERC1155Enumerable */ function totalHolders(uint256 id) public view virtual override returns (uint256) { return ERC1155EnumerableStorage.layout().accountsByToken[id].length(); } /** * @inheritdoc IERC1155Enumerable */ function accountsByToken(uint256 id) public view virtual override returns (address[] memory) { EnumerableSet.AddressSet storage accounts = ERC1155EnumerableStorage .layout() .accountsByToken[id]; address[] memory addresses = new address[](accounts.length()); for (uint256 i; i < accounts.length(); i++) { addresses[i] = accounts.at(i); } return addresses; } /** * @inheritdoc IERC1155Enumerable */ function tokensByAccount(address account) public view virtual override returns (uint256[] memory) { EnumerableSet.UintSet storage tokens = ERC1155EnumerableStorage .layout() .tokensByAccount[account]; uint256[] memory ids = new uint256[](tokens.length()); for (uint256 i; i < tokens.length(); i++) { ids[i] = tokens.at(i); } return ids; } /** * @notice ERC1155 hook: update aggregate values * @inheritdoc ERC1155EnumerableInternal */ function _beforeTokenTransfer( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual override(ERC1155BaseInternal, ERC1155EnumerableInternal) { super._beforeTokenTransfer(operator, from, to, ids, amounts, data); } }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.8.0; import {FeeDiscountStorage} from "./FeeDiscountStorage.sol"; interface IFeeDiscount { event Staked( address indexed user, uint256 amount, uint256 stakePeriod, uint256 lockedUntil ); event Unstaked(address indexed user, uint256 amount); struct StakeLevel { uint256 amount; // Amount to stake uint256 discount; // Discount when amount is reached } /** * @notice Stake using IERC2612 permit * @param amount The amount of xPremia to stake * @param period The lockup period (in seconds) * @param deadline Deadline after which permit will fail * @param v V * @param r R * @param s S */ function stakeWithPermit( uint256 amount, uint256 period, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @notice Lockup xPremia for protocol fee discounts * Longer period of locking will apply a multiplier on the amount staked, in the fee discount calculation * @param amount The amount of xPremia to stake * @param period The lockup period (in seconds) */ function stake(uint256 amount, uint256 period) external; /** * @notice Unstake xPremia (If lockup period has ended) * @param amount The amount of xPremia to unstake */ function unstake(uint256 amount) external; ////////// // View // ////////// /** * Calculate the stake amount of a user, after applying the bonus from the lockup period chosen * @param user The user from which to query the stake amount * @return The user stake amount after applying the bonus */ function getStakeAmountWithBonus(address user) external view returns (uint256); /** * @notice Calculate the % of fee discount for user, based on his stake * @param user The _user for which the discount is for * @return Percentage of protocol fee discount (in basis point) * Ex : 1000 = 10% fee discount */ function getDiscount(address user) external view returns (uint256); /** * @notice Get stake levels * @return Stake levels * Ex : 2500 = -25% */ function getStakeLevels() external returns (StakeLevel[] memory); /** * @notice Get stake period multiplier * @param period The duration (in seconds) for which tokens are locked * @return The multiplier for this staking period * Ex : 20000 = x2 */ function getStakePeriodMultiplier(uint256 period) external returns (uint256); /** * @notice Get staking infos of a user * @param user The user address for which to get staking infos * @return The staking infos of the user */ function getUserInfo(address user) external view returns (FeeDiscountStorage.UserInfo memory); }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.8.0; interface IPoolEvents { event Purchase( address indexed user, uint256 longTokenId, uint256 contractSize, uint256 baseCost, uint256 feeCost, int128 spot64x64 ); event Exercise( address indexed user, uint256 longTokenId, uint256 contractSize, uint256 exerciseValue, uint256 fee ); event Underwrite( address indexed underwriter, address indexed longReceiver, uint256 shortTokenId, uint256 intervalContractSize, uint256 intervalPremium, bool isManualUnderwrite ); event AssignExercise( address indexed underwriter, uint256 shortTokenId, uint256 freedAmount, uint256 intervalContractSize, uint256 fee ); event Deposit(address indexed user, bool isCallPool, uint256 amount); event Withdrawal( address indexed user, bool isCallPool, uint256 depositedAt, uint256 amount ); event FeeWithdrawal(bool indexed isCallPool, uint256 amount); event Annihilate(uint256 shortTokenId, uint256 amount); event UpdateCLevel( bool indexed isCall, int128 cLevel64x64, int128 oldLiquidity64x64, int128 newLiquidity64x64 ); event UpdateSteepness(int128 steepness64x64, bool isCallPool); }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.8.0; import {VolatilitySurfaceOracleStorage} from "./VolatilitySurfaceOracleStorage.sol"; interface IVolatilitySurfaceOracle { function getWhitelistedRelayers() external view returns (address[] memory); function getVolatilitySurface(address baseToken, address underlyingToken) external view returns (VolatilitySurfaceOracleStorage.Update memory); function getVolatilitySurfaceCoefficientsUnpacked( address baseToken, address underlyingToken, bool isCall ) external view returns (int256[] memory); function getTimeToMaturity64x64(uint64 maturity) external view returns (int128); function getAnnualizedVolatility64x64( address baseToken, address underlyingToken, int128 spot64x64, int128 strike64x64, int128 timeToMaturity64x64, bool isCall ) external view returns (int128); function getBlackScholesPrice64x64( address baseToken, address underlyingToken, int128 strike64x64, int128 spot64x64, int128 timeToMaturity64x64, bool isCall ) external view returns (int128); function getBlackScholesPrice( address baseToken, address underlyingToken, int128 strike64x64, int128 spot64x64, int128 timeToMaturity64x64, bool isCall ) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC1155 } from '../IERC1155.sol'; import { IERC1155Receiver } from '../IERC1155Receiver.sol'; import { ERC1155BaseInternal, ERC1155BaseStorage } from './ERC1155BaseInternal.sol'; /** * @title Base ERC1155 contract * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts/ (MIT license) */ abstract contract ERC1155Base is IERC1155, ERC1155BaseInternal { /** * @inheritdoc IERC1155 */ function balanceOf(address account, uint256 id) public view virtual override returns (uint256) { return _balanceOf(account, id); } /** * @inheritdoc IERC1155 */ function balanceOfBatch(address[] memory accounts, uint256[] memory ids) public view virtual override returns (uint256[] memory) { require( accounts.length == ids.length, 'ERC1155: accounts and ids length mismatch' ); mapping(uint256 => mapping(address => uint256)) storage balances = ERC1155BaseStorage.layout().balances; uint256[] memory batchBalances = new uint256[](accounts.length); unchecked { for (uint256 i; i < accounts.length; i++) { require( accounts[i] != address(0), 'ERC1155: batch balance query for the zero address' ); batchBalances[i] = balances[ids[i]][accounts[i]]; } } return batchBalances; } /** * @inheritdoc IERC1155 */ function isApprovedForAll(address account, address operator) public view virtual override returns (bool) { return ERC1155BaseStorage.layout().operatorApprovals[account][operator]; } /** * @inheritdoc IERC1155 */ function setApprovalForAll(address operator, bool status) public virtual override { require( msg.sender != operator, 'ERC1155: setting approval status for self' ); ERC1155BaseStorage.layout().operatorApprovals[msg.sender][ operator ] = status; emit ApprovalForAll(msg.sender, operator, status); } /** * @inheritdoc IERC1155 */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes memory data ) public virtual override { require( from == msg.sender || isApprovedForAll(from, msg.sender), 'ERC1155: caller is not owner nor approved' ); _safeTransfer(msg.sender, from, to, id, amount, data); } /** * @inheritdoc IERC1155 */ function safeBatchTransferFrom( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) public virtual override { require( from == msg.sender || isApprovedForAll(from, msg.sender), 'ERC1155: caller is not owner nor approved' ); _safeTransferBatch(msg.sender, from, to, ids, amounts, data); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title ERC1155 enumerable and aggregate function interface */ interface IERC1155Enumerable { /** * @notice query total minted supply of given token * @param id token id to query * @return token supply */ function totalSupply(uint256 id) external view returns (uint256); /** * @notice query total number of holders for given token * @param id token id to query * @return quantity of holders */ function totalHolders(uint256 id) external view returns (uint256); /** * @notice query holders of given token * @param id token id to query * @return list of holder addresses */ function accountsByToken(uint256 id) external view returns (address[] memory); /** * @notice query tokens held by given address * @param account address to query * @return list of token ids */ function tokensByAccount(address account) external view returns (uint256[] memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { EnumerableSet } from '../../../utils/EnumerableSet.sol'; import { ERC1155BaseInternal, ERC1155BaseStorage } from '../base/ERC1155BaseInternal.sol'; import { ERC1155EnumerableStorage } from './ERC1155EnumerableStorage.sol'; /** * @title ERC1155Enumerable internal functions */ abstract contract ERC1155EnumerableInternal is ERC1155BaseInternal { using EnumerableSet for EnumerableSet.AddressSet; using EnumerableSet for EnumerableSet.UintSet; /** * @notice ERC1155 hook: update aggregate values * @inheritdoc ERC1155BaseInternal */ function _beforeTokenTransfer( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual override { super._beforeTokenTransfer(operator, from, to, ids, amounts, data); if (from != to) { ERC1155EnumerableStorage.Layout storage l = ERC1155EnumerableStorage .layout(); mapping(uint256 => EnumerableSet.AddressSet) storage tokenAccounts = l.accountsByToken; EnumerableSet.UintSet storage fromTokens = l.tokensByAccount[from]; EnumerableSet.UintSet storage toTokens = l.tokensByAccount[to]; for (uint256 i; i < ids.length; i++) { uint256 amount = amounts[i]; if (amount > 0) { uint256 id = ids[i]; if (from == address(0)) { l.totalSupply[id] += amount; } else if (_balanceOf(from, id) == amount) { tokenAccounts[id].remove(from); fromTokens.remove(id); } if (to == address(0)) { l.totalSupply[id] -= amount; } else if (_balanceOf(to, id) == 0) { tokenAccounts[id].add(to); toTokens.add(id); } } } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC1155Internal } from './IERC1155Internal.sol'; import { IERC165 } from '../../introspection/IERC165.sol'; /** * @notice ERC1155 interface * @dev see https://github.com/ethereum/EIPs/issues/1155 */ interface IERC1155 is IERC1155Internal, IERC165 { /** * @notice query the balance of given token held by given address * @param account address to query * @param id token to query * @return token balance */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @notice query the balances of given tokens held by given addresses * @param accounts addresss to query * @param ids tokens to query * @return token balances */ function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); /** * @notice query approval status of given operator with respect to given address * @param account address to query for approval granted * @param operator address to query for approval received * @return whether operator is approved to spend tokens held by account */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @notice grant approval to or revoke approval from given operator to spend held tokens * @param operator address whose approval status to update * @param status whether operator should be considered approved */ function setApprovalForAll(address operator, bool status) external; /** * @notice transfer tokens between given addresses, checking for ERC1155Receiver implementation if applicable * @param from sender of tokens * @param to receiver of tokens * @param id token ID * @param amount quantity of tokens to transfer * @param data data payload */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) external; /** * @notice transfer batch of tokens between given addresses, checking for ERC1155Receiver implementation if applicable * @param from sender of tokens * @param to receiver of tokens * @param ids list of token IDs * @param amounts list of quantities of tokens to transfer * @param data data payload */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC165 } from '../../introspection/IERC165.sol'; /** * @title ERC1155 transfer receiver interface */ interface IERC1155Receiver is IERC165 { /** * @notice validate receipt of ERC1155 transfer * @param operator executor of transfer * @param from sender of tokens * @param id token ID received * @param value quantity of tokens received * @param data data payload * @return function's own selector if transfer is accepted */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @notice validate receipt of ERC1155 batch transfer * @param operator executor of transfer * @param from sender of tokens * @param ids token IDs received * @param values quantities of tokens received * @param data data payload * @return function's own selector if transfer is accepted */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { AddressUtils } from '../../../utils/AddressUtils.sol'; import { IERC1155Internal } from '../IERC1155Internal.sol'; import { IERC1155Receiver } from '../IERC1155Receiver.sol'; import { ERC1155BaseStorage } from './ERC1155BaseStorage.sol'; /** * @title Base ERC1155 internal functions * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts/ (MIT license) */ abstract contract ERC1155BaseInternal is IERC1155Internal { using AddressUtils for address; /** * @notice query the balance of given token held by given address * @param account address to query * @param id token to query * @return token balance */ function _balanceOf(address account, uint256 id) internal view virtual returns (uint256) { require( account != address(0), 'ERC1155: balance query for the zero address' ); return ERC1155BaseStorage.layout().balances[id][account]; } /** * @notice mint given quantity of tokens for given address * @dev ERC1155Receiver implementation is not checked * @param account beneficiary of minting * @param id token ID * @param amount quantity of tokens to mint * @param data data payload */ function _mint( address account, uint256 id, uint256 amount, bytes memory data ) internal virtual { require(account != address(0), 'ERC1155: mint to the zero address'); _beforeTokenTransfer( msg.sender, address(0), account, _asSingletonArray(id), _asSingletonArray(amount), data ); mapping(address => uint256) storage balances = ERC1155BaseStorage .layout() .balances[id]; balances[account] += amount; emit TransferSingle(msg.sender, address(0), account, id, amount); } /** * @notice mint given quantity of tokens for given address * @param account beneficiary of minting * @param id token ID * @param amount quantity of tokens to mint * @param data data payload */ function _safeMint( address account, uint256 id, uint256 amount, bytes memory data ) internal virtual { _mint(account, id, amount, data); _doSafeTransferAcceptanceCheck( msg.sender, address(0), account, id, amount, data ); } /** * @notice mint batch of tokens for given address * @dev ERC1155Receiver implementation is not checked * @param account beneficiary of minting * @param ids list of token IDs * @param amounts list of quantities of tokens to mint * @param data data payload */ function _mintBatch( address account, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { require(account != address(0), 'ERC1155: mint to the zero address'); require( ids.length == amounts.length, 'ERC1155: ids and amounts length mismatch' ); _beforeTokenTransfer( msg.sender, address(0), account, ids, amounts, data ); mapping(uint256 => mapping(address => uint256)) storage balances = ERC1155BaseStorage.layout().balances; for (uint256 i; i < ids.length; i++) { balances[ids[i]][account] += amounts[i]; } emit TransferBatch(msg.sender, address(0), account, ids, amounts); } /** * @notice mint batch of tokens for given address * @param account beneficiary of minting * @param ids list of token IDs * @param amounts list of quantities of tokens to mint * @param data data payload */ function _safeMintBatch( address account, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { _mintBatch(account, ids, amounts, data); _doSafeBatchTransferAcceptanceCheck( msg.sender, address(0), account, ids, amounts, data ); } /** * @notice burn given quantity of tokens held by given address * @param account holder of tokens to burn * @param id token ID * @param amount quantity of tokens to burn */ function _burn( address account, uint256 id, uint256 amount ) internal virtual { require(account != address(0), 'ERC1155: burn from the zero address'); _beforeTokenTransfer( msg.sender, account, address(0), _asSingletonArray(id), _asSingletonArray(amount), '' ); mapping(address => uint256) storage balances = ERC1155BaseStorage .layout() .balances[id]; unchecked { require( balances[account] >= amount, 'ERC1155: burn amount exceeds balances' ); balances[account] -= amount; } emit TransferSingle(msg.sender, account, address(0), id, amount); } /** * @notice burn given batch of tokens held by given address * @param account holder of tokens to burn * @param ids token IDs * @param amounts quantities of tokens to burn */ function _burnBatch( address account, uint256[] memory ids, uint256[] memory amounts ) internal virtual { require(account != address(0), 'ERC1155: burn from the zero address'); require( ids.length == amounts.length, 'ERC1155: ids and amounts length mismatch' ); _beforeTokenTransfer(msg.sender, account, address(0), ids, amounts, ''); mapping(uint256 => mapping(address => uint256)) storage balances = ERC1155BaseStorage.layout().balances; unchecked { for (uint256 i; i < ids.length; i++) { uint256 id = ids[i]; require( balances[id][account] >= amounts[i], 'ERC1155: burn amount exceeds balance' ); balances[id][account] -= amounts[i]; } } emit TransferBatch(msg.sender, account, address(0), ids, amounts); } /** * @notice transfer tokens between given addresses * @dev ERC1155Receiver implementation is not checked * @param operator executor of transfer * @param sender sender of tokens * @param recipient receiver of tokens * @param id token ID * @param amount quantity of tokens to transfer * @param data data payload */ function _transfer( address operator, address sender, address recipient, uint256 id, uint256 amount, bytes memory data ) internal virtual { require( recipient != address(0), 'ERC1155: transfer to the zero address' ); _beforeTokenTransfer( operator, sender, recipient, _asSingletonArray(id), _asSingletonArray(amount), data ); mapping(uint256 => mapping(address => uint256)) storage balances = ERC1155BaseStorage.layout().balances; unchecked { uint256 senderBalance = balances[id][sender]; require( senderBalance >= amount, 'ERC1155: insufficient balances for transfer' ); balances[id][sender] = senderBalance - amount; } balances[id][recipient] += amount; emit TransferSingle(operator, sender, recipient, id, amount); } /** * @notice transfer tokens between given addresses * @param operator executor of transfer * @param sender sender of tokens * @param recipient receiver of tokens * @param id token ID * @param amount quantity of tokens to transfer * @param data data payload */ function _safeTransfer( address operator, address sender, address recipient, uint256 id, uint256 amount, bytes memory data ) internal virtual { _transfer(operator, sender, recipient, id, amount, data); _doSafeTransferAcceptanceCheck( operator, sender, recipient, id, amount, data ); } /** * @notice transfer batch of tokens between given addresses * @dev ERC1155Receiver implementation is not checked * @param operator executor of transfer * @param sender sender of tokens * @param recipient receiver of tokens * @param ids token IDs * @param amounts quantities of tokens to transfer * @param data data payload */ function _transferBatch( address operator, address sender, address recipient, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { require( recipient != address(0), 'ERC1155: transfer to the zero address' ); require( ids.length == amounts.length, 'ERC1155: ids and amounts length mismatch' ); _beforeTokenTransfer(operator, sender, recipient, ids, amounts, data); mapping(uint256 => mapping(address => uint256)) storage balances = ERC1155BaseStorage.layout().balances; for (uint256 i; i < ids.length; i++) { uint256 token = ids[i]; uint256 amount = amounts[i]; unchecked { uint256 senderBalance = balances[token][sender]; require( senderBalance >= amount, 'ERC1155: insufficient balances for transfer' ); balances[token][sender] = senderBalance - amount; } balances[token][recipient] += amount; } emit TransferBatch(operator, sender, recipient, ids, amounts); } /** * @notice transfer batch of tokens between given addresses * @param operator executor of transfer * @param sender sender of tokens * @param recipient receiver of tokens * @param ids token IDs * @param amounts quantities of tokens to transfer * @param data data payload */ function _safeTransferBatch( address operator, address sender, address recipient, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { _transferBatch(operator, sender, recipient, ids, amounts, data); _doSafeBatchTransferAcceptanceCheck( operator, sender, recipient, ids, amounts, data ); } /** * @notice wrap given element in array of length 1 * @param element element to wrap * @return singleton array */ function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) { uint256[] memory array = new uint256[](1); array[0] = element; return array; } /** * @notice revert if applicable transfer recipient is not valid ERC1155Receiver * @param operator executor of transfer * @param from sender of tokens * @param to receiver of tokens * @param id token ID * @param amount quantity of tokens to transfer * @param data data payload */ function _doSafeTransferAcceptanceCheck( address operator, address from, address to, uint256 id, uint256 amount, bytes memory data ) private { if (to.isContract()) { try IERC1155Receiver(to).onERC1155Received( operator, from, id, amount, data ) returns (bytes4 response) { require( response == IERC1155Receiver.onERC1155Received.selector, 'ERC1155: ERC1155Receiver rejected tokens' ); } catch Error(string memory reason) { revert(reason); } catch { revert('ERC1155: transfer to non ERC1155Receiver implementer'); } } } /** * @notice revert if applicable transfer recipient is not valid ERC1155Receiver * @param operator executor of transfer * @param from sender of tokens * @param to receiver of tokens * @param ids token IDs * @param amounts quantities of tokens to transfer * @param data data payload */ function _doSafeBatchTransferAcceptanceCheck( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) private { if (to.isContract()) { try IERC1155Receiver(to).onERC1155BatchReceived( operator, from, ids, amounts, data ) returns (bytes4 response) { require( response == IERC1155Receiver.onERC1155BatchReceived.selector, 'ERC1155: ERC1155Receiver rejected tokens' ); } catch Error(string memory reason) { revert(reason); } catch { revert('ERC1155: transfer to non ERC1155Receiver implementer'); } } } /** * @notice ERC1155 hook, called before all transfers including mint and burn * @dev function should be overridden and new implementation must call super * @dev called for both single and batch transfers * @param operator executor of transfer * @param from sender of tokens * @param to receiver of tokens * @param ids token IDs * @param amounts quantities of tokens to transfer * @param data data payload */ function _beforeTokenTransfer( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC165 } from '../../introspection/IERC165.sol'; /** * @notice Partial ERC1155 interface needed by internal functions */ interface IERC1155Internal { event TransferSingle( address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value ); event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); event ApprovalForAll( address indexed account, address indexed operator, bool approved ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title ERC165 interface registration interface * @dev see https://eips.ethereum.org/EIPS/eip-165 */ interface IERC165 { /** * @notice query whether contract has registered support for given interface * @param interfaceId interface id * @return bool whether interface is supported */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library ERC1155BaseStorage { struct Layout { mapping(uint256 => mapping(address => uint256)) balances; mapping(address => mapping(address => bool)) operatorApprovals; } bytes32 internal constant STORAGE_SLOT = keccak256('solidstate.contracts.storage.ERC1155Base'); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: BUSL-1.1 // For further clarification please see https://license.premia.legal pragma solidity ^0.8.0; library FeeDiscountStorage { bytes32 internal constant STORAGE_SLOT = keccak256("premia.contracts.staking.PremiaFeeDiscount"); struct UserInfo { uint256 balance; // Balance staked by user uint64 stakePeriod; // Stake period selected by user uint64 lockedUntil; // Timestamp at which the lock ends } struct Layout { // User data with xPREMIA balance staked and date at which lock ends mapping(address => UserInfo) userInfo; } function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: BUSL-1.1 // For further clarification please see https://license.premia.legal pragma solidity ^0.8.0; library PremiaMiningStorage { bytes32 internal constant STORAGE_SLOT = keccak256("premia.contracts.storage.PremiaMining"); // Info of each pool. struct PoolInfo { uint256 allocPoint; // How many allocation points assigned to this pool. PREMIA to distribute per block. uint256 lastRewardTimestamp; // Last timestamp that PREMIA distribution occurs uint256 accPremiaPerShare; // Accumulated PREMIA per share, times 1e12. See below. } // Info of each user. struct UserInfo { uint256 reward; // Total allocated unclaimed reward uint256 rewardDebt; // Reward debt. See explanation below. // // We do some fancy math here. Basically, any point in time, the amount of PREMIA // entitled to a user but is pending to be distributed is: // // pending reward = (user.amount * pool.accPremiaPerShare) - user.rewardDebt // // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens: // 1. The pool's `accPremiaPerShare` (and `lastRewardBlock`) gets updated. // 2. User receives the pending reward sent to his/her address. // 3. User's `amount` gets updated. // 4. User's `rewardDebt` gets updated. } struct Layout { // Total PREMIA left to distribute uint256 premiaAvailable; // Amount of premia distributed per year uint256 premiaPerYear; // pool -> isCallPool -> PoolInfo mapping(address => mapping(bool => PoolInfo)) poolInfo; // pool -> isCallPool -> user -> UserInfo mapping(address => mapping(bool => mapping(address => UserInfo))) userInfo; // Total allocation points. Must be the sum of all allocation points in all pools. uint256 totalAllocPoint; } function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } }
// SPDX-License-Identifier: BUSL-1.1 // For further clarification please see https://license.premia.legal pragma solidity ^0.8.0; import {EnumerableSet} from "@solidstate/contracts/utils/EnumerableSet.sol"; library VolatilitySurfaceOracleStorage { bytes32 internal constant STORAGE_SLOT = keccak256("premia.contracts.storage.VolatilitySurfaceOracle"); uint256 internal constant COEFF_BITS = 51; uint256 internal constant COEFF_BITS_MINUS_ONE = 50; uint256 internal constant COEFF_AMOUNT = 5; // START_BIT = COEFF_BITS * (COEFF_AMOUNT - 1) uint256 internal constant START_BIT = 204; struct Update { uint256 updatedAt; bytes32 callCoefficients; bytes32 putCoefficients; } struct Layout { // Base token -> Underlying token -> Update mapping(address => mapping(address => Update)) volatilitySurfaces; // Relayer addresses which can be trusted to provide accurate option trades EnumerableSet.AddressSet whitelistedRelayers; } function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } function getCoefficients( Layout storage l, address baseToken, address underlyingToken, bool isCall ) internal view returns (bytes32) { Update storage u = l.volatilitySurfaces[baseToken][underlyingToken]; return isCall ? u.callCoefficients : u.putCoefficients; } function parseVolatilitySurfaceCoefficients(bytes32 input) internal pure returns (int256[] memory coefficients) { coefficients = new int256[](COEFF_AMOUNT); // Value to add to negative numbers to cast them to int256 int256 toAdd = (int256(-1) >> COEFF_BITS) << COEFF_BITS; assembly { let i := 0 // Value equal to -1 let mid := shl(COEFF_BITS_MINUS_ONE, 1) for { } lt(i, COEFF_AMOUNT) { } { let offset := sub(START_BIT, mul(COEFF_BITS, i)) let coeff := shr( offset, sub( input, shl( add(offset, COEFF_BITS), shr(add(offset, COEFF_BITS), input) ) ) ) // Check if value is a negative number and needs casting if or(eq(coeff, mid), gt(coeff, mid)) { coeff := add(coeff, toAdd) } // Store result in the coefficients array mstore(add(coefficients, add(0x20, mul(0x20, i))), coeff) i := add(i, 1) } } } function formatVolatilitySurfaceCoefficients(int256[5] memory coefficients) internal pure returns (bytes32 result) { for (uint256 i = 0; i < COEFF_AMOUNT; i++) { int256 max = int256(1 << COEFF_BITS_MINUS_ONE); require( coefficients[i] < max && coefficients[i] > -max, "Out of bounds" ); } assembly { let i := 0 for { } lt(i, COEFF_AMOUNT) { } { let offset := sub(START_BIT, mul(COEFF_BITS, i)) let coeff := mload(add(coefficients, mul(0x20, i))) result := add( result, shl( offset, sub(coeff, shl(COEFF_BITS, shr(COEFF_BITS, coeff))) ) ) i := add(i, 1) } } } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "libraries": { "contracts/libraries/OptionMath.sol": { "OptionMath": "0xc7a7275bc25a7bf07c6d0c2f8784c5450cb9b8f5" } } }
[{"inputs":[{"internalType":"address","name":"ivolOracle","type":"address"},{"internalType":"address","name":"weth","type":"address"},{"internalType":"address","name":"premiaMining","type":"address"},{"internalType":"address","name":"feeReceiver","type":"address"},{"internalType":"address","name":"feeDiscountAddress","type":"address"},{"internalType":"int128","name":"fee64x64","type":"int128"},{"internalType":"address","name":"uniswapV2Factory","type":"address"},{"internalType":"address","name":"sushiswapFactory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shortTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Annihilate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underwriter","type":"address"},{"indexed":false,"internalType":"uint256","name":"shortTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"freedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"intervalContractSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"AssignExercise","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"bool","name":"isCallPool","type":"bool"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"longTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"contractSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exerciseValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Exercise","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"isCallPool","type":"bool"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeeWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"longTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"contractSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseCost","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeCost","type":"uint256"},{"indexed":false,"internalType":"int128","name":"spot64x64","type":"int128"}],"name":"Purchase","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underwriter","type":"address"},{"indexed":true,"internalType":"address","name":"longReceiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"shortTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"intervalContractSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"intervalPremium","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isManualUnderwrite","type":"bool"}],"name":"Underwrite","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"isCall","type":"bool"},{"indexed":false,"internalType":"int128","name":"cLevel64x64","type":"int128"},{"indexed":false,"internalType":"int128","name":"oldLiquidity64x64","type":"int128"},{"indexed":false,"internalType":"int128","name":"newLiquidity64x64","type":"int128"}],"name":"UpdateCLevel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int128","name":"steepness64x64","type":"int128"},{"indexed":false,"internalType":"bool","name":"isCallPool","type":"bool"}],"name":"UpdateSteepness","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"bool","name":"isCallPool","type":"bool"},{"indexed":false,"internalType":"uint256","name":"depositedAt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawal","type":"event"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"contractSize","type":"uint256"}],"name":"annihilate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isCallPool","type":"bool"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"isCallPool","type":"bool"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isCallPool","type":"bool"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"contractSize","type":"uint256"}],"name":"reassign","outputs":[{"internalType":"uint256","name":"baseCost","type":"uint256"},{"internalType":"uint256","name":"feeCost","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"contractSizes","type":"uint256[]"}],"name":"reassignBatch","outputs":[{"internalType":"uint256[]","name":"baseCosts","type":"uint256[]"},{"internalType":"uint256[]","name":"feeCosts","type":"uint256[]"},{"internalType":"uint256","name":"amountOutCall","type":"uint256"},{"internalType":"uint256","name":"amountOutPut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"bool","name":"isCallPool","type":"bool"}],"name":"setDivestmentTimestamp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isCallPool","type":"bool"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"bool","name":"isSushi","type":"bool"}],"name":"swapAndDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"updateMiningPools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isCallPool","type":"bool"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isCallPool","type":"bool"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"contractSizes","type":"uint256[]"}],"name":"withdrawAllAndReassignBatch","outputs":[{"internalType":"uint256[]","name":"baseCosts","type":"uint256[]"},{"internalType":"uint256[]","name":"feeCosts","type":"uint256[]"},{"internalType":"uint256","name":"amountOutCall","type":"uint256"},{"internalType":"uint256","name":"amountOutPut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawFees","outputs":[{"internalType":"uint256","name":"amountOutCall","type":"uint256"},{"internalType":"uint256","name":"amountOutPut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6102006040523480156200001257600080fd5b5060405162005b5238038062005b5283398101604081905262000035916200018e565b6001600160a01b038881166101005287811660805286811660a05285811660c052841660e052600f83900b6101205287878787878787878787878787876200008c6000808062000125602090811b62000be517901c565b6101408181525050620000ae60016000806200012560201b62000be51760201c565b6101608181525050620000d060026000806200012560201b62000be51760201c565b6101808181525050620000f260036000806200012560201b62000be51760201c565b6101a0525050506001600160a01b039485166101c052505050166101e052506200027a9c50505050505050505050505050565b600081600f0b6080846001600160401b0316901b60f88660078111156200015057620001506200023d565b6200015d92911b62000253565b62000169919062000253565b949350505050565b80516001600160a01b03811681146200018957600080fd5b919050565b600080600080600080600080610100898b031215620001ac57600080fd5b620001b78962000171565b9750620001c760208a0162000171565b9650620001d760408a0162000171565b9550620001e760608a0162000171565b9450620001f760808a0162000171565b935060a089015180600f0b81146200020e57600080fd5b92506200021e60c08a0162000171565b91506200022e60e08a0162000171565b90509295985092959890939650565b634e487b7160e01b600052602160045260246000fd5b600082198211156200027557634e487b7160e01b600052601160045260246000fd5b500190565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e051615766620003ec60003960008181611529015281816116ae0152818161196701528181612cf10152612d6e015260008181611503015281816116880152818161194101528181611a0d01528181612ccb0152612d48015260008181611036015261241501526000818161105c015281816123eb015261248e015260008181610c33015281816123c10152612534015260008181610c5901528181612398015281816124650152818161250b015261255d01526000613864015260006136330152600081816147ae01526147fa0152600081816104c2015281816104f6015281816113b4015281816113e6015261215d0152600081816105b901528181610af101528181610b7c015281816112c00152612ef1015260008181611453015281816115c30152818161165101528181612fbd01528181613005015261312601526157666000f3fe6080604052600436106100a75760003560e01c80637d09e3bc116100645780637d09e3bc146101ac5780639a408321146101bf578063e4d4517b146101d2578063ebad1dd0146101f2578063ededdfd614610212578063fbe5f3a11461023257600080fd5b80630e6878a3146100ac5780631cee2d36146100ce5780632f6c7a101461010757806338d0743614610142578063476343ee14610162578063491c011a1461018c575b600080fd5b3480156100b857600080fd5b506100cc6100c7366004614d2a565b610247565b005b3480156100da57600080fd5b506100ee6100e9366004614d8b565b610254565b6040516100fe9493929190614e48565b60405180910390f35b34801561011357600080fd5b50610127610122366004614e81565b6102a0565b604080519384526020840192909252908201526060016100fe565b34801561014e57600080fd5b506100cc61015d366004614ea3565b610335565b34801561016e57600080fd5b506101776104a2565b604080519283526020830191909152016100fe565b34801561019857600080fd5b506100cc6101a7366004614eea565b610529565b6100cc6101ba366004614f16565b610631565b6100cc6101cd366004614ea3565b6106cd565b3480156101de57600080fd5b506100cc6101ed366004614f9c565b6106dd565b3480156101fe57600080fd5b506100ee61020d366004614fc6565b61078b565b34801561021e57600080fd5b506100cc61022d366004614e81565b6109cd565b34801561023e57600080fd5b506100cc610a65565b6102513382610529565b50565b606080600080600061026e336102698c610c2a565b610c7f565b9050801561028057610280818b610335565b61028c8989898961078b565b929d919c509a509098509650505050505050565b60008080600080516020615711833981519152816102bd82610d32565b905060f887901c608088901c88600060058460078111156102e0576102e0615031565b14806102fd575060048460078111156102fb576102fb615031565b145b905061030e86338585858f8b610d92565b919a50985096506103283361032283610e05565b89610e5a565b5050505050509250925092565b6000805160206157118339815191528261034f8284610f2f565b336000908152600d83016020908152604080832086151584529091529020544261037c826201518061505d565b106103a25760405162461bcd60e51b815260040161039990615075565b60405180910390fd5b60006103ae8486610fbf565b905060006103bb8661102d565b905060006103c93383610c7f565b905080156103fe576000858210156103e25750806103e5565b50845b6103ef818761509a565b95506103fc338483611081565b505b50508215610435576104193361041387610c2a565b85611081565b60006104258587610fbf565b905061043385838389611213565b505b61044184338789611288565b6104543361044e87610e05565b88610e5a565b6040805186151581526020810184905290810187905233907f477b6b4ae4e555826c33dfac094986168321f8f6295ab29cb8109c27e312e50f906060015b60405180910390a2505050505050565b6000806104af60016113a1565b91506104bb60006113a1565b90506104f17f00000000000000000000000000000000000000000000000000000000000000006104eb6001610e05565b84610e5a565b6105257f000000000000000000000000000000000000000000000000000000000000000061051f6000610e05565b83610e5a565b9091565b6001600160a01b0382811660009081527fbbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df53026020908152604080832085151584528252808320547fbbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df5303909252918290205491516357795f1b60e11b8152600080516020615711833981519152939192917f0000000000000000000000000000000000000000000000000000000000000000169063aef2be36906105f8908890309089908890819089906004016150b1565b600060405180830381600087803b15801561061257600080fd5b505af1158015610626573d6000803e3d6000fd5b505050505050505050565b34158061063c575083155b6106885760405162461bcd60e51b815260206004820152601c60248201527f76616c756520616e6420616d6f756e74496e4d617820706173736564000000006044820152606401610399565b84610691578694505b34156106a9576106a38584848461144f565b506106b8565b6106b68585858585611935565b505b6106c487876001611acf565b50505050505050565b6106d982826000611acf565b5050565b3360009081527fbbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df52f860209081526040808320841515845290915290205460008051602061571183398151915290610736906201518061505d565b836001600160401b0316101561075e5760405162461bcd60e51b815260040161039990615075565b336000908152600e909101602090815260408083209315158352929052206001600160401b039091169055565b6060806000808685146107d45760405162461bcd60e51b81526020600482015260116024820152700c8d2cccc40c2e4e4c2f240d8cadccee8d607b1b6044820152606401610399565b60008051602061571183398151915260006107ee82610d32565b9050886001600160401b03811115610808576108086150e7565b604051908082528060200260200182016040528015610831578160200160208202803683370190505b509550886001600160401b0381111561084c5761084c6150e7565b604051908082528060200260200182016040528015610875578160200160208202803683370190505b50945060005b898110156109975760008060006108b38e8e8681811061089d5761089d6150fd565b9050602002013560f881901c91608082901c9190565b91945092509050600060058460078111156108d0576108d0615031565b14806108ed575060048460078111156108eb576108eb615031565b145b90506000808e8e88818110610904576109046150fd565b90506020020135905061091c8933878787868e610d92565b8f8a8151811061092e5761092e6150fd565b602002602001018f8b81518110610947576109476150fd565b6020908102919091010192909252919052915082156109715761096a828c61505d565b9a5061097e565b61097b828b61505d565b99505b505050505050808061098f90615113565b91505061087b565b506109ac336109a66001610e05565b86610e5a565b6109c0336109ba6000610e05565b85610e5a565b5050945094509450949050565b60f882901c608083901c83600060058460078111156109ee576109ee615031565b1480610a0b57506004846007811115610a0957610a09615031565b145b9050610a1a3384848489611c34565b610a5d33610a2783610e05565b83610a5757610a52610a3d600f87900b8a611cbe565b60008051602061571183398151915290611d26565b610e5a565b87610e5a565b505050505050565b600160008181527fbbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df53036020527f574488069b1552032c6ff89bebe1010d4367afb63ca1952e2124c136d7904c3154604080516358097aa360e11b81523060048201526024810194909452604484019190915251600080516020615711833981519152926001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263b012f5469260648084019382900301818387803b158015610b3357600080fd5b505af1158015610b47573d6000803e3d6000fd5b505060008080526018840160205260408082205490516358097aa360e11b8152306004820152602481019290925260448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316925063b012f5469150606401600060405180830381600087803b158015610bca57600080fd5b505af1158015610bde573d6000803e3d6000fd5b5050505050565b600081600f0b6080846001600160401b0316901b60f8866007811115610c0d57610c0d615031565b610c1892911b61505d565b610c22919061505d565b949350505050565b600081610c57577f0000000000000000000000000000000000000000000000000000000000000000610c79565b7f00000000000000000000000000000000000000000000000000000000000000005b92915050565b60006001600160a01b038316610ceb5760405162461bcd60e51b815260206004820152602b60248201527f455243313135353a2062616c616e636520717565727920666f7220746865207a60448201526a65726f206164647265737360a81b6064820152608401610399565b7f1799cf914cb0cb442ca7c7ac709ee40d0cb89e87351dc08d517fbda27d50c68b6000928352602090815260408084206001600160a01b0395909516845293905250205490565b60004282600c01541415610d4a57610c798242611d61565b610d5382611d8f565b9050610d5f8242611d61565b600f0b610d7157610d71824283611eb2565b42600c830155610d82826001610f2f565b610d8d826000610f2f565b919050565b6000806000610da68a8a8a8a8a8a8a611f30565b9093509150610db88989898989611c34565b600086610ddc57610dd7610dd0600f8a900b88611cbe565b8c90611d26565b610dde565b855b905082610deb858361509a565b610df5919061509a565b9150509750975097945050505050565b600081610e2a57600080516020615711833981519152546001600160a01b0316610c79565b50507fbbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df52ec546001600160a01b031690565b80610e6457505050565b60405163a9059cbb60e01b81526001600160a01b0384811660048301526024820183905283169063a9059cbb90604401602060405180830381600087803b158015610eae57600080fd5b505af1158015610ec2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee6919061512e565b610f2a5760405162461bcd60e51b8152602060048201526015602482015274115490cc8c081d1c985b9cd9995c8819985a5b1959605a1b6044820152606401610399565b505050565b8015156000908152601383016020526040902080541580610f505750805442105b15610f5a57505050565b6000610f668484610fbf565b9050610fa18482610f9b610f908660010154610f8b898b6121f990919063ffffffff16565b61222b565b600f86900b90612241565b86611213565b50501515600090815260139091016020526040812081815560010155565b600080610fdc83610fd1576001610fd4565b60005b600080610be5565b8315156000908152601386016020526040902060010154909150610c22906000805160206156f183398151915260008481526020919091526040902054611023919061509a565b610f8b86866121f9565b60008161105a577f0000000000000000000000000000000000000000000000000000000000000000610c79565b7f000000000000000000000000000000000000000000000000000000000000000092915050565b6001600160a01b0383166110e35760405162461bcd60e51b815260206004820152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b6064820152608401610399565b611111338460006110f386612275565b6110fc86612275565b604051806020016040528060008152506122c0565b60008281527f1799cf914cb0cb442ca7c7ac709ee40d0cb89e87351dc08d517fbda27d50c68b602090815260408083206001600160a01b038716845291829052909120548211156111b25760405162461bcd60e51b815260206004820152602560248201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015264616e63657360d81b6064820152608401610399565b6001600160a01b03841660008181526020838152604080832080548790039055805187815291820186905291929133917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a450505050565b600061121f85836127de565b9050600061123086838787876127f7565b905061123d8682856128fd565b60408051600f83810b825287810b602083015286900b91810191909152831515907f4e23621c6f591f14bf9505cb8326b45af9dc6c5569fd608de2a7a2ddd6146b2e90606001610492565b6001600160a01b03808416600090815260178601602090815260408083208615158452825280832054601889019092529091205490917f00000000000000000000000000000000000000000000000000000000000000001663edaf7d5b863087866112f3898261509a565b876040518763ffffffff1660e01b8152600401611315969594939291906150b1565b600060405180830381600087803b15801561132f57600080fd5b505af1158015611343573d6000803e3d6000fd5b505050508282611353919061509a565b6001600160a01b038616600090815260178801602090815260408083208815158452909152902055611385838261509a565b9315156000908152601890960160205250506040909320555050565b6000806113ad8361102d565b90506113d97f000000000000000000000000000000000000000000000000000000000000000082610c7f565b915081156114495761140c7f00000000000000000000000000000000000000000000000000000000000000008284611081565b8215157f496915fc2759ccee8966a2c2098c4895c608b8decdb351dccea354eb4ca9c4f08360405161144091815260200190565b60405180910390a25b50919050565b60607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168484600081811061148e5761148e6150fd565b90506020020160208101906114a3919061514b565b6001600160a01b0316146114f95760405162461bcd60e51b815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f504154480000006044820152606401610399565b61158582611527577f0000000000000000000000000000000000000000000000000000000000000000611549565b7f00000000000000000000000000000000000000000000000000000000000000005b86868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250889250612954915050565b9050348160008151811061159b5761159b6150fd565b602002602001015111156115c15760405162461bcd60e51b815260040161039990615166565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db082600081518110611603576116036150fd565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561163657600080fd5b505af115801561164a573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb611724846116ac577f00000000000000000000000000000000000000000000000000000000000000006116ce565b7f00000000000000000000000000000000000000000000000000000000000000005b878760008181106116e1576116e16150fd565b90506020020160208101906116f6919061514b565b88886001818110611709576117096150fd565b905060200201602081019061171e919061514b565b87612ae2565b83600081518110611737576117376150fd565b60200260200101516040518363ffffffff1660e01b81526004016117709291906001600160a01b03929092168252602082015260400190565b602060405180830381600087803b15801561178a57600080fd5b505af115801561179e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c2919061512e565b6117ce576117ce6151ad565b61180f81858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250339250879150612be39050565b80600081518110611822576118226150fd565b6020026020010151341115610c22576000336001600160a01b031682600081518110611850576118506150fd565b602002602001015134611863919061509a565b6040805160008152602081019182905261187c916151ef565b60006040518083038185875af1925050503d80600081146118b9576040519150601f19603f3d011682016040523d82523d6000602084013e6118be565b606091505b505090508061192c5760405162461bcd60e51b815260206004820152603460248201527f5472616e7366657248656c7065723a3a736166655472616e736665724554483a60448201527308115512081d1c985b9cd9995c8819985a5b195960621b6064820152608401610399565b50949350505050565b60606119c382611965577f0000000000000000000000000000000000000000000000000000000000000000611987565b7f00000000000000000000000000000000000000000000000000000000000000005b87868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250889250612954915050565b905084816000815181106119d9576119d96150fd565b602002602001015111156119ff5760405162461bcd60e51b815260040161039990615166565b611a8533611a31846116ac577f00000000000000000000000000000000000000000000000000000000000000006116ce565b83600081518110611a4457611a446150fd565b602002602001015187876000818110611a5f57611a5f6150fd565b9050602002016020810190611a74919061514b565b6001600160a01b0316929190612e3f565b611ac681858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250339250879150612be39050565b95945050505050565b3360009081527fbbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df52f9602090815260408083208515158452909152812081905560008051602061571183398151915290611b278285612e9f565b84151560009081526018840160205260409020549091508190611b4b90879061505d565b1115611b995760405162461bcd60e51b815260206004820152601860248201527f706f6f6c206465706f73697420636170207265616368656400000000000000006044820152606401610399565b611ba38285610f2f565b336000818152600d84016020908152604080832088151584529091529020429055611bd19083908688612eb9565b611be533611bde86610e05565b8786612fb6565b611bf03386866132b1565b6040805185151581526020810187905233917f74a132f462598ad738fcdf934a3f668aac78953afdb0c9fb953e16e07cca511c910160405180910390a25050505050565b6000611c4b611c44846001613374565b8686610be5565b90506000611c64611c5d856000613374565b8787610be5565b9050611c71878385611081565b611c7c878285611081565b60408051828152602081018590527f2c36fd3d1ab99ca7bec7ffe3c66b81f331da75eeda6c23fda680a77a7c458979910160405180910390a150505050505050565b600081611ccd57506000610c79565b600083600f0b1215611cde57600080fd5b600f83900b6001600160801b038316810260401c90608084901c026001600160c01b03811115611d0d57600080fd5b60401b8119811115611d1e57600080fd5b019392505050565b600080611d44838560030160149054906101000a900460ff1661222b565b9050610c22818560030160159054906101000a900460ff166133a7565b60006011830181611d74610e1085615221565b8152602081019190915260400160002054600f0b9392505050565b6000808260030160009054906101000a90046001600160a01b03166001600160a01b03166350d25bcd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611de257600080fd5b505afa158015611df6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e1a9190615243565b905060008360020160009054906101000a90046001600160a01b03166001600160a01b03166350d25bcd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e6e57600080fd5b505afa158015611e82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea69190615243565b9050610c2282826133c2565b6000611ec0610e1084615221565b6000818152601186016020526040902080546001600160801b0319166001600160801b0385161790559050611ef960ff8083169061509a565b6001901b846012016000600884901c81526020019081526020016000206000828254611f25919061505d565b909155505050505050565b60008042876001600160401b031611611f755760405162461bcd60e51b8152602060048201526007602482015266195e1c1a5c995960ca1b6044820152606401610399565b8860050154841015611fb55760405162461bcd60e51b81526020600482015260096024820152681d1bdbc81cdb585b1b60ba1b6044820152606401610399565b600085611fd957611fd4611fcd600f89900b87611cbe565b8b90611d26565b611fdb565b845b861515600090815260138c0160205260409020600101549091506000805160206156f1833981519152600061200f89610c2a565b815260200190815260200160002054612028919061509a565b8111156120635760405162461bcd60e51b8152602060048201526009602482015268696e737566206c697160b81b6044820152606401610399565b5060006120b56040518060c001604052808b6001600160a01b031681526020018a6001600160401b0316815260200189600f0b815260200186600f0b815260200187815260200188151581525061345d565b80519091506120cd906120c88c896121f9565b6133a7565b60208201519093506120e3906120c88c896121f9565b915060006120fc6120f5886001613374565b8a8a610be5565b9050600061211561210e896000613374565b8b8b610be5565b90506121228b83896138f9565b600061212e8d8a610fbf565b905061213e8d8d8a89868e613914565b600061214a8e8b610fbf565b90506121588e83838d611213565b61218b7f00000000000000000000000000000000000000000000000000000000000000006121858c61102d565b886138f9565b60408051858152602081018b905290810188905260608101879052600f89900b60808201526001600160a01b038e16907f4719d073a940c087132bffc1aac4f3837ca2c820d95574727828ce38f7fbc8c79060a00160405180910390a2505050505097509795505050505050565b600081612214576003830154600160a81b900460ff16612224565b6003830154600160a01b900460ff165b9392505050565b60006122248361223c84600a615340565b613ba6565b6000600f83810b9083900b0160016001607f1b0319811280159061226c575060016001607f1b038113155b61222457600080fd5b604080516001808252818301909252606091600091906020808301908036833701905050905082816000815181106122af576122af6150fd565b602090810291909101015292915050565b6122ce868686868686613bdd565b60008051602061571183398151915260005b84518110156127d45760008582815181106122fd576122fd6150fd565b60200260200101519050600085838151811061231b5761231b6150fd565b6020026020010151905080600014156123355750506127c2565b6001600160a01b038916612352576123506015850183613dc0565b505b6001600160a01b038816158015612382575060008281526000805160206156f18339815191526020526040902054155b15612396576123946015850183613dcc565b505b7f00000000000000000000000000000000000000000000000000000000000000008214806123e357507f000000000000000000000000000000000000000000000000000000000000000082145b8061240d57507f000000000000000000000000000000000000000000000000000000000000000082145b8061243757507f000000000000000000000000000000000000000000000000000000000000000082145b15612509576001600160a01b0389161580159061245c57506001600160a01b03881615155b156125095760007f00000000000000000000000000000000000000000000000000000000000000008314806124b057507f000000000000000000000000000000000000000000000000000000000000000083145b6001600160a01b038b166000908152600d870160209081526040808320841515845290915290205490915042906124ea906201518061505d565b106125075760405162461bcd60e51b815260040161039990615075565b505b7f000000000000000000000000000000000000000000000000000000000000000082148061255657507f000000000000000000000000000000000000000000000000000000000000000082145b156126fe577f00000000000000000000000000000000000000000000000000000000000000008214600061258a8683613dd8565b90506001600160a01b038b16156126b45760006125a78c86610c7f565b905081811180156125c157506125bd828561505d565b8111155b15612659576001600160a01b038c166000908152601488016020908152604080832086151580855260138c0184528285205485529083528184209084529091529020548490612610908361509a565b101561264e5760405162461bcd60e51b815260206004820152600d60248201526c496e7375662062616c616e636560981b6044820152606401610399565b612659878d85613df2565b6001600160a01b038b16156126b25761268d878d858c8a81518110612680576126806150fd565b6020026020010151611288565b6126b2878c858c8a815181106126a5576126a56150fd565b6020026020010151612eb9565b505b6001600160a01b038a16156126fb5760006126cf8b86610c7f565b90508181111580156126e95750816126e7858361505d565b115b156126f9576126f9878c85613ea3565b505b50505b60f882901c826001600160a01b038b161580159061272457506001600160a01b038a1615155b801561275c5750600582600781111561273f5761273f615031565b148061275c5750600782600781111561275a5761275a615031565b145b156127bd576000600583600781111561277757612777615031565b14905060008161279e57612799612792600f85900b87611cbe565b8990611d26565b6127a0565b845b90506127ae888e8484611288565b6127ba888d8484612eb9565b50505b505050505b806127cc81615113565b9150506122e0565b5050505050505050565b60006127ea8383613f4b565b9050612224838284613f72565b6000808261280c576019870154600f0b61281c565b6019870154600160801b9004600f0b5b905080600f0b6000141561283457506008860154600f0b5b60405163e101a89b60e01b8152600f87810b600483015286810b602483015285810b604483015282900b606482015273c7a7275bc25a7bf07c6d0c2f8784c5450cb9b8f59063e101a89b9060840160206040518083038186803b15801561289a57600080fd5b505af41580156128ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128d29190615361565b915067b33333333333333382600f0b12156128f35767b33333333333333391505b5095945050505050565b801561292d576009830180546001600160801b0384166001600160801b031990911617905542600b840155505050565b6008830180546001600160801b03808516600160801b02911617905542600a840155505050565b60606002835110156129a85760405162461bcd60e51b815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f5041544800006044820152606401610399565b82516001600160401b038111156129c1576129c16150e7565b6040519080825280602002602001820160405280156129ea578160200160208202803683370190505b5090508381600183516129fd919061509a565b81518110612a0d57612a0d6150fd565b602002602001018181525050600060018451612a29919061509a565b90505b801561192c57600080612a7d8887612a4560018761509a565b81518110612a5557612a556150fd565b6020026020010151888681518110612a6f57612a6f6150fd565b602002602001015188614134565b91509150612aa5848481518110612a9657612a966150fd565b6020026020010151838361420f565b84612ab160018661509a565b81518110612ac157612ac16150fd565b60200260200101818152505050508080612ada9061537c565b915050612a2c565b6000806000612af18686614335565b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b166034820152919350915087906048016040516020818303038152906040528051906020012085612b77576040518060400160405280602081526020017f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f815250612bae565b6040518060400160405280602081526020017fe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c63038152505b604051602001612bc093929190615393565b60408051601f198184030181529190528051602090910120979650505050505050565b60005b60018451612bf4919061509a565b811015610bde57600080858381518110612c1057612c106150fd565b602002602001015186846001612c26919061505d565b81518110612c3657612c366150fd565b6020026020010151915091506000612c4e8383614335565b509050600088612c5f86600161505d565b81518110612c6f57612c6f6150fd565b60200260200101519050600080836001600160a01b0316866001600160a01b031614612c9d57826000612ca1565b6000835b91509150600060028b51612cb5919061509a565b8810612cc15789612d3c565b612d3c89612cef577f0000000000000000000000000000000000000000000000000000000000000000612d11565b7f00000000000000000000000000000000000000000000000000000000000000005b878d612d1e8c600261505d565b81518110612d2e57612d2e6150fd565b60200260200101518c612ae2565b9050612d9689612d6c577f0000000000000000000000000000000000000000000000000000000000000000612d8e565b7f00000000000000000000000000000000000000000000000000000000000000005b88888c612ae2565b6001600160a01b031663022c0d9f84848460006040519080825280601f01601f191660200182016040528015612dd3576020820181803683370190505b506040518563ffffffff1660e01b8152600401612df39493929190615408565b600060405180830381600087803b158015612e0d57600080fd5b505af1158015612e21573d6000803e3d6000fd5b50505050505050505050508080612e3790615113565b915050612be6565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612e9990859061442d565b50505050565b600081612eb0578260060154612224565b50506007015490565b6001600160a01b03808416600090815260178601602090815260408083208615158452825280832054601889019092529091205490917f00000000000000000000000000000000000000000000000000000000000000001663edaf7d5b86308786612f24898261505d565b876040518763ffffffff1660e01b8152600401612f46969594939291906150b1565b600060405180830381600087803b158015612f6057600080fd5b505af1158015612f74573d6000803e3d6000fd5b505050508282612f84919061505d565b6001600160a01b038616600090815260178801602090815260408083208815158452909152902055611385838261505d565b806131df577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316141561319e573415613199578134111561311f577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b15801561305e57600080fd5b505af1158015613072573d6000803e3d6000fd5b50505050506000336001600160a01b0316833461308f919061509a565b604051600081818185875af1925050503d80600081146130cb576040519150601f19603f3d011682016040523d82523d6000602084013e6130d0565b606091505b50509050806131155760405162461bcd60e51b8152602060048201526011602482015270115512081c99599d5b990819985a5b1959607a1b6044820152606401610399565b60009250506131df565b34820391507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561317f57600080fd5b505af1158015613193573d6000803e3d6000fd5b50505050505b6131df565b34156131df5760405162461bcd60e51b815260206004820152601060248201526f1b9bdd0815d155120819195c1bdcda5d60821b6044820152606401610399565b8115612e99576040516323b872dd60e01b81526001600160a01b038581166004830152306024830152604482018490528416906323b872dd90606401602060405180830381600087803b15801561323557600080fd5b505af1158015613249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061326d919061512e565b612e995760405162461bcd60e51b8152602060048201526015602482015274115490cc8c081d1c985b9cd9995c8819985a5b1959605a1b6044820152606401610399565b6000805160206157118339815191526132d3846132cd84610c2a565b856138f9565b6000610104806132e38142615221565b6132ed9190615435565b6132f7919061505d565b6001600160a01b038616600090815260148401602090815260408083208484528252808320871515845290915281208054929350869290919061333b90849061505d565b9091555050821515600090815260138301602052604081206001810180549192879261336890849061505d565b90915550505550505050565b60008215613392578161338857600561338b565b60045b9050610c79565b8161339e576007612224565b50600692915050565b60006122246133b783600a615340565b600f85900b90611cbe565b6000816133ce57600080fd5b6000808412156133e357836000039350600190505b60008312156133f55760009290920391155b600061340185856144ff565b9050811561342f576001607f1b816001600160801b0316111561342357600080fd5b6000039150610c799050565b60016001607f1b03816001600160801b0316111561344c57600080fd5b9150610c799050565b505092915050565b60408051608081018252600080825260208201819052918101829052606081019190915260008260400151600f0b13801561349f575060008260600151600f0b135b80156134b85750600082602001516001600160401b0316115b6134f35760405162461bcd60e51b815260206004820152600c60248201526b696e76616c6964206172677360a01b6044820152606401610399565b60808201517fbbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df52ee54600080516020615711833981519152916000916135419190600160a01b900460ff1661222b565b60a085015190915060008061356c61355986856127de565b6135638786610fbf565b87919086614661565b91509150600081600f0b136135ac5760405162461bcd60e51b81526020600482015260066024820152656e6f206c697160d01b6044820152606401610399565b60006135d44289602001516001600160401b03166135ca919061509a565b6301e13380613ba6565b8654600188015460608b01516040808d0151905163c4afd30d60e01b81526001600160a01b0394851660048201529284166024840152600f91820b6044840152810b606483015283900b608482015286151560a48201529192506000917f00000000000000000000000000000000000000000000000000000000000000009091169063c4afd30d9060c40160206040518083038186803b15801561367757600080fd5b505afa15801561368b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136af9190615361565b9050600081600f0b136136ee5760405162461bcd60e51b81526020600482015260076024820152660766f6c203d20360cc1b6044820152606401610399565b600080600073c7a7275bc25a7bf07c6d0c2f8784c5450cb9b8f5630313686c60405180610140016040528061372f8889600f0b6146e990919063ffffffff16565b600f0b81526020018f60400151600f0b81526020018f60600151600f0b815260200188600f0b81526020018a600f0b815260200189600f0b81526020016137828d8b600f0b61471f90919063ffffffff16565b600f0b8152602001600160401b600f0b8152602001674ccccccccccccccd600f0b81526020018b15158152506040518263ffffffff1660e01b81526004016137ca9190615454565b60606040518083038186803b1580156137e257600080fd5b505af41580156137f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061381a919061551d565b9250925092508761383857613833600f84900b8a6146e9565b613858565b60608c01516138589061384f600f86900b8c6146e9565b600f0b90614752565b600f0b808c52613888907f00000000000000000000000000000000000000000000000000000000000000006146e9565b600f90810b60208d015282810b60408d015281900b60608c01528b516000906138bc906138b4906147aa565b612710613ba6565b60208d01519091506138d190600f0b826146e9565b8c6020018181516138e29190615560565b600f0b9052509a9c9b505050505050505050505050565b610f2a83838360405180602001604052806000815250614874565b600061391f82610c2a565b9050826000836139465761394161393a600f84900b89611cbe565b8a90611d26565b613948565b865b90505b8015610626578315156000908152600f8a01602090815260408083208380529091528120546001600160a01b0316906139848286610c7f565b90506139908b87613dd8565b8110156139a9576139a28b8388613df2565b505061394b565b6139b48b838861499b565b6139e2576139c3828683611081565b6139d6826139d08861102d565b836138f9565b6139a28b838884611288565b6000836139ef8a8261505d565b8d6014016000866001600160a01b03166001600160a01b0316815260200190815260200160002060008f60130160008c15151515815260200190815260200160002060000154815260200190815260200160002060008a1515151581526020019081526020016000205484613a64919061509a565b613a6e9190615435565b613a789190615221565b905080613a875750505061394b565b83811115613a925750825b600084613a9f838c615435565b613aa99190615221565b9050613ab5818b61509a565b9950613ac1828661509a565b9450613acf8d858a84612eb9565b613ae38488613ade848661509a565b611081565b87613b0e57613b0b613b0483613afb89600f0b6149d5565b600f0b90611cbe565b8e90614a2b565b91505b613b25848a8715613b1f57846138f9565b8d6138f9565b8b6001600160a01b0316846001600160a01b03167fa30eb1f1bb0892af5e3389941c42bc7f44a8bf7b6071ecfe3e964673c908f2b28b88600014613b695785613b6b565b8e5b60408051928352602083019190915281018590526000606082015260800160405180910390a3613b9b828c61509a565b9a505050505061394b565b600081613bb257600080fd5b6000613bbe84846144ff565b905060016001607f1b036001600160801b038216111561222457600080fd5b836001600160a01b0316856001600160a01b031614610a5d576001600160a01b0385811660009081527fb31c2c74f86ca3ce94d901f5f5bbe66f7161eec2f7b5aa0b75a86371436424ec6020526040808220928716825281206000805160206156f1833981519152927fb31c2c74f86ca3ce94d901f5f5bbe66f7161eec2f7b5aa0b75a86371436424eb929091905b8751811015613db3576000878281518110613c8957613c896150fd565b602002602001015190506000811115613da0576000898381518110613cb057613cb06150fd565b6020026020010151905060006001600160a01b03168c6001600160a01b03161415613cfe5760008181526020889052604081208054849290613cf390849061505d565b90915550613d349050565b81613d098d83610c7f565b1415613d34576000818152602087905260409020613d27908d614a66565b50613d328582613dcc565b505b6001600160a01b038b16613d6b5760008181526020889052604081208054849290613d6090849061509a565b90915550613d9e9050565b613d758b82610c7f565b613d9e576000818152602087905260409020613d91908c614a7b565b50613d9c8482613dc0565b505b505b5080613dab81615113565b915050613c6c565b5050505050505050505050565b60006122248383614a8c565b60006122248383614adb565b600081613de9578260040154612224565b50506005015490565b6001600160a01b038216613e0557600080fd5b8015156000908152600f84016020908152604080832060108701909252909120613e30848383614bc6565b613e3b575050505050565b6001600160a01b0393841660008181526020838152604080832080549683528184208054978a16808652838620805499909b166001600160a01b0319998a168117909b5599855295909252822080548616909717909655528054821690558254169091555050565b6001600160a01b038216613eb657600080fd5b8015156000908152600f84016020908152604080832060108701909252909120613ee1848383614bc6565b15613eed575050505050565b60008080526020828152604080832080546001600160a01b0390811680865296845282852080546001600160a01b03199081169a909216998a1790558885529490925282208054841690941790935580528154169092179091555050565b600081613f66576008830154600160801b9004600f0b612224565b505060090154600f0b90565b60008082613f845784600a0154613f8a565b84600b01545b613f94904261509a565b905061a8c0811115613fb357613fac61a8c08261509a565b9050613fbc565b83915050612224565b6000613fca82613840613ba6565b90506000613fdd85610fd1576001610fd4565b851515600090815260188901602090815260408083205460138c018352818420600101548585526000805160206156f1833981519152909352908320549394509261403b9161402b9161509a565b614035908461509a565b83613ba6565b6040805161012081018252600f87810b82528b810b602083015283900b8183015267b333333333333333606082015267e66666666666666660808201819052600160401b60a0830181905260c083015260e082015268056fc2a2c515da32ea6101008201529051634916d70d60e01b815291925073c7a7275bc25a7bf07c6d0c2f8784c5450cb9b8f591634916d70d916140d7916004016155b0565b60206040518083038186803b1580156140ef57600080fd5b505af4158015614103573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141279190615361565b9998505050505050505050565b60008060006141438686614335565b50905060008061415589898989612ae2565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561418d57600080fd5b505afa1580156141a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141c59190615677565b506001600160701b031691506001600160701b03169150826001600160a01b0316886001600160a01b0316146141fc5780826141ff565b81815b909a909950975050505050505050565b60008084116142755760405162461bcd60e51b815260206004820152602c60248201527f556e697377617056324c6962726172793a20494e53554646494349454e545f4f60448201526b155514155517d05353d5539560a21b6064820152608401610399565b6000831180156142855750600082115b6142e25760405162461bcd60e51b815260206004820152602860248201527f556e697377617056324c6962726172793a20494e53554646494349454e545f4c604482015267495155494449545960c01b6064820152608401610399565b60006142ee8585615435565b6142fa906103e8615435565b90506000614308868561509a565b614314906103e5615435565b90506143208183615221565b61432b90600161505d565b9695505050505050565b600080826001600160a01b0316846001600160a01b031614156143a85760405162461bcd60e51b815260206004820152602560248201527f556e697377617056324c6962726172793a204944454e544943414c5f41444452604482015264455353455360d81b6064820152608401610399565b826001600160a01b0316846001600160a01b0316106143c85782846143cb565b83835b90925090506001600160a01b0382166144265760405162461bcd60e51b815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f4144445245535300006044820152606401610399565b9250929050565b6000614482826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614c129092919063ffffffff16565b805190915015610f2a57808060200190518101906144a0919061512e565b610f2a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610399565b60008161450b57600080fd5b60006001600160c01b0384116145365782604085901b8161452e5761452e61520b565b04905061464d565b60c084811c640100000000811061454f576020918201911c5b620100008110614561576010918201911c5b6101008110614572576008918201911c5b60108110614582576004918201911c5b60048110614592576002918201911c5b600281106145a1576001820191505b60bf820360018603901c6001018260ff0387901b816145c2576145c261520b565b0492506001600160801b038311156145d957600080fd5b608085901c83026001600160801b038616840260c088901c604089901b82811015614605576001820391505b608084901b9290038281101561461c576001820391505b829003608084901c8214614632576146326151ad565b8881816146415761464161520b565b04870196505050505050505b6001600160801b0381111561222457600080fd5b80151560009081526013850160205260408120600181015482919082901580159061468c5750815415155b8015614699575081544210155b156146d75760018201546146b190610f8b8a886121f9565b90506146c1600f87900b82612241565b92506146d088888886896127f7565b93506146de565b8693508592505b505094509492505050565b6000600f83810b9083900b0260401d60016001607f1b0319811280159061226c575060016001607f1b0381131561222457600080fd5b6000600f82810b9084900b0360016001607f1b0319811280159061226c575060016001607f1b0381131561222457600080fd5b600081600f0b6000141561476557600080fd5b600082600f0b604085600f0b901b816147805761478061520b565b05905060016001607f1b0319811280159061226c575060016001607f1b0381131561222457600080fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615610d8d576040516303793c8d60e11b81526001600160a01b0383811660048301527f000000000000000000000000000000000000000000000000000000000000000016906306f2791a9060240160206040518083038186803b15801561483c57600080fd5b505afa158015614850573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c799190615243565b6001600160a01b0384166148d45760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610399565b6148f3336000866148e487612275565b6148ed87612275565b866122c0565b60008381527f1799cf914cb0cb442ca7c7ac709ee40d0cb89e87351dc08d517fbda27d50c68b602090815260408083206001600160a01b038816845291829052822080549192859261494690849061505d565b909155505060408051858152602081018590526001600160a01b0387169160009133917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a45050505050565b6001600160a01b0382166000908152600e8401602090815260408083208415158452909152812054801580611ac657504210949350505050565b600081600f0b600014156149e857600080fd5b600082600f0b600160801b81614a0057614a0061520b565b05905060016001607f1b03198112801590614a22575060016001607f1b038113155b610c7957600080fd5b600080614a49838560030160159054906101000a900460ff1661222b565b9050610c22818560030160149054906101000a900460ff166133a7565b6000612224836001600160a01b038416614adb565b6000612224836001600160a01b0384165b6000818152600183016020526040812054614ad357508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610c79565b506000610c79565b60008181526001830160205260408120548015614bbc576000614aff60018361509a565b85549091506000908690614b159060019061509a565b81548110614b2557614b256150fd565b9060005260206000200154905080866000018381548110614b4857614b486150fd565b600091825260209091200155614b5f82600161505d565b60008281526001880160205260409020558554869080614b8157614b816156c7565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610c79565b6000915050610c79565b6001600160a01b03838116600090815260208490526040812054909116151580610c2257506000808052602083905260409020546001600160a01b039081169085161490509392505050565b6060610c2284846000856060843b614c805760405162461bcd60e51b815260206004820152602b60248201527f416464726573735574696c733a2066756e6374696f6e2063616c6c20746f206e60448201526a1bdb8b58dbdb9d1c9858dd60aa1b6064820152608401610399565b600080866001600160a01b03168587604051614c9c91906151ef565b60006040518083038185875af1925050503d8060008114614cd9576040519150601f19603f3d011682016040523d82523d6000602084013e614cde565b606091505b50915091508115614cf2579150610c229050565b805115614d025780518082602001fd5b8360405162461bcd60e51b815260040161039991906156dd565b801515811461025157600080fd5b600060208284031215614d3c57600080fd5b813561222481614d1c565b60008083601f840112614d5957600080fd5b5081356001600160401b03811115614d7057600080fd5b6020830191508360208260051b850101111561442657600080fd5b600080600080600060608688031215614da357600080fd5b8535614dae81614d1c565b945060208601356001600160401b0380821115614dca57600080fd5b614dd689838a01614d47565b90965094506040880135915080821115614def57600080fd5b50614dfc88828901614d47565b969995985093965092949392505050565b600081518084526020808501945080840160005b83811015614e3d57815187529582019590820190600101614e21565b509495945050505050565b608081526000614e5b6080830187614e0d565b8281036020840152614e6d8187614e0d565b604084019590955250506060015292915050565b60008060408385031215614e9457600080fd5b50508035926020909101359150565b60008060408385031215614eb657600080fd5b823591506020830135614ec881614d1c565b809150509250929050565b80356001600160a01b0381168114610d8d57600080fd5b60008060408385031215614efd57600080fd5b614f0683614ed3565b91506020830135614ec881614d1c565b600080600080600080600060c0888a031215614f3157600080fd5b873596506020880135614f4381614d1c565b9550604088013594506060880135935060808801356001600160401b03811115614f6c57600080fd5b614f788a828b01614d47565b90945092505060a0880135614f8c81614d1c565b8091505092959891949750929550565b60008060408385031215614faf57600080fd5b82356001600160401b0381168114614f0657600080fd5b60008060008060408587031215614fdc57600080fd5b84356001600160401b0380821115614ff357600080fd5b614fff88838901614d47565b9096509450602087013591508082111561501857600080fd5b5061502587828801614d47565b95989497509550505050565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000821982111561507057615070615047565b500190565b6020808252600b908201526a1b1a5c481b1bd8dac80c5960aa1b604082015260600190565b6000828210156150ac576150ac615047565b500390565b6001600160a01b03968716815294909516602085015291151560408401526060830152608082015260a081019190915260c00190565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060001982141561512757615127615047565b5060010190565b60006020828403121561514057600080fd5b815161222481614d1c565b60006020828403121561515d57600080fd5b61222482614ed3565b60208082526027908201527f556e69737761705632526f757465723a204558434553534956455f494e50555460408201526617d05353d5539560ca1b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b60005b838110156151de5781810151838201526020016151c6565b83811115612e995750506000910152565b600082516152018184602087016151c3565b9190910192915050565b634e487b7160e01b600052601260045260246000fd5b60008261523e57634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561525557600080fd5b5051919050565b600181815b8085111561529757816000190482111561527d5761527d615047565b8085161561528a57918102915b93841c9390800290615261565b509250929050565b6000826152ae57506001610c79565b816152bb57506000610c79565b81600181146152d157600281146152db576152f7565b6001915050610c79565b60ff8411156152ec576152ec615047565b50506001821b610c79565b5060208310610133831016604e8410600b841016171561531a575081810a610c79565b615324838361525c565b806000190482111561533857615338615047565b029392505050565b600061222460ff84168361529f565b8051600f81900b8114610d8d57600080fd5b60006020828403121561537357600080fd5b6122248261534f565b60008161538b5761538b615047565b506000190190565b60ff60f81b81526bffffffffffffffffffffffff198460601b166001820152826015820152600082516153cd8160358501602087016151c3565b91909101603501949350505050565b600081518084526153f48160208601602086016151c3565b601f01601f19169290920160200192915050565b84815283602082015260018060a01b038316604082015260806060820152600061432b60808301846153dc565b600081600019048311821515161561544f5761544f615047565b500290565b8151600f0b8152610140810160208301516154746020840182600f0b9052565b5060408301516154896040840182600f0b9052565b50606083015161549e6060840182600f0b9052565b5060808301516154b36080840182600f0b9052565b5060a08301516154c860a0840182600f0b9052565b5060c08301516154dd60c0840182600f0b9052565b5060e08301516154f260e0840182600f0b9052565b506101008084015161550882850182600f0b9052565b50506101208381015180151584830152613455565b60008060006060848603121561553257600080fd5b61553b8461534f565b92506155496020850161534f565b91506155576040850161534f565b90509250925092565b600081600f0b83600f0b600081128160016001607f1b03190183128115161561558b5761558b615047565b8160016001607f1b030183138116156155a6576155a6615047565b5090039392505050565b6000610120820190508251600f0b82526020830151600f0b602083015260408301516155e16040840182600f0b9052565b5060608301516155f66060840182600f0b9052565b50608083015161560b6080840182600f0b9052565b5060a083015161562060a0840182600f0b9052565b5060c083015161563560c0840182600f0b9052565b5060e083015161564a60e0840182600f0b9052565b506101008084015161345582850182600f0b9052565b80516001600160701b0381168114610d8d57600080fd5b60008060006060848603121561568c57600080fd5b61569584615660565b92506156a360208501615660565b9150604084015163ffffffff811681146156bc57600080fd5b809150509250925092565b634e487b7160e01b600052603160045260246000fd5b60208152600061222460208301846153dc56feb31c2c74f86ca3ce94d901f5f5bbe66f7161eec2f7b5aa0b75a86371436424eabbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df52eba264697066735822122001aa5baa08f11f41aee0d511e5b1f8b80113a83a20b79929c17f071ff95d893c64736f6c63430008090033000000000000000000000000c4b2c51f969e0713e799de73b7f130fb7bb604cf00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000bc3c01d954282eed8433da4359c1ac1443a7d09a0000000000000000000000007bf2392bd078c8353069cffeacc67c094079be230000000000000000000000007fa86681a7c19416950bae6c04a5116f3b07116d00000000000000000000000000000000000000000000000007ae147ae147ae140000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f000000000000000000000000c35dadb65012ec5796536bd9864ed8773abc74c4
Deployed Bytecode
0x6080604052600436106100a75760003560e01c80637d09e3bc116100645780637d09e3bc146101ac5780639a408321146101bf578063e4d4517b146101d2578063ebad1dd0146101f2578063ededdfd614610212578063fbe5f3a11461023257600080fd5b80630e6878a3146100ac5780631cee2d36146100ce5780632f6c7a101461010757806338d0743614610142578063476343ee14610162578063491c011a1461018c575b600080fd5b3480156100b857600080fd5b506100cc6100c7366004614d2a565b610247565b005b3480156100da57600080fd5b506100ee6100e9366004614d8b565b610254565b6040516100fe9493929190614e48565b60405180910390f35b34801561011357600080fd5b50610127610122366004614e81565b6102a0565b604080519384526020840192909252908201526060016100fe565b34801561014e57600080fd5b506100cc61015d366004614ea3565b610335565b34801561016e57600080fd5b506101776104a2565b604080519283526020830191909152016100fe565b34801561019857600080fd5b506100cc6101a7366004614eea565b610529565b6100cc6101ba366004614f16565b610631565b6100cc6101cd366004614ea3565b6106cd565b3480156101de57600080fd5b506100cc6101ed366004614f9c565b6106dd565b3480156101fe57600080fd5b506100ee61020d366004614fc6565b61078b565b34801561021e57600080fd5b506100cc61022d366004614e81565b6109cd565b34801561023e57600080fd5b506100cc610a65565b6102513382610529565b50565b606080600080600061026e336102698c610c2a565b610c7f565b9050801561028057610280818b610335565b61028c8989898961078b565b929d919c509a509098509650505050505050565b60008080600080516020615711833981519152816102bd82610d32565b905060f887901c608088901c88600060058460078111156102e0576102e0615031565b14806102fd575060048460078111156102fb576102fb615031565b145b905061030e86338585858f8b610d92565b919a50985096506103283361032283610e05565b89610e5a565b5050505050509250925092565b6000805160206157118339815191528261034f8284610f2f565b336000908152600d83016020908152604080832086151584529091529020544261037c826201518061505d565b106103a25760405162461bcd60e51b815260040161039990615075565b60405180910390fd5b60006103ae8486610fbf565b905060006103bb8661102d565b905060006103c93383610c7f565b905080156103fe576000858210156103e25750806103e5565b50845b6103ef818761509a565b95506103fc338483611081565b505b50508215610435576104193361041387610c2a565b85611081565b60006104258587610fbf565b905061043385838389611213565b505b61044184338789611288565b6104543361044e87610e05565b88610e5a565b6040805186151581526020810184905290810187905233907f477b6b4ae4e555826c33dfac094986168321f8f6295ab29cb8109c27e312e50f906060015b60405180910390a2505050505050565b6000806104af60016113a1565b91506104bb60006113a1565b90506104f17f0000000000000000000000007bf2392bd078c8353069cffeacc67c094079be236104eb6001610e05565b84610e5a565b6105257f0000000000000000000000007bf2392bd078c8353069cffeacc67c094079be2361051f6000610e05565b83610e5a565b9091565b6001600160a01b0382811660009081527fbbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df53026020908152604080832085151584528252808320547fbbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df5303909252918290205491516357795f1b60e11b8152600080516020615711833981519152939192917f000000000000000000000000bc3c01d954282eed8433da4359c1ac1443a7d09a169063aef2be36906105f8908890309089908890819089906004016150b1565b600060405180830381600087803b15801561061257600080fd5b505af1158015610626573d6000803e3d6000fd5b505050505050505050565b34158061063c575083155b6106885760405162461bcd60e51b815260206004820152601c60248201527f76616c756520616e6420616d6f756e74496e4d617820706173736564000000006044820152606401610399565b84610691578694505b34156106a9576106a38584848461144f565b506106b8565b6106b68585858585611935565b505b6106c487876001611acf565b50505050505050565b6106d982826000611acf565b5050565b3360009081527fbbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df52f860209081526040808320841515845290915290205460008051602061571183398151915290610736906201518061505d565b836001600160401b0316101561075e5760405162461bcd60e51b815260040161039990615075565b336000908152600e909101602090815260408083209315158352929052206001600160401b039091169055565b6060806000808685146107d45760405162461bcd60e51b81526020600482015260116024820152700c8d2cccc40c2e4e4c2f240d8cadccee8d607b1b6044820152606401610399565b60008051602061571183398151915260006107ee82610d32565b9050886001600160401b03811115610808576108086150e7565b604051908082528060200260200182016040528015610831578160200160208202803683370190505b509550886001600160401b0381111561084c5761084c6150e7565b604051908082528060200260200182016040528015610875578160200160208202803683370190505b50945060005b898110156109975760008060006108b38e8e8681811061089d5761089d6150fd565b9050602002013560f881901c91608082901c9190565b91945092509050600060058460078111156108d0576108d0615031565b14806108ed575060048460078111156108eb576108eb615031565b145b90506000808e8e88818110610904576109046150fd565b90506020020135905061091c8933878787868e610d92565b8f8a8151811061092e5761092e6150fd565b602002602001018f8b81518110610947576109476150fd565b6020908102919091010192909252919052915082156109715761096a828c61505d565b9a5061097e565b61097b828b61505d565b99505b505050505050808061098f90615113565b91505061087b565b506109ac336109a66001610e05565b86610e5a565b6109c0336109ba6000610e05565b85610e5a565b5050945094509450949050565b60f882901c608083901c83600060058460078111156109ee576109ee615031565b1480610a0b57506004846007811115610a0957610a09615031565b145b9050610a1a3384848489611c34565b610a5d33610a2783610e05565b83610a5757610a52610a3d600f87900b8a611cbe565b60008051602061571183398151915290611d26565b610e5a565b87610e5a565b505050505050565b600160008181527fbbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df53036020527f574488069b1552032c6ff89bebe1010d4367afb63ca1952e2124c136d7904c3154604080516358097aa360e11b81523060048201526024810194909452604484019190915251600080516020615711833981519152926001600160a01b037f000000000000000000000000bc3c01d954282eed8433da4359c1ac1443a7d09a169263b012f5469260648084019382900301818387803b158015610b3357600080fd5b505af1158015610b47573d6000803e3d6000fd5b505060008080526018840160205260408082205490516358097aa360e11b8152306004820152602481019290925260448201527f000000000000000000000000bc3c01d954282eed8433da4359c1ac1443a7d09a6001600160a01b0316925063b012f5469150606401600060405180830381600087803b158015610bca57600080fd5b505af1158015610bde573d6000803e3d6000fd5b5050505050565b600081600f0b6080846001600160401b0316901b60f8866007811115610c0d57610c0d615031565b610c1892911b61505d565b610c22919061505d565b949350505050565b600081610c57577f0100000000000000000000000000000000000000000000000000000000000000610c79565b7f00000000000000000000000000000000000000000000000000000000000000005b92915050565b60006001600160a01b038316610ceb5760405162461bcd60e51b815260206004820152602b60248201527f455243313135353a2062616c616e636520717565727920666f7220746865207a60448201526a65726f206164647265737360a81b6064820152608401610399565b7f1799cf914cb0cb442ca7c7ac709ee40d0cb89e87351dc08d517fbda27d50c68b6000928352602090815260408084206001600160a01b0395909516845293905250205490565b60004282600c01541415610d4a57610c798242611d61565b610d5382611d8f565b9050610d5f8242611d61565b600f0b610d7157610d71824283611eb2565b42600c830155610d82826001610f2f565b610d8d826000610f2f565b919050565b6000806000610da68a8a8a8a8a8a8a611f30565b9093509150610db88989898989611c34565b600086610ddc57610dd7610dd0600f8a900b88611cbe565b8c90611d26565b610dde565b855b905082610deb858361509a565b610df5919061509a565b9150509750975097945050505050565b600081610e2a57600080516020615711833981519152546001600160a01b0316610c79565b50507fbbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df52ec546001600160a01b031690565b80610e6457505050565b60405163a9059cbb60e01b81526001600160a01b0384811660048301526024820183905283169063a9059cbb90604401602060405180830381600087803b158015610eae57600080fd5b505af1158015610ec2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee6919061512e565b610f2a5760405162461bcd60e51b8152602060048201526015602482015274115490cc8c081d1c985b9cd9995c8819985a5b1959605a1b6044820152606401610399565b505050565b8015156000908152601383016020526040902080541580610f505750805442105b15610f5a57505050565b6000610f668484610fbf565b9050610fa18482610f9b610f908660010154610f8b898b6121f990919063ffffffff16565b61222b565b600f86900b90612241565b86611213565b50501515600090815260139091016020526040812081815560010155565b600080610fdc83610fd1576001610fd4565b60005b600080610be5565b8315156000908152601386016020526040902060010154909150610c22906000805160206156f183398151915260008481526020919091526040902054611023919061509a565b610f8b86866121f9565b60008161105a577f0300000000000000000000000000000000000000000000000000000000000000610c79565b7f020000000000000000000000000000000000000000000000000000000000000092915050565b6001600160a01b0383166110e35760405162461bcd60e51b815260206004820152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b6064820152608401610399565b611111338460006110f386612275565b6110fc86612275565b604051806020016040528060008152506122c0565b60008281527f1799cf914cb0cb442ca7c7ac709ee40d0cb89e87351dc08d517fbda27d50c68b602090815260408083206001600160a01b038716845291829052909120548211156111b25760405162461bcd60e51b815260206004820152602560248201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015264616e63657360d81b6064820152608401610399565b6001600160a01b03841660008181526020838152604080832080548790039055805187815291820186905291929133917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a450505050565b600061121f85836127de565b9050600061123086838787876127f7565b905061123d8682856128fd565b60408051600f83810b825287810b602083015286900b91810191909152831515907f4e23621c6f591f14bf9505cb8326b45af9dc6c5569fd608de2a7a2ddd6146b2e90606001610492565b6001600160a01b03808416600090815260178601602090815260408083208615158452825280832054601889019092529091205490917f000000000000000000000000bc3c01d954282eed8433da4359c1ac1443a7d09a1663edaf7d5b863087866112f3898261509a565b876040518763ffffffff1660e01b8152600401611315969594939291906150b1565b600060405180830381600087803b15801561132f57600080fd5b505af1158015611343573d6000803e3d6000fd5b505050508282611353919061509a565b6001600160a01b038616600090815260178801602090815260408083208815158452909152902055611385838261509a565b9315156000908152601890960160205250506040909320555050565b6000806113ad8361102d565b90506113d97f0000000000000000000000007bf2392bd078c8353069cffeacc67c094079be2382610c7f565b915081156114495761140c7f0000000000000000000000007bf2392bd078c8353069cffeacc67c094079be238284611081565b8215157f496915fc2759ccee8966a2c2098c4895c608b8decdb351dccea354eb4ca9c4f08360405161144091815260200190565b60405180910390a25b50919050565b60607f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b03168484600081811061148e5761148e6150fd565b90506020020160208101906114a3919061514b565b6001600160a01b0316146114f95760405162461bcd60e51b815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f504154480000006044820152606401610399565b61158582611527577f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f611549565b7f000000000000000000000000c35dadb65012ec5796536bd9864ed8773abc74c45b86868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250889250612954915050565b9050348160008151811061159b5761159b6150fd565b602002602001015111156115c15760405162461bcd60e51b815260040161039990615166565b7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b031663d0e30db082600081518110611603576116036150fd565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561163657600080fd5b505af115801561164a573d6000803e3d6000fd5b50505050507f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b031663a9059cbb611724846116ac577f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f6116ce565b7f000000000000000000000000c35dadb65012ec5796536bd9864ed8773abc74c45b878760008181106116e1576116e16150fd565b90506020020160208101906116f6919061514b565b88886001818110611709576117096150fd565b905060200201602081019061171e919061514b565b87612ae2565b83600081518110611737576117376150fd565b60200260200101516040518363ffffffff1660e01b81526004016117709291906001600160a01b03929092168252602082015260400190565b602060405180830381600087803b15801561178a57600080fd5b505af115801561179e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c2919061512e565b6117ce576117ce6151ad565b61180f81858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250339250879150612be39050565b80600081518110611822576118226150fd565b6020026020010151341115610c22576000336001600160a01b031682600081518110611850576118506150fd565b602002602001015134611863919061509a565b6040805160008152602081019182905261187c916151ef565b60006040518083038185875af1925050503d80600081146118b9576040519150601f19603f3d011682016040523d82523d6000602084013e6118be565b606091505b505090508061192c5760405162461bcd60e51b815260206004820152603460248201527f5472616e7366657248656c7065723a3a736166655472616e736665724554483a60448201527308115512081d1c985b9cd9995c8819985a5b195960621b6064820152608401610399565b50949350505050565b60606119c382611965577f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f611987565b7f000000000000000000000000c35dadb65012ec5796536bd9864ed8773abc74c45b87868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250889250612954915050565b905084816000815181106119d9576119d96150fd565b602002602001015111156119ff5760405162461bcd60e51b815260040161039990615166565b611a8533611a31846116ac577f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f6116ce565b83600081518110611a4457611a446150fd565b602002602001015187876000818110611a5f57611a5f6150fd565b9050602002016020810190611a74919061514b565b6001600160a01b0316929190612e3f565b611ac681858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250339250879150612be39050565b95945050505050565b3360009081527fbbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df52f9602090815260408083208515158452909152812081905560008051602061571183398151915290611b278285612e9f565b84151560009081526018840160205260409020549091508190611b4b90879061505d565b1115611b995760405162461bcd60e51b815260206004820152601860248201527f706f6f6c206465706f73697420636170207265616368656400000000000000006044820152606401610399565b611ba38285610f2f565b336000818152600d84016020908152604080832088151584529091529020429055611bd19083908688612eb9565b611be533611bde86610e05565b8786612fb6565b611bf03386866132b1565b6040805185151581526020810187905233917f74a132f462598ad738fcdf934a3f668aac78953afdb0c9fb953e16e07cca511c910160405180910390a25050505050565b6000611c4b611c44846001613374565b8686610be5565b90506000611c64611c5d856000613374565b8787610be5565b9050611c71878385611081565b611c7c878285611081565b60408051828152602081018590527f2c36fd3d1ab99ca7bec7ffe3c66b81f331da75eeda6c23fda680a77a7c458979910160405180910390a150505050505050565b600081611ccd57506000610c79565b600083600f0b1215611cde57600080fd5b600f83900b6001600160801b038316810260401c90608084901c026001600160c01b03811115611d0d57600080fd5b60401b8119811115611d1e57600080fd5b019392505050565b600080611d44838560030160149054906101000a900460ff1661222b565b9050610c22818560030160159054906101000a900460ff166133a7565b60006011830181611d74610e1085615221565b8152602081019190915260400160002054600f0b9392505050565b6000808260030160009054906101000a90046001600160a01b03166001600160a01b03166350d25bcd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611de257600080fd5b505afa158015611df6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e1a9190615243565b905060008360020160009054906101000a90046001600160a01b03166001600160a01b03166350d25bcd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e6e57600080fd5b505afa158015611e82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea69190615243565b9050610c2282826133c2565b6000611ec0610e1084615221565b6000818152601186016020526040902080546001600160801b0319166001600160801b0385161790559050611ef960ff8083169061509a565b6001901b846012016000600884901c81526020019081526020016000206000828254611f25919061505d565b909155505050505050565b60008042876001600160401b031611611f755760405162461bcd60e51b8152602060048201526007602482015266195e1c1a5c995960ca1b6044820152606401610399565b8860050154841015611fb55760405162461bcd60e51b81526020600482015260096024820152681d1bdbc81cdb585b1b60ba1b6044820152606401610399565b600085611fd957611fd4611fcd600f89900b87611cbe565b8b90611d26565b611fdb565b845b861515600090815260138c0160205260409020600101549091506000805160206156f1833981519152600061200f89610c2a565b815260200190815260200160002054612028919061509a565b8111156120635760405162461bcd60e51b8152602060048201526009602482015268696e737566206c697160b81b6044820152606401610399565b5060006120b56040518060c001604052808b6001600160a01b031681526020018a6001600160401b0316815260200189600f0b815260200186600f0b815260200187815260200188151581525061345d565b80519091506120cd906120c88c896121f9565b6133a7565b60208201519093506120e3906120c88c896121f9565b915060006120fc6120f5886001613374565b8a8a610be5565b9050600061211561210e896000613374565b8b8b610be5565b90506121228b83896138f9565b600061212e8d8a610fbf565b905061213e8d8d8a89868e613914565b600061214a8e8b610fbf565b90506121588e83838d611213565b61218b7f0000000000000000000000007bf2392bd078c8353069cffeacc67c094079be236121858c61102d565b886138f9565b60408051858152602081018b905290810188905260608101879052600f89900b60808201526001600160a01b038e16907f4719d073a940c087132bffc1aac4f3837ca2c820d95574727828ce38f7fbc8c79060a00160405180910390a2505050505097509795505050505050565b600081612214576003830154600160a81b900460ff16612224565b6003830154600160a01b900460ff165b9392505050565b60006122248361223c84600a615340565b613ba6565b6000600f83810b9083900b0160016001607f1b0319811280159061226c575060016001607f1b038113155b61222457600080fd5b604080516001808252818301909252606091600091906020808301908036833701905050905082816000815181106122af576122af6150fd565b602090810291909101015292915050565b6122ce868686868686613bdd565b60008051602061571183398151915260005b84518110156127d45760008582815181106122fd576122fd6150fd565b60200260200101519050600085838151811061231b5761231b6150fd565b6020026020010151905080600014156123355750506127c2565b6001600160a01b038916612352576123506015850183613dc0565b505b6001600160a01b038816158015612382575060008281526000805160206156f18339815191526020526040902054155b15612396576123946015850183613dcc565b505b7f00000000000000000000000000000000000000000000000000000000000000008214806123e357507f010000000000000000000000000000000000000000000000000000000000000082145b8061240d57507f020000000000000000000000000000000000000000000000000000000000000082145b8061243757507f030000000000000000000000000000000000000000000000000000000000000082145b15612509576001600160a01b0389161580159061245c57506001600160a01b03881615155b156125095760007f00000000000000000000000000000000000000000000000000000000000000008314806124b057507f020000000000000000000000000000000000000000000000000000000000000083145b6001600160a01b038b166000908152600d870160209081526040808320841515845290915290205490915042906124ea906201518061505d565b106125075760405162461bcd60e51b815260040161039990615075565b505b7f000000000000000000000000000000000000000000000000000000000000000082148061255657507f010000000000000000000000000000000000000000000000000000000000000082145b156126fe577f00000000000000000000000000000000000000000000000000000000000000008214600061258a8683613dd8565b90506001600160a01b038b16156126b45760006125a78c86610c7f565b905081811180156125c157506125bd828561505d565b8111155b15612659576001600160a01b038c166000908152601488016020908152604080832086151580855260138c0184528285205485529083528184209084529091529020548490612610908361509a565b101561264e5760405162461bcd60e51b815260206004820152600d60248201526c496e7375662062616c616e636560981b6044820152606401610399565b612659878d85613df2565b6001600160a01b038b16156126b25761268d878d858c8a81518110612680576126806150fd565b6020026020010151611288565b6126b2878c858c8a815181106126a5576126a56150fd565b6020026020010151612eb9565b505b6001600160a01b038a16156126fb5760006126cf8b86610c7f565b90508181111580156126e95750816126e7858361505d565b115b156126f9576126f9878c85613ea3565b505b50505b60f882901c826001600160a01b038b161580159061272457506001600160a01b038a1615155b801561275c5750600582600781111561273f5761273f615031565b148061275c5750600782600781111561275a5761275a615031565b145b156127bd576000600583600781111561277757612777615031565b14905060008161279e57612799612792600f85900b87611cbe565b8990611d26565b6127a0565b845b90506127ae888e8484611288565b6127ba888d8484612eb9565b50505b505050505b806127cc81615113565b9150506122e0565b5050505050505050565b60006127ea8383613f4b565b9050612224838284613f72565b6000808261280c576019870154600f0b61281c565b6019870154600160801b9004600f0b5b905080600f0b6000141561283457506008860154600f0b5b60405163e101a89b60e01b8152600f87810b600483015286810b602483015285810b604483015282900b606482015273c7a7275bc25a7bf07c6d0c2f8784c5450cb9b8f59063e101a89b9060840160206040518083038186803b15801561289a57600080fd5b505af41580156128ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128d29190615361565b915067b33333333333333382600f0b12156128f35767b33333333333333391505b5095945050505050565b801561292d576009830180546001600160801b0384166001600160801b031990911617905542600b840155505050565b6008830180546001600160801b03808516600160801b02911617905542600a840155505050565b60606002835110156129a85760405162461bcd60e51b815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f5041544800006044820152606401610399565b82516001600160401b038111156129c1576129c16150e7565b6040519080825280602002602001820160405280156129ea578160200160208202803683370190505b5090508381600183516129fd919061509a565b81518110612a0d57612a0d6150fd565b602002602001018181525050600060018451612a29919061509a565b90505b801561192c57600080612a7d8887612a4560018761509a565b81518110612a5557612a556150fd565b6020026020010151888681518110612a6f57612a6f6150fd565b602002602001015188614134565b91509150612aa5848481518110612a9657612a966150fd565b6020026020010151838361420f565b84612ab160018661509a565b81518110612ac157612ac16150fd565b60200260200101818152505050508080612ada9061537c565b915050612a2c565b6000806000612af18686614335565b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b166034820152919350915087906048016040516020818303038152906040528051906020012085612b77576040518060400160405280602081526020017f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f815250612bae565b6040518060400160405280602081526020017fe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c63038152505b604051602001612bc093929190615393565b60408051601f198184030181529190528051602090910120979650505050505050565b60005b60018451612bf4919061509a565b811015610bde57600080858381518110612c1057612c106150fd565b602002602001015186846001612c26919061505d565b81518110612c3657612c366150fd565b6020026020010151915091506000612c4e8383614335565b509050600088612c5f86600161505d565b81518110612c6f57612c6f6150fd565b60200260200101519050600080836001600160a01b0316866001600160a01b031614612c9d57826000612ca1565b6000835b91509150600060028b51612cb5919061509a565b8810612cc15789612d3c565b612d3c89612cef577f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f612d11565b7f000000000000000000000000c35dadb65012ec5796536bd9864ed8773abc74c45b878d612d1e8c600261505d565b81518110612d2e57612d2e6150fd565b60200260200101518c612ae2565b9050612d9689612d6c577f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f612d8e565b7f000000000000000000000000c35dadb65012ec5796536bd9864ed8773abc74c45b88888c612ae2565b6001600160a01b031663022c0d9f84848460006040519080825280601f01601f191660200182016040528015612dd3576020820181803683370190505b506040518563ffffffff1660e01b8152600401612df39493929190615408565b600060405180830381600087803b158015612e0d57600080fd5b505af1158015612e21573d6000803e3d6000fd5b50505050505050505050508080612e3790615113565b915050612be6565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612e9990859061442d565b50505050565b600081612eb0578260060154612224565b50506007015490565b6001600160a01b03808416600090815260178601602090815260408083208615158452825280832054601889019092529091205490917f000000000000000000000000bc3c01d954282eed8433da4359c1ac1443a7d09a1663edaf7d5b86308786612f24898261505d565b876040518763ffffffff1660e01b8152600401612f46969594939291906150b1565b600060405180830381600087803b158015612f6057600080fd5b505af1158015612f74573d6000803e3d6000fd5b505050508282612f84919061505d565b6001600160a01b038616600090815260178801602090815260408083208815158452909152902055611385838261505d565b806131df577f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b0316836001600160a01b0316141561319e573415613199578134111561311f577f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b15801561305e57600080fd5b505af1158015613072573d6000803e3d6000fd5b50505050506000336001600160a01b0316833461308f919061509a565b604051600081818185875af1925050503d80600081146130cb576040519150601f19603f3d011682016040523d82523d6000602084013e6130d0565b606091505b50509050806131155760405162461bcd60e51b8152602060048201526011602482015270115512081c99599d5b990819985a5b1959607a1b6044820152606401610399565b60009250506131df565b34820391507f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561317f57600080fd5b505af1158015613193573d6000803e3d6000fd5b50505050505b6131df565b34156131df5760405162461bcd60e51b815260206004820152601060248201526f1b9bdd0815d155120819195c1bdcda5d60821b6044820152606401610399565b8115612e99576040516323b872dd60e01b81526001600160a01b038581166004830152306024830152604482018490528416906323b872dd90606401602060405180830381600087803b15801561323557600080fd5b505af1158015613249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061326d919061512e565b612e995760405162461bcd60e51b8152602060048201526015602482015274115490cc8c081d1c985b9cd9995c8819985a5b1959605a1b6044820152606401610399565b6000805160206157118339815191526132d3846132cd84610c2a565b856138f9565b6000610104806132e38142615221565b6132ed9190615435565b6132f7919061505d565b6001600160a01b038616600090815260148401602090815260408083208484528252808320871515845290915281208054929350869290919061333b90849061505d565b9091555050821515600090815260138301602052604081206001810180549192879261336890849061505d565b90915550505550505050565b60008215613392578161338857600561338b565b60045b9050610c79565b8161339e576007612224565b50600692915050565b60006122246133b783600a615340565b600f85900b90611cbe565b6000816133ce57600080fd5b6000808412156133e357836000039350600190505b60008312156133f55760009290920391155b600061340185856144ff565b9050811561342f576001607f1b816001600160801b0316111561342357600080fd5b6000039150610c799050565b60016001607f1b03816001600160801b0316111561344c57600080fd5b9150610c799050565b505092915050565b60408051608081018252600080825260208201819052918101829052606081019190915260008260400151600f0b13801561349f575060008260600151600f0b135b80156134b85750600082602001516001600160401b0316115b6134f35760405162461bcd60e51b815260206004820152600c60248201526b696e76616c6964206172677360a01b6044820152606401610399565b60808201517fbbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df52ee54600080516020615711833981519152916000916135419190600160a01b900460ff1661222b565b60a085015190915060008061356c61355986856127de565b6135638786610fbf565b87919086614661565b91509150600081600f0b136135ac5760405162461bcd60e51b81526020600482015260066024820152656e6f206c697160d01b6044820152606401610399565b60006135d44289602001516001600160401b03166135ca919061509a565b6301e13380613ba6565b8654600188015460608b01516040808d0151905163c4afd30d60e01b81526001600160a01b0394851660048201529284166024840152600f91820b6044840152810b606483015283900b608482015286151560a48201529192506000917f000000000000000000000000c4b2c51f969e0713e799de73b7f130fb7bb604cf9091169063c4afd30d9060c40160206040518083038186803b15801561367757600080fd5b505afa15801561368b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136af9190615361565b9050600081600f0b136136ee5760405162461bcd60e51b81526020600482015260076024820152660766f6c203d20360cc1b6044820152606401610399565b600080600073c7a7275bc25a7bf07c6d0c2f8784c5450cb9b8f5630313686c60405180610140016040528061372f8889600f0b6146e990919063ffffffff16565b600f0b81526020018f60400151600f0b81526020018f60600151600f0b815260200188600f0b81526020018a600f0b815260200189600f0b81526020016137828d8b600f0b61471f90919063ffffffff16565b600f0b8152602001600160401b600f0b8152602001674ccccccccccccccd600f0b81526020018b15158152506040518263ffffffff1660e01b81526004016137ca9190615454565b60606040518083038186803b1580156137e257600080fd5b505af41580156137f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061381a919061551d565b9250925092508761383857613833600f84900b8a6146e9565b613858565b60608c01516138589061384f600f86900b8c6146e9565b600f0b90614752565b600f0b808c52613888907f00000000000000000000000000000000000000000000000007ae147ae147ae146146e9565b600f90810b60208d015282810b60408d015281900b60608c01528b516000906138bc906138b4906147aa565b612710613ba6565b60208d01519091506138d190600f0b826146e9565b8c6020018181516138e29190615560565b600f0b9052509a9c9b505050505050505050505050565b610f2a83838360405180602001604052806000815250614874565b600061391f82610c2a565b9050826000836139465761394161393a600f84900b89611cbe565b8a90611d26565b613948565b865b90505b8015610626578315156000908152600f8a01602090815260408083208380529091528120546001600160a01b0316906139848286610c7f565b90506139908b87613dd8565b8110156139a9576139a28b8388613df2565b505061394b565b6139b48b838861499b565b6139e2576139c3828683611081565b6139d6826139d08861102d565b836138f9565b6139a28b838884611288565b6000836139ef8a8261505d565b8d6014016000866001600160a01b03166001600160a01b0316815260200190815260200160002060008f60130160008c15151515815260200190815260200160002060000154815260200190815260200160002060008a1515151581526020019081526020016000205484613a64919061509a565b613a6e9190615435565b613a789190615221565b905080613a875750505061394b565b83811115613a925750825b600084613a9f838c615435565b613aa99190615221565b9050613ab5818b61509a565b9950613ac1828661509a565b9450613acf8d858a84612eb9565b613ae38488613ade848661509a565b611081565b87613b0e57613b0b613b0483613afb89600f0b6149d5565b600f0b90611cbe565b8e90614a2b565b91505b613b25848a8715613b1f57846138f9565b8d6138f9565b8b6001600160a01b0316846001600160a01b03167fa30eb1f1bb0892af5e3389941c42bc7f44a8bf7b6071ecfe3e964673c908f2b28b88600014613b695785613b6b565b8e5b60408051928352602083019190915281018590526000606082015260800160405180910390a3613b9b828c61509a565b9a505050505061394b565b600081613bb257600080fd5b6000613bbe84846144ff565b905060016001607f1b036001600160801b038216111561222457600080fd5b836001600160a01b0316856001600160a01b031614610a5d576001600160a01b0385811660009081527fb31c2c74f86ca3ce94d901f5f5bbe66f7161eec2f7b5aa0b75a86371436424ec6020526040808220928716825281206000805160206156f1833981519152927fb31c2c74f86ca3ce94d901f5f5bbe66f7161eec2f7b5aa0b75a86371436424eb929091905b8751811015613db3576000878281518110613c8957613c896150fd565b602002602001015190506000811115613da0576000898381518110613cb057613cb06150fd565b6020026020010151905060006001600160a01b03168c6001600160a01b03161415613cfe5760008181526020889052604081208054849290613cf390849061505d565b90915550613d349050565b81613d098d83610c7f565b1415613d34576000818152602087905260409020613d27908d614a66565b50613d328582613dcc565b505b6001600160a01b038b16613d6b5760008181526020889052604081208054849290613d6090849061509a565b90915550613d9e9050565b613d758b82610c7f565b613d9e576000818152602087905260409020613d91908c614a7b565b50613d9c8482613dc0565b505b505b5080613dab81615113565b915050613c6c565b5050505050505050505050565b60006122248383614a8c565b60006122248383614adb565b600081613de9578260040154612224565b50506005015490565b6001600160a01b038216613e0557600080fd5b8015156000908152600f84016020908152604080832060108701909252909120613e30848383614bc6565b613e3b575050505050565b6001600160a01b0393841660008181526020838152604080832080549683528184208054978a16808652838620805499909b166001600160a01b0319998a168117909b5599855295909252822080548616909717909655528054821690558254169091555050565b6001600160a01b038216613eb657600080fd5b8015156000908152600f84016020908152604080832060108701909252909120613ee1848383614bc6565b15613eed575050505050565b60008080526020828152604080832080546001600160a01b0390811680865296845282852080546001600160a01b03199081169a909216998a1790558885529490925282208054841690941790935580528154169092179091555050565b600081613f66576008830154600160801b9004600f0b612224565b505060090154600f0b90565b60008082613f845784600a0154613f8a565b84600b01545b613f94904261509a565b905061a8c0811115613fb357613fac61a8c08261509a565b9050613fbc565b83915050612224565b6000613fca82613840613ba6565b90506000613fdd85610fd1576001610fd4565b851515600090815260188901602090815260408083205460138c018352818420600101548585526000805160206156f1833981519152909352908320549394509261403b9161402b9161509a565b614035908461509a565b83613ba6565b6040805161012081018252600f87810b82528b810b602083015283900b8183015267b333333333333333606082015267e66666666666666660808201819052600160401b60a0830181905260c083015260e082015268056fc2a2c515da32ea6101008201529051634916d70d60e01b815291925073c7a7275bc25a7bf07c6d0c2f8784c5450cb9b8f591634916d70d916140d7916004016155b0565b60206040518083038186803b1580156140ef57600080fd5b505af4158015614103573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141279190615361565b9998505050505050505050565b60008060006141438686614335565b50905060008061415589898989612ae2565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561418d57600080fd5b505afa1580156141a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141c59190615677565b506001600160701b031691506001600160701b03169150826001600160a01b0316886001600160a01b0316146141fc5780826141ff565b81815b909a909950975050505050505050565b60008084116142755760405162461bcd60e51b815260206004820152602c60248201527f556e697377617056324c6962726172793a20494e53554646494349454e545f4f60448201526b155514155517d05353d5539560a21b6064820152608401610399565b6000831180156142855750600082115b6142e25760405162461bcd60e51b815260206004820152602860248201527f556e697377617056324c6962726172793a20494e53554646494349454e545f4c604482015267495155494449545960c01b6064820152608401610399565b60006142ee8585615435565b6142fa906103e8615435565b90506000614308868561509a565b614314906103e5615435565b90506143208183615221565b61432b90600161505d565b9695505050505050565b600080826001600160a01b0316846001600160a01b031614156143a85760405162461bcd60e51b815260206004820152602560248201527f556e697377617056324c6962726172793a204944454e544943414c5f41444452604482015264455353455360d81b6064820152608401610399565b826001600160a01b0316846001600160a01b0316106143c85782846143cb565b83835b90925090506001600160a01b0382166144265760405162461bcd60e51b815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f4144445245535300006044820152606401610399565b9250929050565b6000614482826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614c129092919063ffffffff16565b805190915015610f2a57808060200190518101906144a0919061512e565b610f2a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610399565b60008161450b57600080fd5b60006001600160c01b0384116145365782604085901b8161452e5761452e61520b565b04905061464d565b60c084811c640100000000811061454f576020918201911c5b620100008110614561576010918201911c5b6101008110614572576008918201911c5b60108110614582576004918201911c5b60048110614592576002918201911c5b600281106145a1576001820191505b60bf820360018603901c6001018260ff0387901b816145c2576145c261520b565b0492506001600160801b038311156145d957600080fd5b608085901c83026001600160801b038616840260c088901c604089901b82811015614605576001820391505b608084901b9290038281101561461c576001820391505b829003608084901c8214614632576146326151ad565b8881816146415761464161520b565b04870196505050505050505b6001600160801b0381111561222457600080fd5b80151560009081526013850160205260408120600181015482919082901580159061468c5750815415155b8015614699575081544210155b156146d75760018201546146b190610f8b8a886121f9565b90506146c1600f87900b82612241565b92506146d088888886896127f7565b93506146de565b8693508592505b505094509492505050565b6000600f83810b9083900b0260401d60016001607f1b0319811280159061226c575060016001607f1b0381131561222457600080fd5b6000600f82810b9084900b0360016001607f1b0319811280159061226c575060016001607f1b0381131561222457600080fd5b600081600f0b6000141561476557600080fd5b600082600f0b604085600f0b901b816147805761478061520b565b05905060016001607f1b0319811280159061226c575060016001607f1b0381131561222457600080fd5b60007f0000000000000000000000007fa86681a7c19416950bae6c04a5116f3b07116d6001600160a01b031615610d8d576040516303793c8d60e11b81526001600160a01b0383811660048301527f0000000000000000000000007fa86681a7c19416950bae6c04a5116f3b07116d16906306f2791a9060240160206040518083038186803b15801561483c57600080fd5b505afa158015614850573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c799190615243565b6001600160a01b0384166148d45760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610399565b6148f3336000866148e487612275565b6148ed87612275565b866122c0565b60008381527f1799cf914cb0cb442ca7c7ac709ee40d0cb89e87351dc08d517fbda27d50c68b602090815260408083206001600160a01b038816845291829052822080549192859261494690849061505d565b909155505060408051858152602081018590526001600160a01b0387169160009133917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a45050505050565b6001600160a01b0382166000908152600e8401602090815260408083208415158452909152812054801580611ac657504210949350505050565b600081600f0b600014156149e857600080fd5b600082600f0b600160801b81614a0057614a0061520b565b05905060016001607f1b03198112801590614a22575060016001607f1b038113155b610c7957600080fd5b600080614a49838560030160159054906101000a900460ff1661222b565b9050610c22818560030160149054906101000a900460ff166133a7565b6000612224836001600160a01b038416614adb565b6000612224836001600160a01b0384165b6000818152600183016020526040812054614ad357508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610c79565b506000610c79565b60008181526001830160205260408120548015614bbc576000614aff60018361509a565b85549091506000908690614b159060019061509a565b81548110614b2557614b256150fd565b9060005260206000200154905080866000018381548110614b4857614b486150fd565b600091825260209091200155614b5f82600161505d565b60008281526001880160205260409020558554869080614b8157614b816156c7565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610c79565b6000915050610c79565b6001600160a01b03838116600090815260208490526040812054909116151580610c2257506000808052602083905260409020546001600160a01b039081169085161490509392505050565b6060610c2284846000856060843b614c805760405162461bcd60e51b815260206004820152602b60248201527f416464726573735574696c733a2066756e6374696f6e2063616c6c20746f206e60448201526a1bdb8b58dbdb9d1c9858dd60aa1b6064820152608401610399565b600080866001600160a01b03168587604051614c9c91906151ef565b60006040518083038185875af1925050503d8060008114614cd9576040519150601f19603f3d011682016040523d82523d6000602084013e614cde565b606091505b50915091508115614cf2579150610c229050565b805115614d025780518082602001fd5b8360405162461bcd60e51b815260040161039991906156dd565b801515811461025157600080fd5b600060208284031215614d3c57600080fd5b813561222481614d1c565b60008083601f840112614d5957600080fd5b5081356001600160401b03811115614d7057600080fd5b6020830191508360208260051b850101111561442657600080fd5b600080600080600060608688031215614da357600080fd5b8535614dae81614d1c565b945060208601356001600160401b0380821115614dca57600080fd5b614dd689838a01614d47565b90965094506040880135915080821115614def57600080fd5b50614dfc88828901614d47565b969995985093965092949392505050565b600081518084526020808501945080840160005b83811015614e3d57815187529582019590820190600101614e21565b509495945050505050565b608081526000614e5b6080830187614e0d565b8281036020840152614e6d8187614e0d565b604084019590955250506060015292915050565b60008060408385031215614e9457600080fd5b50508035926020909101359150565b60008060408385031215614eb657600080fd5b823591506020830135614ec881614d1c565b809150509250929050565b80356001600160a01b0381168114610d8d57600080fd5b60008060408385031215614efd57600080fd5b614f0683614ed3565b91506020830135614ec881614d1c565b600080600080600080600060c0888a031215614f3157600080fd5b873596506020880135614f4381614d1c565b9550604088013594506060880135935060808801356001600160401b03811115614f6c57600080fd5b614f788a828b01614d47565b90945092505060a0880135614f8c81614d1c565b8091505092959891949750929550565b60008060408385031215614faf57600080fd5b82356001600160401b0381168114614f0657600080fd5b60008060008060408587031215614fdc57600080fd5b84356001600160401b0380821115614ff357600080fd5b614fff88838901614d47565b9096509450602087013591508082111561501857600080fd5b5061502587828801614d47565b95989497509550505050565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000821982111561507057615070615047565b500190565b6020808252600b908201526a1b1a5c481b1bd8dac80c5960aa1b604082015260600190565b6000828210156150ac576150ac615047565b500390565b6001600160a01b03968716815294909516602085015291151560408401526060830152608082015260a081019190915260c00190565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600060001982141561512757615127615047565b5060010190565b60006020828403121561514057600080fd5b815161222481614d1c565b60006020828403121561515d57600080fd5b61222482614ed3565b60208082526027908201527f556e69737761705632526f757465723a204558434553534956455f494e50555460408201526617d05353d5539560ca1b606082015260800190565b634e487b7160e01b600052600160045260246000fd5b60005b838110156151de5781810151838201526020016151c6565b83811115612e995750506000910152565b600082516152018184602087016151c3565b9190910192915050565b634e487b7160e01b600052601260045260246000fd5b60008261523e57634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561525557600080fd5b5051919050565b600181815b8085111561529757816000190482111561527d5761527d615047565b8085161561528a57918102915b93841c9390800290615261565b509250929050565b6000826152ae57506001610c79565b816152bb57506000610c79565b81600181146152d157600281146152db576152f7565b6001915050610c79565b60ff8411156152ec576152ec615047565b50506001821b610c79565b5060208310610133831016604e8410600b841016171561531a575081810a610c79565b615324838361525c565b806000190482111561533857615338615047565b029392505050565b600061222460ff84168361529f565b8051600f81900b8114610d8d57600080fd5b60006020828403121561537357600080fd5b6122248261534f565b60008161538b5761538b615047565b506000190190565b60ff60f81b81526bffffffffffffffffffffffff198460601b166001820152826015820152600082516153cd8160358501602087016151c3565b91909101603501949350505050565b600081518084526153f48160208601602086016151c3565b601f01601f19169290920160200192915050565b84815283602082015260018060a01b038316604082015260806060820152600061432b60808301846153dc565b600081600019048311821515161561544f5761544f615047565b500290565b8151600f0b8152610140810160208301516154746020840182600f0b9052565b5060408301516154896040840182600f0b9052565b50606083015161549e6060840182600f0b9052565b5060808301516154b36080840182600f0b9052565b5060a08301516154c860a0840182600f0b9052565b5060c08301516154dd60c0840182600f0b9052565b5060e08301516154f260e0840182600f0b9052565b506101008084015161550882850182600f0b9052565b50506101208381015180151584830152613455565b60008060006060848603121561553257600080fd5b61553b8461534f565b92506155496020850161534f565b91506155576040850161534f565b90509250925092565b600081600f0b83600f0b600081128160016001607f1b03190183128115161561558b5761558b615047565b8160016001607f1b030183138116156155a6576155a6615047565b5090039392505050565b6000610120820190508251600f0b82526020830151600f0b602083015260408301516155e16040840182600f0b9052565b5060608301516155f66060840182600f0b9052565b50608083015161560b6080840182600f0b9052565b5060a083015161562060a0840182600f0b9052565b5060c083015161563560c0840182600f0b9052565b5060e083015161564a60e0840182600f0b9052565b506101008084015161345582850182600f0b9052565b80516001600160701b0381168114610d8d57600080fd5b60008060006060848603121561568c57600080fd5b61569584615660565b92506156a360208501615660565b9150604084015163ffffffff811681146156bc57600080fd5b809150509250925092565b634e487b7160e01b600052603160045260246000fd5b60208152600061222460208301846153dc56feb31c2c74f86ca3ce94d901f5f5bbe66f7161eec2f7b5aa0b75a86371436424eabbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df52eba264697066735822122001aa5baa08f11f41aee0d511e5b1f8b80113a83a20b79929c17f071ff95d893c64736f6c63430008090033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c4b2c51f969e0713e799de73b7f130fb7bb604cf00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000bc3c01d954282eed8433da4359c1ac1443a7d09a0000000000000000000000007bf2392bd078c8353069cffeacc67c094079be230000000000000000000000007fa86681a7c19416950bae6c04a5116f3b07116d00000000000000000000000000000000000000000000000007ae147ae147ae140000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f000000000000000000000000c35dadb65012ec5796536bd9864ed8773abc74c4
-----Decoded View---------------
Arg [0] : ivolOracle (address): 0xC4B2C51f969e0713E799De73b7f130Fb7Bb604CF
Arg [1] : weth (address): 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1
Arg [2] : premiaMining (address): 0xbC3c01D954282eEd8433da4359C1ac1443a7d09A
Arg [3] : feeReceiver (address): 0x7bf2392bd078C8353069CffeAcc67c094079be23
Arg [4] : feeDiscountAddress (address): 0x7Fa86681A7c19416950bAE6c04A5116f3b07116D
Arg [5] : fee64x64 (int128): 553402322211286548
Arg [6] : uniswapV2Factory (address): 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f
Arg [7] : sushiswapFactory (address): 0xc35DADB65012eC5796536bD9864eD8773aBc74C4
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000c4b2c51f969e0713e799de73b7f130fb7bb604cf
Arg [1] : 00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1
Arg [2] : 000000000000000000000000bc3c01d954282eed8433da4359c1ac1443a7d09a
Arg [3] : 0000000000000000000000007bf2392bd078c8353069cffeacc67c094079be23
Arg [4] : 0000000000000000000000007fa86681a7c19416950bae6c04a5116f3b07116d
Arg [5] : 00000000000000000000000000000000000000000000000007ae147ae147ae14
Arg [6] : 0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f
Arg [7] : 000000000000000000000000c35dadb65012ec5796536bd9864ed8773abc74c4
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.