diff --git a/.forge-snapshots/poolManager bytecode size.snap b/.forge-snapshots/poolManager bytecode size.snap index 57601b4f4..927367108 100644 --- a/.forge-snapshots/poolManager bytecode size.snap +++ b/.forge-snapshots/poolManager bytecode size.snap @@ -1 +1 @@ -23858 \ No newline at end of file +23817 \ No newline at end of file diff --git a/.forge-snapshots/simple swap with native.snap b/.forge-snapshots/simple swap with native.snap index 70853a19b..5267f17bf 100644 --- a/.forge-snapshots/simple swap with native.snap +++ b/.forge-snapshots/simple swap with native.snap @@ -1 +1 @@ -117512 \ No newline at end of file +117381 \ No newline at end of file diff --git a/.forge-snapshots/simple swap.snap b/.forge-snapshots/simple swap.snap index 010793a84..bc35833dc 100644 --- a/.forge-snapshots/simple swap.snap +++ b/.forge-snapshots/simple swap.snap @@ -1 +1 @@ -132751 \ No newline at end of file +132620 \ No newline at end of file diff --git a/.forge-snapshots/swap CA custom curve + swap noop.snap b/.forge-snapshots/swap CA custom curve + swap noop.snap index dd5e33e5c..33ed96a1a 100644 --- a/.forge-snapshots/swap CA custom curve + swap noop.snap +++ b/.forge-snapshots/swap CA custom curve + swap noop.snap @@ -1 +1 @@ -135903 \ No newline at end of file +135892 \ No newline at end of file diff --git a/.forge-snapshots/swap CA fee on unspecified.snap b/.forge-snapshots/swap CA fee on unspecified.snap index d2350df5e..473c75dcb 100644 --- a/.forge-snapshots/swap CA fee on unspecified.snap +++ b/.forge-snapshots/swap CA fee on unspecified.snap @@ -1 +1 @@ -185018 \ No newline at end of file +184887 \ No newline at end of file diff --git a/.forge-snapshots/swap against liquidity with native token.snap b/.forge-snapshots/swap against liquidity with native token.snap index 6767b79b1..df619ebc1 100644 --- a/.forge-snapshots/swap against liquidity with native token.snap +++ b/.forge-snapshots/swap against liquidity with native token.snap @@ -1 +1 @@ -113919 \ No newline at end of file +113834 \ No newline at end of file diff --git a/.forge-snapshots/swap against liquidity.snap b/.forge-snapshots/swap against liquidity.snap index 651ad1a40..42ec59cb4 100644 --- a/.forge-snapshots/swap against liquidity.snap +++ b/.forge-snapshots/swap against liquidity.snap @@ -1 +1 @@ -125340 \ No newline at end of file +125255 \ No newline at end of file diff --git a/.forge-snapshots/swap burn 6909 for input.snap b/.forge-snapshots/swap burn 6909 for input.snap index e12fdbcd2..0663fd6c5 100644 --- a/.forge-snapshots/swap burn 6909 for input.snap +++ b/.forge-snapshots/swap burn 6909 for input.snap @@ -1 +1 @@ -137302 \ No newline at end of file +137257 \ No newline at end of file diff --git a/.forge-snapshots/swap burn native 6909 for input.snap b/.forge-snapshots/swap burn native 6909 for input.snap index 38cda8546..75d6c8585 100644 --- a/.forge-snapshots/swap burn native 6909 for input.snap +++ b/.forge-snapshots/swap burn native 6909 for input.snap @@ -1 +1 @@ -126402 \ No newline at end of file +126357 \ No newline at end of file diff --git a/.forge-snapshots/swap mint native output as 6909.snap b/.forge-snapshots/swap mint native output as 6909.snap index 2de90b885..2f0f3d4b4 100644 --- a/.forge-snapshots/swap mint native output as 6909.snap +++ b/.forge-snapshots/swap mint native output as 6909.snap @@ -1 +1 @@ -148480 \ No newline at end of file +148435 \ No newline at end of file diff --git a/.forge-snapshots/swap mint output as 6909.snap b/.forge-snapshots/swap mint output as 6909.snap index c6f46e583..d765b4c6a 100644 --- a/.forge-snapshots/swap mint output as 6909.snap +++ b/.forge-snapshots/swap mint output as 6909.snap @@ -1 +1 @@ -165375 \ No newline at end of file +165244 \ No newline at end of file diff --git a/.forge-snapshots/swap skips hook call if hook is caller.snap b/.forge-snapshots/swap skips hook call if hook is caller.snap index 1a6c091bc..11b96cf97 100644 --- a/.forge-snapshots/swap skips hook call if hook is caller.snap +++ b/.forge-snapshots/swap skips hook call if hook is caller.snap @@ -1 +1 @@ -224993 \ No newline at end of file +224777 \ No newline at end of file diff --git a/.forge-snapshots/swap with dynamic fee.snap b/.forge-snapshots/swap with dynamic fee.snap index eed13f498..1f6dfff04 100644 --- a/.forge-snapshots/swap with dynamic fee.snap +++ b/.forge-snapshots/swap with dynamic fee.snap @@ -1 +1 @@ -149642 \ No newline at end of file +149511 \ No newline at end of file diff --git a/.forge-snapshots/swap with hooks.snap b/.forge-snapshots/swap with hooks.snap index a863190a9..8eab8b1e5 100644 --- a/.forge-snapshots/swap with hooks.snap +++ b/.forge-snapshots/swap with hooks.snap @@ -1 +1 @@ -125352 \ No newline at end of file +125267 \ No newline at end of file diff --git a/.forge-snapshots/swap with lp fee and protocol fee.snap b/.forge-snapshots/swap with lp fee and protocol fee.snap index ba9f25241..fa7dfe554 100644 --- a/.forge-snapshots/swap with lp fee and protocol fee.snap +++ b/.forge-snapshots/swap with lp fee and protocol fee.snap @@ -1 +1 @@ -181904 \ No newline at end of file +181833 \ No newline at end of file diff --git a/.forge-snapshots/update dynamic fee in before swap.snap b/.forge-snapshots/update dynamic fee in before swap.snap index b4a3b3a3e..a2b21541f 100644 --- a/.forge-snapshots/update dynamic fee in before swap.snap +++ b/.forge-snapshots/update dynamic fee in before swap.snap @@ -1 +1 @@ -160195 \ No newline at end of file +160064 \ No newline at end of file diff --git a/src/libraries/Pool.sol b/src/libraries/Pool.sol index 73d3a6277..567fc3272 100644 --- a/src/libraries/Pool.sol +++ b/src/libraries/Pool.sol @@ -217,8 +217,7 @@ library Pool { } if (liquidityDelta != 0) { - int24 tick = self.slot0.tick; - uint160 sqrtPriceX96 = self.slot0.sqrtPriceX96; + (int24 tick, uint160 sqrtPriceX96) = (self.slot0.tick, self.slot0.sqrtPriceX96); if (tick < tickLower) { // current tick is below the passed range; liquidity can only become in range by crossing from left to // right, when we'll need _more_ currency0 (it's becoming more valuable) so user must provide it @@ -305,7 +304,6 @@ library Pool { { Slot0 memory slot0Start = self.slot0; bool zeroForOne = params.zeroForOne; - bool exactInput = params.amountSpecified < 0; SwapCache memory cache = SwapCache({ liquidityStart: self.liquidity, @@ -322,6 +320,8 @@ library Pool { swapFee = cache.protocolFee == 0 ? slot0Start.lpFee : uint24(cache.protocolFee).calculateSwapFee(slot0Start.lpFee); + bool exactInput = params.amountSpecified < 0; + if (!exactInput && (swapFee == LPFeeLibrary.MAX_LP_FEE)) { revert InvalidFeeForExactOut(); } @@ -347,16 +347,17 @@ library Pool { StepComputations memory step; // continue swapping as long as we haven't used the entire input/output and haven't reached the price limit - while (state.amountSpecifiedRemaining != 0 && state.sqrtPriceX96 != params.sqrtPriceLimitX96) { + while (!(state.amountSpecifiedRemaining == 0 || state.sqrtPriceX96 == params.sqrtPriceLimitX96)) { step.sqrtPriceStartX96 = state.sqrtPriceX96; (step.tickNext, step.initialized) = self.tickBitmap.nextInitializedTickWithinOneWord(state.tick, params.tickSpacing, zeroForOne); // ensure that we do not overshoot the min/max tick, as the tick bitmap is not aware of these bounds - if (step.tickNext < TickMath.MIN_TICK) { + if (step.tickNext <= TickMath.MIN_TICK) { step.tickNext = TickMath.MIN_TICK; - } else if (step.tickNext > TickMath.MAX_TICK) { + } + if (step.tickNext >= TickMath.MAX_TICK) { step.tickNext = TickMath.MAX_TICK; } @@ -376,17 +377,17 @@ library Pool { swapFee ); - if (exactInput) { - // safe because we test that amountSpecified > amountIn + feeAmount in SwapMath + if (!exactInput) { unchecked { - state.amountSpecifiedRemaining += (step.amountIn + step.feeAmount).toInt256(); + state.amountSpecifiedRemaining -= step.amountOut.toInt256(); } - state.amountCalculated = state.amountCalculated + step.amountOut.toInt256(); + state.amountCalculated = state.amountCalculated - (step.amountIn + step.feeAmount).toInt256(); } else { + // safe because we test that amountSpecified > amountIn + feeAmount in SwapMath unchecked { - state.amountSpecifiedRemaining -= step.amountOut.toInt256(); + state.amountSpecifiedRemaining += (step.amountIn + step.feeAmount).toInt256(); } - state.amountCalculated = state.amountCalculated - (step.amountIn + step.feeAmount).toInt256(); + state.amountCalculated = state.amountCalculated + step.amountOut.toInt256(); } // if the protocol fee is on, calculate how much is owed, decrement feeAmount, and increment protocolFee @@ -413,15 +414,9 @@ library Pool { if (state.sqrtPriceX96 == step.sqrtPriceNextX96) { // if the tick is initialized, run the tick transition if (step.initialized) { - uint256 feeGrowthGlobal0X128; - uint256 feeGrowthGlobal1X128; - if (!zeroForOne) { - feeGrowthGlobal0X128 = self.feeGrowthGlobal0X128; - feeGrowthGlobal1X128 = state.feeGrowthGlobalX128; - } else { - feeGrowthGlobal0X128 = state.feeGrowthGlobalX128; - feeGrowthGlobal1X128 = self.feeGrowthGlobal1X128; - } + (uint256 feeGrowthGlobal0X128, uint256 feeGrowthGlobal1X128) = zeroForOne + ? (state.feeGrowthGlobalX128, self.feeGrowthGlobal1X128) + : (self.feeGrowthGlobal0X128, state.feeGrowthGlobalX128); int128 liquidityNet = Pool.crossTick(self, step.tickNext, feeGrowthGlobal0X128, feeGrowthGlobal1X128); // if we're moving leftward, we interpret liquidityNet as the opposite sign @@ -433,8 +428,14 @@ library Pool { state.liquidity = LiquidityMath.addDelta(state.liquidity, liquidityNet); } + // Equivalent to `state.tick = zeroForOne ? step.tickNext - 1 : step.tickNext;` unchecked { - state.tick = zeroForOne ? step.tickNext - 1 : step.tickNext; + // cannot cast a bool to an int24 in Solidity + int24 _zeroForOne; + assembly { + _zeroForOne := zeroForOne + } + state.tick = step.tickNext - _zeroForOne; } } else if (state.sqrtPriceX96 != step.sqrtPriceStartX96) { // recompute unless we're on a lower tick boundary (i.e. already transitioned ticks), and haven't moved @@ -442,28 +443,28 @@ library Pool { } } - (self.slot0.sqrtPriceX96, self.slot0.tick) = (state.sqrtPriceX96, state.tick); + (self.slot0.tick, self.slot0.sqrtPriceX96) = (state.tick, state.sqrtPriceX96); // update liquidity if it changed if (cache.liquidityStart != state.liquidity) self.liquidity = state.liquidity; // update fee growth global - if (zeroForOne) { - self.feeGrowthGlobal0X128 = state.feeGrowthGlobalX128; - } else { + if (!zeroForOne) { self.feeGrowthGlobal1X128 = state.feeGrowthGlobalX128; + } else { + self.feeGrowthGlobal0X128 = state.feeGrowthGlobalX128; } unchecked { - if (zeroForOne == exactInput) { + if (zeroForOne != exactInput) { result = toBalanceDelta( - (params.amountSpecified - state.amountSpecifiedRemaining).toInt128(), - state.amountCalculated.toInt128() + state.amountCalculated.toInt128(), + (params.amountSpecified - state.amountSpecifiedRemaining).toInt128() ); } else { result = toBalanceDelta( - state.amountCalculated.toInt128(), - (params.amountSpecified - state.amountSpecifiedRemaining).toInt128() + (params.amountSpecified - state.amountSpecifiedRemaining).toInt128(), + state.amountCalculated.toInt128() ); } }