Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
9.531832907670688078 ETH
Eth Value
$32,540.91 (@ $3,413.92/ETH)Token Holdings
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 508 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Sell | 20747296 | 104 days ago | IN | 0 ETH | 0.00037192 | ||||
Sell | 20742055 | 104 days ago | IN | 0 ETH | 0.00086859 | ||||
Sell | 20741938 | 104 days ago | IN | 0 ETH | 0.00098013 | ||||
Withdraw | 15586871 | 827 days ago | IN | 0 ETH | 0.00022974 | ||||
Withdraw | 15448133 | 848 days ago | IN | 0 ETH | 0.00089587 | ||||
Withdraw | 15448133 | 848 days ago | IN | 0 ETH | 0.00111611 | ||||
Withdraw | 14983562 | 923 days ago | IN | 0 ETH | 0.00150588 | ||||
Sell | 13188121 | 1205 days ago | IN | 0 ETH | 0.03818552 | ||||
Withdraw | 13059407 | 1225 days ago | IN | 0 ETH | 0.00219944 | ||||
Sell | 13006745 | 1233 days ago | IN | 0 ETH | 0.02036261 | ||||
Sell | 13006724 | 1233 days ago | IN | 0 ETH | 0.01702484 | ||||
Withdraw | 12906161 | 1249 days ago | IN | 0 ETH | 0.00082565 | ||||
Withdraw | 12829141 | 1261 days ago | IN | 0 ETH | 0.00128297 | ||||
Withdraw | 12817751 | 1263 days ago | IN | 0 ETH | 0.00118006 | ||||
Sell | 12802348 | 1265 days ago | IN | 0 ETH | 0.00431082 | ||||
Withdraw | 12797897 | 1266 days ago | IN | 0 ETH | 0.00066699 | ||||
Sell | 12788638 | 1267 days ago | IN | 0 ETH | 0.01046914 | ||||
Withdraw | 12763556 | 1271 days ago | IN | 0 ETH | 0.00051319 | ||||
Withdraw | 12763546 | 1271 days ago | IN | 0 ETH | 0.00051307 | ||||
Withdraw | 12763540 | 1271 days ago | IN | 0 ETH | 0.00051307 | ||||
Withdraw | 12763537 | 1271 days ago | IN | 0 ETH | 0.00051307 | ||||
Sell | 12761607 | 1271 days ago | IN | 0 ETH | 0.00246331 | ||||
Sell | 12756856 | 1272 days ago | IN | 0 ETH | 0.00117165 | ||||
Sell | 12756856 | 1272 days ago | IN | 0 ETH | 0.00123183 | ||||
Sell | 12756854 | 1272 days ago | IN | 0 ETH | 0.00123183 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
20747296 | 104 days ago | 0.01 ETH | ||||
20742055 | 104 days ago | 0.1 ETH | ||||
20741938 | 104 days ago | 0.1 ETH | ||||
15586871 | 827 days ago | 0.10335302 ETH | ||||
15448133 | 848 days ago | 0.0206706 ETH | ||||
14983562 | 923 days ago | 0.853696 ETH | ||||
13188121 | 1205 days ago | 3 ETH | ||||
13059407 | 1225 days ago | 0.0206706 ETH | ||||
13006745 | 1233 days ago | 0.00854424 ETH | ||||
13006724 | 1233 days ago | 0.02025309 ETH | ||||
12906161 | 1249 days ago | 0.04134121 ETH | ||||
12829141 | 1261 days ago | 0.43984526 ETH | ||||
12817751 | 1263 days ago | 0.20670605 ETH | ||||
12802348 | 1265 days ago | 0.17088499 ETH | ||||
12797897 | 1266 days ago | 7.64812405 ETH | ||||
12788638 | 1267 days ago | 0.08860623 ETH | ||||
12763556 | 1271 days ago | 0.25838256 ETH | ||||
12763546 | 1271 days ago | 0.31005908 ETH | ||||
12763540 | 1271 days ago | 0.26871787 ETH | ||||
12763537 | 1271 days ago | 0.18355497 ETH | ||||
12761607 | 1271 days ago | 0.13427892 ETH | ||||
12756856 | 1272 days ago | 0.12341812 ETH | ||||
12756856 | 1272 days ago | 0.1250637 ETH | ||||
12756854 | 1272 days ago | 0.13230423 ETH | ||||
12756853 | 1272 days ago | 0.12177255 ETH |
Loading...
Loading
Minimal Proxy Contract for 0xf3e90025276fcf0955aa66f8f07f090380410d80
Contract Name:
OptionMarket
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2021-02-01 */ // SPDX-License-Identifier: MIT pragma solidity 0.6.12; // Part: ABDKMath64x64 /** * 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) { 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) { 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) { require (x <= 0x7FFFFFFFFFFFFFFF); return int128 (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) { require (x >= 0); return uint64 (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) { 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) { 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) { 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) { 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) { 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) { 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) { if (y == 0) return 0; require (x >= 0); uint256 lo = (uint256 (x) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64; uint256 hi = uint256 (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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { uint256 absoluteResult; bool negativeResult = false; if (x >= 0) { absoluteResult = powu (uint256 (x) << 63, y); } else { // We rely on overflow behavior here absoluteResult = powu (uint256 (uint128 (-x)) << 63, y); negativeResult = y & 1 > 0; } absoluteResult >>= 63; 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 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) { require (x >= 0); return int128 (sqrtu (uint256 (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) { 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 (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) { require (x > 0); return int128 ( uint256 (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) { 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 (63 - (x >> 64)); require (result <= uint256 (MAX_64x64)); return int128 (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) { 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) { 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 x^y assuming 0^0 is 1, where x is unsigned 129.127 fixed point * number and y is unsigned 256-bit integer number. Revert on overflow. * * @param x unsigned 129.127-bit fixed point number * @param y uint256 value * @return unsigned 129.127-bit fixed point number */ function powu (uint256 x, uint256 y) private pure returns (uint256) { if (y == 0) return 0x80000000000000000000000000000000; else if (x == 0) return 0; else { int256 msb = 0; uint256 xc = x; if (xc >= 0x100000000000000000000000000000000) { xc >>= 128; msb += 128; } 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 xe = msb - 127; if (xe > 0) x >>= uint256 (xe); else x <<= uint256 (-xe); uint256 result = 0x80000000000000000000000000000000; int256 re = 0; while (y > 0) { if (y & 1 > 0) { result = result * x; y -= 1; re += xe; if (result >= 0x8000000000000000000000000000000000000000000000000000000000000000) { result >>= 128; re += 1; } else result >>= 127; if (re < -127) return 0; // Underflow require (re < 128); // Overflow } else { x = x * x; y >>= 1; xe <<= 1; if (x >= 0x8000000000000000000000000000000000000000000000000000000000000000) { x >>= 128; xe += 1; } else x >>= 127; if (xe < -127) return 0; // Underflow require (xe < 128); // Overflow } } if (re > 0) result <<= uint256 (re); else if (re < 0) result >>= uint256 (-re); return 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) { 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); } } } // Part: IOracle interface IOracle { function getPrice() external view returns (uint256); } // Part: Initializable /** * @title Initializable * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. */ contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized"); bool isTopLevelCall = !initializing; if (isTopLevelCall) { initializing = true; initialized = true; } _; if (isTopLevelCall) { initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. address self = address(this); uint256 cs; assembly { cs := extcodesize(self) } return cs == 0; } // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; } // Part: OpenZeppelin/[email protected]/Address /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies in extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); return _functionCallWithValue(target, data, value, errorMessage); } function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) { require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // Part: OpenZeppelin/[email protected]/IERC20 /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // Part: OpenZeppelin/[email protected]/Math /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } } // Part: OpenZeppelin/[email protected]/SafeMath /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // Part: ContextUpgradeSafe /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract ContextUpgradeSafe is Initializable { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } uint256[50] private __gap; } // Part: OpenZeppelin/[email protected]/SafeERC20 /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } // Part: OptionMath library OptionMath { using SafeMath for uint256; uint256 public constant SCALE = 1e18; /** * Converts total supplies of options into the tokenized payoff quantities used * by the LMSR * * For puts, multiply by strike price since option quantity is in terms of the * underlying, but lmsr quantities should be in terms of the strike currency */ function calcQuantities( uint256[] memory strikePrices, bool isPut, uint256[] memory longSupplies, uint256[] memory shortSupplies ) internal pure returns (uint256[] memory) { uint256 n = strikePrices.length; require(longSupplies.length == n, "Lengths do not match"); require(shortSupplies.length == n, "Lengths do not match"); // this mutates the method arguments, but costs less gas if (isPut) { for (uint256 i = 0; i < n; i++) { longSupplies[i] = longSupplies[i].mul(strikePrices[i]).div(SCALE); shortSupplies[i] = shortSupplies[i].mul(strikePrices[i]).div(SCALE); } } // swap shortSupplies and longSupplies for puts uint256[] memory leftSupplies = isPut ? shortSupplies : longSupplies; uint256[] memory rightSupplies = isPut ? longSupplies : shortSupplies; uint256[] memory quantities = new uint256[](n + 1); // set quantities[0] = sum(rightSupplies) for (uint256 i = 0; i < n; i++) { quantities[0] = quantities[0].add(rightSupplies[i]); } // set quantities[i] = leftSupplies[:i] + rightSupplies[i:] for (uint256 i = 0; i < n; i++) { quantities[i + 1] = quantities[i].add(leftSupplies[i]).sub(rightSupplies[i]); } return quantities; } /** * Calculates the LMSR cost function * * C(q_1, ..., q_n) = b * log(exp(q_1 / b) + ... + exp(q_n / b)) * * where * * q_i = total supply of ith tokenized payoff * b = liquidity parameter * * An equivalent expression for C is used to avoid overflow when calculating exponentials * * C(q_1, ..., q_n) = m + b * log(exp((q_1 - m) / b) + ... + exp((q_n - m) / b)) * * where * * m = max(q_1, ..., q_n) */ function calcLmsrCost(uint256[] memory quantities, uint256 b) internal pure returns (uint256) { uint256 maxQuantity = quantities[0]; for (uint256 i = 1; i < quantities.length; i++) { maxQuantity = Math.max(maxQuantity, quantities[i]); } // cost converges to max(q) as b tends to 0 if (b == 0) { return maxQuantity; } int128 sumExp; for (uint256 i = 0; i < quantities.length; i++) { // max(q) - q_i uint256 diff = maxQuantity.sub(quantities[i]); // (max(q) - q_i) / b int128 div = ABDKMath64x64.divu(diff, b); // exp((q_i - max(q)) / b) int128 exp = ABDKMath64x64.exp(ABDKMath64x64.neg(div)); sumExp = ABDKMath64x64.add(sumExp, exp); } // log(sumExp) int128 log = ABDKMath64x64.ln(sumExp); // b * log(sumExp) + max(q) return ABDKMath64x64.mulu(log, b).add(maxQuantity); } /** * Calculate total payoff of all outstanding options * * This value will decrease as options are redeemed * * For calls, divide by expiry price since payoff should be in terms of the * `baseToken` */ function calcPayoff( uint256[] memory strikePrices, uint256 expiryPrice, bool isPut, uint256[] memory longSupplies, uint256[] memory shortSupplies ) internal pure returns (uint256) { require(longSupplies.length == strikePrices.length, "Lengths do not match"); require(shortSupplies.length == strikePrices.length, "Lengths do not match"); if (expiryPrice == 0) { return 0; } uint256 payoff; for (uint256 i = 0; i < strikePrices.length; i++) { uint256 strikePrice = strikePrices[i]; if (isPut && expiryPrice < strikePrice) { // put payoff = max(K - S, 0) payoff = payoff.add(longSupplies[i].mul(strikePrice.sub(expiryPrice))); } else if (!isPut && expiryPrice > strikePrice) { // call payoff = max(S - K, 0) payoff = payoff.add(longSupplies[i].mul(expiryPrice.sub(strikePrice))); } // short payoff = min(S, K) payoff = payoff.add(shortSupplies[i].mul(Math.min(expiryPrice, strikePrice))); } return payoff.div(isPut ? SCALE : expiryPrice); } } // Part: ReentrancyGuardUpgradeSafe /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ contract ReentrancyGuardUpgradeSafe is Initializable { bool private _notEntered; function __ReentrancyGuard_init() internal initializer { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal initializer { // Storing an initial non-zero value makes deployment a bit more // expensive, but in exchange the refund on every call to nonReentrant // will be lower in amount. Since refunds are capped to a percetange of // the total transaction's gas, it is best to keep them low in cases // like this one, to increase the likelihood of the full refund coming // into effect. _notEntered = true; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_notEntered, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _notEntered = false; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _notEntered = true; } uint256[49] private __gap; } // Part: ERC20UpgradeSafe /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20MinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20UpgradeSafe is Initializable, ContextUpgradeSafe, IERC20 { using SafeMath for uint256; using Address for address; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name, string memory symbol) internal initializer { __Context_init_unchained(); __ERC20_init_unchained(name, symbol); } function __ERC20_init_unchained(string memory name, string memory symbol) internal initializer { _name = name; _symbol = symbol; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } uint256[44] private __gap; } // Part: OwnableUpgradeSafe /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ contract OwnableUpgradeSafe is Initializable, ContextUpgradeSafe { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal initializer { __Context_init_unchained(); __Ownable_init_unchained(); } function __Ownable_init_unchained() internal initializer { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_owner == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } uint256[49] private __gap; } // Part: UniERC20 library UniERC20 { using SafeMath for uint256; using SafeERC20 for IERC20; function isETH(IERC20 token) internal pure returns (bool) { return (address(token) == address(0)); } function uniBalanceOf(IERC20 token, address account) internal view returns (uint256) { if (isETH(token)) { return account.balance; } else { return token.balanceOf(account); } } function uniTransfer( IERC20 token, address payable to, uint256 amount ) internal { if (amount > 0) { if (isETH(token)) { (bool success, ) = to.call{value: amount}(""); require(success, "Transfer failed"); } else { token.safeTransfer(to, amount); } } } function uniTransferFromSenderToThis(IERC20 token, uint256 amount) internal { if (amount > 0) { if (isETH(token)) { require(msg.value >= amount, "UniERC20: not enough value"); if (msg.value > amount) { // Return remainder if exist uint256 refundAmount = msg.value.sub(amount); (bool success, ) = msg.sender.call{value: refundAmount}(""); require(success, "Transfer failed"); } } else { token.safeTransferFrom(msg.sender, address(this), amount); } } } function uniSymbol(IERC20 token) internal view returns (string memory) { if (isETH(token)) { return "ETH"; } (bool success, bytes memory data) = address(token).staticcall{gas: 20000}(abi.encodeWithSignature("symbol()")); if (!success) { (success, data) = address(token).staticcall{gas: 20000}(abi.encodeWithSignature("SYMBOL()")); } if (success && data.length >= 96) { (uint256 offset, uint256 len) = abi.decode(data, (uint256, uint256)); if (offset == 0x20 && len > 0 && len <= 256) { return string(abi.decode(data, (bytes))); } } if (success && data.length == 32) { uint256 len = 0; while (len < data.length && data[len] >= 0x20 && data[len] <= 0x7E) { len++; } if (len > 0) { bytes memory result = new bytes(len); for (uint256 i = 0; i < len; i++) { result[i] = data[i]; } return string(result); } } return _toHex(address(token)); } function _toHex(address account) private pure returns (string memory) { return _toHex(abi.encodePacked(account)); } function _toHex(bytes memory data) private pure returns (string memory) { bytes memory str = new bytes(2 + data.length * 2); str[0] = "0"; str[1] = "x"; uint256 j = 2; for (uint256 i = 0; i < data.length; i++) { uint256 a = uint8(data[i]) >> 4; uint256 b = uint8(data[i]) & 0x0f; str[j++] = bytes1(uint8(a + 48 + (a / 10) * 39)); str[j++] = bytes1(uint8(b + 48 + (b / 10) * 39)); } return string(str); } } // Part: OptionToken /** * ERC20 token representing a long or short option position. It is intended to be * used by `OptionMarket`, which mints/burns these tokens when users buy/sell options * * Note that `decimals` should match the decimals of the `baseToken` in `OptionMarket` */ contract OptionToken is ERC20UpgradeSafe { using Address for address; using SafeERC20 for IERC20; using SafeMath for uint256; address public market; function initialize( address _market, string memory name, string memory symbol, uint8 decimals ) public initializer { __ERC20_init(name, symbol); _setupDecimals(decimals); market = _market; } function mint(address account, uint256 amount) external { require(msg.sender == market, "!market"); _mint(account, amount); } function burn(address account, uint256 amount) external { require(msg.sender == market, "!market"); _burn(account, amount); } } // File: OptionMarket.sol /** * Automated market-maker for options * * This contract allows an asset to be split up into tokenized payoffs such that * different combinations of payoffs sum up to different call/put option payoffs. * An LMSR (Hanson's market-maker) is used to provide liquidity for the tokenized * payoffs. * * The parameter `b` in the LMSR represents the market depth. `b` is increased when * users provide liquidity by depositing funds and it is decreased when they withdraw * liquidity. Trading fees are distributed proportionally to liquidity providers * at the time of the trade. * * Call and put option with any of the supported strikes are provided. Short options * (equivalent to owning 1 underlying + sell 1 option) are provided, which let users * take on short option exposure * * `buy`, `sell`, `deposit` and `withdraw` are the main methods used to interact with * this contract. * * After expiration, `settle` can be called to fetch the expiry price from a * price oracle. `buy` and `deposit` cannot be called after expiration, but `sell` * can be called to redeem options for their corresponding payouts and `withdraw` * can be called to redeem LP tokens for a stake of the remaining funds left * in the contract. * * Methods to calculate the LMSR cost and option payoffs can be found in `OptionMath`. * `OptionToken` is an ERC20 token representing a long or short option position * that's minted or burned when users buy or sell options. * * This contract is also an ERC20 token itself representing shares in the liquidity * pool. * * The intended way to deploy this contract is to call `createMarket` in `OptionFactory` * Then liquidity has to be provided using `deposit` before trades can occur. * * Please note that the deployer of this contract is highly privileged and has * permissions such as withdrawing all funds from the contract, being able to pause * trading, modify the market parameters and override the settlement price. These * permissions will be removed in future versions. */ contract OptionMarket is ERC20UpgradeSafe, ReentrancyGuardUpgradeSafe, OwnableUpgradeSafe { using Address for address; using SafeERC20 for IERC20; using UniERC20 for IERC20; using SafeMath for uint256; event Buy( address indexed account, bool isLongToken, uint256 strikeIndex, uint256 optionsOut, uint256 amountIn, uint256 newSupply ); event Sell( address indexed account, bool isLongToken, uint256 strikeIndex, uint256 optionsIn, uint256 amountOut, uint256 newSupply, bool isSettled ); event Deposit(address indexed account, uint256 sharesOut, uint256 amountIn, uint256 newSupply); event Withdraw(address indexed account, uint256 sharesIn, uint256 amountOut, uint256 newSupply, bool isSettled); event Settle(uint256 expiryPrice); uint256 public constant SCALE = 1e18; uint256 public constant SCALE_SCALE = 1e36; IERC20 public baseToken; IOracle public oracle; OptionToken[] public longTokens; OptionToken[] public shortTokens; uint256[] public strikePrices; uint256 public expiryTime; bool public isPut; uint256 public tradingFee; uint256 public balanceCap; uint256 public totalSupplyCap; uint256 public disputePeriod; bool public isPaused; bool public isSettled; uint256 public expiryPrice; // cache getCurrentCost and getCurrentPayoff between trades to save gas uint256 public lastCost; uint256 public lastPayoff; // total value of fees owed to LPs uint256 public poolValue; /** * @param _baseToken Underlying asset if call. Strike currency if put * Represents ETH if equal to 0x0 * @param _oracle Oracle from which settlement price is obtained * @param _longTokens Tokens representing long calls/puts * @param _shortTokens Tokens representing short calls/puts * @param _strikePrices Strike prices expressed in wei. Must be in increasing order * @param _expiryTime Expiration time as a unix timestamp * @param _isPut Whether this market provides calls or puts * @param _tradingFee Trading fee as fraction of underlying expressed in wei * @param _symbol Name and symbol of LP tokens */ function initialize( address _baseToken, address _oracle, address[] memory _longTokens, address[] memory _shortTokens, uint256[] memory _strikePrices, uint256 _expiryTime, bool _isPut, uint256 _tradingFee, string memory _symbol ) public payable initializer { // this contract is also an ERC20 token, representing shares in the liquidity pool __ERC20_init(_symbol, _symbol); __ReentrancyGuard_init(); __Ownable_init(); // use same decimals as base token uint8 decimals = IERC20(_baseToken).isETH() ? 18 : ERC20UpgradeSafe(_baseToken).decimals(); _setupDecimals(decimals); require(_longTokens.length == _strikePrices.length, "Lengths do not match"); require(_shortTokens.length == _strikePrices.length, "Lengths do not match"); require(_strikePrices.length > 0, "Strike prices must not be empty"); require(_strikePrices[0] > 0, "Strike prices must be > 0"); // check strike prices are increasing for (uint256 i = 0; i < _strikePrices.length - 1; i++) { require(_strikePrices[i] < _strikePrices[i + 1], "Strike prices must be increasing"); } // check trading fee is less than 100% // note trading fee can be 0 require(_tradingFee < SCALE, "Trading fee must be < 1"); baseToken = IERC20(_baseToken); oracle = IOracle(_oracle); strikePrices = _strikePrices; expiryTime = _expiryTime; isPut = _isPut; tradingFee = _tradingFee; for (uint256 i = 0; i < _strikePrices.length; i++) { longTokens.push(OptionToken(_longTokens[i])); shortTokens.push(OptionToken(_shortTokens[i])); } require(!isExpired(), "Already expired"); } /** * Buy options * * The option bought is specified by `isLongToken` and `strikeIndex` and the * amount by `optionsOut` * * This method reverts if the resulting cost is greater than `maxAmountIn` */ function buy( bool isLongToken, uint256 strikeIndex, uint256 optionsOut, uint256 maxAmountIn ) external payable nonReentrant returns (uint256 amountIn) { require(totalSupply() > 0, "No liquidity"); require(!isExpired(), "Already expired"); require(msg.sender == owner() || !isPaused, "Paused"); require(strikeIndex < strikePrices.length, "Index too large"); require(optionsOut > 0, "Options out must be > 0"); // mint options to user OptionToken option = isLongToken ? longTokens[strikeIndex] : shortTokens[strikeIndex]; option.mint(msg.sender, optionsOut); // calculate trading fee and allocate it to the LP pool // like LMSR cost, fees have to be multiplied by strike price uint256 fee = optionsOut.mul(tradingFee); fee = isPut ? fee.mul(strikePrices[strikeIndex]).div(SCALE_SCALE) : fee.div(SCALE); poolValue = poolValue.add(fee); // calculate amount that needs to be paid by user to buy these options // it's equal to the increase in LMSR cost after minting the options uint256 costAfter = getCurrentCost(); amountIn = costAfter.sub(lastCost).add(fee); // do sub first as a check since should not fail lastCost = costAfter; require(amountIn > 0, "Amount in must be > 0"); require(amountIn <= maxAmountIn, "Max slippage exceeded"); // transfer in amount from user _transferIn(amountIn); emit Buy(msg.sender, isLongToken, strikeIndex, optionsOut, amountIn, option.totalSupply()); } /** * Sell options * * The option sold is specified by `isLongToken` and `strikeIndex` and the * amount by `optionsIn` * * This method reverts if the resulting amount returned is less than `minAmountOut` */ function sell( bool isLongToken, uint256 strikeIndex, uint256 optionsIn, uint256 minAmountOut ) external nonReentrant returns (uint256 amountOut) { require(!isExpired() || isSettled, "Must be called before expiry or after settlement"); require(!isDisputePeriod(), "Dispute period"); require(msg.sender == owner() || !isPaused, "Paused"); require(strikeIndex < strikePrices.length, "Index too large"); require(optionsIn > 0, "Options in must be > 0"); // burn user's options OptionToken option = isLongToken ? longTokens[strikeIndex] : shortTokens[strikeIndex]; option.burn(msg.sender, optionsIn); // calculate amount that needs to be returned to user if (isSettled) { // if after settlement, amount is the option payoff uint256 payoffAfter = getCurrentPayoff(); amountOut = lastPayoff.sub(payoffAfter); lastPayoff = payoffAfter; } else { // if before expiry, amount is the decrease in LMSR cost after burning the options uint256 costAfter = getCurrentCost(); amountOut = lastCost.sub(costAfter); lastCost = costAfter; } require(amountOut > 0, "Amount out must be > 0"); require(amountOut >= minAmountOut, "Max slippage exceeded"); // transfer amount to user baseToken.uniTransfer(msg.sender, amountOut); emit Sell(msg.sender, isLongToken, strikeIndex, optionsIn, amountOut, option.totalSupply(), isSettled); } /** * Deposit liquidity * * `sharesOut` is the intended increase in the parameter `b` * * This method reverts if the resulting cost is greater than `maxAmountIn` */ function deposit(uint256 sharesOut, uint256 maxAmountIn) external payable nonReentrant returns (uint256 amountIn) { require(!isExpired(), "Already expired"); require(msg.sender == owner() || !isPaused, "Paused"); require(sharesOut > 0, "Shares out must be > 0"); // user needs to contribute proportional amount of fees to pool, which // ensures they are only earning fees generated after they have deposited if (totalSupply() > 0) { // add 1 to round up amountIn = poolValue.mul(sharesOut).div(totalSupply()).add(1); poolValue = poolValue.add(amountIn); } _mint(msg.sender, sharesOut); require(totalSupplyCap == 0 || totalSupply() <= totalSupplyCap, "Total supply cap exceeded"); // need to add increase in LMSR cost after increasing b uint256 costAfter = getCurrentCost(); amountIn = costAfter.sub(lastCost).add(amountIn); // do sub first as a check since should not fail lastCost = costAfter; require(amountIn > 0, "Amount in must be > 0"); require(amountIn <= maxAmountIn, "Max slippage exceeded"); // transfer in amount from user _transferIn(amountIn); emit Deposit(msg.sender, sharesOut, amountIn, totalSupply()); } /** * Withdraw liquidity * * `sharesIn` is the intended decrease in the parameter `b` * * This method reverts if the resulting amount returned is less than `minAmountOut` */ function withdraw(uint256 sharesIn, uint256 minAmountOut) external nonReentrant returns (uint256 amountOut) { require(!isExpired() || isSettled, "Must be called before expiry or after settlement"); require(!isDisputePeriod(), "Dispute period"); require(msg.sender == owner() || !isPaused, "Paused"); require(sharesIn > 0, "Shares in must be > 0"); // calculate cut of fees earned by user amountOut = poolValue.mul(sharesIn).div(totalSupply()); poolValue = poolValue.sub(amountOut); _burn(msg.sender, sharesIn); // if before expiry, add decrease in LMSR cost after decreasing b if (!isSettled) { uint256 costAfter = getCurrentCost(); amountOut = lastCost.sub(costAfter).add(amountOut); // do sub first as a check since should not fail lastCost = costAfter; } require(amountOut > 0, "Amount out must be > 0"); require(amountOut >= minAmountOut, "Max slippage exceeded"); // return amount to user baseToken.uniTransfer(msg.sender, amountOut); emit Withdraw(msg.sender, sharesIn, amountOut, totalSupply(), isSettled); } /** * Retrieve and store the underlying price from the oracle * * This method can be called by anyone after expiration but cannot be called * more than once. In practice it should be called as soon as possible after the * expiration time. */ function settle() external nonReentrant { require(isExpired(), "Cannot be called before expiry"); require(!isSettled, "Already settled"); // fetch expiry price from oracle isSettled = true; expiryPrice = oracle.getPrice(); require(expiryPrice > 0, "Price from oracle must be > 0"); // update cached payoff and pool value lastPayoff = getCurrentPayoff(); poolValue = baseToken.uniBalanceOf(address(this)).sub(lastPayoff); emit Settle(expiryPrice); } /** * Calculate LMSR cost * * Represents total amount locked in the LMSR * * This value will increase as options are bought and decrease as options * are sold. The change in value corresponds to the total cost of a purchase * or the amount returned from a sale. * * This method is only used before expiry. Before expiry, the `baseToken` * balance of this contract is always at least current cost + pool value. * Current cost is maximum possible amount that needs to be paid out to * option holders. Pool value is the fees earned by LPs. */ function getCurrentCost() public view returns (uint256) { uint256[] memory longSupplies = getTotalSupplies(longTokens); uint256[] memory shortSupplies = getTotalSupplies(shortTokens); uint256[] memory quantities = OptionMath.calcQuantities(strikePrices, isPut, longSupplies, shortSupplies); return OptionMath.calcLmsrCost(quantities, totalSupply()); } /** * Calculate option payoff * * Represents total payoff to option holders * * This value will decrease as options are redeemed. The change in value * corresponds to the payoff returned from a redemption. * * This method is only used after expiry. After expiry, the `baseToken` balance * of this contract is always at least current payoff + pool value. Current * payoff is the amount owed to option holders and pool value is the amount * owed to LPs. */ function getCurrentPayoff() public view returns (uint256) { uint256[] memory longSupplies = getTotalSupplies(longTokens); uint256[] memory shortSupplies = getTotalSupplies(shortTokens); return OptionMath.calcPayoff(strikePrices, expiryPrice, isPut, longSupplies, shortSupplies); } function getTotalSupplies(OptionToken[] memory optionTokens) public view returns (uint256[] memory totalSupplies) { totalSupplies = new uint256[](optionTokens.length); for (uint256 i = 0; i < optionTokens.length; i++) { totalSupplies[i] = optionTokens[i].totalSupply(); } } function isExpired() public view returns (bool) { return block.timestamp >= expiryTime; } function isDisputePeriod() public view returns (bool) { return block.timestamp >= expiryTime && block.timestamp < expiryTime.add(disputePeriod); } function numStrikes() external view returns (uint256) { return strikePrices.length; } /** * Transfer amount from sender and do additional checks */ function _transferIn(uint256 amountIn) private { // save gas IERC20 _baseToken = baseToken; uint256 balanceBefore = _baseToken.uniBalanceOf(address(this)); _baseToken.uniTransferFromSenderToThis(amountIn); uint256 balanceAfter = _baseToken.uniBalanceOf(address(this)); require(_baseToken.isETH() || balanceAfter.sub(balanceBefore) == amountIn, "Deflationary tokens not supported"); require(balanceCap == 0 || _baseToken.uniBalanceOf(address(this)) <= balanceCap, "Balance cap exceeded"); } // used for guarded launch function setBalanceCap(uint256 _balanceCap) external onlyOwner { balanceCap = _balanceCap; } // used for guarded launch function setTotalSupplyCap(uint256 _totalSupplyCap) external onlyOwner { totalSupplyCap = _totalSupplyCap; } // emergency use only. to be removed in future versions function pause() external onlyOwner { isPaused = true; } // emergency use only. to be removed in future versions function unpause() external onlyOwner { isPaused = false; } // emergency use only. to be removed in future versions function setOracle(IOracle _oracle) external onlyOwner { oracle = _oracle; } // emergency use only. to be removed in future versions function setExpiryTime(uint256 _expiryTime) external onlyOwner { expiryTime = _expiryTime; } // emergency use only. to be removed in future versions function setDisputePeriod(uint256 _disputePeriod) external onlyOwner { disputePeriod = _disputePeriod; } // emergency use only. to be removed in future versions function disputeExpiryPrice(uint256 _expiryPrice) external onlyOwner { require(isDisputePeriod(), "Not dispute period"); require(isSettled, "Cannot be called before settlement"); expiryPrice = _expiryPrice; // update cached payoff and pool value lastPayoff = getCurrentPayoff(); poolValue = baseToken.uniBalanceOf(address(this)).sub(lastPayoff); emit Settle(_expiryPrice); } // emergency use only. to be removed in future versions function emergencyWithdraw() external onlyOwner { baseToken.uniTransfer(msg.sender, baseToken.uniBalanceOf(address(this))); } }
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"isLongToken","type":"bool"},{"indexed":false,"internalType":"uint256","name":"strikeIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"optionsOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSupply","type":"uint256"}],"name":"Buy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"sharesOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSupply","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"isLongToken","type":"bool"},{"indexed":false,"internalType":"uint256","name":"strikeIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"optionsIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSupply","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isSettled","type":"bool"}],"name":"Sell","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"expiryPrice","type":"uint256"}],"name":"Settle","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"sharesIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSupply","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isSettled","type":"bool"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"SCALE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SCALE_SCALE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"balanceCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"isLongToken","type":"bool"},{"internalType":"uint256","name":"strikeIndex","type":"uint256"},{"internalType":"uint256","name":"optionsOut","type":"uint256"},{"internalType":"uint256","name":"maxAmountIn","type":"uint256"}],"name":"buy","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"sharesOut","type":"uint256"},{"internalType":"uint256","name":"maxAmountIn","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_expiryPrice","type":"uint256"}],"name":"disputeExpiryPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disputePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"expiryPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"expiryTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentPayoff","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract OptionToken[]","name":"optionTokens","type":"address[]"}],"name":"getTotalSupplies","outputs":[{"internalType":"uint256[]","name":"totalSupplies","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_baseToken","type":"address"},{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"address[]","name":"_longTokens","type":"address[]"},{"internalType":"address[]","name":"_shortTokens","type":"address[]"},{"internalType":"uint256[]","name":"_strikePrices","type":"uint256[]"},{"internalType":"uint256","name":"_expiryTime","type":"uint256"},{"internalType":"bool","name":"_isPut","type":"bool"},{"internalType":"uint256","name":"_tradingFee","type":"uint256"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"isDisputePeriod","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isExpired","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPut","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isSettled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPayoff","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"longTokens","outputs":[{"internalType":"contract OptionToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numStrikes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract IOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"poolValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isLongToken","type":"bool"},{"internalType":"uint256","name":"strikeIndex","type":"uint256"},{"internalType":"uint256","name":"optionsIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"}],"name":"sell","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_balanceCap","type":"uint256"}],"name":"setBalanceCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_disputePeriod","type":"uint256"}],"name":"setDisputePeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_expiryTime","type":"uint256"}],"name":"setExpiryTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IOracle","name":"_oracle","type":"address"}],"name":"setOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalSupplyCap","type":"uint256"}],"name":"setTotalSupplyCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"shortTokens","outputs":[{"internalType":"contract OptionToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"strikePrices","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupplyCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tradingFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"sharesIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | Ether (ETH) | 100.00% | $3,412.63 | 9.5318 | $32,528.65 |
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.