diff --git a/.forge-snapshots/FullOracleObserve0After5Seconds.snap b/.forge-snapshots/FullOracleObserve0After5Seconds.snap index a08fb8e1..8fa2b472 100644 --- a/.forge-snapshots/FullOracleObserve0After5Seconds.snap +++ b/.forge-snapshots/FullOracleObserve0After5Seconds.snap @@ -1 +1 @@ -2687 \ No newline at end of file +1922 \ No newline at end of file diff --git a/.forge-snapshots/FullOracleObserve200By13.snap b/.forge-snapshots/FullOracleObserve200By13.snap index bb219663..9e3ceb1e 100644 --- a/.forge-snapshots/FullOracleObserve200By13.snap +++ b/.forge-snapshots/FullOracleObserve200By13.snap @@ -1 +1 @@ -22933 \ No newline at end of file +20282 \ No newline at end of file diff --git a/.forge-snapshots/FullOracleObserve200By13Plus5.snap b/.forge-snapshots/FullOracleObserve200By13Plus5.snap index 6eb59a1d..0da8d066 100644 --- a/.forge-snapshots/FullOracleObserve200By13Plus5.snap +++ b/.forge-snapshots/FullOracleObserve200By13Plus5.snap @@ -1 +1 @@ -23180 \ No newline at end of file +20520 \ No newline at end of file diff --git a/.forge-snapshots/FullOracleObserve5After5Seconds.snap b/.forge-snapshots/FullOracleObserve5After5Seconds.snap index 94c197e9..5ee5d632 100644 --- a/.forge-snapshots/FullOracleObserve5After5Seconds.snap +++ b/.forge-snapshots/FullOracleObserve5After5Seconds.snap @@ -1 +1 @@ -2738 \ No newline at end of file +2034 \ No newline at end of file diff --git a/.forge-snapshots/FullOracleObserveOldest.snap b/.forge-snapshots/FullOracleObserveOldest.snap index 75080690..3c45c181 100644 --- a/.forge-snapshots/FullOracleObserveOldest.snap +++ b/.forge-snapshots/FullOracleObserveOldest.snap @@ -1 +1 @@ -21892 \ No newline at end of file +19330 \ No newline at end of file diff --git a/.forge-snapshots/FullOracleObserveOldestAfter5Seconds.snap b/.forge-snapshots/FullOracleObserveOldestAfter5Seconds.snap index 9b54c31b..eda3bfd7 100644 --- a/.forge-snapshots/FullOracleObserveOldestAfter5Seconds.snap +++ b/.forge-snapshots/FullOracleObserveOldestAfter5Seconds.snap @@ -1 +1 @@ -22191 \ No newline at end of file +19612 \ No newline at end of file diff --git a/.forge-snapshots/FullOracleObserveZero.snap b/.forge-snapshots/FullOracleObserveZero.snap index 2a55d550..ce4798b6 100644 --- a/.forge-snapshots/FullOracleObserveZero.snap +++ b/.forge-snapshots/FullOracleObserveZero.snap @@ -1 +1 @@ -2070 \ No newline at end of file +1483 \ No newline at end of file diff --git a/.forge-snapshots/FullRangeAddInitialLiquidity.snap b/.forge-snapshots/FullRangeAddInitialLiquidity.snap index 94ac0e08..fac70738 100644 --- a/.forge-snapshots/FullRangeAddInitialLiquidity.snap +++ b/.forge-snapshots/FullRangeAddInitialLiquidity.snap @@ -1 +1 @@ -407968 \ No newline at end of file +393062 \ No newline at end of file diff --git a/.forge-snapshots/FullRangeAddLiquidity.snap b/.forge-snapshots/FullRangeAddLiquidity.snap index d1198e0f..8ff9c7d3 100644 --- a/.forge-snapshots/FullRangeAddLiquidity.snap +++ b/.forge-snapshots/FullRangeAddLiquidity.snap @@ -1 +1 @@ -201962 \ No newline at end of file +187418 \ No newline at end of file diff --git a/.forge-snapshots/FullRangeFirstSwap.snap b/.forge-snapshots/FullRangeFirstSwap.snap index aef75115..6350e081 100644 --- a/.forge-snapshots/FullRangeFirstSwap.snap +++ b/.forge-snapshots/FullRangeFirstSwap.snap @@ -1 +1 @@ -153306 \ No newline at end of file +136762 \ No newline at end of file diff --git a/.forge-snapshots/FullRangeInitialize.snap b/.forge-snapshots/FullRangeInitialize.snap index 3b5a43d1..44dce048 100644 --- a/.forge-snapshots/FullRangeInitialize.snap +++ b/.forge-snapshots/FullRangeInitialize.snap @@ -1 +1 @@ -1112212 \ No newline at end of file +1059719 \ No newline at end of file diff --git a/.forge-snapshots/FullRangeRemoveLiquidity.snap b/.forge-snapshots/FullRangeRemoveLiquidity.snap index 58273980..232c6f67 100644 --- a/.forge-snapshots/FullRangeRemoveLiquidity.snap +++ b/.forge-snapshots/FullRangeRemoveLiquidity.snap @@ -1 +1 @@ -197519 \ No newline at end of file +180886 \ No newline at end of file diff --git a/.forge-snapshots/FullRangeRemoveLiquidityAndRebalance.snap b/.forge-snapshots/FullRangeRemoveLiquidityAndRebalance.snap index 8e473407..569e77f5 100644 --- a/.forge-snapshots/FullRangeRemoveLiquidityAndRebalance.snap +++ b/.forge-snapshots/FullRangeRemoveLiquidityAndRebalance.snap @@ -1 +1 @@ -379147 \ No newline at end of file +373831 \ No newline at end of file diff --git a/.forge-snapshots/FullRangeSecondSwap.snap b/.forge-snapshots/FullRangeSecondSwap.snap index 3f185fb2..6620403b 100644 --- a/.forge-snapshots/FullRangeSecondSwap.snap +++ b/.forge-snapshots/FullRangeSecondSwap.snap @@ -1 +1 @@ -111940 \ No newline at end of file +97479 \ No newline at end of file diff --git a/.forge-snapshots/FullRangeSwap.snap b/.forge-snapshots/FullRangeSwap.snap index 68f6f4d2..c7357ed2 100644 --- a/.forge-snapshots/FullRangeSwap.snap +++ b/.forge-snapshots/FullRangeSwap.snap @@ -1 +1 @@ -151523 \ No newline at end of file +135037 \ No newline at end of file diff --git a/.forge-snapshots/OracleGrow10Slots.snap b/.forge-snapshots/OracleGrow10Slots.snap index f484e31f..c82060cc 100644 --- a/.forge-snapshots/OracleGrow10Slots.snap +++ b/.forge-snapshots/OracleGrow10Slots.snap @@ -1 +1 @@ -254660 \ No newline at end of file +232968 \ No newline at end of file diff --git a/.forge-snapshots/OracleGrow10SlotsCardinalityGreater.snap b/.forge-snapshots/OracleGrow10SlotsCardinalityGreater.snap index 83917a8d..d8ee5c94 100644 --- a/.forge-snapshots/OracleGrow10SlotsCardinalityGreater.snap +++ b/.forge-snapshots/OracleGrow10SlotsCardinalityGreater.snap @@ -1 +1 @@ -245360 \ No newline at end of file +223657 \ No newline at end of file diff --git a/.forge-snapshots/OracleGrow1Slot.snap b/.forge-snapshots/OracleGrow1Slot.snap index 8f98b8b1..3c7800f1 100644 --- a/.forge-snapshots/OracleGrow1Slot.snap +++ b/.forge-snapshots/OracleGrow1Slot.snap @@ -1 +1 @@ -54869 \ No newline at end of file +32853 \ No newline at end of file diff --git a/.forge-snapshots/OracleGrow1SlotCardinalityGreater.snap b/.forge-snapshots/OracleGrow1SlotCardinalityGreater.snap index ee2ae68d..80d77105 100644 --- a/.forge-snapshots/OracleGrow1SlotCardinalityGreater.snap +++ b/.forge-snapshots/OracleGrow1SlotCardinalityGreater.snap @@ -1 +1 @@ -45569 \ No newline at end of file +23553 \ No newline at end of file diff --git a/.forge-snapshots/OracleInitialize.snap b/.forge-snapshots/OracleInitialize.snap index 1e8b26e0..4262e6e4 100644 --- a/.forge-snapshots/OracleInitialize.snap +++ b/.forge-snapshots/OracleInitialize.snap @@ -1 +1 @@ -72316 \ No newline at end of file +51321 \ No newline at end of file diff --git a/.forge-snapshots/OracleObserveBetweenOldestAndOldestPlusOne.snap b/.forge-snapshots/OracleObserveBetweenOldestAndOldestPlusOne.snap index a695bf26..e4417bef 100644 --- a/.forge-snapshots/OracleObserveBetweenOldestAndOldestPlusOne.snap +++ b/.forge-snapshots/OracleObserveBetweenOldestAndOldestPlusOne.snap @@ -1 +1 @@ -6492 \ No newline at end of file +5397 \ No newline at end of file diff --git a/.forge-snapshots/OracleObserveCurrentTime.snap b/.forge-snapshots/OracleObserveCurrentTime.snap index 2a55d550..ce4798b6 100644 --- a/.forge-snapshots/OracleObserveCurrentTime.snap +++ b/.forge-snapshots/OracleObserveCurrentTime.snap @@ -1 +1 @@ -2070 \ No newline at end of file +1483 \ No newline at end of file diff --git a/.forge-snapshots/OracleObserveCurrentTimeCounterfactual.snap b/.forge-snapshots/OracleObserveCurrentTimeCounterfactual.snap index 2a55d550..ce4798b6 100644 --- a/.forge-snapshots/OracleObserveCurrentTimeCounterfactual.snap +++ b/.forge-snapshots/OracleObserveCurrentTimeCounterfactual.snap @@ -1 +1 @@ -2070 \ No newline at end of file +1483 \ No newline at end of file diff --git a/.forge-snapshots/OracleObserveLast20Seconds.snap b/.forge-snapshots/OracleObserveLast20Seconds.snap index 5265bba3..bbc0ec1f 100644 --- a/.forge-snapshots/OracleObserveLast20Seconds.snap +++ b/.forge-snapshots/OracleObserveLast20Seconds.snap @@ -1 +1 @@ -86878 \ No newline at end of file +73451 \ No newline at end of file diff --git a/.forge-snapshots/OracleObserveLatestEqual.snap b/.forge-snapshots/OracleObserveLatestEqual.snap index 2a55d550..ce4798b6 100644 --- a/.forge-snapshots/OracleObserveLatestEqual.snap +++ b/.forge-snapshots/OracleObserveLatestEqual.snap @@ -1 +1 @@ -2070 \ No newline at end of file +1483 \ No newline at end of file diff --git a/.forge-snapshots/OracleObserveLatestTransform.snap b/.forge-snapshots/OracleObserveLatestTransform.snap index a08fb8e1..8fa2b472 100644 --- a/.forge-snapshots/OracleObserveLatestTransform.snap +++ b/.forge-snapshots/OracleObserveLatestTransform.snap @@ -1 +1 @@ -2687 \ No newline at end of file +1922 \ No newline at end of file diff --git a/.forge-snapshots/OracleObserveMiddle.snap b/.forge-snapshots/OracleObserveMiddle.snap index d0974c4f..dd7e3e1f 100644 --- a/.forge-snapshots/OracleObserveMiddle.snap +++ b/.forge-snapshots/OracleObserveMiddle.snap @@ -1 +1 @@ -6684 \ No newline at end of file +5572 \ No newline at end of file diff --git a/.forge-snapshots/OracleObserveOldest.snap b/.forge-snapshots/OracleObserveOldest.snap index 05796bbf..63bada90 100644 --- a/.forge-snapshots/OracleObserveOldest.snap +++ b/.forge-snapshots/OracleObserveOldest.snap @@ -1 +1 @@ -6193 \ No newline at end of file +5115 \ No newline at end of file diff --git a/.forge-snapshots/OracleObserveSinceMostRecent.snap b/.forge-snapshots/OracleObserveSinceMostRecent.snap index ed8dd329..13e432b0 100644 --- a/.forge-snapshots/OracleObserveSinceMostRecent.snap +++ b/.forge-snapshots/OracleObserveSinceMostRecent.snap @@ -1 +1 @@ -3382 \ No newline at end of file +2537 \ No newline at end of file diff --git a/.forge-snapshots/TWAMMSubmitOrder.snap b/.forge-snapshots/TWAMMSubmitOrder.snap index 1ba4a8d1..7c2297c1 100644 --- a/.forge-snapshots/TWAMMSubmitOrder.snap +++ b/.forge-snapshots/TWAMMSubmitOrder.snap @@ -1 +1 @@ -145648 \ No newline at end of file +122817 \ No newline at end of file diff --git a/contracts/hooks/examples/LimitOrder.sol b/contracts/hooks/examples/LimitOrder.sol index 2a5287bf..8e9ddbf7 100644 --- a/contracts/hooks/examples/LimitOrder.sol +++ b/contracts/hooks/examples/LimitOrder.sol @@ -299,8 +299,6 @@ contract LimitOrder is BaseHook { uint128 liquidity = epochInfo.liquidity[msg.sender]; if (liquidity == 0) revert ZeroLiquidity(); delete epochInfo.liquidity[msg.sender]; - uint128 liquidityTotal = epochInfo.liquidityTotal; - epochInfo.liquidityTotal = liquidityTotal - liquidity; uint256 amount0Fee; uint256 amount1Fee; @@ -309,12 +307,12 @@ contract LimitOrder is BaseHook { address(this), abi.encodeCall( this.lockAcquiredKill, - (key, tickLower, -int256(uint256(liquidity)), to, liquidity == liquidityTotal) + (key, tickLower, -int256(uint256(liquidity)), to, liquidity == epochInfo.liquidityTotal) ) ), (uint256, uint256, uint256, uint256) ); - + epochInfo.liquidityTotal -= liquidity; unchecked { epochInfo.token0Total += amount0Fee; epochInfo.token1Total += amount1Fee; @@ -378,15 +376,13 @@ contract LimitOrder is BaseHook { if (liquidity == 0) revert ZeroLiquidity(); delete epochInfo.liquidity[msg.sender]; - uint256 token0Total = epochInfo.token0Total; - uint256 token1Total = epochInfo.token1Total; uint128 liquidityTotal = epochInfo.liquidityTotal; - amount0 = FullMath.mulDiv(token0Total, liquidity, liquidityTotal); - amount1 = FullMath.mulDiv(token1Total, liquidity, liquidityTotal); + amount0 = FullMath.mulDiv(epochInfo.token0Total, liquidity, liquidityTotal); + amount1 = FullMath.mulDiv(epochInfo.token1Total, liquidity, liquidityTotal); - epochInfo.token0Total = token0Total - amount0; - epochInfo.token1Total = token1Total - amount1; + epochInfo.token0Total -= amount0; + epochInfo.token1Total -= amount1; epochInfo.liquidityTotal = liquidityTotal - liquidity; poolManager.lock( diff --git a/contracts/lens/Quoter.sol b/contracts/lens/Quoter.sol index 8b2b16e0..1f9350a8 100644 --- a/contracts/lens/Quoter.sol +++ b/contracts/lens/Quoter.sol @@ -29,6 +29,23 @@ contract Quoter is IQuoter, ILockCallback { /// @dev int128[2] + sqrtPriceX96After padded to 32bytes + intializeTicksLoaded padded to 32bytes uint256 internal constant MINIMUM_VALID_RESPONSE_LENGTH = 96; + struct QuoteResult { + int128[] deltaAmounts; + uint160[] sqrtPriceX96AfterList; + uint32[] initializedTicksLoadedList; + } + + struct QuoteCache { + BalanceDelta curDeltas; + uint128 prevAmount; + int128 deltaIn; + int128 deltaOut; + int24 tickBefore; + int24 tickAfter; + Currency prevCurrency; + uint160 sqrtPriceX96After; + } + /// @dev Only this address may call this function modifier selfOnly() { if (msg.sender != address(this)) revert NotSelf(); @@ -151,39 +168,42 @@ contract Quoter is IQuoter, ILockCallback { function _quoteExactInput(QuoteExactParams memory params) public selfOnly returns (bytes memory) { uint256 pathLength = params.path.length; - int128[] memory deltaAmounts = new int128[](pathLength + 1); - uint160[] memory sqrtPriceX96AfterList = new uint160[](pathLength); - uint32[] memory initializedTicksLoadedList = new uint32[](pathLength); - Currency prevCurrencyOut; - uint128 prevAmountOut; + QuoteResult memory result = QuoteResult({ + deltaAmounts: new int128[](pathLength + 1), + sqrtPriceX96AfterList: new uint160[](pathLength), + initializedTicksLoadedList: new uint32[](pathLength) + }); + QuoteCache memory cache; for (uint256 i = 0; i < pathLength; i++) { (PoolKey memory poolKey, bool zeroForOne) = - params.path[i].getPoolAndSwapDirection(i == 0 ? params.exactCurrency : prevCurrencyOut); - (, int24 tickBefore,) = manager.getSlot0(poolKey.toId()); + params.path[i].getPoolAndSwapDirection(i == 0 ? params.exactCurrency : cache.prevCurrency); + (, cache.tickBefore,) = manager.getSlot0(poolKey.toId()); - (BalanceDelta curDeltas, uint160 sqrtPriceX96After, int24 tickAfter) = _swap( + (cache.curDeltas, cache.sqrtPriceX96After, cache.tickAfter) = _swap( poolKey, zeroForOne, - int256(int128(i == 0 ? params.exactAmount : prevAmountOut)), + int256(int128(i == 0 ? params.exactAmount : cache.prevAmount)), 0, params.path[i].hookData ); - (int128 deltaIn, int128 deltaOut) = - zeroForOne ? (curDeltas.amount0(), curDeltas.amount1()) : (curDeltas.amount1(), curDeltas.amount0()); - deltaAmounts[i] += deltaIn; - deltaAmounts[i + 1] += deltaOut; - - prevAmountOut = zeroForOne ? uint128(-curDeltas.amount1()) : uint128(-curDeltas.amount0()); - prevCurrencyOut = params.path[i].intermediateCurrency; - sqrtPriceX96AfterList[i] = sqrtPriceX96After; - initializedTicksLoadedList[i] = - PoolTicksCounter.countInitializedTicksLoaded(manager, poolKey, tickBefore, tickAfter); + (cache.deltaIn, cache.deltaOut) = zeroForOne + ? (cache.curDeltas.amount0(), cache.curDeltas.amount1()) + : (cache.curDeltas.amount1(), cache.curDeltas.amount0()); + result.deltaAmounts[i] += cache.deltaIn; + result.deltaAmounts[i + 1] += cache.deltaOut; + + cache.prevAmount = zeroForOne ? uint128(-cache.curDeltas.amount1()) : uint128(-cache.curDeltas.amount0()); + cache.prevCurrency = params.path[i].intermediateCurrency; + result.sqrtPriceX96AfterList[i] = cache.sqrtPriceX96After; + result.initializedTicksLoadedList[i] = + PoolTicksCounter.countInitializedTicksLoaded(manager, poolKey, cache.tickBefore, cache.tickAfter); } - bytes memory result = abi.encode(deltaAmounts, sqrtPriceX96AfterList, initializedTicksLoadedList); + bytes memory r = + abi.encode(result.deltaAmounts, result.sqrtPriceX96AfterList, result.initializedTicksLoadedList); assembly { - revert(add(0x20, result), mload(result)) + revert(add(0x20, r), mload(r)) } } @@ -216,42 +236,45 @@ contract Quoter is IQuoter, ILockCallback { function _quoteExactOutput(QuoteExactParams memory params) public selfOnly returns (bytes memory) { uint256 pathLength = params.path.length; - int128[] memory deltaAmounts = new int128[](pathLength + 1); - uint160[] memory sqrtPriceX96AfterList = new uint160[](pathLength); - uint32[] memory initializedTicksLoadedList = new uint32[](pathLength); - Currency prevCurrencyIn; - uint128 prevAmountIn; + QuoteResult memory result = QuoteResult({ + deltaAmounts: new int128[](pathLength + 1), + sqrtPriceX96AfterList: new uint160[](pathLength), + initializedTicksLoadedList: new uint32[](pathLength) + }); + QuoteCache memory cache; uint128 curAmountOut; for (uint256 i = pathLength; i > 0; i--) { - curAmountOut = i == pathLength ? params.exactAmount : prevAmountIn; + curAmountOut = i == pathLength ? params.exactAmount : cache.prevAmount; amountOutCached = curAmountOut; (PoolKey memory poolKey, bool oneForZero) = PathKeyLib.getPoolAndSwapDirection( - params.path[i - 1], i == pathLength ? params.exactCurrency : prevCurrencyIn + params.path[i - 1], i == pathLength ? params.exactCurrency : cache.prevCurrency ); - (, int24 tickBefore,) = manager.getSlot0(poolKey.toId()); + (, cache.tickBefore,) = manager.getSlot0(poolKey.toId()); - (BalanceDelta curDeltas, uint160 sqrtPriceX96After, int24 tickAfter) = + (cache.curDeltas, cache.sqrtPriceX96After, cache.tickAfter) = _swap(poolKey, !oneForZero, -int256(uint256(curAmountOut)), 0, params.path[i - 1].hookData); // always clear because sqrtPriceLimitX96 is set to 0 always delete amountOutCached; - (int128 deltaIn, int128 deltaOut) = - !oneForZero ? (curDeltas.amount0(), curDeltas.amount1()) : (curDeltas.amount1(), curDeltas.amount0()); - deltaAmounts[i - 1] += deltaIn; - deltaAmounts[i] += deltaOut; - - prevAmountIn = !oneForZero ? uint128(curDeltas.amount0()) : uint128(curDeltas.amount1()); - prevCurrencyIn = params.path[i - 1].intermediateCurrency; - sqrtPriceX96AfterList[i - 1] = sqrtPriceX96After; - initializedTicksLoadedList[i - 1] = - PoolTicksCounter.countInitializedTicksLoaded(manager, poolKey, tickBefore, tickAfter); + (cache.deltaIn, cache.deltaOut) = !oneForZero + ? (cache.curDeltas.amount0(), cache.curDeltas.amount1()) + : (cache.curDeltas.amount1(), cache.curDeltas.amount0()); + result.deltaAmounts[i - 1] += cache.deltaIn; + result.deltaAmounts[i] += cache.deltaOut; + + cache.prevAmount = !oneForZero ? uint128(cache.curDeltas.amount0()) : uint128(cache.curDeltas.amount1()); + cache.prevCurrency = params.path[i - 1].intermediateCurrency; + result.sqrtPriceX96AfterList[i - 1] = cache.sqrtPriceX96After; + result.initializedTicksLoadedList[i - 1] = + PoolTicksCounter.countInitializedTicksLoaded(manager, poolKey, cache.tickBefore, cache.tickAfter); } - bytes memory result = abi.encode(deltaAmounts, sqrtPriceX96AfterList, initializedTicksLoadedList); + bytes memory r = + abi.encode(result.deltaAmounts, result.sqrtPriceX96AfterList, result.initializedTicksLoadedList); assembly { - revert(add(0x20, result), mload(result)) + revert(add(0x20, r), mload(r)) } } diff --git a/contracts/libraries/PoolTicksCounter.sol b/contracts/libraries/PoolTicksCounter.sol index b0e9ab5b..077ef4a6 100644 --- a/contracts/libraries/PoolTicksCounter.sol +++ b/contracts/libraries/PoolTicksCounter.sol @@ -9,6 +9,15 @@ import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/src/types/PoolId.sol"; library PoolTicksCounter { using PoolIdLibrary for PoolKey; + struct TickCache { + int16 wordPosLower; + int16 wordPosHigher; + uint8 bitPosLower; + uint8 bitPosHigher; + bool tickBeforeInitialized; + bool tickAfterInitialized; + } + /// @dev This function counts the number of initialized ticks that would incur a gas cost between tickBefore and tickAfter. /// When tickBefore and/or tickAfter themselves are initialized, the logic over whether we should count them depends on the /// direction of the swap. If we are swapping upwards (tickAfter > tickBefore) we don't want to count tickBefore but we do @@ -18,12 +27,7 @@ library PoolTicksCounter { view returns (uint32 initializedTicksLoaded) { - int16 wordPosLower; - int16 wordPosHigher; - uint8 bitPosLower; - uint8 bitPosHigher; - bool tickBeforeInitialized; - bool tickAfterInitialized; + TickCache memory cache; { // Get the key and offset in the tick bitmap of the active tick before and after the swap. @@ -39,53 +43,53 @@ library PoolTicksCounter { // and we shouldn't count it. uint256 bmAfter = self.getPoolBitmapInfo(key.toId(), wordPosAfter); //uint256 bmAfter = PoolGetters.getTickBitmapAtWord(self, key.toId(), wordPosAfter); - tickAfterInitialized = + cache.tickAfterInitialized = ((bmAfter & (1 << bitPosAfter)) > 0) && ((tickAfter % key.tickSpacing) == 0) && (tickBefore > tickAfter); // In the case where tickBefore is initialized, we only want to count it if we are swapping upwards. // Use the same logic as above to decide whether we should count tickBefore or not. uint256 bmBefore = self.getPoolBitmapInfo(key.toId(), wordPos); //uint256 bmBefore = PoolGetters.getTickBitmapAtWord(self, key.toId(), wordPos); - tickBeforeInitialized = + cache.tickBeforeInitialized = ((bmBefore & (1 << bitPos)) > 0) && ((tickBefore % key.tickSpacing) == 0) && (tickBefore < tickAfter); if (wordPos < wordPosAfter || (wordPos == wordPosAfter && bitPos <= bitPosAfter)) { - wordPosLower = wordPos; - bitPosLower = bitPos; - wordPosHigher = wordPosAfter; - bitPosHigher = bitPosAfter; + cache.wordPosLower = wordPos; + cache.bitPosLower = bitPos; + cache.wordPosHigher = wordPosAfter; + cache.bitPosHigher = bitPosAfter; } else { - wordPosLower = wordPosAfter; - bitPosLower = bitPosAfter; - wordPosHigher = wordPos; - bitPosHigher = bitPos; + cache.wordPosLower = wordPosAfter; + cache.bitPosLower = bitPosAfter; + cache.wordPosHigher = wordPos; + cache.bitPosHigher = bitPos; } } // Count the number of initialized ticks crossed by iterating through the tick bitmap. // Our first mask should include the lower tick and everything to its left. - uint256 mask = type(uint256).max << bitPosLower; - while (wordPosLower <= wordPosHigher) { + uint256 mask = type(uint256).max << cache.bitPosLower; + while (cache.wordPosLower <= cache.wordPosHigher) { // If we're on the final tick bitmap page, ensure we only count up to our // ending tick. - if (wordPosLower == wordPosHigher) { - mask = mask & (type(uint256).max >> (255 - bitPosHigher)); + if (cache.wordPosLower == cache.wordPosHigher) { + mask = mask & (type(uint256).max >> (255 - cache.bitPosHigher)); } - //uint256 bmLower = PoolGetters.getTickBitmapAtWord(self, key.toId(), wordPosLower); - uint256 bmLower = self.getPoolBitmapInfo(key.toId(), wordPosLower); + //uint256 bmLower = PoolGetters.getTickBitmapAtWord(self, key.toId(), cache.wordPosLower); + uint256 bmLower = self.getPoolBitmapInfo(key.toId(), cache.wordPosLower); uint256 masked = bmLower & mask; initializedTicksLoaded += countOneBits(masked); - wordPosLower++; + cache.wordPosLower++; // Reset our mask so we consider all bits on the next iteration. mask = type(uint256).max; } - if (tickAfterInitialized) { + if (cache.tickAfterInitialized) { initializedTicksLoaded -= 1; } - if (tickBeforeInitialized) { + if (cache.tickBeforeInitialized) { initializedTicksLoaded -= 1; } diff --git a/foundry.toml b/foundry.toml index 620d06a6..d957fe5b 100644 --- a/foundry.toml +++ b/foundry.toml @@ -2,7 +2,6 @@ src = 'contracts' out = 'foundry-out' solc_version = '0.8.20' -via_ir = true optimizer_runs = 1000000 ffi = true fs_permissions = [{ access = "read-write", path = ".forge-snapshots/"}] diff --git a/test/Quoter.t.sol b/test/Quoter.t.sol index 056b0818..31d266d4 100644 --- a/test/Quoter.t.sol +++ b/test/Quoter.t.sol @@ -53,14 +53,15 @@ contract QuoterTest is Test, Deployers { quoter = new Quoter(address(manager)); positionManager = new PoolModifyPositionTest(manager); - // salts are chosen so that address(token0) < address(token2) && address(1) < address(token2) - bytes32 salt1 = "ffff"; - bytes32 salt2 = "gm"; - token0 = new MockERC20{salt: salt1}("Test0", "0", 18); + // salts are chosen so that address(token0) < address(token1) && address(token1) < address(token2) + bytes32 salt0 = "1234"; + bytes32 salt1 = "gm uniswap"; + bytes32 salt2 = "ffff"; + token0 = new MockERC20{salt: salt0}("Test0", "0", 18); token0.mint(address(this), 2 ** 128); - token1 = new MockERC20{salt: salt2}("Test1", "1", 18); + token1 = new MockERC20{salt: salt1}("Test1", "1", 18); token1.mint(address(this), 2 ** 128); - token2 = new MockERC20("Test2", "2", 18); + token2 = new MockERC20{salt: salt2}("Test2", "2", 18); token2.mint(address(this), 2 ** 128); key01 = createPoolKey(token0, token1, address(0));