// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.19; import "@uniswap-v3-core/interfaces/IUniswapV3Factory.sol"; import "@uniswap-v3-core/interfaces/IUniswapV3Pool.sol"; import "forge-std/Script.sol"; import "@aperture/uni-v3-lib/LiquidityAmounts.sol"; import "@aperture/uni-v3-lib/TickMath.sol"; interface ILM { function positions(uint8 stage) external view returns (uint128 liquidity, int24 tickLower, int24 tickUpper); } interface IWETH { function balanceOf(address) external view returns (uint256); } /// @title LmTotalEth /// @notice Read-only script: prints total ETH controlled by LiquidityManager /// (free ETH + free WETH + ETH locked in all 3 Uni V3 positions). /// @dev forge script script/LmTotalEth.s.sol --rpc-url $RPC_URL /// Env: LM, WETH, POOL contract LmTotalEth is Script { function run() external view { address lm = vm.envAddress("LM"); address weth = vm.envAddress("WETH"); address pool = vm.envAddress("POOL"); // Free balances uint256 freeEth = lm.balance; uint256 freeWeth = IWETH(weth).balanceOf(lm); // Current sqrtPrice from pool (uint160 sqrtPriceX96,,,,,,) = IUniswapV3Pool(pool).slot0(); // Determine which token is WETH (token0 or token1) bool wethIsToken0 = IUniswapV3Pool(pool).token0() == weth; // Sum ETH in all 3 positions: FLOOR=0, ANCHOR=1, DISCOVERY=2 uint256 positionEth = 0; for (uint8 stage = 0; stage < 3; stage++) { (uint128 liquidity, int24 tickLower, int24 tickUpper) = ILM(lm).positions(stage); if (liquidity == 0) continue; uint160 sqrtA = TickMath.getSqrtRatioAtTick(tickLower); uint160 sqrtB = TickMath.getSqrtRatioAtTick(tickUpper); (uint256 amount0, uint256 amount1) = LiquidityAmounts.getAmountsForLiquidity(sqrtPriceX96, sqrtA, sqrtB, liquidity); positionEth += wethIsToken0 ? amount0 : amount1; } uint256 total = freeEth + freeWeth + positionEth; // Output as plain number for easy bash consumption console2.log(total); } }