Description:
Decentralized Finance (DeFi) protocol contract providing Swap, Liquidity, Factory functionality.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/Batcher.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @notice Minimal subset of the Uniswap V3 pool interface needed for reads.
interface IUniswapV3Pool {
function slot0() external view returns (
uint160 sqrtPriceX96,
int24 tick,
uint16 observationIndex,
uint16 observationCardinality,
uint16 observationCardinalityNext,
uint8 feeProtocol,
bool unlocked
);
function tickSpacing() external view returns (int24);
// ticks mapping: returns (liquidityGross, liquidityNet, feeGrowthOutside0X128, feeGrowthOutside1X128,
// tickCumulativeOutside, secondsPerLiquidityOutsideX128, secondsOutside, initialized)
function ticks(int24) external view returns (
uint128 liquidityGross,
int128 liquidityNet,
uint256 feeGrowthOutside0X128,
uint256 feeGrowthOutside1X128,
int56 tickCumulativeOutside,
uint160 secondsPerLiquidityOutsideX128,
uint32 secondsOutside,
bool initialized
);
}
type PoolId is bytes32;
interface StateView {
function getSlot0(PoolId poolId)
external
view
returns (uint160 sqrtPriceX96, int24 tick, uint24 protocolFee, uint24 lpFee);
function getTickLiquidity(PoolId poolId, int24 tick)
external
view
returns (uint128 liquidityGross, int128 liquidityNet);
}
library TickMath {
/// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
int24 internal constant MIN_TICK = -887272;
/// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
int24 internal constant MAX_TICK = -MIN_TICK;
/// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
uint160 internal constant MIN_SQRT_RATIO = 4295128739;
/// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
/// @notice Calculates sqrt(1.0001^tick) * 2^96
/// @dev Throws if |tick| > max tick
/// @param tick The input tick for the above formula
/// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)
/// at the given tick
function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
require(absTick <= uint256(uint24(MAX_TICK)), 'T');
uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;
if (tick > 0) ratio = type(uint256).max / ratio;
// this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
// we then downcast because we know the result always fits within 160 bits due to our tick input constraint
// we round up in the division so getTickAtSqrtRatio of the output price is always consistent
sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
}
}
/// @notice Batch reader for Uniswap V3 ticks and computed prices.
/// The function `readTicksAroundCurrent` returns arrays describing ticks in the window.
///
/// Usage:
/// - call readTicksAroundCurrent(pool, N) to get `2N+1` items centered (aligned to tickSpacing).
contract Batcher {
address immutable stateLibraryAddress = 0x7fFE42C4a5DEeA5b0feC41C94C136Cf115597227;
struct TickInfov3 {
int24 tick;
uint160 sqrtPriceX96;
uint256 priceX96; // price = (sqrtPriceX96^2) >> 96 (token1/token0 as Q96)
uint128 liquidityGross;
int128 liquidityNet;
bool initialized;
}
struct TickInfov4 {
int24 tick;
uint160 sqrtPriceX96;
uint256 priceX96; // price = (sqrtPriceX96^2) >> 96 (token1/token0 as Q96)
uint128 liquidityGross;
int128 liquidityNet;
}
/// @notice Read tick data for ticks in the range [-N, +N] (in tick steps of pool.tickSpacing()).
/// @param poolAddress address of the Uniswap V3 pool
/// @param tickRadius how many ticks on each side (total items returned = 2*N + 1)
/// @return infos array of TickInfo structs (length = 2*N+1)
function uniV3Ticks(address poolAddress, uint16 tickRadius) external view returns (TickInfov3[] memory infos) {
IUniswapV3Pool pool = IUniswapV3Pool(poolAddress);
// get current tick from slot0
(, int24 currentTick, , , , , ) = pool.slot0();
// tick spacing (positive)
int24 tickSpacing = pool.tickSpacing();
require(tickSpacing > 0, "Invalid tickSpacing");
// Align currentTick down to the nearest multiple of tickSpacing
int24 alignedCurrent = _floorToTickSpacing(currentTick, tickSpacing);
// prepare array
uint256 total = uint256(2) * tickRadius + 1;
infos = new TickInfov3[](total);
// iterate from -N to +N
for (int256 i = -int256(int16(tickRadius)); i <= int256(int16(tickRadius)); ++i) {
uint256 idx = uint256(i + int256(int16(tickRadius))); // array index 0..2N
int24 targetTick = int24(int256(alignedCurrent) + int256(tickSpacing) * i);
// compute sqrtPrice for this tick (may revert if tick out of math bounds)
uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(targetTick);
// price in Q96 fixed point = (sqrtPriceX96 * sqrtPriceX96) >> 96
uint256 priceX96 = (uint256(sqrtPriceX96) * uint256(sqrtPriceX96)) >> 96;
// read tick storage
(uint128 liquidityGross, int128 liquidityNet, , , , , , bool initialized) = pool.ticks(targetTick);
infos[idx] = TickInfov3({
tick: targetTick,
sqrtPriceX96: sqrtPriceX96,
priceX96: priceX96,
liquidityGross: liquidityGross,
liquidityNet: liquidityNet,
initialized: initialized
});
}
return infos;
}
function uniV4Ticks(PoolId poolId, uint16 tickRadius, int24 tickSpacing) external view returns (TickInfov4[] memory infos) {
StateView stateLibrary = StateView(stateLibraryAddress);
// get current tick from slot0
(, int24 currentTick, , ) = stateLibrary.getSlot0(poolId);
// tick spacing (positive)
require(tickSpacing > 0, "Invalid tickSpacing");
// Align currentTick down to the nearest multiple of tickSpacing
int24 alignedCurrent = _floorToTickSpacing(currentTick, tickSpacing);
// prepare array
uint256 total = uint256(2) * tickRadius + 1;
infos = new TickInfov4[](total);
// iterate from -N to +N
for (int256 i = -int256(int16(tickRadius)); i <= int256(int16(tickRadius)); ++i) {
uint256 idx = uint256(i + int256(int16(tickRadius))); // array index 0..2N
int24 targetTick = int24(int256(alignedCurrent) + int256(tickSpacing) * i);
// compute sqrtPrice for this tick (may revert if tick out of math bounds)
uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(targetTick);
// price in Q96 fixed point = (sqrtPriceX96 * sqrtPriceX96) >> 96
uint256 priceX96 = (uint256(sqrtPriceX96) * uint256(sqrtPriceX96)) >> 96;
// read tick storage
(uint128 liquidityGross, int128 liquidityNet) = stateLibrary.getTickLiquidity(poolId, targetTick);
infos[idx] = TickInfov4({
tick: targetTick,
sqrtPriceX96: sqrtPriceX96,
priceX96: priceX96,
liquidityGross: liquidityGross,
liquidityNet: liquidityNet
});
}
return infos;
}
/// @dev floor currentTick to nearest multiple of tickSpacing (towards negative infinity)
function _floorToTickSpacing(int24 tick, int24 tickSpacing) internal pure returns (int24) {
// integer division toward negative infinity
int256 ts = int256(tickSpacing);
int256 t = int256(tick);
if (t >= 0) {
int256 down = (t / ts) * ts;
return int24(down);
} else {
// for negative numbers, if not evenly divisible we need to subtract one spacing to floor
int256 div = t / ts;
if (t % ts != 0) div -= 1;
int256 down = div * ts;
return int24(down);
}
}
}
"
}
},
"settings": {
"remappings": [
"@solmate/=lib/solmate/src/",
"@permit2/=lib/permit2/src/",
"@forge-std/=lib/forge-std/src/",
"@forge-gas-snapshot/=lib/forge-gas-snapshot/src/",
"@uniswapv4/=lib/v4-core/src/",
"@eulerswap/=lib/euler-swap/src/",
"forge-std/src/=lib/forge-std/src/",
"solmate/=lib/solmate/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 2000,
"details": {
"constantOptimizer": true,
"yul": true
}
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": false
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": true
}
}}
Submitted on: 2025-10-27 19:39:46
Comments
Log in to comment.
No comments yet.