@zoralabs/coins 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +69 -55
- package/CHANGELOG.md +12 -0
- package/abis/BaseTest.json +0 -23
- package/abis/Coin.json +186 -77
- package/abis/CoinConfigurationVersions.json +7 -0
- package/abis/CoinSetup.json +7 -0
- package/abis/CoinTest.json +5 -49
- package/abis/CustomRevert.json +28 -0
- package/abis/DopplerUniswapV3Test.json +891 -0
- package/abis/FactoryTest.json +7 -23
- package/abis/IAirlock.json +15 -0
- package/abis/ICoin.json +52 -34
- package/abis/IDopplerErrors.json +44 -0
- package/abis/INonfungiblePositionManager.json +13 -0
- package/abis/IUniswapV3Factory.json +198 -0
- package/abis/IUniswapV3Pool.json +135 -0
- package/abis/MultiOwnableTest.json +0 -23
- package/abis/SafeCast.json +7 -0
- package/abis/Simulate.json +120 -0
- package/abis/SqrtPriceMath.json +22 -0
- package/abis/TickMath.json +24 -0
- package/abis/ZoraFactoryImpl.json +59 -0
- package/addresses/8453.json +3 -3
- package/dist/index.cjs +160 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +160 -39
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +349 -67
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/package/wagmiGenerated.ts +161 -40
- package/package.json +3 -3
- package/script/CoinsDeployerBase.sol +1 -1
- package/script/Simulate.s.sol +67 -0
- package/src/Coin.sol +159 -90
- package/src/ZoraFactoryImpl.sol +47 -1
- package/src/interfaces/IAirlock.sol +6 -0
- package/src/interfaces/ICoin.sol +18 -2
- package/src/interfaces/IDopplerErrors.sol +14 -0
- package/src/interfaces/INonfungiblePositionManager.sol +2 -0
- package/src/interfaces/IUniswapV3Factory.sol +64 -0
- package/src/interfaces/IUniswapV3Pool.sol +48 -0
- package/src/libs/CoinConfigurationVersions.sol +9 -0
- package/src/libs/CoinDopplerUniV3.sol +202 -0
- package/src/libs/CoinLegacy.sol +48 -0
- package/src/libs/CoinSetup.sol +37 -0
- package/src/libs/MarketConstants.sol +25 -0
- package/src/types/LpPosition.sol +8 -0
- package/src/types/PoolState.sol +24 -0
- package/src/utils/CoinConstants.sol +5 -12
- package/src/utils/uniswap/BitMath.sol +55 -0
- package/src/utils/uniswap/CustomRevert.sol +111 -0
- package/src/utils/uniswap/FixedPoint96.sol +11 -0
- package/src/utils/uniswap/FullMath.sol +118 -0
- package/src/utils/uniswap/LiquidityAmounts.sol +117 -0
- package/src/utils/uniswap/SafeCast.sol +61 -0
- package/src/utils/uniswap/SqrtPriceMath.sol +249 -0
- package/src/utils/uniswap/TickMath.sol +244 -0
- package/src/utils/uniswap/UnsafeMath.sol +30 -0
- package/src/version/ContractVersionBase.sol +1 -1
- package/test/Coin.t.sol +65 -65
- package/test/CoinDopplerUniV3.t.sol +452 -0
- package/test/Factory.t.sol +49 -7
- package/test/utils/BaseTest.sol +26 -7
- package/wagmi.config.ts +1 -1
- package/abis/IERC721Receiver.json +0 -36
- package/src/utils/TickMath.sol +0 -210
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
/// @dev https://github.com/Uniswap/v4-core/blob/80311e34080fee64b6fc6c916e9a51a437d0e482/src/libraries/FullMath.sol
|
|
5
|
+
/// @title Contains 512-bit math functions
|
|
6
|
+
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
|
|
7
|
+
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
|
|
8
|
+
library FullMath {
|
|
9
|
+
/// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
|
|
10
|
+
/// @param a The multiplicand
|
|
11
|
+
/// @param b The multiplier
|
|
12
|
+
/// @param denominator The divisor
|
|
13
|
+
/// @return result The 256-bit result
|
|
14
|
+
/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
|
|
15
|
+
function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
|
|
16
|
+
unchecked {
|
|
17
|
+
// 512-bit multiply [prod1 prod0] = a * b
|
|
18
|
+
// Compute the product mod 2**256 and mod 2**256 - 1
|
|
19
|
+
// then use the Chinese Remainder Theorem to reconstruct
|
|
20
|
+
// the 512 bit result. The result is stored in two 256
|
|
21
|
+
// variables such that product = prod1 * 2**256 + prod0
|
|
22
|
+
uint256 prod0 = a * b; // Least significant 256 bits of the product
|
|
23
|
+
uint256 prod1; // Most significant 256 bits of the product
|
|
24
|
+
assembly ("memory-safe") {
|
|
25
|
+
let mm := mulmod(a, b, not(0))
|
|
26
|
+
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Make sure the result is less than 2**256.
|
|
30
|
+
// Also prevents denominator == 0
|
|
31
|
+
require(denominator > prod1);
|
|
32
|
+
|
|
33
|
+
// Handle non-overflow cases, 256 by 256 division
|
|
34
|
+
if (prod1 == 0) {
|
|
35
|
+
assembly ("memory-safe") {
|
|
36
|
+
result := div(prod0, denominator)
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
///////////////////////////////////////////////
|
|
42
|
+
// 512 by 256 division.
|
|
43
|
+
///////////////////////////////////////////////
|
|
44
|
+
|
|
45
|
+
// Make division exact by subtracting the remainder from [prod1 prod0]
|
|
46
|
+
// Compute remainder using mulmod
|
|
47
|
+
uint256 remainder;
|
|
48
|
+
assembly ("memory-safe") {
|
|
49
|
+
remainder := mulmod(a, b, denominator)
|
|
50
|
+
}
|
|
51
|
+
// Subtract 256 bit number from 512 bit number
|
|
52
|
+
assembly ("memory-safe") {
|
|
53
|
+
prod1 := sub(prod1, gt(remainder, prod0))
|
|
54
|
+
prod0 := sub(prod0, remainder)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Factor powers of two out of denominator
|
|
58
|
+
// Compute largest power of two divisor of denominator.
|
|
59
|
+
// Always >= 1.
|
|
60
|
+
uint256 twos = (0 - denominator) & denominator;
|
|
61
|
+
// Divide denominator by power of two
|
|
62
|
+
assembly ("memory-safe") {
|
|
63
|
+
denominator := div(denominator, twos)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Divide [prod1 prod0] by the factors of two
|
|
67
|
+
assembly ("memory-safe") {
|
|
68
|
+
prod0 := div(prod0, twos)
|
|
69
|
+
}
|
|
70
|
+
// Shift in bits from prod1 into prod0. For this we need
|
|
71
|
+
// to flip `twos` such that it is 2**256 / twos.
|
|
72
|
+
// If twos is zero, then it becomes one
|
|
73
|
+
assembly ("memory-safe") {
|
|
74
|
+
twos := add(div(sub(0, twos), twos), 1)
|
|
75
|
+
}
|
|
76
|
+
prod0 |= prod1 * twos;
|
|
77
|
+
|
|
78
|
+
// Invert denominator mod 2**256
|
|
79
|
+
// Now that denominator is an odd number, it has an inverse
|
|
80
|
+
// modulo 2**256 such that denominator * inv = 1 mod 2**256.
|
|
81
|
+
// Compute the inverse by starting with a seed that is correct
|
|
82
|
+
// correct for four bits. That is, denominator * inv = 1 mod 2**4
|
|
83
|
+
uint256 inv = (3 * denominator) ^ 2;
|
|
84
|
+
// Now use Newton-Raphson iteration to improve the precision.
|
|
85
|
+
// Thanks to Hensel's lifting lemma, this also works in modular
|
|
86
|
+
// arithmetic, doubling the correct bits in each step.
|
|
87
|
+
inv *= 2 - denominator * inv; // inverse mod 2**8
|
|
88
|
+
inv *= 2 - denominator * inv; // inverse mod 2**16
|
|
89
|
+
inv *= 2 - denominator * inv; // inverse mod 2**32
|
|
90
|
+
inv *= 2 - denominator * inv; // inverse mod 2**64
|
|
91
|
+
inv *= 2 - denominator * inv; // inverse mod 2**128
|
|
92
|
+
inv *= 2 - denominator * inv; // inverse mod 2**256
|
|
93
|
+
|
|
94
|
+
// Because the division is now exact we can divide by multiplying
|
|
95
|
+
// with the modular inverse of denominator. This will give us the
|
|
96
|
+
// correct result modulo 2**256. Since the preconditions guarantee
|
|
97
|
+
// that the outcome is less than 2**256, this is the final result.
|
|
98
|
+
// We don't need to compute the high bits of the result and prod1
|
|
99
|
+
// is no longer required.
|
|
100
|
+
result = prod0 * inv;
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
|
|
106
|
+
/// @param a The multiplicand
|
|
107
|
+
/// @param b The multiplier
|
|
108
|
+
/// @param denominator The divisor
|
|
109
|
+
/// @return result The 256-bit result
|
|
110
|
+
function mulDivRoundingUp(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
|
|
111
|
+
unchecked {
|
|
112
|
+
result = mulDiv(a, b, denominator);
|
|
113
|
+
if (mulmod(a, b, denominator) != 0) {
|
|
114
|
+
require(++result > 0);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// SPDX-License-Identifier: UNLICENSED
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
import "./FullMath.sol";
|
|
5
|
+
import "./FixedPoint96.sol";
|
|
6
|
+
|
|
7
|
+
/// @dev https://github.com/Uniswap/v4-core/blob/80311e34080fee64b6fc6c916e9a51a437d0e482/test/utils/LiquidityAmounts.sol
|
|
8
|
+
/// @title Liquidity amount functions
|
|
9
|
+
/// @notice Provides functions for computing liquidity amounts from token amounts and prices
|
|
10
|
+
library LiquidityAmounts {
|
|
11
|
+
/// @notice Downcasts uint256 to uint128
|
|
12
|
+
/// @param x The uint258 to be downcasted
|
|
13
|
+
/// @return y The passed value, downcasted to uint128
|
|
14
|
+
function toUint128(uint256 x) private pure returns (uint128 y) {
|
|
15
|
+
require((y = uint128(x)) == x, "liquidity overflow");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/// @notice Computes the amount of liquidity received for a given amount of token0 and price range
|
|
19
|
+
/// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower))
|
|
20
|
+
/// @param sqrtPriceAX96 A sqrt price representing the first tick boundary
|
|
21
|
+
/// @param sqrtPriceBX96 A sqrt price representing the second tick boundary
|
|
22
|
+
/// @param amount0 The amount0 being sent in
|
|
23
|
+
/// @return liquidity The amount of returned liquidity
|
|
24
|
+
function getLiquidityForAmount0(uint160 sqrtPriceAX96, uint160 sqrtPriceBX96, uint256 amount0) internal pure returns (uint128 liquidity) {
|
|
25
|
+
if (sqrtPriceAX96 > sqrtPriceBX96) (sqrtPriceAX96, sqrtPriceBX96) = (sqrtPriceBX96, sqrtPriceAX96);
|
|
26
|
+
uint256 intermediate = FullMath.mulDiv(sqrtPriceAX96, sqrtPriceBX96, FixedPoint96.Q96);
|
|
27
|
+
return toUint128(FullMath.mulDiv(amount0, intermediate, sqrtPriceBX96 - sqrtPriceAX96));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// @notice Computes the amount of liquidity received for a given amount of token1 and price range
|
|
31
|
+
/// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)).
|
|
32
|
+
/// @param sqrtPriceAX96 A sqrt price representing the first tick boundary
|
|
33
|
+
/// @param sqrtPriceBX96 A sqrt price representing the second tick boundary
|
|
34
|
+
/// @param amount1 The amount1 being sent in
|
|
35
|
+
/// @return liquidity The amount of returned liquidity
|
|
36
|
+
function getLiquidityForAmount1(uint160 sqrtPriceAX96, uint160 sqrtPriceBX96, uint256 amount1) internal pure returns (uint128 liquidity) {
|
|
37
|
+
if (sqrtPriceAX96 > sqrtPriceBX96) (sqrtPriceAX96, sqrtPriceBX96) = (sqrtPriceBX96, sqrtPriceAX96);
|
|
38
|
+
return toUint128(FullMath.mulDiv(amount1, FixedPoint96.Q96, sqrtPriceBX96 - sqrtPriceAX96));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current
|
|
42
|
+
/// pool prices and the prices at the tick boundaries
|
|
43
|
+
/// @param sqrtPriceX96 A sqrt price representing the current pool prices
|
|
44
|
+
/// @param sqrtPriceAX96 A sqrt price representing the first tick boundary
|
|
45
|
+
/// @param sqrtPriceBX96 A sqrt price representing the second tick boundary
|
|
46
|
+
/// @param amount0 The amount of token0 being sent in
|
|
47
|
+
/// @param amount1 The amount of token1 being sent in
|
|
48
|
+
/// @return liquidity The maximum amount of liquidity received
|
|
49
|
+
function getLiquidityForAmounts(
|
|
50
|
+
uint160 sqrtPriceX96,
|
|
51
|
+
uint160 sqrtPriceAX96,
|
|
52
|
+
uint160 sqrtPriceBX96,
|
|
53
|
+
uint256 amount0,
|
|
54
|
+
uint256 amount1
|
|
55
|
+
) internal pure returns (uint128 liquidity) {
|
|
56
|
+
if (sqrtPriceAX96 > sqrtPriceBX96) (sqrtPriceAX96, sqrtPriceBX96) = (sqrtPriceBX96, sqrtPriceAX96);
|
|
57
|
+
|
|
58
|
+
if (sqrtPriceX96 <= sqrtPriceAX96) {
|
|
59
|
+
liquidity = getLiquidityForAmount0(sqrtPriceAX96, sqrtPriceBX96, amount0);
|
|
60
|
+
} else if (sqrtPriceX96 < sqrtPriceBX96) {
|
|
61
|
+
uint128 liquidity0 = getLiquidityForAmount0(sqrtPriceX96, sqrtPriceBX96, amount0);
|
|
62
|
+
uint128 liquidity1 = getLiquidityForAmount1(sqrtPriceAX96, sqrtPriceX96, amount1);
|
|
63
|
+
|
|
64
|
+
liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1;
|
|
65
|
+
} else {
|
|
66
|
+
liquidity = getLiquidityForAmount1(sqrtPriceAX96, sqrtPriceBX96, amount1);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// @notice Computes the amount of token0 for a given amount of liquidity and a price range
|
|
71
|
+
/// @param sqrtPriceAX96 A sqrt price representing the first tick boundary
|
|
72
|
+
/// @param sqrtPriceBX96 A sqrt price representing the second tick boundary
|
|
73
|
+
/// @param liquidity The liquidity being valued
|
|
74
|
+
/// @return amount0 The amount of token0
|
|
75
|
+
function getAmount0ForLiquidity(uint160 sqrtPriceAX96, uint160 sqrtPriceBX96, uint128 liquidity) internal pure returns (uint256 amount0) {
|
|
76
|
+
if (sqrtPriceAX96 > sqrtPriceBX96) (sqrtPriceAX96, sqrtPriceBX96) = (sqrtPriceBX96, sqrtPriceAX96);
|
|
77
|
+
|
|
78
|
+
return FullMath.mulDiv(uint256(liquidity) << FixedPoint96.RESOLUTION, sqrtPriceBX96 - sqrtPriceAX96, sqrtPriceBX96) / sqrtPriceAX96;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// @notice Computes the amount of token1 for a given amount of liquidity and a price range
|
|
82
|
+
/// @param sqrtPriceAX96 A sqrt price representing the first tick boundary
|
|
83
|
+
/// @param sqrtPriceBX96 A sqrt price representing the second tick boundary
|
|
84
|
+
/// @param liquidity The liquidity being valued
|
|
85
|
+
/// @return amount1 The amount of token1
|
|
86
|
+
function getAmount1ForLiquidity(uint160 sqrtPriceAX96, uint160 sqrtPriceBX96, uint128 liquidity) internal pure returns (uint256 amount1) {
|
|
87
|
+
if (sqrtPriceAX96 > sqrtPriceBX96) (sqrtPriceAX96, sqrtPriceBX96) = (sqrtPriceBX96, sqrtPriceAX96);
|
|
88
|
+
|
|
89
|
+
return FullMath.mulDiv(liquidity, sqrtPriceBX96 - sqrtPriceAX96, FixedPoint96.Q96);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// @notice Computes the token0 and token1 value for a given amount of liquidity, the current
|
|
93
|
+
/// pool prices and the prices at the tick boundaries
|
|
94
|
+
/// @param sqrtPriceX96 A sqrt price representing the current pool prices
|
|
95
|
+
/// @param sqrtPriceAX96 A sqrt price representing the first tick boundary
|
|
96
|
+
/// @param sqrtPriceBX96 A sqrt price representing the second tick boundary
|
|
97
|
+
/// @param liquidity The liquidity being valued
|
|
98
|
+
/// @return amount0 The amount of token0
|
|
99
|
+
/// @return amount1 The amount of token1
|
|
100
|
+
function getAmountsForLiquidity(
|
|
101
|
+
uint160 sqrtPriceX96,
|
|
102
|
+
uint160 sqrtPriceAX96,
|
|
103
|
+
uint160 sqrtPriceBX96,
|
|
104
|
+
uint128 liquidity
|
|
105
|
+
) internal pure returns (uint256 amount0, uint256 amount1) {
|
|
106
|
+
if (sqrtPriceAX96 > sqrtPriceBX96) (sqrtPriceAX96, sqrtPriceBX96) = (sqrtPriceBX96, sqrtPriceAX96);
|
|
107
|
+
|
|
108
|
+
if (sqrtPriceX96 <= sqrtPriceAX96) {
|
|
109
|
+
amount0 = getAmount0ForLiquidity(sqrtPriceAX96, sqrtPriceBX96, liquidity);
|
|
110
|
+
} else if (sqrtPriceX96 < sqrtPriceBX96) {
|
|
111
|
+
amount0 = getAmount0ForLiquidity(sqrtPriceX96, sqrtPriceBX96, liquidity);
|
|
112
|
+
amount1 = getAmount1ForLiquidity(sqrtPriceAX96, sqrtPriceX96, liquidity);
|
|
113
|
+
} else {
|
|
114
|
+
amount1 = getAmount1ForLiquidity(sqrtPriceAX96, sqrtPriceBX96, liquidity);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
import {CustomRevert} from "./CustomRevert.sol";
|
|
5
|
+
|
|
6
|
+
/// @dev https://github.com/Uniswap/v4-core/blob/80311e34080fee64b6fc6c916e9a51a437d0e482/src/libraries/SafeCast.sol
|
|
7
|
+
/// @title Safe casting methods
|
|
8
|
+
/// @notice Contains methods for safely casting between types
|
|
9
|
+
library SafeCast {
|
|
10
|
+
using CustomRevert for bytes4;
|
|
11
|
+
|
|
12
|
+
error SafeCastOverflow();
|
|
13
|
+
|
|
14
|
+
/// @notice Cast a uint256 to a uint160, revert on overflow
|
|
15
|
+
/// @param x The uint256 to be downcasted
|
|
16
|
+
/// @return y The downcasted integer, now type uint160
|
|
17
|
+
function toUint160(uint256 x) internal pure returns (uint160 y) {
|
|
18
|
+
y = uint160(x);
|
|
19
|
+
if (y != x) SafeCastOverflow.selector.revertWith();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/// @notice Cast a uint256 to a uint128, revert on overflow
|
|
23
|
+
/// @param x The uint256 to be downcasted
|
|
24
|
+
/// @return y The downcasted integer, now type uint128
|
|
25
|
+
function toUint128(uint256 x) internal pure returns (uint128 y) {
|
|
26
|
+
y = uint128(x);
|
|
27
|
+
if (x != y) SafeCastOverflow.selector.revertWith();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// @notice Cast a int128 to a uint128, revert on overflow or underflow
|
|
31
|
+
/// @param x The int128 to be casted
|
|
32
|
+
/// @return y The casted integer, now type uint128
|
|
33
|
+
function toUint128(int128 x) internal pure returns (uint128 y) {
|
|
34
|
+
if (x < 0) SafeCastOverflow.selector.revertWith();
|
|
35
|
+
y = uint128(x);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/// @notice Cast a int256 to a int128, revert on overflow or underflow
|
|
39
|
+
/// @param x The int256 to be downcasted
|
|
40
|
+
/// @return y The downcasted integer, now type int128
|
|
41
|
+
function toInt128(int256 x) internal pure returns (int128 y) {
|
|
42
|
+
y = int128(x);
|
|
43
|
+
if (y != x) SafeCastOverflow.selector.revertWith();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/// @notice Cast a uint256 to a int256, revert on overflow
|
|
47
|
+
/// @param x The uint256 to be casted
|
|
48
|
+
/// @return y The casted integer, now type int256
|
|
49
|
+
function toInt256(uint256 x) internal pure returns (int256 y) {
|
|
50
|
+
y = int256(x);
|
|
51
|
+
if (y < 0) SafeCastOverflow.selector.revertWith();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/// @notice Cast a uint256 to a int128, revert on overflow
|
|
55
|
+
/// @param x The uint256 to be downcasted
|
|
56
|
+
/// @return The downcasted integer, now type int128
|
|
57
|
+
function toInt128(uint256 x) internal pure returns (int128) {
|
|
58
|
+
if (x >= 1 << 127) SafeCastOverflow.selector.revertWith();
|
|
59
|
+
return int128(int256(x));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
import {SafeCast} from "./SafeCast.sol";
|
|
5
|
+
|
|
6
|
+
import {FullMath} from "./FullMath.sol";
|
|
7
|
+
import {UnsafeMath} from "./UnsafeMath.sol";
|
|
8
|
+
import {FixedPoint96} from "./FixedPoint96.sol";
|
|
9
|
+
|
|
10
|
+
/// @dev https://github.com/Uniswap/v4-core/blob/80311e34080fee64b6fc6c916e9a51a437d0e482/src/libraries/SqrtPriceMath.sol
|
|
11
|
+
/// @title Functions based on Q64.96 sqrt price and liquidity
|
|
12
|
+
/// @notice Contains the math that uses square root of price as a Q64.96 and liquidity to compute deltas
|
|
13
|
+
library SqrtPriceMath {
|
|
14
|
+
using SafeCast for uint256;
|
|
15
|
+
|
|
16
|
+
error InvalidPriceOrLiquidity();
|
|
17
|
+
error InvalidPrice();
|
|
18
|
+
error NotEnoughLiquidity();
|
|
19
|
+
error PriceOverflow();
|
|
20
|
+
|
|
21
|
+
/// @notice Gets the next sqrt price given a delta of currency0
|
|
22
|
+
/// @dev Always rounds up, because in the exact output case (increasing price) we need to move the price at least
|
|
23
|
+
/// far enough to get the desired output amount, and in the exact input case (decreasing price) we need to move the
|
|
24
|
+
/// price less in order to not send too much output.
|
|
25
|
+
/// The most precise formula for this is liquidity * sqrtPX96 / (liquidity +- amount * sqrtPX96),
|
|
26
|
+
/// if this is impossible because of overflow, we calculate liquidity / (liquidity / sqrtPX96 +- amount).
|
|
27
|
+
/// @param sqrtPX96 The starting price, i.e. before accounting for the currency0 delta
|
|
28
|
+
/// @param liquidity The amount of usable liquidity
|
|
29
|
+
/// @param amount How much of currency0 to add or remove from virtual reserves
|
|
30
|
+
/// @param add Whether to add or remove the amount of currency0
|
|
31
|
+
/// @return The price after adding or removing amount, depending on add
|
|
32
|
+
function getNextSqrtPriceFromAmount0RoundingUp(uint160 sqrtPX96, uint128 liquidity, uint256 amount, bool add) internal pure returns (uint160) {
|
|
33
|
+
// we short circuit amount == 0 because the result is otherwise not guaranteed to equal the input price
|
|
34
|
+
if (amount == 0) return sqrtPX96;
|
|
35
|
+
uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION;
|
|
36
|
+
|
|
37
|
+
if (add) {
|
|
38
|
+
unchecked {
|
|
39
|
+
uint256 product = amount * sqrtPX96;
|
|
40
|
+
if (product / amount == sqrtPX96) {
|
|
41
|
+
uint256 denominator = numerator1 + product;
|
|
42
|
+
if (denominator >= numerator1) {
|
|
43
|
+
// always fits in 160 bits
|
|
44
|
+
return uint160(FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// denominator is checked for overflow
|
|
49
|
+
return uint160(UnsafeMath.divRoundingUp(numerator1, (numerator1 / sqrtPX96) + amount));
|
|
50
|
+
} else {
|
|
51
|
+
unchecked {
|
|
52
|
+
uint256 product = amount * sqrtPX96;
|
|
53
|
+
// if the product overflows, we know the denominator underflows
|
|
54
|
+
// in addition, we must check that the denominator does not underflow
|
|
55
|
+
// equivalent: if (product / amount != sqrtPX96 || numerator1 <= product) revert PriceOverflow();
|
|
56
|
+
assembly ("memory-safe") {
|
|
57
|
+
if iszero(and(eq(div(product, amount), and(sqrtPX96, 0xffffffffffffffffffffffffffffffffffffffff)), gt(numerator1, product))) {
|
|
58
|
+
mstore(0, 0xf5c787f1) // selector for PriceOverflow()
|
|
59
|
+
revert(0x1c, 0x04)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
uint256 denominator = numerator1 - product;
|
|
63
|
+
return FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator).toUint160();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/// @notice Gets the next sqrt price given a delta of currency1
|
|
69
|
+
/// @dev Always rounds down, because in the exact output case (decreasing price) we need to move the price at least
|
|
70
|
+
/// far enough to get the desired output amount, and in the exact input case (increasing price) we need to move the
|
|
71
|
+
/// price less in order to not send too much output.
|
|
72
|
+
/// The formula we compute is within <1 wei of the lossless version: sqrtPX96 +- amount / liquidity
|
|
73
|
+
/// @param sqrtPX96 The starting price, i.e., before accounting for the currency1 delta
|
|
74
|
+
/// @param liquidity The amount of usable liquidity
|
|
75
|
+
/// @param amount How much of currency1 to add, or remove, from virtual reserves
|
|
76
|
+
/// @param add Whether to add, or remove, the amount of currency1
|
|
77
|
+
/// @return The price after adding or removing `amount`
|
|
78
|
+
function getNextSqrtPriceFromAmount1RoundingDown(uint160 sqrtPX96, uint128 liquidity, uint256 amount, bool add) internal pure returns (uint160) {
|
|
79
|
+
// if we're adding (subtracting), rounding down requires rounding the quotient down (up)
|
|
80
|
+
// in both cases, avoid a mulDiv for most inputs
|
|
81
|
+
if (add) {
|
|
82
|
+
uint256 quotient = (
|
|
83
|
+
amount <= type(uint160).max ? (amount << FixedPoint96.RESOLUTION) / liquidity : FullMath.mulDiv(amount, FixedPoint96.Q96, liquidity)
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
return (uint256(sqrtPX96) + quotient).toUint160();
|
|
87
|
+
} else {
|
|
88
|
+
uint256 quotient = (
|
|
89
|
+
amount <= type(uint160).max
|
|
90
|
+
? UnsafeMath.divRoundingUp(amount << FixedPoint96.RESOLUTION, liquidity)
|
|
91
|
+
: FullMath.mulDivRoundingUp(amount, FixedPoint96.Q96, liquidity)
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
// equivalent: if (sqrtPX96 <= quotient) revert NotEnoughLiquidity();
|
|
95
|
+
assembly ("memory-safe") {
|
|
96
|
+
if iszero(gt(and(sqrtPX96, 0xffffffffffffffffffffffffffffffffffffffff), quotient)) {
|
|
97
|
+
mstore(0, 0x4323a555) // selector for NotEnoughLiquidity()
|
|
98
|
+
revert(0x1c, 0x04)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// always fits 160 bits
|
|
102
|
+
unchecked {
|
|
103
|
+
return uint160(sqrtPX96 - quotient);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/// @notice Gets the next sqrt price given an input amount of currency0 or currency1
|
|
109
|
+
/// @dev Throws if price or liquidity are 0, or if the next price is out of bounds
|
|
110
|
+
/// @param sqrtPX96 The starting price, i.e., before accounting for the input amount
|
|
111
|
+
/// @param liquidity The amount of usable liquidity
|
|
112
|
+
/// @param amountIn How much of currency0, or currency1, is being swapped in
|
|
113
|
+
/// @param zeroForOne Whether the amount in is currency0 or currency1
|
|
114
|
+
/// @return uint160 The price after adding the input amount to currency0 or currency1
|
|
115
|
+
function getNextSqrtPriceFromInput(uint160 sqrtPX96, uint128 liquidity, uint256 amountIn, bool zeroForOne) internal pure returns (uint160) {
|
|
116
|
+
// equivalent: if (sqrtPX96 == 0 || liquidity == 0) revert InvalidPriceOrLiquidity();
|
|
117
|
+
assembly ("memory-safe") {
|
|
118
|
+
if or(iszero(and(sqrtPX96, 0xffffffffffffffffffffffffffffffffffffffff)), iszero(and(liquidity, 0xffffffffffffffffffffffffffffffff))) {
|
|
119
|
+
mstore(0, 0x4f2461b8) // selector for InvalidPriceOrLiquidity()
|
|
120
|
+
revert(0x1c, 0x04)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// round to make sure that we don't pass the target price
|
|
125
|
+
return
|
|
126
|
+
zeroForOne
|
|
127
|
+
? getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true)
|
|
128
|
+
: getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/// @notice Gets the next sqrt price given an output amount of currency0 or currency1
|
|
132
|
+
/// @dev Throws if price or liquidity are 0 or the next price is out of bounds
|
|
133
|
+
/// @param sqrtPX96 The starting price before accounting for the output amount
|
|
134
|
+
/// @param liquidity The amount of usable liquidity
|
|
135
|
+
/// @param amountOut How much of currency0, or currency1, is being swapped out
|
|
136
|
+
/// @param zeroForOne Whether the amount out is currency1 or currency0
|
|
137
|
+
/// @return uint160 The price after removing the output amount of currency0 or currency1
|
|
138
|
+
function getNextSqrtPriceFromOutput(uint160 sqrtPX96, uint128 liquidity, uint256 amountOut, bool zeroForOne) internal pure returns (uint160) {
|
|
139
|
+
// equivalent: if (sqrtPX96 == 0 || liquidity == 0) revert InvalidPriceOrLiquidity();
|
|
140
|
+
assembly ("memory-safe") {
|
|
141
|
+
if or(iszero(and(sqrtPX96, 0xffffffffffffffffffffffffffffffffffffffff)), iszero(and(liquidity, 0xffffffffffffffffffffffffffffffff))) {
|
|
142
|
+
mstore(0, 0x4f2461b8) // selector for InvalidPriceOrLiquidity()
|
|
143
|
+
revert(0x1c, 0x04)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// round to make sure that we pass the target price
|
|
148
|
+
return
|
|
149
|
+
zeroForOne
|
|
150
|
+
? getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false)
|
|
151
|
+
: getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/// @notice Gets the amount0 delta between two prices
|
|
155
|
+
/// @dev Calculates liquidity / sqrt(lower) - liquidity / sqrt(upper),
|
|
156
|
+
/// i.e. liquidity * (sqrt(upper) - sqrt(lower)) / (sqrt(upper) * sqrt(lower))
|
|
157
|
+
/// @param sqrtPriceAX96 A sqrt price
|
|
158
|
+
/// @param sqrtPriceBX96 Another sqrt price
|
|
159
|
+
/// @param liquidity The amount of usable liquidity
|
|
160
|
+
/// @param roundUp Whether to round the amount up or down
|
|
161
|
+
/// @return uint256 Amount of currency0 required to cover a position of size liquidity between the two passed prices
|
|
162
|
+
function getAmount0Delta(uint160 sqrtPriceAX96, uint160 sqrtPriceBX96, uint128 liquidity, bool roundUp) internal pure returns (uint256) {
|
|
163
|
+
unchecked {
|
|
164
|
+
if (sqrtPriceAX96 > sqrtPriceBX96) (sqrtPriceAX96, sqrtPriceBX96) = (sqrtPriceBX96, sqrtPriceAX96);
|
|
165
|
+
|
|
166
|
+
// equivalent: if (sqrtPriceAX96 == 0) revert InvalidPrice();
|
|
167
|
+
assembly ("memory-safe") {
|
|
168
|
+
if iszero(and(sqrtPriceAX96, 0xffffffffffffffffffffffffffffffffffffffff)) {
|
|
169
|
+
mstore(0, 0x00bfc921) // selector for InvalidPrice()
|
|
170
|
+
revert(0x1c, 0x04)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION;
|
|
175
|
+
uint256 numerator2 = sqrtPriceBX96 - sqrtPriceAX96;
|
|
176
|
+
|
|
177
|
+
return
|
|
178
|
+
roundUp
|
|
179
|
+
? UnsafeMath.divRoundingUp(FullMath.mulDivRoundingUp(numerator1, numerator2, sqrtPriceBX96), sqrtPriceAX96)
|
|
180
|
+
: FullMath.mulDiv(numerator1, numerator2, sqrtPriceBX96) / sqrtPriceAX96;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/// @notice Equivalent to: `a >= b ? a - b : b - a`
|
|
185
|
+
function absDiff(uint160 a, uint160 b) internal pure returns (uint256 res) {
|
|
186
|
+
assembly ("memory-safe") {
|
|
187
|
+
let diff := sub(and(a, 0xffffffffffffffffffffffffffffffffffffffff), and(b, 0xffffffffffffffffffffffffffffffffffffffff))
|
|
188
|
+
// mask = 0 if a >= b else -1 (all 1s)
|
|
189
|
+
let mask := sar(255, diff)
|
|
190
|
+
// if a >= b, res = a - b = 0 ^ (a - b)
|
|
191
|
+
// if a < b, res = b - a = ~~(b - a) = ~(-(b - a) - 1) = ~(a - b - 1) = (-1) ^ (a - b - 1)
|
|
192
|
+
// either way, res = mask ^ (a - b + mask)
|
|
193
|
+
res := xor(mask, add(mask, diff))
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/// @notice Gets the amount1 delta between two prices
|
|
198
|
+
/// @dev Calculates liquidity * (sqrt(upper) - sqrt(lower))
|
|
199
|
+
/// @param sqrtPriceAX96 A sqrt price
|
|
200
|
+
/// @param sqrtPriceBX96 Another sqrt price
|
|
201
|
+
/// @param liquidity The amount of usable liquidity
|
|
202
|
+
/// @param roundUp Whether to round the amount up, or down
|
|
203
|
+
/// @return amount1 Amount of currency1 required to cover a position of size liquidity between the two passed prices
|
|
204
|
+
function getAmount1Delta(uint160 sqrtPriceAX96, uint160 sqrtPriceBX96, uint128 liquidity, bool roundUp) internal pure returns (uint256 amount1) {
|
|
205
|
+
uint256 numerator = absDiff(sqrtPriceAX96, sqrtPriceBX96);
|
|
206
|
+
uint256 denominator = FixedPoint96.Q96;
|
|
207
|
+
uint256 _liquidity = uint256(liquidity);
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Equivalent to:
|
|
211
|
+
* amount1 = roundUp
|
|
212
|
+
* ? FullMath.mulDivRoundingUp(liquidity, sqrtPriceBX96 - sqrtPriceAX96, FixedPoint96.Q96)
|
|
213
|
+
* : FullMath.mulDiv(liquidity, sqrtPriceBX96 - sqrtPriceAX96, FixedPoint96.Q96);
|
|
214
|
+
* Cannot overflow because `type(uint128).max * type(uint160).max >> 96 < (1 << 192)`.
|
|
215
|
+
*/
|
|
216
|
+
amount1 = FullMath.mulDiv(_liquidity, numerator, denominator);
|
|
217
|
+
assembly ("memory-safe") {
|
|
218
|
+
amount1 := add(amount1, and(gt(mulmod(_liquidity, numerator, denominator), 0), roundUp))
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/// @notice Helper that gets signed currency0 delta
|
|
223
|
+
/// @param sqrtPriceAX96 A sqrt price
|
|
224
|
+
/// @param sqrtPriceBX96 Another sqrt price
|
|
225
|
+
/// @param liquidity The change in liquidity for which to compute the amount0 delta
|
|
226
|
+
/// @return int256 Amount of currency0 corresponding to the passed liquidityDelta between the two prices
|
|
227
|
+
function getAmount0Delta(uint160 sqrtPriceAX96, uint160 sqrtPriceBX96, int128 liquidity) internal pure returns (int256) {
|
|
228
|
+
unchecked {
|
|
229
|
+
return
|
|
230
|
+
liquidity < 0
|
|
231
|
+
? getAmount0Delta(sqrtPriceAX96, sqrtPriceBX96, uint128(-liquidity), false).toInt256()
|
|
232
|
+
: -getAmount0Delta(sqrtPriceAX96, sqrtPriceBX96, uint128(liquidity), true).toInt256();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/// @notice Helper that gets signed currency1 delta
|
|
237
|
+
/// @param sqrtPriceAX96 A sqrt price
|
|
238
|
+
/// @param sqrtPriceBX96 Another sqrt price
|
|
239
|
+
/// @param liquidity The change in liquidity for which to compute the amount1 delta
|
|
240
|
+
/// @return int256 Amount of currency1 corresponding to the passed liquidityDelta between the two prices
|
|
241
|
+
function getAmount1Delta(uint160 sqrtPriceAX96, uint160 sqrtPriceBX96, int128 liquidity) internal pure returns (int256) {
|
|
242
|
+
unchecked {
|
|
243
|
+
return
|
|
244
|
+
liquidity < 0
|
|
245
|
+
? getAmount1Delta(sqrtPriceAX96, sqrtPriceBX96, uint128(-liquidity), false).toInt256()
|
|
246
|
+
: -getAmount1Delta(sqrtPriceAX96, sqrtPriceBX96, uint128(liquidity), true).toInt256();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|