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);
}