1
0
forked from mico/idle_moloch
idle_moloch/lib/v3-periphery/contracts/libraries/PositionValue.sol
2024-11-01 11:55:27 +01:00

168 lines
7.0 KiB
Solidity

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.8 <0.8.0;
import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol';
import '@uniswap/v3-core/contracts/libraries/FixedPoint128.sol';
import '@uniswap/v3-core/contracts/libraries/TickMath.sol';
import '@uniswap/v3-core/contracts/libraries/Tick.sol';
import '../interfaces/INonfungiblePositionManager.sol';
import './LiquidityAmounts.sol';
import './PoolAddress.sol';
import './PositionKey.sol';
/// @title Returns information about the token value held in a Uniswap V3 NFT
library PositionValue {
/// @notice Returns the total amounts of token0 and token1, i.e. the sum of fees and principal
/// that a given nonfungible position manager token is worth
/// @param positionManager The Uniswap V3 NonfungiblePositionManager
/// @param tokenId The tokenId of the token for which to get the total value
/// @param sqrtRatioX96 The square root price X96 for which to calculate the principal amounts
/// @return amount0 The total amount of token0 including principal and fees
/// @return amount1 The total amount of token1 including principal and fees
function total(
INonfungiblePositionManager positionManager,
uint256 tokenId,
uint160 sqrtRatioX96
) internal view returns (uint256 amount0, uint256 amount1) {
(uint256 amount0Principal, uint256 amount1Principal) = principal(positionManager, tokenId, sqrtRatioX96);
(uint256 amount0Fee, uint256 amount1Fee) = fees(positionManager, tokenId);
return (amount0Principal + amount0Fee, amount1Principal + amount1Fee);
}
/// @notice Calculates the principal (currently acting as liquidity) owed to the token owner in the event
/// that the position is burned
/// @param positionManager The Uniswap V3 NonfungiblePositionManager
/// @param tokenId The tokenId of the token for which to get the total principal owed
/// @param sqrtRatioX96 The square root price X96 for which to calculate the principal amounts
/// @return amount0 The principal amount of token0
/// @return amount1 The principal amount of token1
function principal(
INonfungiblePositionManager positionManager,
uint256 tokenId,
uint160 sqrtRatioX96
) internal view returns (uint256 amount0, uint256 amount1) {
(, , , , , int24 tickLower, int24 tickUpper, uint128 liquidity, , , , ) = positionManager.positions(tokenId);
return
LiquidityAmounts.getAmountsForLiquidity(
sqrtRatioX96,
TickMath.getSqrtRatioAtTick(tickLower),
TickMath.getSqrtRatioAtTick(tickUpper),
liquidity
);
}
struct FeeParams {
address token0;
address token1;
uint24 fee;
int24 tickLower;
int24 tickUpper;
uint128 liquidity;
uint256 positionFeeGrowthInside0LastX128;
uint256 positionFeeGrowthInside1LastX128;
uint256 tokensOwed0;
uint256 tokensOwed1;
}
/// @notice Calculates the total fees owed to the token owner
/// @param positionManager The Uniswap V3 NonfungiblePositionManager
/// @param tokenId The tokenId of the token for which to get the total fees owed
/// @return amount0 The amount of fees owed in token0
/// @return amount1 The amount of fees owed in token1
function fees(INonfungiblePositionManager positionManager, uint256 tokenId)
internal
view
returns (uint256 amount0, uint256 amount1)
{
(
,
,
address token0,
address token1,
uint24 fee,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint256 positionFeeGrowthInside0LastX128,
uint256 positionFeeGrowthInside1LastX128,
uint256 tokensOwed0,
uint256 tokensOwed1
) = positionManager.positions(tokenId);
return
_fees(
positionManager,
FeeParams({
token0: token0,
token1: token1,
fee: fee,
tickLower: tickLower,
tickUpper: tickUpper,
liquidity: liquidity,
positionFeeGrowthInside0LastX128: positionFeeGrowthInside0LastX128,
positionFeeGrowthInside1LastX128: positionFeeGrowthInside1LastX128,
tokensOwed0: tokensOwed0,
tokensOwed1: tokensOwed1
})
);
}
function _fees(INonfungiblePositionManager positionManager, FeeParams memory feeParams)
private
view
returns (uint256 amount0, uint256 amount1)
{
(uint256 poolFeeGrowthInside0LastX128, uint256 poolFeeGrowthInside1LastX128) =
_getFeeGrowthInside(
IUniswapV3Pool(
PoolAddress.computeAddress(
positionManager.factory(),
PoolAddress.PoolKey({token0: feeParams.token0, token1: feeParams.token1, fee: feeParams.fee})
)
),
feeParams.tickLower,
feeParams.tickUpper
);
amount0 =
FullMath.mulDiv(
poolFeeGrowthInside0LastX128 - feeParams.positionFeeGrowthInside0LastX128,
feeParams.liquidity,
FixedPoint128.Q128
) +
feeParams.tokensOwed0;
amount1 =
FullMath.mulDiv(
poolFeeGrowthInside1LastX128 - feeParams.positionFeeGrowthInside1LastX128,
feeParams.liquidity,
FixedPoint128.Q128
) +
feeParams.tokensOwed1;
}
function _getFeeGrowthInside(
IUniswapV3Pool pool,
int24 tickLower,
int24 tickUpper
) private view returns (uint256 feeGrowthInside0X128, uint256 feeGrowthInside1X128) {
(, int24 tickCurrent, , , , , ) = pool.slot0();
(, , uint256 lowerFeeGrowthOutside0X128, uint256 lowerFeeGrowthOutside1X128, , , , ) = pool.ticks(tickLower);
(, , uint256 upperFeeGrowthOutside0X128, uint256 upperFeeGrowthOutside1X128, , , , ) = pool.ticks(tickUpper);
if (tickCurrent < tickLower) {
feeGrowthInside0X128 = lowerFeeGrowthOutside0X128 - upperFeeGrowthOutside0X128;
feeGrowthInside1X128 = lowerFeeGrowthOutside1X128 - upperFeeGrowthOutside1X128;
} else if (tickCurrent < tickUpper) {
uint256 feeGrowthGlobal0X128 = pool.feeGrowthGlobal0X128();
uint256 feeGrowthGlobal1X128 = pool.feeGrowthGlobal1X128();
feeGrowthInside0X128 = feeGrowthGlobal0X128 - lowerFeeGrowthOutside0X128 - upperFeeGrowthOutside0X128;
feeGrowthInside1X128 = feeGrowthGlobal1X128 - lowerFeeGrowthOutside1X128 - upperFeeGrowthOutside1X128;
} else {
feeGrowthInside0X128 = upperFeeGrowthOutside0X128 - lowerFeeGrowthOutside0X128;
feeGrowthInside1X128 = upperFeeGrowthOutside1X128 - lowerFeeGrowthOutside1X128;
}
}
}