forked from Uniswap/v4-core
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added delta overflow checks (Uniswap#433)
- Loading branch information
Showing
2 changed files
with
150 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.20; | ||
|
||
import "../../src/libraries/FullMath.sol"; | ||
import "../../src/libraries/FixedPoint96.sol"; | ||
|
||
/// @title Liquidity amount functions | ||
/// @notice Provides functions for computing liquidity amounts from token amounts and prices | ||
library LiquidityAmounts { | ||
/// @notice Downcasts uint256 to uint128 | ||
/// @param x The uint258 to be downcasted | ||
/// @return y The passed value, downcasted to uint128 | ||
function toUint128(uint256 x) private pure returns (uint128 y) { | ||
require((y = uint128(x)) == x); | ||
} | ||
|
||
/// @notice Computes the amount of liquidity received for a given amount of token0 and price range | ||
/// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower)) | ||
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary | ||
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary | ||
/// @param amount0 The amount0 being sent in | ||
/// @return liquidity The amount of returned liquidity | ||
function getLiquidityForAmount0(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint256 amount0) | ||
internal | ||
pure | ||
returns (uint128 liquidity) | ||
{ | ||
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); | ||
uint256 intermediate = FullMath.mulDiv(sqrtRatioAX96, sqrtRatioBX96, FixedPoint96.Q96); | ||
return toUint128(FullMath.mulDiv(amount0, intermediate, sqrtRatioBX96 - sqrtRatioAX96)); | ||
} | ||
|
||
/// @notice Computes the amount of liquidity received for a given amount of token1 and price range | ||
/// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)). | ||
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary | ||
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary | ||
/// @param amount1 The amount1 being sent in | ||
/// @return liquidity The amount of returned liquidity | ||
function getLiquidityForAmount1(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint256 amount1) | ||
internal | ||
pure | ||
returns (uint128 liquidity) | ||
{ | ||
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); | ||
return toUint128(FullMath.mulDiv(amount1, FixedPoint96.Q96, sqrtRatioBX96 - sqrtRatioAX96)); | ||
} | ||
|
||
/// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current | ||
/// pool prices and the prices at the tick boundaries | ||
/// @param sqrtRatioX96 A sqrt price representing the current pool prices | ||
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary | ||
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary | ||
/// @param amount0 The amount of token0 being sent in | ||
/// @param amount1 The amount of token1 being sent in | ||
/// @return liquidity The maximum amount of liquidity received | ||
function getLiquidityForAmounts( | ||
uint160 sqrtRatioX96, | ||
uint160 sqrtRatioAX96, | ||
uint160 sqrtRatioBX96, | ||
uint256 amount0, | ||
uint256 amount1 | ||
) internal pure returns (uint128 liquidity) { | ||
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); | ||
|
||
if (sqrtRatioX96 <= sqrtRatioAX96) { | ||
liquidity = getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0); | ||
} else if (sqrtRatioX96 < sqrtRatioBX96) { | ||
uint128 liquidity0 = getLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0); | ||
uint128 liquidity1 = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1); | ||
|
||
liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1; | ||
} else { | ||
liquidity = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1); | ||
} | ||
} | ||
|
||
/// @notice Computes the amount of token0 for a given amount of liquidity and a price range | ||
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary | ||
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary | ||
/// @param liquidity The liquidity being valued | ||
/// @return amount0 The amount of token0 | ||
function getAmount0ForLiquidity(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity) | ||
internal | ||
pure | ||
returns (uint256 amount0) | ||
{ | ||
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); | ||
|
||
return FullMath.mulDiv( | ||
uint256(liquidity) << FixedPoint96.RESOLUTION, sqrtRatioBX96 - sqrtRatioAX96, sqrtRatioBX96 | ||
) / sqrtRatioAX96; | ||
} | ||
|
||
/// @notice Computes the amount of token1 for a given amount of liquidity and a price range | ||
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary | ||
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary | ||
/// @param liquidity The liquidity being valued | ||
/// @return amount1 The amount of token1 | ||
function getAmount1ForLiquidity(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity) | ||
internal | ||
pure | ||
returns (uint256 amount1) | ||
{ | ||
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); | ||
|
||
return FullMath.mulDiv(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96); | ||
} | ||
|
||
/// @notice Computes the token0 and token1 value for a given amount of liquidity, the current | ||
/// pool prices and the prices at the tick boundaries | ||
/// @param sqrtRatioX96 A sqrt price representing the current pool prices | ||
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary | ||
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary | ||
/// @param liquidity The liquidity being valued | ||
/// @return amount0 The amount of token0 | ||
/// @return amount1 The amount of token1 | ||
function getAmountsForLiquidity( | ||
uint160 sqrtRatioX96, | ||
uint160 sqrtRatioAX96, | ||
uint160 sqrtRatioBX96, | ||
uint128 liquidity | ||
) internal pure returns (uint256 amount0, uint256 amount1) { | ||
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); | ||
|
||
if (sqrtRatioX96 <= sqrtRatioAX96) { | ||
amount0 = getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity); | ||
} else if (sqrtRatioX96 < sqrtRatioBX96) { | ||
amount0 = getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity); | ||
amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity); | ||
} else { | ||
amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity); | ||
} | ||
} | ||
} |