We can adapt code from the actual Uniswap v3-periphery library function OracleLibrary.getQuoteAtTick. Instead of having the function accept the tick
and then convert the tick
to sqrtRatioX96
using TickMath.getSqrtRatioAtTick(tick)
, we modify it to directly accept the sqrtRatioX96
as shown below:
/**
* @dev Calculates the amount of quote token received for a given amount of base token
* based on the square root of the price ratio (sqrtRatioX96).
*
* @param sqrtRatioX96 The square root of the price ratio(in terms of token1/token0) between two tokens, encoded as a Q64.96 value.
* @param baseAmount The amount of the base token for which the quote is to be calculated. Specify 1e18 for a price(quoteAmount) with 18 decimals of precision.
* @param inverse Specifies the direction of the price quote. If true then baseAmount must be the amount of token1, if false then baseAmount must be the amount for token0
*
* @return quoteAmount The calculated amount of the quote token for the specified baseAmount
*/
function getQuoteFromSqrtRatioX96(
uint160 sqrtRatioX96,
uint128 baseAmount,
bool inverse
) internal pure returns (uint256 quoteAmount) {
// Calculate quoteAmount with better precision if it doesn't overflow when multiplied by itself
if (sqrtRatioX96 <= type(uint128).max) {
uint256 ratioX192 = uint256(sqrtRatioX96) * sqrtRatioX96;
quoteAmount = !inverse
? FullMath.mulDiv(ratioX192, baseAmount, 1 << 192)
: FullMath.mulDiv(1 << 192, baseAmount, ratioX192);
} else {
uint256 ratioX128 = FullMath.mulDiv(
sqrtRatioX96,
sqrtRatioX96,
1 << 64
);
quoteAmount = !inverse
? FullMath.mulDiv(ratioX128, baseAmount, 1 << 128)
: FullMath.mulDiv(1 << 128, baseAmount, ratioX128);
}
}
To further simplify getting the price we can define the following function.
/**
* @dev Returns the fixed-point price for a specified sqrtRatioX96, denoted in terms of token1/token0.
* This function simplifies the process of obtaining the price from sqrtRatioX96 by using a standard
* base amount (1e18) and setting the price as non-inverted (token1/token0).
*
* @param sqrtRatioX96 The square root of the price ratio between two tokens, encoded as a Q64.96 value.
*
* @return priceU18 The calculated price in terms of token1/token0, with 18 decimal places of precision.
*/
function getPriceFromSqrtRatioX96(uint160 sqrtRatioX96) internal pure returns (uint256 priceU18) {
// if we specified inverted = true, then we'd get the price in terms of token0/token1
// whereas the UniswapV3Pool sqrtRatioX96 is in terms of token1/token0
return getQuoteFromSqrtRatioX96(sqrtRatioX96, 1e18, false);
}