How to Compute Nearest Lower and Higher Initializable Ticks in Uniswap V3?

I am developing applications interacting with Uniswap V3 pools and need to calculate the nearest lower and higher ticks that are initializable given a specific tick and tick spacing. In Uniswap V3, tick values are represented as int24 in Solidity. tickSpacing is a uint24 in Solidity, though it's limited to less than 16384 i.e. 2 ** 14 in the UniswapV3Factory. Could anyone provide robust functions in both Solidity and JavaScript to accurately compute these values using the floor and ceil concepts?

To compute the nearest lower and higher initializable ticks for a Uniswap V3 pool, you can use the following Solidity and JavaScript implementations:

Solidity Implementation:

pragma solidity ^0.8.0;

contract TickCalculator {
// Function to calculate the closest low tick
function getClosestLowTick(int24 tick, uint16 tickSpacing) public pure returns (int24) {
require(tickSpacing != 0, "tickSpacing cannot be zero");
int24 remainder = tick % int24(tickSpacing);
if (remainder < 0) {
return (tick / int24(tickSpacing)) * int24(tickSpacing) - int24(tickSpacing);
} else {
return (tick / int24(tickSpacing)) * int24(tickSpacing);
}
}

// Function to calculate the closest high tick
function getClosestHighTick(int24 tick, uint16 tickSpacing) public pure returns (int24) {
require(tickSpacing != 0, "tickSpacing cannot be zero");
int24 closestLowTick = getClosestLowTick(tick, tickSpacing);
if (tick % int24(tickSpacing) == 0) {
return closestLowTick; // Tick is exactly on a spacing boundary
} else {
return closestLowTick + int24(tickSpacing);
}
}
}

JavaScript Implementation:

function getClosestLowTick(tick, tickSpacing) {
return Math.floor(tick / tickSpacing) * tickSpacing;
}

function getClosestHighTick(tick, tickSpacing) {
const closestLowTick = getClosestLowTick(tick, tickSpacing);
return (tick % tickSpacing === 0) ? closestLowTick : closestLowTick + tickSpacing;
}
// Example usage:
console.log(getClosestLowTick(-1, 2));  // Outputs -2
console.log(getClosestLowTick(1, 2));   // Outputs 0
console.log(getClosestHighTick(1, 2));  // Outputs 2
console.log(getClosestHighTick(-1, 2)); // Outputs 0

Explanation:

Solidity Functions: The getClosestLowTick in Solidity handles both positive and negative ticks, adjusting for negative ticks by checking the remainder. The getClosestHighTick calculates the nearest higher tick using the output of the getClosestLowTick.

JavaScript Functions: These functions use standard JavaScript math operations to achieve similar functionality, with Math.floor() handling the floor operation effectively for both positive and negative numbers.