@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.
Files changed (66) hide show
  1. package/.turbo/turbo-build.log +69 -55
  2. package/CHANGELOG.md +12 -0
  3. package/abis/BaseTest.json +0 -23
  4. package/abis/Coin.json +186 -77
  5. package/abis/CoinConfigurationVersions.json +7 -0
  6. package/abis/CoinSetup.json +7 -0
  7. package/abis/CoinTest.json +5 -49
  8. package/abis/CustomRevert.json +28 -0
  9. package/abis/DopplerUniswapV3Test.json +891 -0
  10. package/abis/FactoryTest.json +7 -23
  11. package/abis/IAirlock.json +15 -0
  12. package/abis/ICoin.json +52 -34
  13. package/abis/IDopplerErrors.json +44 -0
  14. package/abis/INonfungiblePositionManager.json +13 -0
  15. package/abis/IUniswapV3Factory.json +198 -0
  16. package/abis/IUniswapV3Pool.json +135 -0
  17. package/abis/MultiOwnableTest.json +0 -23
  18. package/abis/SafeCast.json +7 -0
  19. package/abis/Simulate.json +120 -0
  20. package/abis/SqrtPriceMath.json +22 -0
  21. package/abis/TickMath.json +24 -0
  22. package/abis/ZoraFactoryImpl.json +59 -0
  23. package/addresses/8453.json +3 -3
  24. package/dist/index.cjs +160 -39
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.js +160 -39
  27. package/dist/index.js.map +1 -1
  28. package/dist/wagmiGenerated.d.ts +349 -67
  29. package/dist/wagmiGenerated.d.ts.map +1 -1
  30. package/package/wagmiGenerated.ts +161 -40
  31. package/package.json +3 -3
  32. package/script/CoinsDeployerBase.sol +1 -1
  33. package/script/Simulate.s.sol +67 -0
  34. package/src/Coin.sol +159 -90
  35. package/src/ZoraFactoryImpl.sol +47 -1
  36. package/src/interfaces/IAirlock.sol +6 -0
  37. package/src/interfaces/ICoin.sol +18 -2
  38. package/src/interfaces/IDopplerErrors.sol +14 -0
  39. package/src/interfaces/INonfungiblePositionManager.sol +2 -0
  40. package/src/interfaces/IUniswapV3Factory.sol +64 -0
  41. package/src/interfaces/IUniswapV3Pool.sol +48 -0
  42. package/src/libs/CoinConfigurationVersions.sol +9 -0
  43. package/src/libs/CoinDopplerUniV3.sol +202 -0
  44. package/src/libs/CoinLegacy.sol +48 -0
  45. package/src/libs/CoinSetup.sol +37 -0
  46. package/src/libs/MarketConstants.sol +25 -0
  47. package/src/types/LpPosition.sol +8 -0
  48. package/src/types/PoolState.sol +24 -0
  49. package/src/utils/CoinConstants.sol +5 -12
  50. package/src/utils/uniswap/BitMath.sol +55 -0
  51. package/src/utils/uniswap/CustomRevert.sol +111 -0
  52. package/src/utils/uniswap/FixedPoint96.sol +11 -0
  53. package/src/utils/uniswap/FullMath.sol +118 -0
  54. package/src/utils/uniswap/LiquidityAmounts.sol +117 -0
  55. package/src/utils/uniswap/SafeCast.sol +61 -0
  56. package/src/utils/uniswap/SqrtPriceMath.sol +249 -0
  57. package/src/utils/uniswap/TickMath.sol +244 -0
  58. package/src/utils/uniswap/UnsafeMath.sol +30 -0
  59. package/src/version/ContractVersionBase.sol +1 -1
  60. package/test/Coin.t.sol +65 -65
  61. package/test/CoinDopplerUniV3.t.sol +452 -0
  62. package/test/Factory.t.sol +49 -7
  63. package/test/utils/BaseTest.sol +26 -7
  64. package/wagmi.config.ts +1 -1
  65. package/abis/IERC721Receiver.json +0 -36
  66. 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
+ }