//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IUniswapV3Pool { function token0() external view returns (address); function token1() external view returns (address); function fee() external view returns (uint24); function tickSpacing() external view returns (int24); function liquidity() external view returns (uint128); function slot0() external view returns ( uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked ); function ticks(int24 tick) external view returns ( uint128 liquidityGross, int128 liquidityNet, uint256 feeGrowthOutside0X128, uint256 feeGrowthOutside1X128, int56 tickCumulativeOutside, uint160 secondsPerLiquidityOutsideX128, uint32 secondsOutside, bool initialized ); } interface IERC20 { function decimals() external view returns (uint8); } /** @dev This contract is not meant to be deployed. Instead, use a static call with the deployment bytecode as payload. */ contract GetUniswapV3PoolDataBatchRequest { struct PoolData { address tokenA; uint8 tokenADecimals; address tokenB; uint8 tokenBDecimals; uint128 liquidity; uint160 sqrtPrice; int24 tick; int24 tickSpacing; uint24 fee; int128 liquidityNet; } constructor(address[] memory pools) { PoolData[] memory allPoolData = new PoolData[](pools.length); for (uint256 i = 0; i < pools.length; ++i) { address poolAddress = pools[i]; if (codeSizeIsZero(poolAddress)) continue; PoolData memory poolData; poolData.tokenA = IUniswapV3Pool(poolAddress).token0(); poolData.tokenB = IUniswapV3Pool(poolAddress).token1(); //Check that tokenA and tokenB do not have codesize of 0 if (codeSizeIsZero(poolData.tokenA)) continue; if (codeSizeIsZero(poolData.tokenB)) continue; //Get tokenA decimals ( bool tokenADecimalsSuccess, bytes memory tokenADecimalsData ) = poolData.tokenA.call(abi.encodeWithSignature("decimals()")); if (tokenADecimalsSuccess) { uint256 tokenADecimals; if (tokenADecimalsData.length == 32) { (tokenADecimals) = abi.decode( tokenADecimalsData, (uint256) ); if (tokenADecimals == 0 || tokenADecimals > 255) { continue; } else { poolData.tokenADecimals = uint8(tokenADecimals); } } else { continue; } } else { continue; } ( bool tokenBDecimalsSuccess, bytes memory tokenBDecimalsData ) = poolData.tokenB.call(abi.encodeWithSignature("decimals()")); if (tokenBDecimalsSuccess) { uint256 tokenBDecimals; if (tokenBDecimalsData.length == 32) { (tokenBDecimals) = abi.decode( tokenBDecimalsData, (uint256) ); if (tokenBDecimals == 0 || tokenBDecimals > 255) { continue; } else { poolData.tokenBDecimals = uint8(tokenBDecimals); } } else { continue; } } else { continue; } (uint160 sqrtPriceX96, int24 tick, , , , , ) = IUniswapV3Pool( poolAddress ).slot0(); (, int128 liquidityNet, , , , , , ) = IUniswapV3Pool(poolAddress) .ticks(tick); poolData.liquidity = IUniswapV3Pool(poolAddress).liquidity(); poolData.tickSpacing = IUniswapV3Pool(poolAddress).tickSpacing(); poolData.fee = IUniswapV3Pool(poolAddress).fee(); poolData.sqrtPrice = sqrtPriceX96; poolData.tick = tick; poolData.liquidityNet = liquidityNet; allPoolData[i] = poolData; } bytes memory _abiEncodedData = abi.encode(allPoolData); assembly { // Return from the start of the data (discarding the original data address) // up to the end of the memory used let dataStart := add(_abiEncodedData, 0x20) return(dataStart, sub(msize(), dataStart)) } } function codeSizeIsZero(address target) internal view returns (bool) { if (target.code.length == 0) { return true; } else { return false; } } }