diff --git a/.forge-snapshots/BitMathLeastSignificantBitMaxUint128.snap b/.forge-snapshots/BitMathLeastSignificantBitMaxUint128.snap deleted file mode 100644 index d99e90eb9..000000000 --- a/.forge-snapshots/BitMathLeastSignificantBitMaxUint128.snap +++ /dev/null @@ -1 +0,0 @@ -29 \ No newline at end of file diff --git a/.forge-snapshots/BitMathLeastSignificantBitMaxUint256.snap b/.forge-snapshots/BitMathLeastSignificantBitMaxUint256.snap deleted file mode 100644 index d99e90eb9..000000000 --- a/.forge-snapshots/BitMathLeastSignificantBitMaxUint256.snap +++ /dev/null @@ -1 +0,0 @@ -29 \ No newline at end of file diff --git a/.forge-snapshots/BitMathLeastSignificantBitSmallNumber.snap b/.forge-snapshots/BitMathLeastSignificantBitSmallNumber.snap deleted file mode 100644 index d99e90eb9..000000000 --- a/.forge-snapshots/BitMathLeastSignificantBitSmallNumber.snap +++ /dev/null @@ -1 +0,0 @@ -29 \ No newline at end of file diff --git a/.forge-snapshots/BitMathMostSignificantBitMaxUint128.snap b/.forge-snapshots/BitMathMostSignificantBitMaxUint128.snap deleted file mode 100644 index d99e90eb9..000000000 --- a/.forge-snapshots/BitMathMostSignificantBitMaxUint128.snap +++ /dev/null @@ -1 +0,0 @@ -29 \ No newline at end of file diff --git a/.forge-snapshots/BitMathMostSignificantBitMaxUint256.snap b/.forge-snapshots/BitMathMostSignificantBitMaxUint256.snap deleted file mode 100644 index d99e90eb9..000000000 --- a/.forge-snapshots/BitMathMostSignificantBitMaxUint256.snap +++ /dev/null @@ -1 +0,0 @@ -29 \ No newline at end of file diff --git a/.forge-snapshots/BitMathMostSignificantBitSmallNumber.snap b/.forge-snapshots/BitMathMostSignificantBitSmallNumber.snap deleted file mode 100644 index d99e90eb9..000000000 --- a/.forge-snapshots/BitMathMostSignificantBitSmallNumber.snap +++ /dev/null @@ -1 +0,0 @@ -29 \ No newline at end of file diff --git a/.forge-snapshots/ERC6909Claims approve.snap b/.forge-snapshots/ERC6909Claims approve.snap deleted file mode 100644 index 3fd1f86d8..000000000 --- a/.forge-snapshots/ERC6909Claims approve.snap +++ /dev/null @@ -1 +0,0 @@ -46323 \ No newline at end of file diff --git a/.forge-snapshots/ERC6909Claims burn.snap b/.forge-snapshots/ERC6909Claims burn.snap deleted file mode 100644 index ce114354d..000000000 --- a/.forge-snapshots/ERC6909Claims burn.snap +++ /dev/null @@ -1 +0,0 @@ -29389 \ No newline at end of file diff --git a/.forge-snapshots/ERC6909Claims mint.snap b/.forge-snapshots/ERC6909Claims mint.snap deleted file mode 100644 index dd2b6be6b..000000000 --- a/.forge-snapshots/ERC6909Claims mint.snap +++ /dev/null @@ -1 +0,0 @@ -46603 \ No newline at end of file diff --git a/.forge-snapshots/ERC6909Claims transfer.snap b/.forge-snapshots/ERC6909Claims transfer.snap deleted file mode 100644 index 46563dfdc..000000000 --- a/.forge-snapshots/ERC6909Claims transfer.snap +++ /dev/null @@ -1 +0,0 @@ -51756 \ No newline at end of file diff --git a/.forge-snapshots/ERC6909Claims transferFrom as operator.snap b/.forge-snapshots/ERC6909Claims transferFrom as operator.snap deleted file mode 100644 index 666e4e2f7..000000000 --- a/.forge-snapshots/ERC6909Claims transferFrom as operator.snap +++ /dev/null @@ -1 +0,0 @@ -54437 \ No newline at end of file diff --git a/.forge-snapshots/ERC6909Claims transferFrom with approval.snap b/.forge-snapshots/ERC6909Claims transferFrom with approval.snap deleted file mode 100644 index a55a87caf..000000000 --- a/.forge-snapshots/ERC6909Claims transferFrom with approval.snap +++ /dev/null @@ -1 +0,0 @@ -59939 \ No newline at end of file diff --git a/.forge-snapshots/ERC6909Claims transferFrom with infinite approval.snap b/.forge-snapshots/ERC6909Claims transferFrom with infinite approval.snap deleted file mode 100644 index 53b9db994..000000000 --- a/.forge-snapshots/ERC6909Claims transferFrom with infinite approval.snap +++ /dev/null @@ -1 +0,0 @@ -56770 \ No newline at end of file diff --git a/.forge-snapshots/NoDelegateCall.snap b/.forge-snapshots/NoDelegateCall.snap deleted file mode 100644 index 7003e7fe1..000000000 --- a/.forge-snapshots/NoDelegateCall.snap +++ /dev/null @@ -1 +0,0 @@ -51 \ No newline at end of file diff --git a/.forge-snapshots/SwapMath_oneForZero_exactInCapped.snap b/.forge-snapshots/SwapMath_oneForZero_exactInCapped.snap deleted file mode 100644 index 0a30b7dc3..000000000 --- a/.forge-snapshots/SwapMath_oneForZero_exactInCapped.snap +++ /dev/null @@ -1 +0,0 @@ -1192 \ No newline at end of file diff --git a/.forge-snapshots/SwapMath_oneForZero_exactInPartial.snap b/.forge-snapshots/SwapMath_oneForZero_exactInPartial.snap deleted file mode 100644 index 15448f161..000000000 --- a/.forge-snapshots/SwapMath_oneForZero_exactInPartial.snap +++ /dev/null @@ -1 +0,0 @@ -1261 \ No newline at end of file diff --git a/.forge-snapshots/SwapMath_oneForZero_exactOutCapped.snap b/.forge-snapshots/SwapMath_oneForZero_exactOutCapped.snap deleted file mode 100644 index 546440c6f..000000000 --- a/.forge-snapshots/SwapMath_oneForZero_exactOutCapped.snap +++ /dev/null @@ -1 +0,0 @@ -1005 \ No newline at end of file diff --git a/.forge-snapshots/SwapMath_oneForZero_exactOutPartial.snap b/.forge-snapshots/SwapMath_oneForZero_exactOutPartial.snap deleted file mode 100644 index 62692420f..000000000 --- a/.forge-snapshots/SwapMath_oneForZero_exactOutPartial.snap +++ /dev/null @@ -1 +0,0 @@ -1569 \ No newline at end of file diff --git a/.forge-snapshots/SwapMath_zeroForOne_exactInCapped.snap b/.forge-snapshots/SwapMath_zeroForOne_exactInCapped.snap deleted file mode 100644 index 0b078c5a8..000000000 --- a/.forge-snapshots/SwapMath_zeroForOne_exactInCapped.snap +++ /dev/null @@ -1 +0,0 @@ -1130 \ No newline at end of file diff --git a/.forge-snapshots/SwapMath_zeroForOne_exactInPartial.snap b/.forge-snapshots/SwapMath_zeroForOne_exactInPartial.snap deleted file mode 100644 index 2a915b96a..000000000 --- a/.forge-snapshots/SwapMath_zeroForOne_exactInPartial.snap +++ /dev/null @@ -1 +0,0 @@ -1443 \ No newline at end of file diff --git a/.forge-snapshots/SwapMath_zeroForOne_exactOutCapped.snap b/.forge-snapshots/SwapMath_zeroForOne_exactOutCapped.snap deleted file mode 100644 index 6b65e9713..000000000 --- a/.forge-snapshots/SwapMath_zeroForOne_exactOutCapped.snap +++ /dev/null @@ -1 +0,0 @@ -920 \ No newline at end of file diff --git a/.forge-snapshots/SwapMath_zeroForOne_exactOutPartial.snap b/.forge-snapshots/SwapMath_zeroForOne_exactOutPartial.snap deleted file mode 100644 index ff7be5376..000000000 --- a/.forge-snapshots/SwapMath_zeroForOne_exactOutPartial.snap +++ /dev/null @@ -1 +0,0 @@ -1134 \ No newline at end of file diff --git a/.forge-snapshots/TickMathGetSqrtPriceAtTick.snap b/.forge-snapshots/TickMathGetSqrtPriceAtTick.snap deleted file mode 100644 index 04b715f23..000000000 --- a/.forge-snapshots/TickMathGetSqrtPriceAtTick.snap +++ /dev/null @@ -1 +0,0 @@ -72353 \ No newline at end of file diff --git a/.forge-snapshots/TickMathGetTickAtSqrtPrice.snap b/.forge-snapshots/TickMathGetTickAtSqrtPrice.snap deleted file mode 100644 index f0f525d2f..000000000 --- a/.forge-snapshots/TickMathGetTickAtSqrtPrice.snap +++ /dev/null @@ -1 +0,0 @@ -195023 \ No newline at end of file diff --git a/.forge-snapshots/add liquidity to already existing position with salt.snap b/.forge-snapshots/add liquidity to already existing position with salt.snap deleted file mode 100644 index 342163227..000000000 --- a/.forge-snapshots/add liquidity to already existing position with salt.snap +++ /dev/null @@ -1 +0,0 @@ -144663 \ No newline at end of file diff --git a/.forge-snapshots/addLiquidity CA fee.snap b/.forge-snapshots/addLiquidity CA fee.snap deleted file mode 100644 index d4dff6e54..000000000 --- a/.forge-snapshots/addLiquidity CA fee.snap +++ /dev/null @@ -1 +0,0 @@ -170959 \ No newline at end of file diff --git a/.forge-snapshots/addLiquidity with empty hook.snap b/.forge-snapshots/addLiquidity with empty hook.snap deleted file mode 100644 index 9d9c26d43..000000000 --- a/.forge-snapshots/addLiquidity with empty hook.snap +++ /dev/null @@ -1 +0,0 @@ -274264 \ No newline at end of file diff --git a/.forge-snapshots/addLiquidity with native token.snap b/.forge-snapshots/addLiquidity with native token.snap deleted file mode 100644 index a7684fdf5..000000000 --- a/.forge-snapshots/addLiquidity with native token.snap +++ /dev/null @@ -1 +0,0 @@ -135141 \ No newline at end of file diff --git a/.forge-snapshots/clear.snap b/.forge-snapshots/clear.snap deleted file mode 100644 index f0e160769..000000000 --- a/.forge-snapshots/clear.snap +++ /dev/null @@ -1 +0,0 @@ -1717 \ No newline at end of file diff --git a/.forge-snapshots/create new liquidity to a position with salt.snap b/.forge-snapshots/create new liquidity to a position with salt.snap deleted file mode 100644 index 3c4d3e51e..000000000 --- a/.forge-snapshots/create new liquidity to a position with salt.snap +++ /dev/null @@ -1 +0,0 @@ -292855 \ No newline at end of file diff --git a/.forge-snapshots/donate gas with 1 token.snap b/.forge-snapshots/donate gas with 1 token.snap deleted file mode 100644 index cb54169dc..000000000 --- a/.forge-snapshots/donate gas with 1 token.snap +++ /dev/null @@ -1 +0,0 @@ -106345 \ No newline at end of file diff --git a/.forge-snapshots/donate gas with 2 tokens.snap b/.forge-snapshots/donate gas with 2 tokens.snap deleted file mode 100644 index 0f05365bd..000000000 --- a/.forge-snapshots/donate gas with 2 tokens.snap +++ /dev/null @@ -1 +0,0 @@ -145766 \ No newline at end of file diff --git a/.forge-snapshots/erc20 collect protocol fees.snap b/.forge-snapshots/erc20 collect protocol fees.snap deleted file mode 100644 index 7606bacbf..000000000 --- a/.forge-snapshots/erc20 collect protocol fees.snap +++ /dev/null @@ -1 +0,0 @@ -57454 \ No newline at end of file diff --git a/.forge-snapshots/extsload getFeeGrowthGlobals.snap b/.forge-snapshots/extsload getFeeGrowthGlobals.snap deleted file mode 100644 index 5c1d4541a..000000000 --- a/.forge-snapshots/extsload getFeeGrowthGlobals.snap +++ /dev/null @@ -1 +0,0 @@ -777 \ No newline at end of file diff --git a/.forge-snapshots/extsload getFeeGrowthInside.snap b/.forge-snapshots/extsload getFeeGrowthInside.snap deleted file mode 100644 index 5f5d9b11a..000000000 --- a/.forge-snapshots/extsload getFeeGrowthInside.snap +++ /dev/null @@ -1 +0,0 @@ -375 \ No newline at end of file diff --git a/.forge-snapshots/extsload getLiquidity.snap b/.forge-snapshots/extsload getLiquidity.snap deleted file mode 100644 index 5f5d9b11a..000000000 --- a/.forge-snapshots/extsload getLiquidity.snap +++ /dev/null @@ -1 +0,0 @@ -375 \ No newline at end of file diff --git a/.forge-snapshots/extsload getPositionInfo.snap b/.forge-snapshots/extsload getPositionInfo.snap deleted file mode 100644 index 9f02e1c9e..000000000 --- a/.forge-snapshots/extsload getPositionInfo.snap +++ /dev/null @@ -1 +0,0 @@ -952 \ No newline at end of file diff --git a/.forge-snapshots/extsload getPositionLiquidity.snap b/.forge-snapshots/extsload getPositionLiquidity.snap deleted file mode 100644 index 5f5d9b11a..000000000 --- a/.forge-snapshots/extsload getPositionLiquidity.snap +++ /dev/null @@ -1 +0,0 @@ -375 \ No newline at end of file diff --git a/.forge-snapshots/extsload getSlot0.snap b/.forge-snapshots/extsload getSlot0.snap deleted file mode 100644 index 5f5d9b11a..000000000 --- a/.forge-snapshots/extsload getSlot0.snap +++ /dev/null @@ -1 +0,0 @@ -375 \ No newline at end of file diff --git a/.forge-snapshots/extsload getTickBitmap.snap b/.forge-snapshots/extsload getTickBitmap.snap deleted file mode 100644 index 5f5d9b11a..000000000 --- a/.forge-snapshots/extsload getTickBitmap.snap +++ /dev/null @@ -1 +0,0 @@ -375 \ No newline at end of file diff --git a/.forge-snapshots/extsload getTickFeeGrowthOutside.snap b/.forge-snapshots/extsload getTickFeeGrowthOutside.snap deleted file mode 100644 index 5c1d4541a..000000000 --- a/.forge-snapshots/extsload getTickFeeGrowthOutside.snap +++ /dev/null @@ -1 +0,0 @@ -777 \ No newline at end of file diff --git a/.forge-snapshots/extsload getTickInfo.snap b/.forge-snapshots/extsload getTickInfo.snap deleted file mode 100644 index 9f02e1c9e..000000000 --- a/.forge-snapshots/extsload getTickInfo.snap +++ /dev/null @@ -1 +0,0 @@ -952 \ No newline at end of file diff --git a/.forge-snapshots/extsload getTickLiquidity.snap b/.forge-snapshots/extsload getTickLiquidity.snap deleted file mode 100644 index 5f5d9b11a..000000000 --- a/.forge-snapshots/extsload getTickLiquidity.snap +++ /dev/null @@ -1 +0,0 @@ -375 \ No newline at end of file diff --git a/.forge-snapshots/flipTick_flippingATickThatResultsInDeletingAWord.snap b/.forge-snapshots/flipTick_flippingATickThatResultsInDeletingAWord.snap deleted file mode 100644 index c2fcf4010..000000000 --- a/.forge-snapshots/flipTick_flippingATickThatResultsInDeletingAWord.snap +++ /dev/null @@ -1 +0,0 @@ -5113 \ No newline at end of file diff --git a/.forge-snapshots/flipTick_flippingFirstTickInWordToInitialized.snap b/.forge-snapshots/flipTick_flippingFirstTickInWordToInitialized.snap deleted file mode 100644 index d40f731c3..000000000 --- a/.forge-snapshots/flipTick_flippingFirstTickInWordToInitialized.snap +++ /dev/null @@ -1 +0,0 @@ -22213 \ No newline at end of file diff --git a/.forge-snapshots/flipTick_flippingSecondTickInWordToInitialized.snap b/.forge-snapshots/flipTick_flippingSecondTickInWordToInitialized.snap deleted file mode 100644 index 77d22989c..000000000 --- a/.forge-snapshots/flipTick_flippingSecondTickInWordToInitialized.snap +++ /dev/null @@ -1 +0,0 @@ -5182 \ No newline at end of file diff --git a/.forge-snapshots/getAmount0Delta_gasCostForAmount0WhereRoundUpIsFalse.snap b/.forge-snapshots/getAmount0Delta_gasCostForAmount0WhereRoundUpIsFalse.snap deleted file mode 100644 index 34251f6b2..000000000 --- a/.forge-snapshots/getAmount0Delta_gasCostForAmount0WhereRoundUpIsFalse.snap +++ /dev/null @@ -1 +0,0 @@ -247 \ No newline at end of file diff --git a/.forge-snapshots/getAmount0Delta_gasCostForAmount0WhereRoundUpIsTrue.snap b/.forge-snapshots/getAmount0Delta_gasCostForAmount0WhereRoundUpIsTrue.snap deleted file mode 100644 index e8930b6df..000000000 --- a/.forge-snapshots/getAmount0Delta_gasCostForAmount0WhereRoundUpIsTrue.snap +++ /dev/null @@ -1 +0,0 @@ -364 \ No newline at end of file diff --git a/.forge-snapshots/getAmount1Delta_gasCostForAmount1WhereRoundUpIsFalse.snap b/.forge-snapshots/getAmount1Delta_gasCostForAmount1WhereRoundUpIsFalse.snap deleted file mode 100644 index f937f7e2b..000000000 --- a/.forge-snapshots/getAmount1Delta_gasCostForAmount1WhereRoundUpIsFalse.snap +++ /dev/null @@ -1 +0,0 @@ -233 \ No newline at end of file diff --git a/.forge-snapshots/getAmount1Delta_gasCostForAmount1WhereRoundUpIsTrue.snap b/.forge-snapshots/getAmount1Delta_gasCostForAmount1WhereRoundUpIsTrue.snap deleted file mode 100644 index 02225a563..000000000 --- a/.forge-snapshots/getAmount1Delta_gasCostForAmount1WhereRoundUpIsTrue.snap +++ /dev/null @@ -1 +0,0 @@ -268 \ No newline at end of file diff --git a/.forge-snapshots/getNextSqrtPriceFromInput_zeroForOneEqualsFalseGas.snap b/.forge-snapshots/getNextSqrtPriceFromInput_zeroForOneEqualsFalseGas.snap deleted file mode 100644 index 194ba8cc7..000000000 --- a/.forge-snapshots/getNextSqrtPriceFromInput_zeroForOneEqualsFalseGas.snap +++ /dev/null @@ -1 +0,0 @@ -320 \ No newline at end of file diff --git a/.forge-snapshots/getNextSqrtPriceFromInput_zeroForOneEqualsTrueGas.snap b/.forge-snapshots/getNextSqrtPriceFromInput_zeroForOneEqualsTrueGas.snap deleted file mode 100644 index 878b70634..000000000 --- a/.forge-snapshots/getNextSqrtPriceFromInput_zeroForOneEqualsTrueGas.snap +++ /dev/null @@ -1 +0,0 @@ -543 \ No newline at end of file diff --git a/.forge-snapshots/getNextSqrtPriceFromOutput_zeroForOneEqualsFalseGas.snap b/.forge-snapshots/getNextSqrtPriceFromOutput_zeroForOneEqualsFalseGas.snap deleted file mode 100644 index dd35c6b71..000000000 --- a/.forge-snapshots/getNextSqrtPriceFromOutput_zeroForOneEqualsFalseGas.snap +++ /dev/null @@ -1 +0,0 @@ -548 \ No newline at end of file diff --git a/.forge-snapshots/getNextSqrtPriceFromOutput_zeroForOneEqualsTrueGas.snap b/.forge-snapshots/getNextSqrtPriceFromOutput_zeroForOneEqualsTrueGas.snap deleted file mode 100644 index cc4f7f3fe..000000000 --- a/.forge-snapshots/getNextSqrtPriceFromOutput_zeroForOneEqualsTrueGas.snap +++ /dev/null @@ -1 +0,0 @@ -218 \ No newline at end of file diff --git a/.forge-snapshots/getReserves.snap b/.forge-snapshots/getReserves.snap deleted file mode 100644 index 10868a277..000000000 --- a/.forge-snapshots/getReserves.snap +++ /dev/null @@ -1 +0,0 @@ -3917 \ No newline at end of file diff --git a/.forge-snapshots/initialize.snap b/.forge-snapshots/initialize.snap deleted file mode 100644 index 450c7974e..000000000 --- a/.forge-snapshots/initialize.snap +++ /dev/null @@ -1 +0,0 @@ -51536 \ No newline at end of file diff --git a/.forge-snapshots/native collect protocol fees.snap b/.forge-snapshots/native collect protocol fees.snap deleted file mode 100644 index 1c6c78447..000000000 --- a/.forge-snapshots/native collect protocol fees.snap +++ /dev/null @@ -1 +0,0 @@ -59726 \ No newline at end of file diff --git a/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_forEntireWord.snap b/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_forEntireWord.snap deleted file mode 100644 index c57606715..000000000 --- a/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_forEntireWord.snap +++ /dev/null @@ -1 +0,0 @@ -2267 \ No newline at end of file diff --git a/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_justBelowBoundary.snap b/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_justBelowBoundary.snap deleted file mode 100644 index 29684ea29..000000000 --- a/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_justBelowBoundary.snap +++ /dev/null @@ -1 +0,0 @@ -2272 \ No newline at end of file diff --git a/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_onBoundary.snap b/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_onBoundary.snap deleted file mode 100644 index cf04c8c6d..000000000 --- a/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_onBoundary.snap +++ /dev/null @@ -1 +0,0 @@ -2285 \ No newline at end of file diff --git a/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_forEntireWord.snap b/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_forEntireWord.snap deleted file mode 100644 index a8964c48c..000000000 --- a/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_forEntireWord.snap +++ /dev/null @@ -1 +0,0 @@ -2262 \ No newline at end of file diff --git a/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_justBelowBoundary.snap b/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_justBelowBoundary.snap deleted file mode 100644 index a311f3e7e..000000000 --- a/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_justBelowBoundary.snap +++ /dev/null @@ -1 +0,0 @@ -2246 \ No newline at end of file diff --git a/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_onBoundary_gas.snap b/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_onBoundary_gas.snap deleted file mode 100644 index b1957f2d1..000000000 --- a/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_onBoundary_gas.snap +++ /dev/null @@ -1 +0,0 @@ -2291 \ No newline at end of file diff --git a/.forge-snapshots/poolManager bytecode size.snap b/.forge-snapshots/poolManager bytecode size.snap deleted file mode 100644 index 37be6af7a..000000000 --- a/.forge-snapshots/poolManager bytecode size.snap +++ /dev/null @@ -1 +0,0 @@ -23621 \ No newline at end of file diff --git a/.forge-snapshots/removeLiquidity CA fee.snap b/.forge-snapshots/removeLiquidity CA fee.snap deleted file mode 100644 index 3ea79996d..000000000 --- a/.forge-snapshots/removeLiquidity CA fee.snap +++ /dev/null @@ -1 +0,0 @@ -141219 \ No newline at end of file diff --git a/.forge-snapshots/removeLiquidity with empty hook.snap b/.forge-snapshots/removeLiquidity with empty hook.snap deleted file mode 100644 index 07ce00e06..000000000 --- a/.forge-snapshots/removeLiquidity with empty hook.snap +++ /dev/null @@ -1 +0,0 @@ -130621 \ No newline at end of file diff --git a/.forge-snapshots/removeLiquidity with native token.snap b/.forge-snapshots/removeLiquidity with native token.snap deleted file mode 100644 index 35f7a9f26..000000000 --- a/.forge-snapshots/removeLiquidity with native token.snap +++ /dev/null @@ -1 +0,0 @@ -112535 \ No newline at end of file diff --git a/.forge-snapshots/set protocol fee.snap b/.forge-snapshots/set protocol fee.snap deleted file mode 100644 index 648e16347..000000000 --- a/.forge-snapshots/set protocol fee.snap +++ /dev/null @@ -1 +0,0 @@ -31730 \ No newline at end of file diff --git a/.forge-snapshots/simple addLiquidity second addition same range.snap b/.forge-snapshots/simple addLiquidity second addition same range.snap deleted file mode 100644 index 85250c467..000000000 --- a/.forge-snapshots/simple addLiquidity second addition same range.snap +++ /dev/null @@ -1 +0,0 @@ -98862 \ No newline at end of file diff --git a/.forge-snapshots/simple addLiquidity.snap b/.forge-snapshots/simple addLiquidity.snap deleted file mode 100644 index 16a8472c7..000000000 --- a/.forge-snapshots/simple addLiquidity.snap +++ /dev/null @@ -1 +0,0 @@ -161407 \ No newline at end of file diff --git a/.forge-snapshots/simple removeLiquidity some liquidity remains.snap b/.forge-snapshots/simple removeLiquidity some liquidity remains.snap deleted file mode 100644 index 94c9272f7..000000000 --- a/.forge-snapshots/simple removeLiquidity some liquidity remains.snap +++ /dev/null @@ -1 +0,0 @@ -92995 \ No newline at end of file diff --git a/.forge-snapshots/simple removeLiquidity.snap b/.forge-snapshots/simple removeLiquidity.snap deleted file mode 100644 index f12c87689..000000000 --- a/.forge-snapshots/simple removeLiquidity.snap +++ /dev/null @@ -1 +0,0 @@ -85108 \ No newline at end of file diff --git a/.forge-snapshots/simple swap with native.snap b/.forge-snapshots/simple swap with native.snap deleted file mode 100644 index 4bf8e4447..000000000 --- a/.forge-snapshots/simple swap with native.snap +++ /dev/null @@ -1 +0,0 @@ -108515 \ No newline at end of file diff --git a/.forge-snapshots/simple swap.snap b/.forge-snapshots/simple swap.snap deleted file mode 100644 index 141489c72..000000000 --- a/.forge-snapshots/simple swap.snap +++ /dev/null @@ -1 +0,0 @@ -123347 \ No newline at end of file diff --git a/.forge-snapshots/sparse external sload.snap b/.forge-snapshots/sparse external sload.snap deleted file mode 100644 index bdedcd994..000000000 --- a/.forge-snapshots/sparse external sload.snap +++ /dev/null @@ -1 +0,0 @@ -2164 \ 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 deleted file mode 100644 index 8ad9f5434..000000000 --- a/.forge-snapshots/swap CA custom curve + swap noop.snap +++ /dev/null @@ -1 +0,0 @@ -124653 \ 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 deleted file mode 100644 index 6360928ab..000000000 --- a/.forge-snapshots/swap CA fee on unspecified.snap +++ /dev/null @@ -1 +0,0 @@ -154773 \ 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 deleted file mode 100644 index 24cd0f5c3..000000000 --- a/.forge-snapshots/swap against liquidity with native token.snap +++ /dev/null @@ -1 +0,0 @@ -105637 \ No newline at end of file diff --git a/.forge-snapshots/swap against liquidity.snap b/.forge-snapshots/swap against liquidity.snap deleted file mode 100644 index 0452eb72f..000000000 --- a/.forge-snapshots/swap against liquidity.snap +++ /dev/null @@ -1 +0,0 @@ -116717 \ 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 deleted file mode 100644 index 8cfb479ef..000000000 --- a/.forge-snapshots/swap burn 6909 for input.snap +++ /dev/null @@ -1 +0,0 @@ -129281 \ 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 deleted file mode 100644 index 4b0be0884..000000000 --- a/.forge-snapshots/swap burn native 6909 for input.snap +++ /dev/null @@ -1 +0,0 @@ -118725 \ 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 deleted file mode 100644 index 63a0a75cf..000000000 --- a/.forge-snapshots/swap mint native output as 6909.snap +++ /dev/null @@ -1 +0,0 @@ -139747 \ 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 deleted file mode 100644 index 72228b87c..000000000 --- a/.forge-snapshots/swap mint output as 6909.snap +++ /dev/null @@ -1 +0,0 @@ -155188 \ 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 deleted file mode 100644 index f1e126934..000000000 --- a/.forge-snapshots/swap skips hook call if hook is caller.snap +++ /dev/null @@ -1 +0,0 @@ -206403 \ No newline at end of file diff --git a/.forge-snapshots/swap with dynamic fee.snap b/.forge-snapshots/swap with dynamic fee.snap deleted file mode 100644 index feaacc0ab..000000000 --- a/.forge-snapshots/swap with dynamic fee.snap +++ /dev/null @@ -1 +0,0 @@ -139368 \ No newline at end of file diff --git a/.forge-snapshots/swap with hooks.snap b/.forge-snapshots/swap with hooks.snap deleted file mode 100644 index f36933737..000000000 --- a/.forge-snapshots/swap with hooks.snap +++ /dev/null @@ -1 +0,0 @@ -132345 \ 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 deleted file mode 100644 index 8c298d1fe..000000000 --- a/.forge-snapshots/swap with lp fee and protocol fee.snap +++ /dev/null @@ -1 +0,0 @@ -169593 \ No newline at end of file diff --git a/.forge-snapshots/swap with return dynamic fee.snap b/.forge-snapshots/swap with return dynamic fee.snap deleted file mode 100644 index bcbae20f7..000000000 --- a/.forge-snapshots/swap with return dynamic fee.snap +++ /dev/null @@ -1 +0,0 @@ -145661 \ No newline at end of file diff --git a/.forge-snapshots/tickSpacingToMaxLiquidityPerTick_gasCost60TickSpacing.snap b/.forge-snapshots/tickSpacingToMaxLiquidityPerTick_gasCost60TickSpacing.snap deleted file mode 100644 index d99e90eb9..000000000 --- a/.forge-snapshots/tickSpacingToMaxLiquidityPerTick_gasCost60TickSpacing.snap +++ /dev/null @@ -1 +0,0 @@ -29 \ No newline at end of file diff --git a/.forge-snapshots/tickSpacingToMaxLiquidityPerTick_gasCostMaxTickSpacing.snap b/.forge-snapshots/tickSpacingToMaxLiquidityPerTick_gasCostMaxTickSpacing.snap deleted file mode 100644 index d99e90eb9..000000000 --- a/.forge-snapshots/tickSpacingToMaxLiquidityPerTick_gasCostMaxTickSpacing.snap +++ /dev/null @@ -1 +0,0 @@ -29 \ No newline at end of file diff --git a/.forge-snapshots/tickSpacingToMaxLiquidityPerTick_gasCostMinTickSpacing.snap b/.forge-snapshots/tickSpacingToMaxLiquidityPerTick_gasCostMinTickSpacing.snap deleted file mode 100644 index d99e90eb9..000000000 --- a/.forge-snapshots/tickSpacingToMaxLiquidityPerTick_gasCostMinTickSpacing.snap +++ /dev/null @@ -1 +0,0 @@ -29 \ 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 deleted file mode 100644 index 8a6f38517..000000000 --- a/.forge-snapshots/update dynamic fee in before swap.snap +++ /dev/null @@ -1 +0,0 @@ -147956 \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 98db66f14..e0a2fad2a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std -[submodule "lib/forge-gas-snapshot"] - path = lib/forge-gas-snapshot - url = https://github.com/marktoda/forge-gas-snapshot [submodule "lib/solmate"] path = lib/solmate url = https://github.com/transmissions11/solmate diff --git a/.prettierignore b/.prettierignore index ae7db4672..3b88377f1 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,4 +4,5 @@ out lib/ cache/ *.sol -dist/ \ No newline at end of file +dist/ +snapshots/ diff --git a/lib/forge-gas-snapshot b/lib/forge-gas-snapshot deleted file mode 160000 index 9161f7c0b..000000000 --- a/lib/forge-gas-snapshot +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9161f7c0b6c6788a89081e2b3b9c67592b71e689 diff --git a/lib/forge-std b/lib/forge-std index 5475f852e..1de6eecf8 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit 5475f852e3f530d7e25dfb4596aa1f9baa8ffdfc +Subproject commit 1de6eecf821de7fe2c908cc48d3ab3dced20717f diff --git a/remappings.txt b/remappings.txt index 840510a32..c1dfc1541 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,7 +1,6 @@ @ensdomains/=node_modules/@ensdomains/ @openzeppelin/=lib/openzeppelin-contracts/ ds-test/=lib/forge-std/lib/ds-test/src/ -forge-gas-snapshot/=lib/forge-gas-snapshot/src/ forge-std/=lib/forge-std/src/ hardhat/=node_modules/hardhat/ solmate/=lib/solmate/ diff --git a/snapshots/ClearTest.json b/snapshots/ClearTest.json new file mode 100644 index 000000000..af8bd5151 --- /dev/null +++ b/snapshots/ClearTest.json @@ -0,0 +1,3 @@ +{ + "clear": "1717" +} \ No newline at end of file diff --git a/snapshots/CustomAccountingTest.json b/snapshots/CustomAccountingTest.json new file mode 100644 index 000000000..348909c5f --- /dev/null +++ b/snapshots/CustomAccountingTest.json @@ -0,0 +1,6 @@ +{ + "addLiquidity CA fee": "170695", + "removeLiquidity CA fee": "141199", + "swap CA custom curve + swap noop": "124402", + "swap CA fee on unspecified": "154572" +} \ No newline at end of file diff --git a/snapshots/ERC6909ClaimsTest.json b/snapshots/ERC6909ClaimsTest.json new file mode 100644 index 000000000..bf1a063d7 --- /dev/null +++ b/snapshots/ERC6909ClaimsTest.json @@ -0,0 +1,9 @@ +{ + "ERC6909Claims approve": "46323", + "ERC6909Claims burn": "29389", + "ERC6909Claims mint": "46603", + "ERC6909Claims transfer": "51756", + "ERC6909Claims transferFrom as operator": "54437", + "ERC6909Claims transferFrom with approval": "59939", + "ERC6909Claims transferFrom with infinite approval": "56770" +} \ No newline at end of file diff --git a/snapshots/ExtsloadTest.json b/snapshots/ExtsloadTest.json new file mode 100644 index 000000000..31ed61658 --- /dev/null +++ b/snapshots/ExtsloadTest.json @@ -0,0 +1,3 @@ +{ + "sparse external sload": "2164" +} \ No newline at end of file diff --git a/snapshots/ModifyLiquidityTest.json b/snapshots/ModifyLiquidityTest.json new file mode 100644 index 000000000..7744b9abe --- /dev/null +++ b/snapshots/ModifyLiquidityTest.json @@ -0,0 +1,4 @@ +{ + "add liquidity to already existing position with salt": "144401", + "create new liquidity to a position with salt": "292593" +} \ No newline at end of file diff --git a/snapshots/PoolManagerInitializeTest.json b/snapshots/PoolManagerInitializeTest.json new file mode 100644 index 000000000..4c6900768 --- /dev/null +++ b/snapshots/PoolManagerInitializeTest.json @@ -0,0 +1,3 @@ +{ + "initialize": "51532" +} \ No newline at end of file diff --git a/snapshots/PoolManagerTest.json b/snapshots/PoolManagerTest.json new file mode 100644 index 000000000..4b6cd6039 --- /dev/null +++ b/snapshots/PoolManagerTest.json @@ -0,0 +1,24 @@ +{ + "addLiquidity with empty hook": "274012", + "addLiquidity with native token": "135001", + "donate gas with 1 token": "106214", + "donate gas with 2 tokens": "145510", + "erc20 collect protocol fees": "57500", + "native collect protocol fees": "59643", + "poolManager bytecode size": "24050", + "removeLiquidity with empty hook": "130613", + "removeLiquidity with native token": "112523", + "simple addLiquidity": "161276", + "simple addLiquidity second addition same range": "98731", + "simple removeLiquidity": "85099", + "simple removeLiquidity some liquidity remains": "92986", + "simple swap": "123144", + "simple swap with native": "108434", + "swap against liquidity": "116527", + "swap against liquidity with native token": "105569", + "swap burn 6909 for input": "129285", + "swap burn native 6909 for input": "118672", + "swap mint native output as 6909": "139620", + "swap mint output as 6909": "154985", + "swap with hooks": "132165" +} \ No newline at end of file diff --git a/snapshots/ProtocolFeesTest.json b/snapshots/ProtocolFeesTest.json new file mode 100644 index 000000000..9b33cd5ff --- /dev/null +++ b/snapshots/ProtocolFeesTest.json @@ -0,0 +1,3 @@ +{ + "set protocol fee": "31730" +} \ No newline at end of file diff --git a/snapshots/SkipCallsTest.json b/snapshots/SkipCallsTest.json new file mode 100644 index 000000000..6aa00e361 --- /dev/null +++ b/snapshots/SkipCallsTest.json @@ -0,0 +1,3 @@ +{ + "swap skips hook call if hook is caller": "206030" +} \ No newline at end of file diff --git a/snapshots/SqrtPriceMathTest.json b/snapshots/SqrtPriceMathTest.json new file mode 100644 index 000000000..14f190d92 --- /dev/null +++ b/snapshots/SqrtPriceMathTest.json @@ -0,0 +1,10 @@ +{ + "getAmount0Delta_gasCostForAmount0WhereRoundUpIsFalse": "243", + "getAmount0Delta_gasCostForAmount0WhereRoundUpIsTrue": "360", + "getAmount1Delta_gasCostForAmount1WhereRoundUpIsFalse": "229", + "getAmount1Delta_gasCostForAmount1WhereRoundUpIsTrue": "264", + "getNextSqrtPriceFromInput_zeroForOneEqualsFalseGas": "316", + "getNextSqrtPriceFromInput_zeroForOneEqualsTrueGas": "539", + "getNextSqrtPriceFromOutput_zeroForOneEqualsFalseGas": "544", + "getNextSqrtPriceFromOutput_zeroForOneEqualsTrueGas": "214" +} \ No newline at end of file diff --git a/snapshots/StateLibraryTest.json b/snapshots/StateLibraryTest.json new file mode 100644 index 000000000..6d36ff0dc --- /dev/null +++ b/snapshots/StateLibraryTest.json @@ -0,0 +1,12 @@ +{ + "extsload getFeeGrowthGlobals": "774", + "extsload getFeeGrowthInside": "375", + "extsload getLiquidity": "375", + "extsload getPositionInfo": "949", + "extsload getPositionLiquidity": "375", + "extsload getSlot0": "375", + "extsload getTickBitmap": "375", + "extsload getTickFeeGrowthOutside": "774", + "extsload getTickInfo": "949", + "extsload getTickLiquidity": "375" +} \ No newline at end of file diff --git a/snapshots/SwapMathTest.json b/snapshots/SwapMathTest.json new file mode 100644 index 000000000..b2cd78767 --- /dev/null +++ b/snapshots/SwapMathTest.json @@ -0,0 +1,10 @@ +{ + "SwapMath_oneForZero_exactInCapped": "1188", + "SwapMath_oneForZero_exactInPartial": "1274", + "SwapMath_oneForZero_exactOutCapped": "1001", + "SwapMath_oneForZero_exactOutPartial": "1565", + "SwapMath_zeroForOne_exactInCapped": "1126", + "SwapMath_zeroForOne_exactInPartial": "1439", + "SwapMath_zeroForOne_exactOutCapped": "919", + "SwapMath_zeroForOne_exactOutPartial": "1133" +} \ No newline at end of file diff --git a/snapshots/SyncTest.json b/snapshots/SyncTest.json new file mode 100644 index 000000000..80aa773b0 --- /dev/null +++ b/snapshots/SyncTest.json @@ -0,0 +1,3 @@ +{ + "getReserves": "3973" +} \ No newline at end of file diff --git a/snapshots/TestBitMath.json b/snapshots/TestBitMath.json new file mode 100644 index 000000000..3fe5a93b7 --- /dev/null +++ b/snapshots/TestBitMath.json @@ -0,0 +1,8 @@ +{ + "BitMathLeastSignificantBitMaxUint128": "648", + "BitMathLeastSignificantBitMaxUint256": "648", + "BitMathLeastSignificantBitSmallNumber": "25", + "BitMathMostSignificantBitMaxUint128": "648", + "BitMathMostSignificantBitMaxUint256": "648", + "BitMathMostSignificantBitSmallNumber": "14" +} \ No newline at end of file diff --git a/snapshots/TestDelegateCall.json b/snapshots/TestDelegateCall.json new file mode 100644 index 000000000..fb67febdc --- /dev/null +++ b/snapshots/TestDelegateCall.json @@ -0,0 +1,3 @@ +{ + "NoDelegateCall": "51" +} \ No newline at end of file diff --git a/snapshots/TestDynamicFees.json b/snapshots/TestDynamicFees.json new file mode 100644 index 000000000..b25bd6b18 --- /dev/null +++ b/snapshots/TestDynamicFees.json @@ -0,0 +1,4 @@ +{ + "swap with dynamic fee": "139153", + "update dynamic fee in before swap": "147743" +} \ No newline at end of file diff --git a/snapshots/TestDynamicReturnFees.json b/snapshots/TestDynamicReturnFees.json new file mode 100644 index 000000000..d2635299d --- /dev/null +++ b/snapshots/TestDynamicReturnFees.json @@ -0,0 +1,3 @@ +{ + "swap with return dynamic fee": "145475" +} \ No newline at end of file diff --git a/snapshots/TickBitmapTest.json b/snapshots/TickBitmapTest.json new file mode 100644 index 000000000..58ea2043c --- /dev/null +++ b/snapshots/TickBitmapTest.json @@ -0,0 +1,11 @@ +{ + "flipTick_flippingATickThatResultsInDeletingAWord": "5109", + "flipTick_flippingFirstTickInWordToInitialized": "22209", + "flipTick_flippingSecondTickInWordToInitialized": "5178", + "nextInitializedTickWithinOneWord_lteFalse_forEntireWord": "2263", + "nextInitializedTickWithinOneWord_lteFalse_justBelowBoundary": "2252", + "nextInitializedTickWithinOneWord_lteFalse_onBoundary": "2281", + "nextInitializedTickWithinOneWord_lteTrue_forEntireWord": "2258", + "nextInitializedTickWithinOneWord_lteTrue_justBelowBoundary": "2242", + "nextInitializedTickWithinOneWord_lteTrue_onBoundary_gas": "2287" +} \ No newline at end of file diff --git a/snapshots/TickMathTestTest.json b/snapshots/TickMathTestTest.json new file mode 100644 index 000000000..40e17de11 --- /dev/null +++ b/snapshots/TickMathTestTest.json @@ -0,0 +1,4 @@ +{ + "TickMathGetSqrtPriceAtTick": "72349", + "TickMathGetTickAtSqrtPrice": "195022" +} \ No newline at end of file diff --git a/snapshots/TickTest.json b/snapshots/TickTest.json new file mode 100644 index 000000000..ec655cb3b --- /dev/null +++ b/snapshots/TickTest.json @@ -0,0 +1,5 @@ +{ + "tickSpacingToMaxLiquidityPerTick_gasCost60TickSpacing": "25", + "tickSpacingToMaxLiquidityPerTick_gasCostMaxTickSpacing": "25", + "tickSpacingToMaxLiquidityPerTick_gasCostMinTickSpacing": "25" +} \ No newline at end of file diff --git a/src/PoolManager.sol b/src/PoolManager.sol index 0afc17384..c24fbc0ea 100644 --- a/src/PoolManager.sol +++ b/src/PoolManager.sol @@ -97,6 +97,8 @@ contract PoolManager is IPoolManager, ProtocolFees, NoDelegateCall, ERC6909Claim _; } + constructor(address initialOwner) ProtocolFees(initialOwner) {} + /// @inheritdoc IPoolManager function unlock(bytes calldata data) external override returns (bytes memory result) { if (Lock.isUnlocked()) AlreadyUnlocked.selector.revertWith(); @@ -130,11 +132,12 @@ contract PoolManager is IPoolManager, ProtocolFees, NoDelegateCall, ERC6909Claim tick = _pools[id].initialize(sqrtPriceX96, lpFee); - key.hooks.afterInitialize(key, sqrtPriceX96, tick); - + // event is emitted before the afterInitialize call to ensure events are always emitted in order // emit all details of a pool key. poolkeys are not saved in storage and must always be provided by the caller // the key's fee may be a static fee or a sentinel to denote a dynamic fee. emit Initialize(id, key.currency0, key.currency1, key.fee, key.tickSpacing, key.hooks, sqrtPriceX96, tick); + + key.hooks.afterInitialize(key, sqrtPriceX96, tick); } /// @inheritdoc IPoolManager @@ -271,7 +274,7 @@ contract PoolManager is IPoolManager, ProtocolFees, NoDelegateCall, ERC6909Claim } /// @inheritdoc IPoolManager - function sync(Currency currency) external onlyWhenUnlocked { + function sync(Currency currency) external { // address(0) is used for the native currency if (currency.isAddressZero()) { // The reserves balance is not used for native settling, so we only need to reset the currency. @@ -340,6 +343,7 @@ contract PoolManager is IPoolManager, ProtocolFees, NoDelegateCall, ERC6909Claim _pools[id].setLPFee(newDynamicLPFee); } + // if settling native, integrators should still call `sync` first to avoid DoS attack vectors function _settle(address recipient) internal returns (uint256 paid) { Currency currency = CurrencyReserves.getSyncedCurrency(); diff --git a/src/ProtocolFees.sol b/src/ProtocolFees.sol index ecea47484..8d6c5d9ce 100644 --- a/src/ProtocolFees.sol +++ b/src/ProtocolFees.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import {Currency} from "./types/Currency.sol"; -import {IProtocolFeeController} from "./interfaces/IProtocolFeeController.sol"; +import {CurrencyReserves} from "./libraries/CurrencyReserves.sol"; import {IProtocolFees} from "./interfaces/IProtocolFees.sol"; import {PoolKey} from "./types/PoolKey.sol"; import {ProtocolFeeLibrary} from "./libraries/ProtocolFeeLibrary.sol"; @@ -21,19 +21,19 @@ abstract contract ProtocolFees is IProtocolFees, Owned { mapping(Currency currency => uint256 amount) public protocolFeesAccrued; /// @inheritdoc IProtocolFees - IProtocolFeeController public protocolFeeController; + address public protocolFeeController; - constructor() Owned(msg.sender) {} + constructor(address initialOwner) Owned(initialOwner) {} /// @inheritdoc IProtocolFees - function setProtocolFeeController(IProtocolFeeController controller) external onlyOwner { + function setProtocolFeeController(address controller) external onlyOwner { protocolFeeController = controller; - emit ProtocolFeeControllerUpdated(address(controller)); + emit ProtocolFeeControllerUpdated(controller); } /// @inheritdoc IProtocolFees function setProtocolFee(PoolKey memory key, uint24 newProtocolFee) external { - if (msg.sender != address(protocolFeeController)) InvalidCaller.selector.revertWith(); + if (msg.sender != protocolFeeController) InvalidCaller.selector.revertWith(); if (!newProtocolFee.isValidProtocolFee()) ProtocolFeeTooLarge.selector.revertWith(newProtocolFee); PoolId id = key.toId(); _getPool(id).setProtocolFee(newProtocolFee); @@ -45,8 +45,11 @@ abstract contract ProtocolFees is IProtocolFees, Owned { external returns (uint256 amountCollected) { - if (msg.sender != address(protocolFeeController)) InvalidCaller.selector.revertWith(); - if (_isUnlocked()) ContractUnlocked.selector.revertWith(); + if (msg.sender != protocolFeeController) InvalidCaller.selector.revertWith(); + if (!currency.isAddressZero() && CurrencyReserves.getSyncedCurrency() == currency) { + // prevent transfer between the sync and settle balanceOfs (native settle uses msg.value) + ProtocolFeeCurrencySynced.selector.revertWith(); + } amountCollected = (amount == 0) ? protocolFeesAccrued[currency] : amount; protocolFeesAccrued[currency] -= amountCollected; diff --git a/src/interfaces/IHooks.sol b/src/interfaces/IHooks.sol index a541e2681..4acfe941a 100644 --- a/src/interfaces/IHooks.sol +++ b/src/interfaces/IHooks.sol @@ -78,7 +78,7 @@ interface IHooks { /// @param sender The initial msg.sender for the remove liquidity call /// @param key The key for the pool /// @param params The parameters for removing liquidity - /// @param delta The caller's balance delta after adding liquidity; the sum of principal delta, fees accrued, and hook delta + /// @param delta The caller's balance delta after removing liquidity; the sum of principal delta, fees accrued, and hook delta /// @param feesAccrued The fees accrued since the last time fees were collected from this position /// @param hookData Arbitrary data handed into the PoolManager by the liquidity provider to be be passed on to the hook /// @return bytes4 The function selector for the hook diff --git a/src/interfaces/IPoolManager.sol b/src/interfaces/IPoolManager.sol index 3269851d0..88c200a41 100644 --- a/src/interfaces/IPoolManager.sol +++ b/src/interfaces/IPoolManager.sol @@ -55,7 +55,7 @@ interface IPoolManager is IProtocolFees, IERC6909Claims, IExtsload, IExttload { /// @param tickSpacing The minimum number of ticks between initialized ticks /// @param hooks The hooks contract address for the pool, or address(0) if none /// @param sqrtPriceX96 The price of the pool on initialization - /// @param tick The initial tick of the pool corresponding to the intialized price + /// @param tick The initial tick of the pool corresponding to the initialized price event Initialize( PoolId indexed id, Currency indexed currency0, @@ -186,7 +186,8 @@ interface IPoolManager is IProtocolFees, IERC6909Claims, IExtsload, IExttload { function sync(Currency currency) external; /// @notice Called by the user to net out some value owed to the user - /// @dev Can also be used as a mechanism for _free_ flash loans + /// @dev Will revert if the requested amount is not available, consider using `mint` instead + /// @dev Can also be used as a mechanism for free flash loans /// @param currency The currency to withdraw from the pool manager /// @param to The address to withdraw to /// @param amount The amount of currency to withdraw diff --git a/src/interfaces/IProtocolFeeController.sol b/src/interfaces/IProtocolFeeController.sol deleted file mode 100644 index 44f4f2cf2..000000000 --- a/src/interfaces/IProtocolFeeController.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {PoolKey} from "../types/PoolKey.sol"; - -/// @notice Interface to fetch the protocol fees for a pool from the protocol fee controller -interface IProtocolFeeController { - /// @notice Returns the protocol fees for a pool given the conditions of this contract - /// @param poolKey The pool key to identify the pool. The controller may want to use attributes on the pool - /// to determine the protocol fee, hence the entire key is needed. - /// @return protocolFee The pool's protocol fee, expressed in hundredths of a bip. The upper 12 bits are for 1->0 - /// and the lower 12 are for 0->1. The maximum is 1000 - meaning the maximum protocol fee is 0.1%. - /// the protocolFee is taken from the input first, then the lpFee is taken from the remaining input - function protocolFeeForPool(PoolKey memory poolKey) external view returns (uint24 protocolFee); -} diff --git a/src/interfaces/IProtocolFees.sol b/src/interfaces/IProtocolFees.sol index 0717bfc88..2c2af5944 100644 --- a/src/interfaces/IProtocolFees.sol +++ b/src/interfaces/IProtocolFees.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.0; import {Currency} from "../types/Currency.sol"; -import {IProtocolFeeController} from "../interfaces/IProtocolFeeController.sol"; import {PoolId} from "../types/PoolId.sol"; import {PoolKey} from "../types/PoolKey.sol"; @@ -11,12 +10,12 @@ interface IProtocolFees { /// @notice Thrown when protocol fee is set too high error ProtocolFeeTooLarge(uint24 fee); - /// @notice Thrown when the contract is unlocked - error ContractUnlocked(); - /// @notice Thrown when collectProtocolFees or setProtocolFee is not called by the controller. error InvalidCaller(); + /// @notice Thrown when collectProtocolFees is attempted on a token that is synced. + error ProtocolFeeCurrencySynced(); + /// @notice Emitted when the protocol fee controller address is updated in setProtocolFeeController. event ProtocolFeeControllerUpdated(address indexed protocolFeeController); @@ -35,7 +34,7 @@ interface IProtocolFees { /// @notice Sets the protocol fee controller /// @param controller The new protocol fee controller - function setProtocolFeeController(IProtocolFeeController controller) external; + function setProtocolFeeController(address controller) external; /// @notice Collects the protocol fees for a given recipient and currency, returning the amount collected /// @dev This will revert if the contract is unlocked @@ -48,6 +47,6 @@ interface IProtocolFees { returns (uint256 amountCollected); /// @notice Returns the current protocol fee controller address - /// @return IProtocolFeeController The currency protocol fee controller - function protocolFeeController() external view returns (IProtocolFeeController); + /// @return address The current protocol fee controller address + function protocolFeeController() external view returns (address); } diff --git a/src/libraries/CustomRevert.sol b/src/libraries/CustomRevert.sol index 8ea27d2e4..5d7073308 100644 --- a/src/libraries/CustomRevert.sol +++ b/src/libraries/CustomRevert.sol @@ -7,6 +7,9 @@ pragma solidity ^0.8.0; /// `CustomError.selector.revertWith()` /// @dev The functions may tamper with the free memory pointer but it is fine since the call context is exited immediately library CustomRevert { + /// @dev ERC-7751 error for wrapping bubbled up reverts + error WrappedError(address target, bytes4 selector, bytes reason, bytes details); + /// @dev Reverts with the selector of a custom error in the scratch space function revertWith(bytes4 selector) internal pure { assembly ("memory-safe") { @@ -75,23 +78,43 @@ library CustomRevert { } } - /// @notice bubble up the revert message returned by a call and revert with the selector provided - /// @dev this function should only be used with custom errors of the type `CustomError(address target, bytes revertReason)` - function bubbleUpAndRevertWith(bytes4 selector, address addr) internal pure { + /// @notice bubble up the revert message returned by a call and revert with a wrapped ERC-7751 error + /// @dev this method can be vulnerable to revert data bombs + function bubbleUpAndRevertWith( + address revertingContract, + bytes4 revertingFunctionSelector, + bytes4 additionalContext + ) internal pure { + bytes4 wrappedErrorSelector = WrappedError.selector; assembly ("memory-safe") { - let size := returndatasize() - let fmp := mload(0x40) + // Ensure the size of the revert data is a multiple of 32 bytes + let encodedDataSize := mul(div(add(returndatasize(), 31), 32), 32) - // Encode selector, address, offset, size, data - mstore(fmp, selector) - mstore(add(fmp, 0x04), addr) - mstore(add(fmp, 0x24), 0x40) - mstore(add(fmp, 0x44), size) - returndatacopy(add(fmp, 0x64), 0, size) + let fmp := mload(0x40) - // Ensure the size is a multiple of 32 bytes - let encodedSize := add(0x64, mul(div(add(size, 31), 32), 32)) - revert(fmp, encodedSize) + // Encode wrapped error selector, address, function selector, offset, additional context, size, revert reason + mstore(fmp, wrappedErrorSelector) + mstore(add(fmp, 0x04), and(revertingContract, 0xffffffffffffffffffffffffffffffffffffffff)) + mstore( + add(fmp, 0x24), + and(revertingFunctionSelector, 0xffffffff00000000000000000000000000000000000000000000000000000000) + ) + // offset revert reason + mstore(add(fmp, 0x44), 0x80) + // offset additional context + mstore(add(fmp, 0x64), add(0xa0, encodedDataSize)) + // size revert reason + mstore(add(fmp, 0x84), returndatasize()) + // revert reason + returndatacopy(add(fmp, 0xa4), 0, returndatasize()) + // size additional context + mstore(add(fmp, add(0xa4, encodedDataSize)), 0x04) + // additional context + mstore( + add(fmp, add(0xc4, encodedDataSize)), + and(additionalContext, 0xffffffff00000000000000000000000000000000000000000000000000000000) + ) + revert(fmp, add(0xe4, encodedDataSize)) } } } diff --git a/src/libraries/Hooks.sol b/src/libraries/Hooks.sol index 2f02548f5..0b8c869da 100644 --- a/src/libraries/Hooks.sol +++ b/src/libraries/Hooks.sol @@ -69,9 +69,8 @@ library Hooks { /// @notice Hook did not return its selector error InvalidHookResponse(); - /// @notice thrown when a hook call fails - /// @param revertReason bubbled up revert reason - error Wrap__FailedHookCall(address hook, bytes revertReason); + /// @notice Additional context for ERC-7751 wrapped error when a hook call fails + error HookCallFailed(); /// @notice The hook's delta changed the swap from exactIn to exactOut or vice versa error HookDeltaExceedsSwapAmount(); @@ -134,7 +133,7 @@ library Hooks { success := call(gas(), self, 0, add(data, 0x20), mload(data), 0, 0) } // Revert with FailedHookCall, containing any error message to bubble up - if (!success) Wrap__FailedHookCall.selector.bubbleUpAndRevertWith(address(self)); + if (!success) CustomRevert.bubbleUpAndRevertWith(address(self), bytes4(data), HookCallFailed.selector); // The call was successful, fetch the returned data assembly ("memory-safe") { @@ -159,7 +158,7 @@ library Hooks { function callHookWithReturnDelta(IHooks self, bytes memory data, bool parseReturn) internal returns (int256) { bytes memory result = callHook(self, data); - // If this hook wasnt meant to return something, default to 0 delta + // If this hook wasn't meant to return something, default to 0 delta if (!parseReturn) return 0; // A length of 64 bytes is required to return a bytes4, and a 32 byte delta @@ -258,7 +257,8 @@ library Hooks { // A length of 96 bytes is required to return a bytes4, a 32 byte delta, and an LP fee if (result.length != 96) InvalidHookResponse.selector.revertWith(); - // dynamic fee pools that do not want to override the cache fee, return 0 otherwise they return a valid fee with the override flag + // dynamic fee pools that want to override the cache fee, return a valid fee with the override flag. If override flag + // is set but an invalid fee is returned, the transaction will revert. Otherwise the current LP fee will be used if (key.fee.isDynamicFee()) lpFeeOverride = result.parseFee(); // skip this logic for the case where the hook return is 0 diff --git a/src/libraries/LPFeeLibrary.sol b/src/libraries/LPFeeLibrary.sol index a2a732a81..b7e145332 100644 --- a/src/libraries/LPFeeLibrary.sol +++ b/src/libraries/LPFeeLibrary.sol @@ -11,7 +11,7 @@ library LPFeeLibrary { /// @notice Thrown when the static or dynamic fee on a pool exceeds 100%. error LPFeeTooLarge(uint24 fee); - /// @notice An lp fee of exactly 0b1000000... signals a dynamic fee pool. This isnt a valid static fee as it is > MAX_LP_FEE + /// @notice An lp fee of exactly 0b1000000... signals a dynamic fee pool. This isn't a valid static fee as it is > MAX_LP_FEE uint24 public constant DYNAMIC_FEE_FLAG = 0x800000; /// @notice the second bit of the fee returned by beforeSwap is used to signal if the stored LP fee should be overridden in this swap diff --git a/src/libraries/Pool.sol b/src/libraries/Pool.sol index bdd9b3994..1dfb56cc9 100644 --- a/src/libraries/Pool.sol +++ b/src/libraries/Pool.sol @@ -383,8 +383,11 @@ library Pool { unchecked { // step.amountIn does not include the swap fee, as it's already been taken from it, // so add it back to get the total amountIn and use that to calculate the amount of fees owed to the protocol - // this line cannot overflow due to limits on the size of protocolFee and params.amountSpecified - uint256 delta = (step.amountIn + step.feeAmount) * protocolFee / ProtocolFeeLibrary.PIPS_DENOMINATOR; + // cannot overflow due to limits on the size of protocolFee and params.amountSpecified + // this rounds down to favor LPs over the protocol + uint256 delta = (swapFee == protocolFee) + ? step.feeAmount // lp fee is 0, so the entire fee is owed to the protocol instead + : (step.amountIn + step.feeAmount) * protocolFee / ProtocolFeeLibrary.PIPS_DENOMINATOR; // subtract it from the total fee and add it to the protocol fee step.feeAmount -= delta; amountToProtocol += delta; @@ -532,7 +535,8 @@ library Pool { } } - // when the lower (upper) tick is crossed left to right (right to left), liquidity must be added (removed) + // when the lower (upper) tick is crossed left to right, liquidity must be added (removed) + // when the lower (upper) tick is crossed right to left, liquidity must be removed (added) int128 liquidityNet = upper ? liquidityNetBefore - liquidityDelta : liquidityNetBefore + liquidityDelta; assembly ("memory-safe") { // liquidityGrossAfter and liquidityNet are packed in the first slot of `info` @@ -558,6 +562,7 @@ library Pool { function tickSpacingToMaxLiquidityPerTick(int24 tickSpacing) internal pure returns (uint128 result) { // Equivalent to: // int24 minTick = (TickMath.MIN_TICK / tickSpacing); + // if (TickMath.MIN_TICK % tickSpacing != 0) minTick--; // int24 maxTick = (TickMath.MAX_TICK / tickSpacing); // uint24 numTicks = maxTick - minTick + 1; // return type(uint128).max / numTicks; diff --git a/src/libraries/ProtocolFeeLibrary.sol b/src/libraries/ProtocolFeeLibrary.sol index 48adf0fd3..512a49928 100644 --- a/src/libraries/ProtocolFeeLibrary.sol +++ b/src/libraries/ProtocolFeeLibrary.sol @@ -33,16 +33,15 @@ library ProtocolFeeLibrary { // The protocol fee is taken from the input amount first and then the LP fee is taken from the remaining // The swap fee is capped at 100% - // Equivalent to protocolFee + lpFee(1_000_000 - protocolFee) / 1_000_000 + // Equivalent to protocolFee + lpFee(1_000_000 - protocolFee) / 1_000_000 (rounded up) /// @dev here `self` is just a single direction's protocol fee, not a packed type of 2 protocol fees function calculateSwapFee(uint16 self, uint24 lpFee) internal pure returns (uint24 swapFee) { - // protocolFee + lpFee - (protocolFee * lpFee / 1_000_000). Div rounds up to favor LPs over the protocol. + // protocolFee + lpFee - (protocolFee * lpFee / 1_000_000) assembly ("memory-safe") { self := and(self, 0xfff) lpFee := and(lpFee, 0xffffff) let numerator := mul(self, lpFee) - let divRoundingUp := add(div(numerator, PIPS_DENOMINATOR), gt(mod(numerator, PIPS_DENOMINATOR), 0)) - swapFee := sub(add(self, lpFee), divRoundingUp) + swapFee := sub(add(self, lpFee), div(numerator, PIPS_DENOMINATOR)) } } } diff --git a/src/libraries/UnsafeMath.sol b/src/libraries/UnsafeMath.sol index c3f23c83c..4c313952a 100644 --- a/src/libraries/UnsafeMath.sol +++ b/src/libraries/UnsafeMath.sol @@ -5,7 +5,7 @@ pragma solidity ^0.8.0; /// @notice Contains methods that perform common math functions but do not do any overflow or underflow checks library UnsafeMath { /// @notice Returns ceil(x / y) - /// @dev division by 0 has unspecified behavior, and must be checked externally + /// @dev division by 0 will return 0, and should be checked externally /// @param x The dividend /// @param y The divisor /// @return z The quotient, ceil(x / y) @@ -16,7 +16,7 @@ library UnsafeMath { } /// @notice Calculates floor(a×b÷denominator) - /// @dev division by 0 has unspecified behavior, and must be checked externally + /// @dev division by 0 will return 0, and should be checked externally /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor diff --git a/src/test/ActionsRouter.sol b/src/test/ActionsRouter.sol index 331e110a0..b1e2bed51 100644 --- a/src/test/ActionsRouter.sol +++ b/src/test/ActionsRouter.sol @@ -8,7 +8,6 @@ import {Currency} from "../types/Currency.sol"; import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; import {StateLibrary} from "../libraries/StateLibrary.sol"; import {TransientStateLibrary} from "../libraries/TransientStateLibrary.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; // Supported Actions. enum Actions { @@ -24,7 +23,8 @@ enum Actions { ASSERT_RESERVES_EQUALS, ASSERT_DELTA_EQUALS, ASSERT_NONZERO_DELTA_COUNT_EQUALS, - TRANSFER_FROM + TRANSFER_FROM, + COLLECT_PROTOCOL_FEES } // TODO: Add other actions as needed. // BURN, @@ -34,7 +34,7 @@ enum Actions { /// @notice A router that handles an arbitrary input of actions. /// TODO: Can continue to add functions per action. -contract ActionsRouter is IUnlockCallback, Test, GasSnapshot { +contract ActionsRouter is IUnlockCallback, Test { using StateLibrary for IPoolManager; using TransientStateLibrary for IPoolManager; @@ -81,6 +81,8 @@ contract ActionsRouter is IUnlockCallback, Test, GasSnapshot { _assertNonzeroDeltaCountEquals(param); } else if (action == Actions.TRANSFER_FROM) { _transferFrom(param); + } else if (action == Actions.COLLECT_PROTOCOL_FEES) { + _collectProtocolFees(param); } } return ""; @@ -131,7 +133,7 @@ contract ActionsRouter is IUnlockCallback, Test, GasSnapshot { abi.decode(params, (Currency, uint256, bool, string)); manager.clear(currency, amount); - if (measureGas) snapLastCall(gasSnapName); + if (measureGas) vm.snapshotGasLastCall(gasSnapName); } function _assertBalanceEquals(bytes memory params) internal view { @@ -160,4 +162,9 @@ contract ActionsRouter is IUnlockCallback, Test, GasSnapshot { abi.decode(params, (Currency, address, address, uint256)); MockERC20(Currency.unwrap(currency)).transferFrom(from, recipient, uint256(amount)); } + + function _collectProtocolFees(bytes memory params) internal { + (address to, Currency currency, uint256 amount) = abi.decode(params, (address, Currency, uint256)); + manager.collectProtocolFees(to, currency, amount); + } } diff --git a/src/test/Fuzzers.sol b/src/test/Fuzzers.sol index eccf55b57..04c2c11bf 100644 --- a/src/test/Fuzzers.sol +++ b/src/test/Fuzzers.sol @@ -142,7 +142,7 @@ contract Fuzzers is StdUtils { result.liquidityDelta = boundLiquidityDelta(key, params.liquidityDelta, liquidityDeltaFromAmounts); } - // Creates liquidity parameters with a stricter bound. Should be used if multiple positions being intitialized on the pool, with potential for tick overlap. + // Creates liquidity parameters with a stricter bound. Should be used if multiple positions being initialized on the pool, with potential for tick overlap. function createFuzzyLiquidityParamsWithTightBound( PoolKey memory key, IPoolManager.ModifyLiquidityParams memory params, diff --git a/src/test/ProtocolFeeControllerTest.sol b/src/test/ProtocolFeeControllerTest.sol deleted file mode 100644 index 25fc0795d..000000000 --- a/src/test/ProtocolFeeControllerTest.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.20; - -import {IProtocolFeeController} from "../interfaces/IProtocolFeeController.sol"; -import {PoolId} from "../types/PoolId.sol"; -import {PoolKey} from "../types/PoolKey.sol"; - -contract ProtocolFeeControllerTest is IProtocolFeeController { - mapping(PoolId => uint24) public protocolFee; - - function protocolFeeForPool(PoolKey memory key) external view returns (uint24) { - return protocolFee[key.toId()]; - } - - // for tests to set pool protocol fees - function setProtocolFeeForPool(PoolId id, uint24 fee) external { - protocolFee[id] = fee; - } -} diff --git a/src/test/ProtocolFeesImplementation.sol b/src/test/ProtocolFeesImplementation.sol index f485e26e1..f26ac849e 100644 --- a/src/test/ProtocolFeesImplementation.sol +++ b/src/test/ProtocolFeesImplementation.sol @@ -12,6 +12,8 @@ contract ProtocolFeesImplementation is ProtocolFees { mapping(PoolId id => Pool.State) internal _pools; bool internal isUnlocked; + constructor() ProtocolFees(msg.sender) {} + // Used to set the price of a pool to pretend that the pool has been initialized in order to successfully set a protocol fee function setPrice(PoolKey memory key, uint160 sqrtPriceX96) public { Pool.State storage pool = _getPool(key.toId()); diff --git a/src/test/ProxyPoolManager.sol b/src/test/ProxyPoolManager.sol index 530e48172..44a631ec5 100644 --- a/src/test/ProxyPoolManager.sol +++ b/src/test/ProxyPoolManager.sol @@ -43,7 +43,7 @@ contract ProxyPoolManager is IPoolManager, ProtocolFees, NoDelegateCall, ERC6909 address internal immutable _delegateManager; - constructor(address delegateManager) { + constructor(address delegateManager) ProtocolFees(msg.sender) { _delegateManager = delegateManager; } diff --git a/src/types/Currency.sol b/src/types/Currency.sol index 47cb077de..771653400 100644 --- a/src/types/Currency.sol +++ b/src/types/Currency.sol @@ -28,15 +28,11 @@ function greaterThanOrEqualTo(Currency currency, Currency other) pure returns (b /// @title CurrencyLibrary /// @dev This library allows for transferring and holding native tokens and ERC20 tokens library CurrencyLibrary { - using CustomRevert for bytes4; + /// @notice Additional context for ERC-7751 wrapped error when a native transfer fails + error NativeTransferFailed(); - /// @notice Thrown when a native transfer fails - /// @param reason bubbled up revert reason - error Wrap__NativeTransferFailed(address recipient, bytes reason); - - /// @notice Thrown when an ERC20 transfer fails - /// @param reason bubbled up revert reason - error Wrap__ERC20TransferFailed(address token, bytes reason); + /// @notice Additional context for ERC-7751 wrapped error when an ERC20 transfer fails + error ERC20TransferFailed(); /// @notice A constant to represent the native currency Currency public constant ADDRESS_ZERO = Currency.wrap(address(0)); @@ -52,7 +48,9 @@ library CurrencyLibrary { success := call(gas(), to, amount, 0, 0, 0, 0) } // revert with NativeTransferFailed, containing the bubbled up error as an argument - if (!success) Wrap__NativeTransferFailed.selector.bubbleUpAndRevertWith(to); + if (!success) { + CustomRevert.bubbleUpAndRevertWith(to, bytes4(0), NativeTransferFailed.selector); + } } else { assembly ("memory-safe") { // Get a pointer to some free memory. @@ -81,7 +79,11 @@ library CurrencyLibrary { mstore(add(fmp, 0x40), 0) // 4 bytes of `amount` were stored here } // revert with ERC20TransferFailed, containing the bubbled up error as an argument - if (!success) Wrap__ERC20TransferFailed.selector.bubbleUpAndRevertWith(Currency.unwrap(currency)); + if (!success) { + CustomRevert.bubbleUpAndRevertWith( + Currency.unwrap(currency), IERC20Minimal.transfer.selector, ERC20TransferFailed.selector + ); + } } } diff --git a/test/CustomAccounting.t.sol b/test/CustomAccounting.t.sol index e4942dce3..142b76291 100644 --- a/test/CustomAccounting.t.sol +++ b/test/CustomAccounting.t.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {Deployers} from "./utils/Deployers.sol"; import {FeeTakingHook} from "../src/test/FeeTakingHook.sol"; import {LPFeeTakingHook} from "../src/test/LPFeeTakingHook.sol"; @@ -17,7 +16,7 @@ import {Currency} from "../src/types/Currency.sol"; import {BalanceDelta} from "../src/types/BalanceDelta.sol"; import {SafeCast} from "../src/libraries/SafeCast.sol"; -contract CustomAccountingTest is Test, Deployers, GasSnapshot { +contract CustomAccountingTest is Test, Deployers { using SafeCast for *; address hook; @@ -84,7 +83,7 @@ contract CustomAccountingTest is Test, Deployers, GasSnapshot { sqrtPriceLimitX96: SQRT_PRICE_1_2 }); swapRouter.swap(key, params, testSettings, ZERO_BYTES); - snapLastCall("swap CA fee on unspecified"); + vm.snapshotGasLastCall("swap CA fee on unspecified"); // input is 1000 for output of 998 with this much liquidity available // plus a fee of 1.23% on unspecified (output) => (998*123)/10000 = 12 @@ -133,7 +132,7 @@ contract CustomAccountingTest is Test, Deployers, GasSnapshot { sqrtPriceLimitX96: SQRT_PRICE_1_2 }); swapRouter.swap(key, params, testSettings, ZERO_BYTES); - snapLastCall("swap CA custom curve + swap noop"); + vm.snapshotGasLastCall("swap CA custom curve + swap noop"); // the custom curve hook is 1-1 linear assertEq(currency0.balanceOf(address(this)), balanceBefore0 - amountToSwap, "amount 0"); @@ -254,7 +253,7 @@ contract CustomAccountingTest is Test, Deployers, GasSnapshot { "manager balance change exact input" ); - // exact output, where there isnt enough output reserves available to pay swap and hook + // exact output, where there isn't enough output reserves available to pay swap and hook } else if (!isExactIn && (hookDeltaSpecified + amountSpecified > maxPossibleOut_fuzz_test)) { // the hook will have taken hookDeltaSpecified of the maxPossibleOut assertEq(deltaSpecified, maxPossibleOut_fuzz_test - hookDeltaSpecified, "deltaSpecified exact output"); @@ -290,7 +289,7 @@ contract CustomAccountingTest is Test, Deployers, GasSnapshot { uint256 managerBalanceBefore1 = currency1.balanceOf(address(manager)); // console2.log(address(key.hooks)); modifyLiquidityRouter.modifyLiquidity(key, LIQUIDITY_PARAMS, ZERO_BYTES); - snapLastCall("addLiquidity CA fee"); + vm.snapshotGasLastCall("addLiquidity CA fee"); uint256 hookGain0 = currency0.balanceOf(hook) - hookBalanceBefore0; uint256 hookGain1 = currency1.balanceOf(hook) - hookBalanceBefore1; @@ -317,7 +316,7 @@ contract CustomAccountingTest is Test, Deployers, GasSnapshot { uint256 managerBalanceBefore1 = currency1.balanceOf(address(manager)); modifyLiquidityRouter.modifyLiquidity(key, REMOVE_LIQUIDITY_PARAMS, ZERO_BYTES); - snapLastCall("removeLiquidity CA fee"); + vm.snapshotGasLastCall("removeLiquidity CA fee"); uint256 hookGain0 = currency0.balanceOf(hook) - hookBalanceBefore0; uint256 hookGain1 = currency1.balanceOf(hook) - hookBalanceBefore1; diff --git a/test/DynamicFees.t.sol b/test/DynamicFees.t.sol index cd8a3b332..1dfc69599 100644 --- a/test/DynamicFees.t.sol +++ b/test/DynamicFees.t.sol @@ -13,16 +13,18 @@ import {PoolKey} from "../src/types/PoolKey.sol"; import {PoolManager} from "../src/PoolManager.sol"; import {PoolSwapTest} from "../src/test/PoolSwapTest.sol"; import {Deployers} from "./utils/Deployers.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {DynamicFeesTestHook} from "../src/test/DynamicFeesTestHook.sol"; import {Currency} from "../src/types/Currency.sol"; import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; import {Pool} from "../src/libraries/Pool.sol"; import {BalanceDelta, BalanceDeltaLibrary} from "../src/types/BalanceDelta.sol"; import {StateLibrary} from "../src/libraries/StateLibrary.sol"; +import {CustomRevert} from "../src/libraries/CustomRevert.sol"; +import {ProtocolFeeLibrary} from "../src/libraries/ProtocolFeeLibrary.sol"; -contract TestDynamicFees is Test, Deployers, GasSnapshot { +contract TestDynamicFees is Test, Deployers { using StateLibrary for IPoolManager; + using ProtocolFeeLibrary for uint16; DynamicFeesTestHook dynamicFeesHooks = DynamicFeesTestHook( address( @@ -69,9 +71,11 @@ contract TestDynamicFees is Test, Deployers, GasSnapshot { vm.expectRevert( abi.encodeWithSelector( - Hooks.Wrap__FailedHookCall.selector, + CustomRevert.WrappedError.selector, address(dynamicFeesHooks), - abi.encodeWithSelector(LPFeeLibrary.LPFeeTooLarge.selector, fee) + IHooks.afterInitialize.selector, + abi.encodeWithSelector(LPFeeLibrary.LPFeeTooLarge.selector, fee), + abi.encodeWithSelector(Hooks.HookCallFailed.selector) ) ); manager.initialize(key, SQRT_PRICE_1_1); @@ -107,9 +111,11 @@ contract TestDynamicFees is Test, Deployers, GasSnapshot { // afterInitialize will try to update the fee, and fail vm.expectRevert( abi.encodeWithSelector( - Hooks.Wrap__FailedHookCall.selector, + CustomRevert.WrappedError.selector, address(dynamicFeesHooks), - abi.encodeWithSelector(IPoolManager.UnauthorizedDynamicLPFeeUpdate.selector) + IHooks.afterInitialize.selector, + abi.encodeWithSelector(IPoolManager.UnauthorizedDynamicLPFeeUpdate.selector), + abi.encodeWithSelector(Hooks.HookCallFailed.selector) ) ); manager.initialize(key, SQRT_PRICE_1_1); @@ -126,11 +132,14 @@ contract TestDynamicFees is Test, Deployers, GasSnapshot { vm.expectRevert( abi.encodeWithSelector( - Hooks.Wrap__FailedHookCall.selector, + CustomRevert.WrappedError.selector, address(dynamicFeesHooks), - abi.encodeWithSelector(LPFeeLibrary.LPFeeTooLarge.selector, fee) + IHooks.beforeSwap.selector, + abi.encodeWithSelector(LPFeeLibrary.LPFeeTooLarge.selector, fee), + abi.encodeWithSelector(Hooks.HookCallFailed.selector) ) ); + swapRouter.swap(key, SWAP_PARAMS, testSettings, ZERO_BYTES); } @@ -146,7 +155,7 @@ contract TestDynamicFees is Test, Deployers, GasSnapshot { emit Swap(key.toId(), address(swapRouter), -100, 98, 79228162514264329749955861424, 1e18, -1, 123); swapRouter.swap(key, SWAP_PARAMS, testSettings, ZERO_BYTES); - snapLastCall("update dynamic fee in before swap"); + vm.snapshotGasLastCall("update dynamic fee in before swap"); assertEq(_fetchPoolLPFee(key), 123); } @@ -220,7 +229,7 @@ contract TestDynamicFees is Test, Deployers, GasSnapshot { dynamicFeesHooks.setFee(999999); - vm.prank(address(feeController)); + vm.prank(feeController); manager.setProtocolFee(key, 1000); IPoolManager.SwapParams memory params = @@ -228,16 +237,8 @@ contract TestDynamicFees is Test, Deployers, GasSnapshot { PoolSwapTest.TestSettings memory testSettings = PoolSwapTest.TestSettings({takeClaims: false, settleUsingBurn: false}); - vm.expectEmit(true, true, true, true, address(manager)); - emit Swap(key.toId(), address(swapRouter), -101000000, 100, 79228162514264329670727698909, 1e18, -1, 999999); - - BalanceDelta delta = swapRouter.swap(key, params, testSettings, ZERO_BYTES); - snapLastCall("swap with lp fee and protocol fee"); - - uint256 expectedProtocolFee = uint256(uint128(-delta.amount0())) * 1000 / 1e6; - assertEq(manager.protocolFeesAccrued(currency0), expectedProtocolFee); - - assertEq(_fetchPoolLPFee(key), 999999); + vm.expectRevert(Pool.InvalidFeeForExactOut.selector); + swapRouter.swap(key, params, testSettings, ZERO_BYTES); } function test_swap_100PercentFee_AmountIn_WithProtocol() public { @@ -245,7 +246,7 @@ contract TestDynamicFees is Test, Deployers, GasSnapshot { dynamicFeesHooks.setFee(1000000); - vm.prank(address(feeController)); + vm.prank(feeController); manager.setProtocolFee(key, 1000); IPoolManager.SwapParams memory params = @@ -267,14 +268,14 @@ contract TestDynamicFees is Test, Deployers, GasSnapshot { dynamicFeesHooks.setFee(123); - vm.prank(address(feeController)); + vm.prank(feeController); manager.setProtocolFee(key, 1000); PoolSwapTest.TestSettings memory testSettings = PoolSwapTest.TestSettings({takeClaims: false, settleUsingBurn: false}); vm.expectEmit(true, true, true, true, address(manager)); - emit Swap(key.toId(), address(swapRouter), -100, 98, 79228162514264329749955861424, 1e18, -1, 1122); + emit Swap(key.toId(), address(swapRouter), -100, 98, 79228162514264329749955861424, 1e18, -1, 1123); swapRouter.swap(key, SWAP_PARAMS, testSettings, ZERO_BYTES); @@ -294,7 +295,7 @@ contract TestDynamicFees is Test, Deployers, GasSnapshot { uint24 protocolFee = (uint24(protocolFee1) << 12) | uint24(protocolFee0); dynamicFeesHooks.setFee(lpFee); - vm.prank(address(feeController)); + vm.prank(feeController); manager.setProtocolFee(key, protocolFee); IPoolManager.SwapParams memory params = IPoolManager.SwapParams({ @@ -307,7 +308,14 @@ contract TestDynamicFees is Test, Deployers, GasSnapshot { BalanceDelta delta = swapRouter.swap(key, params, testSettings, ZERO_BYTES); + uint24 swapFee = uint16(protocolFee).calculateSwapFee(lpFee); + uint256 expectedProtocolFee = uint256(uint128(-delta.amount0())) * protocolFee0 / 1e6; + if (lpFee == 0) { + assertEq(protocolFee0, swapFee); + if (((uint256(uint128(-delta.amount0())) * protocolFee0) % 1e6) != 0) expectedProtocolFee++; + } + assertEq(manager.protocolFeesAccrued(currency0), expectedProtocolFee); } @@ -327,7 +335,7 @@ contract TestDynamicFees is Test, Deployers, GasSnapshot { emit Swap(key.toId(), address(swapRouter), -100, 98, 79228162514264329749955861424, 1e18, -1, 123); swapRouter.swap(key, SWAP_PARAMS, testSettings, ZERO_BYTES); - snapLastCall("swap with dynamic fee"); + vm.snapshotGasLastCall("swap with dynamic fee"); } function _fetchPoolLPFee(PoolKey memory _key) internal view returns (uint256 lpFee) { diff --git a/test/DynamicReturnFees.t.sol b/test/DynamicReturnFees.t.sol index 4975e804d..0f157fbfa 100644 --- a/test/DynamicReturnFees.t.sol +++ b/test/DynamicReturnFees.t.sol @@ -13,7 +13,6 @@ import {PoolKey} from "../src/types/PoolKey.sol"; import {PoolManager} from "../src/PoolManager.sol"; import {PoolSwapTest} from "../src/test/PoolSwapTest.sol"; import {Deployers} from "./utils/Deployers.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {DynamicReturnFeeTestHook} from "../src/test/DynamicReturnFeeTestHook.sol"; import {Currency} from "../src/types/Currency.sol"; import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; @@ -21,7 +20,7 @@ import {FullMath} from "../src/libraries/FullMath.sol"; import {BalanceDelta} from "../src/types/BalanceDelta.sol"; import {StateLibrary} from "../src/libraries/StateLibrary.sol"; -contract TestDynamicReturnFees is Test, Deployers, GasSnapshot { +contract TestDynamicReturnFees is Test, Deployers { using StateLibrary for IPoolManager; using LPFeeLibrary for uint24; @@ -95,7 +94,7 @@ contract TestDynamicReturnFees is Test, Deployers, GasSnapshot { emit Swap(key.toId(), address(swapRouter), -100, 98, 79228162514264329749955861424, 1e18, -1, 123); swapRouter.swap(key, SWAP_PARAMS, testSettings, ZERO_BYTES); - snapLastCall("swap with return dynamic fee"); + vm.snapshotGasLastCall("swap with return dynamic fee"); assertEq(_fetchPoolSwapFee(key), 0); } diff --git a/test/ERC6909Claims.t.sol b/test/ERC6909Claims.t.sol index 2075300d6..f3471beca 100644 --- a/test/ERC6909Claims.t.sol +++ b/test/ERC6909Claims.t.sol @@ -4,9 +4,8 @@ pragma solidity ^0.8.15; import {Test} from "forge-std/Test.sol"; import {Currency} from "../src/types/Currency.sol"; import {MockERC6909Claims} from "../src/test/MockERC6909Claims.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; -contract ERC6909ClaimsTest is Test, GasSnapshot { +contract ERC6909ClaimsTest is Test { MockERC6909Claims token; function setUp() public { @@ -52,7 +51,7 @@ contract ERC6909ClaimsTest is Test, GasSnapshot { function testMint() public { token.mint(address(0xBEEF), 1337, 100); - snapLastCall("ERC6909Claims mint"); + vm.snapshotGasLastCall("ERC6909Claims mint"); assertEq(token.balanceOf(address(0xBEEF), 1337), 100); } @@ -61,7 +60,7 @@ contract ERC6909ClaimsTest is Test, GasSnapshot { token.mint(address(0xBEEF), 1337, 100); vm.prank(address(0xBEEF)); token.burn(1337, 70); - snapLastCall("ERC6909Claims burn"); + vm.snapshotGasLastCall("ERC6909Claims burn"); assertEq(token.balanceOf(address(0xBEEF), 1337), 30); } @@ -74,7 +73,7 @@ contract ERC6909ClaimsTest is Test, GasSnapshot { function testApprove() public { token.approve(address(0xBEEF), 1337, 100); - snapLastCall("ERC6909Claims approve"); + vm.snapshotGasLastCall("ERC6909Claims approve"); assertEq(token.allowance(address(this), address(0xBEEF), 1337), 100); } @@ -87,7 +86,7 @@ contract ERC6909ClaimsTest is Test, GasSnapshot { vm.prank(sender); token.transfer(address(0xBEEF), 1337, 70); - snapLastCall("ERC6909Claims transfer"); + vm.snapshotGasLastCall("ERC6909Claims transfer"); assertEq(token.balanceOf(sender, 1337), 30); assertEq(token.balanceOf(address(0xBEEF), 1337), 70); @@ -103,7 +102,7 @@ contract ERC6909ClaimsTest is Test, GasSnapshot { token.approve(address(this), 1337, 100); token.transferFrom(sender, receiver, 1337, 70); - snapLastCall("ERC6909Claims transferFrom with approval"); + vm.snapshotGasLastCall("ERC6909Claims transferFrom with approval"); assertEq(token.allowance(sender, address(this), 1337), 30); assertEq(token.balanceOf(sender, 1337), 30); @@ -120,7 +119,7 @@ contract ERC6909ClaimsTest is Test, GasSnapshot { token.approve(address(this), 1337, type(uint256).max); token.transferFrom(sender, receiver, 1337, 70); - snapLastCall("ERC6909Claims transferFrom with infinite approval"); + vm.snapshotGasLastCall("ERC6909Claims transferFrom with infinite approval"); assertEq(token.allowance(sender, address(this), 1337), type(uint256).max); assertEq(token.balanceOf(sender, 1337), 30); @@ -137,7 +136,7 @@ contract ERC6909ClaimsTest is Test, GasSnapshot { token.setOperator(address(this), true); token.transferFrom(sender, receiver, 1337, 70); - snapLastCall("ERC6909Claims transferFrom as operator"); + vm.snapshotGasLastCall("ERC6909Claims transferFrom as operator"); assertEq(token.balanceOf(sender, 1337), 30); assertEq(token.balanceOf(receiver, 1337), 70); diff --git a/test/Extsload.t.sol b/test/Extsload.t.sol index f16964cdc..ddc96ceab 100644 --- a/test/Extsload.t.sol +++ b/test/Extsload.t.sol @@ -3,12 +3,11 @@ pragma solidity ^0.8.0; import {Test} from "forge-std/Test.sol"; import {Extsload} from "../src/Extsload.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; contract Loadable is Extsload {} /// @author philogy -contract ExtsloadTest is Test, GasSnapshot { +contract ExtsloadTest is Test { Loadable loadable = new Loadable(); function test_load10_sparse() public { @@ -19,7 +18,7 @@ contract ExtsloadTest is Test, GasSnapshot { } bytes32[] memory values = loadable.extsload(keys); - snapLastCall("sparse external sload"); + vm.snapshotGasLastCall("sparse external sload"); assertEq(values.length, keys.length); for (uint256 i = 0; i < values.length; i++) { assertEq(values[i], bytes32(i)); diff --git a/test/ModifyLiquidity.t.sol b/test/ModifyLiquidity.t.sol index f4ebe74aa..007e41658 100644 --- a/test/ModifyLiquidity.t.sol +++ b/test/ModifyLiquidity.t.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; import {Deployers} from "./utils/Deployers.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {PoolKey} from "src/types/PoolKey.sol"; import {IPoolManager} from "src/interfaces/IPoolManager.sol"; import {IHooks} from "src/interfaces/IHooks.sol"; @@ -21,7 +20,7 @@ import {TickMath} from "src/libraries/TickMath.sol"; import {toBalanceDelta} from "src/types/BalanceDelta.sol"; import {Logger} from "./utils/Logger.sol"; -contract ModifyLiquidityTest is Test, Logger, Deployers, JavascriptFfi, Fuzzers, GasSnapshot { +contract ModifyLiquidityTest is Test, Logger, Deployers, JavascriptFfi, Fuzzers { using StateLibrary for IPoolManager; PoolKey simpleKey; // vanilla pool key @@ -305,12 +304,12 @@ contract ModifyLiquidityTest is Test, Logger, Deployers, JavascriptFfi, Fuzzers, function test_gas_modifyLiquidity_newPosition() public { modifyLiquidityRouter.modifyLiquidity(simpleKey, LIQ_PARAM_SALT, ZERO_BYTES); - snapLastCall("create new liquidity to a position with salt"); + vm.snapshotGasLastCall("create new liquidity to a position with salt"); } function test_gas_modifyLiquidity_updateSamePosition_withSalt() public { modifyLiquidityRouter.modifyLiquidity(simpleKey, LIQ_PARAM_SALT, ZERO_BYTES); modifyLiquidityRouter.modifyLiquidity(simpleKey, LIQ_PARAM_SALT, ZERO_BYTES); - snapLastCall("add liquidity to already existing position with salt"); + vm.snapshotGasLastCall("add liquidity to already existing position with salt"); } } diff --git a/test/NoDelegateCall.t.sol b/test/NoDelegateCall.t.sol index 4aa1f7925..612c9acb8 100644 --- a/test/NoDelegateCall.t.sol +++ b/test/NoDelegateCall.t.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.20; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {Test} from "forge-std/Test.sol"; import {IPoolManager} from "../src/interfaces/IPoolManager.sol"; import {PoolSwapTest} from "../src/test/PoolSwapTest.sol"; @@ -11,10 +10,10 @@ import {PoolManager} from "../src/PoolManager.sol"; import {NoDelegateCall} from "../src/NoDelegateCall.sol"; import {Deployers} from "./utils/Deployers.sol"; -contract TestDelegateCall is Test, Deployers, GasSnapshot { +contract TestDelegateCall is Test, Deployers { // override to use ProxyPoolManager function deployFreshManager() internal virtual override { - IPoolManager delegateManager = new PoolManager(); + IPoolManager delegateManager = new PoolManager(address(this)); manager = new ProxyPoolManager(address(delegateManager)); } @@ -27,7 +26,7 @@ contract TestDelegateCall is Test, Deployers, GasSnapshot { } function test_gas_noDelegateCall() public { - snap( + vm.snapshotValue( "NoDelegateCall", noDelegateCallTest.getGasCostOfCannotBeDelegateCalled() - noDelegateCallTest.getGasCostOfCanBeDelegateCalled() diff --git a/test/PoolManager.t.sol b/test/PoolManager.t.sol index be71725a1..e469b25be 100644 --- a/test/PoolManager.t.sol +++ b/test/PoolManager.t.sol @@ -6,7 +6,6 @@ import {IHooks} from "../src/interfaces/IHooks.sol"; import {Hooks} from "../src/libraries/Hooks.sol"; import {IPoolManager} from "../src/interfaces/IPoolManager.sol"; import {IProtocolFees} from "../src/interfaces/IProtocolFees.sol"; -import {IProtocolFeeController} from "../src/interfaces/IProtocolFeeController.sol"; import {PoolManager} from "../src/PoolManager.sol"; import {TickMath} from "../src/libraries/TickMath.sol"; import {Pool} from "../src/libraries/Pool.sol"; @@ -20,7 +19,6 @@ import {PoolModifyLiquidityTest} from "../src/test/PoolModifyLiquidityTest.sol"; import {BalanceDelta, BalanceDeltaLibrary} from "../src/types/BalanceDelta.sol"; import {PoolSwapTest} from "../src/test/PoolSwapTest.sol"; import {TestInvalidERC20} from "../src/test/TestInvalidERC20.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {PoolEmptyUnlockTest} from "../src/test/PoolEmptyUnlockTest.sol"; import {Action} from "../src/test/PoolNestedActionsTest.sol"; import {PoolId} from "../src/types/PoolId.sol"; @@ -32,14 +30,17 @@ import {AmountHelpers} from "./utils/AmountHelpers.sol"; import {ProtocolFeeLibrary} from "../src/libraries/ProtocolFeeLibrary.sol"; import {IProtocolFees} from "../src/interfaces/IProtocolFees.sol"; import {StateLibrary} from "../src/libraries/StateLibrary.sol"; +import {TransientStateLibrary} from "../src/libraries/TransientStateLibrary.sol"; import {Actions} from "../src/test/ActionsRouter.sol"; +import {CustomRevert} from "../src/libraries/CustomRevert.sol"; -contract PoolManagerTest is Test, Deployers, GasSnapshot { +contract PoolManagerTest is Test, Deployers { using Hooks for IHooks; using LPFeeLibrary for uint24; using SafeCast for *; using ProtocolFeeLibrary for uint24; using StateLibrary for IPoolManager; + using TransientStateLibrary for IPoolManager; event UnlockCallback(); event ProtocolFeeControllerUpdated(address feeController); @@ -79,7 +80,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { } function test_bytecodeSize() public { - snapSize("poolManager bytecode size", address(manager)); + vm.snapshotValue("poolManager bytecode size", address(manager).code.length); } function test_addLiquidity_failsIfNotInitialized() public { @@ -392,7 +393,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { IPoolManager.ModifyLiquidityParams memory uniqueParams = IPoolManager.ModifyLiquidityParams({tickLower: -300, tickUpper: -180, liquidityDelta: 1e18, salt: 0}); modifyLiquidityNoChecks.modifyLiquidity(key, uniqueParams, ZERO_BYTES); - snapLastCall("simple addLiquidity"); + vm.snapshotGasLastCall("simple addLiquidity"); } function test_addLiquidity_secondAdditionSameRange_gas() public { @@ -400,7 +401,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { IPoolManager.ModifyLiquidityParams({tickLower: -300, tickUpper: -180, liquidityDelta: 1e18, salt: 0}); modifyLiquidityNoChecks.modifyLiquidity(key, uniqueParams, ZERO_BYTES); modifyLiquidityNoChecks.modifyLiquidity(key, uniqueParams, ZERO_BYTES); - snapLastCall("simple addLiquidity second addition same range"); + vm.snapshotGasLastCall("simple addLiquidity second addition same range"); } function test_removeLiquidity_gas() public { @@ -411,7 +412,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { uniqueParams.liquidityDelta *= -1; modifyLiquidityNoChecks.modifyLiquidity(key, uniqueParams, ZERO_BYTES); - snapLastCall("simple removeLiquidity"); + vm.snapshotGasLastCall("simple removeLiquidity"); } function test_removeLiquidity_someLiquidityRemains_gas() public { @@ -422,7 +423,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { uniqueParams.liquidityDelta /= -2; modifyLiquidityNoChecks.modifyLiquidity(key, uniqueParams, ZERO_BYTES); - snapLastCall("simple removeLiquidity some liquidity remains"); + vm.snapshotGasLastCall("simple removeLiquidity some liquidity remains"); } function test_addLiquidity_succeeds() public { @@ -435,12 +436,12 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { function test_addLiquidity_withNative_gas() public { modifyLiquidityRouter.modifyLiquidity{value: 1 ether}(nativeKey, LIQUIDITY_PARAMS, ZERO_BYTES); - snapLastCall("addLiquidity with native token"); + vm.snapshotGasLastCall("addLiquidity with native token"); } function test_removeLiquidity_withNative_gas() public { modifyLiquidityRouter.modifyLiquidity{value: 1 ether}(nativeKey, REMOVE_LIQUIDITY_PARAMS, ZERO_BYTES); - snapLastCall("removeLiquidity with native token"); + vm.snapshotGasLastCall("removeLiquidity with native token"); } function test_addLiquidity_withHooks_gas() public { @@ -452,7 +453,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { (key,) = initPool(currency0, currency1, mockHooks, 3000, SQRT_PRICE_1_1); modifyLiquidityRouter.modifyLiquidity(key, LIQUIDITY_PARAMS, ZERO_BYTES); - snapLastCall("addLiquidity with empty hook"); + vm.snapshotGasLastCall("addLiquidity with empty hook"); } function test_removeLiquidity_withHooks_gas() public { @@ -465,7 +466,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { modifyLiquidityRouter.modifyLiquidity(key, LIQUIDITY_PARAMS, ZERO_BYTES); modifyLiquidityRouter.modifyLiquidity(key, REMOVE_LIQUIDITY_PARAMS, ZERO_BYTES); - snapLastCall("removeLiquidity with empty hook"); + vm.snapshotGasLastCall("removeLiquidity with empty hook"); } function test_swap_failsIfNotInitialized(uint160 sqrtPriceX96) public { @@ -608,7 +609,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { function test_swap_gas() public { swapRouterNoChecks.swap(key, SWAP_PARAMS); - snapLastCall("simple swap"); + vm.snapshotGasLastCall("simple swap"); } function test_swap_withNative_succeeds() public { @@ -620,7 +621,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { function test_swap_withNative_gas() public { swapRouterNoChecks.swap{value: 100}(nativeKey, SWAP_PARAMS); - snapLastCall("simple swap with native"); + vm.snapshotGasLastCall("simple swap with native"); } function test_swap_withHooks_gas() public { @@ -642,7 +643,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { testSettings = PoolSwapTest.TestSettings({takeClaims: false, settleUsingBurn: false}); swapRouter.swap(key, swapParams, testSettings, ZERO_BYTES); - snapLastCall("swap with hooks"); + vm.snapshotGasLastCall("swap with hooks"); } function test_swap_mint6909IfOutputNotTaken_gas() public { @@ -652,7 +653,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { vm.expectEmit(); emit Transfer(address(swapRouter), address(0), address(this), CurrencyLibrary.toId(currency1), 98); swapRouter.swap(key, SWAP_PARAMS, testSettings, ZERO_BYTES); - snapLastCall("swap mint output as 6909"); + vm.snapshotGasLastCall("swap mint output as 6909"); uint256 erc6909Balance = manager.balanceOf(address(this), CurrencyLibrary.toId(currency1)); assertEq(erc6909Balance, 98); @@ -670,7 +671,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { address(swapRouter), address(0), address(this), CurrencyLibrary.toId(CurrencyLibrary.ADDRESS_ZERO), 98 ); swapRouter.swap(nativeKey, params, testSettings, ZERO_BYTES); - snapLastCall("swap mint native output as 6909"); + vm.snapshotGasLastCall("swap mint native output as 6909"); uint256 erc6909Balance = manager.balanceOf(address(this), CurrencyLibrary.toId(CurrencyLibrary.ADDRESS_ZERO)); assertEq(erc6909Balance, 98); @@ -698,7 +699,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { vm.expectEmit(); emit Transfer(address(swapRouter), address(this), address(0), CurrencyLibrary.toId(currency1), 27); swapRouter.swap(key, params, testSettings, ZERO_BYTES); - snapLastCall("swap burn 6909 for input"); + vm.snapshotGasLastCall("swap burn 6909 for input"); erc6909Balance = manager.balanceOf(address(this), CurrencyLibrary.toId(currency1)); assertEq(erc6909Balance, 71); @@ -733,7 +734,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { ); // don't have to send in native currency since burning 6909 for input swapRouter.swap(nativeKey, params, testSettings, ZERO_BYTES); - snapLastCall("swap burn native 6909 for input"); + vm.snapshotGasLastCall("swap burn native 6909 for input"); erc6909Balance = manager.balanceOf(address(this), CurrencyLibrary.toId(CurrencyLibrary.ADDRESS_ZERO)); assertEq(erc6909Balance, 71); @@ -749,7 +750,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { IPoolManager.SwapParams({zeroForOne: true, amountSpecified: -100, sqrtPriceLimitX96: SQRT_PRICE_1_4}); swapRouter.swap(key, params, testSettings, ZERO_BYTES); - snapLastCall("swap against liquidity"); + vm.snapshotGasLastCall("swap against liquidity"); } function test_swap_againstLiqWithNative_gas() public { @@ -762,7 +763,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { IPoolManager.SwapParams({zeroForOne: true, amountSpecified: -100, sqrtPriceLimitX96: SQRT_PRICE_1_4}); swapRouter.swap{value: 1 ether}(nativeKey, params, testSettings, ZERO_BYTES); - snapLastCall("swap against liquidity with native token"); + vm.snapshotGasLastCall("swap against liquidity with native token"); } function test_swap_accruesProtocolFees(uint16 protocolFee0, uint16 protocolFee1, int256 amountSpecified) public { @@ -775,7 +776,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { (,, uint24 slot0ProtocolFee,) = manager.getSlot0(key.toId()); assertEq(slot0ProtocolFee, 0); - vm.prank(address(feeController)); + vm.prank(feeController); manager.setProtocolFee(key, protocolFee); (,, slot0ProtocolFee,) = manager.getSlot0(key.toId()); @@ -834,7 +835,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { assertEq(feeGrowthGlobal1X128, 0); donateRouter.donate(key, 100, 200, ZERO_BYTES); - snapLastCall("donate gas with 2 tokens"); + vm.snapshotGasLastCall("donate gas with 2 tokens"); (feeGrowthGlobal0X128, feeGrowthGlobal1X128) = manager.getFeeGrowthGlobals(key.toId()); assertEq(feeGrowthGlobal0X128, 34028236692093846346337); @@ -892,7 +893,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { function test_donate_OneToken_gas() public { donateRouter.donate(key, 100, 0, ZERO_BYTES); - snapLastCall("donate gas with 1 token"); + vm.snapshotGasLastCall("donate gas with 1 token"); } function test_fuzz_donate_emits_event(uint256 amount0, uint256 amount1) public { @@ -930,7 +931,11 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { (uint256 amount0, uint256 amount1) = currency0Invalid ? (1, 0) : (0, 1); vm.expectRevert( abi.encodeWithSelector( - CurrencyLibrary.Wrap__ERC20TransferFailed.selector, invalidToken, abi.encode(bytes32(0)) + CustomRevert.WrappedError.selector, + address(invalidToken), + TestInvalidERC20.transfer.selector, + abi.encode(bytes32(0)), + abi.encodeWithSelector(CurrencyLibrary.ERC20TransferFailed.selector) ) ); takeRouter.take(key, amount0, amount1); @@ -984,13 +989,53 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { manager.burn(address(this), key.currency0.toId(), 1); } + function test_collectProtocolFees_locked_revertsWithProtocolFeeCurrencySynced() public noIsolate { + manager.setProtocolFeeController(address(this)); + // currency1 is never native + manager.sync(key.currency1); + assertEq(Currency.unwrap(key.currency1), Currency.unwrap(manager.getSyncedCurrency())); + vm.expectRevert(IProtocolFees.ProtocolFeeCurrencySynced.selector); + manager.collectProtocolFees(address(this), key.currency1, 1); + } + + function test_sync_locked_collectProtocolFees_unlocked_revertsWithProtocolFeeCurrencySynced() public noIsolate { + manager.setProtocolFeeController(address(actionsRouter)); + manager.sync(key.currency1); + assertEq(Currency.unwrap(key.currency1), Currency.unwrap(manager.getSyncedCurrency())); + + Actions[] memory actions = new Actions[](1); + bytes[] memory params = new bytes[](1); + + actions[0] = Actions.COLLECT_PROTOCOL_FEES; + params[0] = abi.encode(address(this), key.currency1, 1); + + vm.expectRevert(IProtocolFees.ProtocolFeeCurrencySynced.selector); + actionsRouter.executeActions(actions, params); + } + + function test_collectProtocolFees_unlocked_revertsWithProtocolFeeCurrencySynced() public { + manager.setProtocolFeeController(address(actionsRouter)); + + Actions[] memory actions = new Actions[](2); + bytes[] memory params = new bytes[](2); + + actions[0] = Actions.SYNC; + params[0] = abi.encode(key.currency1); + + actions[1] = Actions.COLLECT_PROTOCOL_FEES; + params[1] = abi.encode(address(this), key.currency1, 1); + + vm.expectRevert(IProtocolFees.ProtocolFeeCurrencySynced.selector); + actionsRouter.executeActions(actions, params); + } + function test_collectProtocolFees_ERC20_accumulateFees_gas() public { uint256 expectedFees = 10; (,, uint24 slot0ProtocolFee,) = manager.getSlot0(key.toId()); assertEq(slot0ProtocolFee, 0); - vm.prank(address(feeController)); + vm.prank(feeController); manager.setProtocolFee(key, MAX_PROTOCOL_FEE_BOTH_TOKENS); (,, slot0ProtocolFee,) = manager.getSlot0(key.toId()); @@ -1006,9 +1051,9 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { assertEq(manager.protocolFeesAccrued(currency0), expectedFees); assertEq(manager.protocolFeesAccrued(currency1), 0); assertEq(currency0.balanceOf(address(1)), 0); - vm.prank(address(feeController)); + vm.prank(feeController); manager.collectProtocolFees(address(1), currency0, expectedFees); - snapLastCall("erc20 collect protocol fees"); + vm.snapshotGasLastCall("erc20 collect protocol fees"); assertEq(currency0.balanceOf(address(1)), expectedFees); assertEq(manager.protocolFeesAccrued(currency0), 0); } @@ -1019,7 +1064,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { (,, uint24 slot0ProtocolFee,) = manager.getSlot0(key.toId()); assertEq(slot0ProtocolFee, 0); - vm.prank(address(feeController)); + vm.prank(feeController); manager.setProtocolFee(key, MAX_PROTOCOL_FEE_BOTH_TOKENS); (,, slot0ProtocolFee,) = manager.getSlot0(key.toId()); @@ -1035,7 +1080,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { assertEq(manager.protocolFeesAccrued(currency0), expectedFees); assertEq(manager.protocolFeesAccrued(currency1), 0); assertEq(currency0.balanceOf(address(1)), 0); - vm.prank(address(feeController)); + vm.prank(feeController); manager.collectProtocolFees(address(1), currency0, expectedFees); assertEq(currency0.balanceOf(address(1)), expectedFees); assertEq(manager.protocolFeesAccrued(currency0), 0); @@ -1047,7 +1092,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { (,, uint24 slot0ProtocolFee,) = manager.getSlot0(key.toId()); assertEq(slot0ProtocolFee, 0); - vm.prank(address(feeController)); + vm.prank(feeController); manager.setProtocolFee(key, MAX_PROTOCOL_FEE_BOTH_TOKENS); (,, slot0ProtocolFee,) = manager.getSlot0(key.toId()); @@ -1063,7 +1108,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { assertEq(manager.protocolFeesAccrued(currency0), 0); assertEq(manager.protocolFeesAccrued(currency1), expectedFees); assertEq(currency1.balanceOf(address(1)), 0); - vm.prank(address(feeController)); + vm.prank(feeController); manager.collectProtocolFees(address(1), currency1, 0); assertEq(currency1.balanceOf(address(1)), expectedFees); assertEq(manager.protocolFeesAccrued(currency1), 0); @@ -1076,7 +1121,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { (,, uint24 slot0ProtocolFee,) = manager.getSlot0(nativeKey.toId()); assertEq(slot0ProtocolFee, 0); - vm.prank(address(feeController)); + vm.prank(feeController); manager.setProtocolFee(nativeKey, MAX_PROTOCOL_FEE_BOTH_TOKENS); (,, slot0ProtocolFee,) = manager.getSlot0(nativeKey.toId()); @@ -1092,9 +1137,9 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { assertEq(manager.protocolFeesAccrued(nativeCurrency), expectedFees); assertEq(manager.protocolFeesAccrued(currency1), 0); assertEq(nativeCurrency.balanceOf(address(1)), 0); - vm.prank(address(feeController)); + vm.prank(feeController); manager.collectProtocolFees(address(1), nativeCurrency, expectedFees); - snapLastCall("native collect protocol fees"); + vm.snapshotGasLastCall("native collect protocol fees"); assertEq(nativeCurrency.balanceOf(address(1)), expectedFees); assertEq(manager.protocolFeesAccrued(nativeCurrency), 0); } @@ -1106,7 +1151,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { (,, uint24 slot0ProtocolFee,) = manager.getSlot0(nativeKey.toId()); assertEq(slot0ProtocolFee, 0); - vm.prank(address(feeController)); + vm.prank(feeController); manager.setProtocolFee(nativeKey, MAX_PROTOCOL_FEE_BOTH_TOKENS); (,, slot0ProtocolFee,) = manager.getSlot0(nativeKey.toId()); @@ -1122,7 +1167,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { assertEq(manager.protocolFeesAccrued(nativeCurrency), expectedFees); assertEq(manager.protocolFeesAccrued(currency1), 0); assertEq(nativeCurrency.balanceOf(address(1)), 0); - vm.prank(address(feeController)); + vm.prank(feeController); manager.collectProtocolFees(address(1), nativeCurrency, 0); assertEq(nativeCurrency.balanceOf(address(1)), expectedFees); assertEq(manager.protocolFeesAccrued(nativeCurrency), 0); @@ -1158,7 +1203,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { // PoolId poolId = key.toId(); // bytes32 slot0Bytes = manager.extsload(keccak256(abi.encode(poolId, POOL_SLOT))); - // snapLastCall("poolExtsloadSlot0"); + // vm.snapshotGasLastCall("poolExtsloadSlot0"); // uint160 sqrtPriceX96Extsload; // assembly { @@ -1195,7 +1240,7 @@ contract PoolManagerTest is Test, Deployers, GasSnapshot { // PoolId poolId = key.toId(); // bytes memory value = manager.extsload(bytes32(uint256(keccak256(abi.encode(poolId, POOL_SLOT))) + 1), 2); - // snapLastCall("poolExtsloadTickInfoStruct"); + // vm.snapshotGasLastCall("poolExtsloadTickInfoStruct"); // uint256 feeGrowthGlobal0X128Extsload; // uint256 feeGrowthGlobal1X128Extsload; diff --git a/test/PoolManagerInitialize.t.sol b/test/PoolManagerInitialize.t.sol index b4c9b43d0..8ec018756 100644 --- a/test/PoolManagerInitialize.t.sol +++ b/test/PoolManagerInitialize.t.sol @@ -16,15 +16,12 @@ import {MockHooks} from "../src/test/MockHooks.sol"; import {MockContract} from "../src/test/MockContract.sol"; import {EmptyTestHooks} from "../src/test/EmptyTestHooks.sol"; import {PoolKey} from "../src/types/PoolKey.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {PoolId} from "../src/types/PoolId.sol"; import {LPFeeLibrary} from "../src/libraries/LPFeeLibrary.sol"; -import {ProtocolFeeControllerTest} from "../src/test/ProtocolFeeControllerTest.sol"; -import {IProtocolFeeController} from "../src/interfaces/IProtocolFeeController.sol"; import {ProtocolFeeLibrary} from "../src/libraries/ProtocolFeeLibrary.sol"; import {StateLibrary} from "../src/libraries/StateLibrary.sol"; -contract PoolManagerInitializeTest is Test, Deployers, GasSnapshot { +contract PoolManagerInitializeTest is Test, Deployers { using Hooks for IHooks; using LPFeeLibrary for uint24; using ProtocolFeeLibrary for uint24; @@ -318,6 +315,6 @@ contract PoolManagerInitializeTest is Test, Deployers, GasSnapshot { function test_initialize_gas() public { manager.initialize(uninitializedKey, SQRT_PRICE_1_1); - snapLastCall("initialize"); + vm.snapshotGasLastCall("initialize"); } } diff --git a/test/ProtocolFeesImplementation.t.sol b/test/ProtocolFeesImplementation.t.sol index f5f7007ea..de53a8c03 100644 --- a/test/ProtocolFeesImplementation.t.sol +++ b/test/ProtocolFeesImplementation.t.sol @@ -5,7 +5,6 @@ import {Test} from "forge-std/Test.sol"; import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; import {Currency} from "../src/types/Currency.sol"; import {ProtocolFeesImplementation} from "../src/test/ProtocolFeesImplementation.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {IProtocolFees} from "../src/interfaces/IProtocolFees.sol"; import {ProtocolFeeLibrary} from "../src/libraries/ProtocolFeeLibrary.sol"; import {PoolKey} from "../src/types/PoolKey.sol"; @@ -14,9 +13,8 @@ import {Deployers} from "../test/utils/Deployers.sol"; import {PoolId} from "../src/types/PoolId.sol"; import {IHooks} from "../src/interfaces/IHooks.sol"; import {Constants} from "../test/utils/Constants.sol"; -import {ProtocolFeeControllerTest} from "../src/test/ProtocolFeeControllerTest.sol"; -contract ProtocolFeesTest is Test, GasSnapshot, Deployers { +contract ProtocolFeesTest is Test, Deployers { using ProtocolFeeLibrary for uint24; event ProtocolFeeControllerUpdated(address indexed feeController); @@ -28,26 +26,26 @@ contract ProtocolFeesTest is Test, GasSnapshot, Deployers { function setUp() public { protocolFees = new ProtocolFeesImplementation(); - feeController = new ProtocolFeeControllerTest(); + feeController = makeAddr("feeController"); (currency0, currency1) = deployAndMint2Currencies(); MockERC20(Currency.unwrap(currency0)).transfer(address(protocolFees), 2 ** 255); } function test_setProtocolFeeController_succeedsNoRevert() public { - assertEq(address(protocolFees.protocolFeeController()), address(0)); + assertEq(protocolFees.protocolFeeController(), address(0)); vm.expectEmit(true, false, false, false, address(protocolFees)); - emit ProtocolFeeControllerUpdated(address(feeController)); + emit ProtocolFeeControllerUpdated(feeController); protocolFees.setProtocolFeeController(feeController); - assertEq(address(protocolFees.protocolFeeController()), address(feeController)); + assertEq(protocolFees.protocolFeeController(), feeController); } function test_setProtocolFeeController_revertsWithNotAuthorized() public { - assertEq(address(protocolFees.protocolFeeController()), address(0)); + assertEq(protocolFees.protocolFeeController(), address(0)); vm.prank(address(1)); // not the owner address vm.expectRevert("UNAUTHORIZED"); protocolFees.setProtocolFeeController(feeController); - assertEq(address(protocolFees.protocolFeeController()), address(0)); + assertEq(protocolFees.protocolFeeController(), address(0)); } function test_setProtocolFee_succeeds_gas() public { @@ -55,11 +53,11 @@ contract ProtocolFeesTest is Test, GasSnapshot, Deployers { protocolFees.setProtocolFeeController(feeController); // Set price to pretend that the pool is initialized protocolFees.setPrice(key, Constants.SQRT_PRICE_1_1); - vm.prank(address(feeController)); + vm.prank(feeController); vm.expectEmit(true, false, false, true, address(protocolFees)); emit ProtocolFeeUpdated(key.toId(), MAX_PROTOCOL_FEE_BOTH_TOKENS); protocolFees.setProtocolFee(key, MAX_PROTOCOL_FEE_BOTH_TOKENS); - snapLastCall("set protocol fee"); + vm.snapshotGasLastCall("set protocol fee"); } function test_setProtocolFee_revertsWithInvalidCaller() public { @@ -72,12 +70,12 @@ contract ProtocolFeesTest is Test, GasSnapshot, Deployers { uint24 protocolFee = MAX_PROTOCOL_FEE_BOTH_TOKENS + 1; protocolFees.setProtocolFeeController(feeController); - vm.prank(address(feeController)); + vm.prank(feeController); vm.expectRevert(abi.encodeWithSelector(IProtocolFees.ProtocolFeeTooLarge.selector, protocolFee)); protocolFees.setProtocolFee(key, protocolFee); protocolFee = MAX_PROTOCOL_FEE_BOTH_TOKENS + (1 << 12); - vm.prank(address(feeController)); + vm.prank(feeController); vm.expectRevert(abi.encodeWithSelector(IProtocolFees.ProtocolFeeTooLarge.selector, protocolFee)); protocolFees.setProtocolFee(key, protocolFee); } @@ -88,7 +86,7 @@ contract ProtocolFeesTest is Test, GasSnapshot, Deployers { protocolFees.setPrice(key, Constants.SQRT_PRICE_1_1); uint16 fee0 = protocolFee.getZeroForOneFee(); uint16 fee1 = protocolFee.getOneForZeroFee(); - vm.prank(address(feeController)); + vm.prank(feeController); if ((fee0 > 1000) || (fee1 > 1000)) { vm.expectRevert(abi.encodeWithSelector(IProtocolFees.ProtocolFeeTooLarge.selector, protocolFee)); protocolFees.setProtocolFee(key, protocolFee); @@ -104,23 +102,13 @@ contract ProtocolFeesTest is Test, GasSnapshot, Deployers { protocolFees.collectProtocolFees(address(1), currency0, 0); } - function test_collectProtocolFees_revertsWithContractUnlocked() public { - protocolFees.setIsUnlocked(true); - - protocolFees.setProtocolFeeController(feeController); - vm.prank(address(feeController)); - - vm.expectRevert(IProtocolFees.ContractUnlocked.selector); - protocolFees.collectProtocolFees(address(1), currency0, 0); - } - function test_collectProtocolFees_succeeds() public { // set a balance of protocol fees that can be collected protocolFees.updateProtocolFees(currency0, 100); assertEq(protocolFees.protocolFeesAccrued(currency0), 100); protocolFees.setProtocolFeeController(feeController); - vm.prank(address(feeController)); + vm.prank(feeController); protocolFees.collectProtocolFees(address(this), currency0, 100); assertEq(protocolFees.protocolFeesAccrued(currency0), 0); assertEq(currency0.balanceOf(address(this)), 100); @@ -140,7 +128,7 @@ contract ProtocolFeesTest is Test, GasSnapshot, Deployers { } protocolFees.setProtocolFeeController(feeController); - vm.prank(address(feeController)); + vm.prank(feeController); if (amount > feesAccrued) { vm.expectRevert(); } diff --git a/test/SkipCallsTestHook.t.sol b/test/SkipCallsTestHook.t.sol index 1e6bc584e..9da67da29 100644 --- a/test/SkipCallsTestHook.t.sol +++ b/test/SkipCallsTestHook.t.sol @@ -12,13 +12,12 @@ import {PoolKey} from "../src/types/PoolKey.sol"; import {PoolManager} from "../src/PoolManager.sol"; import {PoolSwapTest} from "../src/test/PoolSwapTest.sol"; import {Deployers} from "./utils/Deployers.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {Currency} from "../src/types/Currency.sol"; import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; import {Constants} from "../test/utils/Constants.sol"; import {SkipCallsTestHook} from "../src/test/SkipCallsTestHook.sol"; -contract SkipCallsTest is Test, Deployers, GasSnapshot { +contract SkipCallsTest is Test, Deployers { PoolSwapTest.TestSettings testSettings = PoolSwapTest.TestSettings({takeClaims: false, settleUsingBurn: false}); function deploy(SkipCallsTestHook skipCallsTestHook) private { @@ -157,7 +156,7 @@ contract SkipCallsTest is Test, Deployers, GasSnapshot { // swaps and increments counter swapRouter.swap(key, SWAP_PARAMS, testSettings, abi.encode(address(this))); - snapLastCall("swap skips hook call if hook is caller"); + vm.snapshotGasLastCall("swap skips hook call if hook is caller"); assertEq(skipCallsTestHook.counter(), 1); } diff --git a/test/Sync.t.sol b/test/Sync.t.sol index 74bf8e800..189f93c12 100644 --- a/test/Sync.t.sol +++ b/test/Sync.t.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; import {Deployers} from "./utils/Deployers.sol"; @@ -21,7 +20,7 @@ import {NativeERC20} from "../src/test/NativeERC20.sol"; import {IPoolManager} from "../src/interfaces/IPoolManager.sol"; import {CurrencyLibrary} from "../src/types/Currency.sol"; -contract SyncTest is Test, Deployers, GasSnapshot { +contract SyncTest is Test, Deployers { using StateLibrary for IPoolManager; using TransientStateLibrary for IPoolManager; @@ -33,9 +32,11 @@ contract SyncTest is Test, Deployers, GasSnapshot { currency2 = deployMintAndApproveCurrency(); } - function test_settle_failsIfLocked() public { - vm.expectRevert(IPoolManager.ManagerLocked.selector); + function test_sync_multiple_unlocked() public noIsolate { + manager.sync(currency1); + assertEq(Currency.unwrap(currency1), Currency.unwrap(manager.getSyncedCurrency())); manager.sync(currency0); + assertEq(Currency.unwrap(currency0), Currency.unwrap(manager.getSyncedCurrency())); } function test_sync_balanceIsZero() public { @@ -210,9 +211,9 @@ contract SyncTest is Test, Deployers, GasSnapshot { Actions[] memory actions = new Actions[](9); bytes[] memory params = new bytes[](9); - snapStart("getReserves"); + vm.startSnapshotGas("getReserves"); uint256 reserves = manager.getSyncedReserves(); - snapEnd(); + vm.stopSnapshotGas(); assertEq(reserves, 0); // reserves are 0. actions[0] = Actions.TAKE; diff --git a/test/Tick.t.sol b/test/Tick.t.sol index 44c2ba57b..920239c7b 100644 --- a/test/Tick.t.sol +++ b/test/Tick.t.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; import {stdError} from "forge-std/StdError.sol"; -import {GasSnapshot} from "../lib/forge-gas-snapshot/src/GasSnapshot.sol"; import {Constants} from "./utils/Constants.sol"; import {Pool} from "../src/libraries/Pool.sol"; import {TickMath} from "../src/libraries/TickMath.sol"; @@ -22,7 +21,7 @@ contract LiquidityMathRef { } } -contract TickTest is Test, GasSnapshot { +contract TickTest is Test { using Pool for Pool.State; int24 constant LOW_TICK_SPACING = 10; @@ -163,21 +162,21 @@ contract TickTest is Test, GasSnapshot { } function testTick_tickSpacingToMaxLiquidityPerTick_gasCostMinTickSpacing() public { - snapStart("tickSpacingToMaxLiquidityPerTick_gasCostMinTickSpacing"); + vm.startSnapshotGas("tickSpacingToMaxLiquidityPerTick_gasCostMinTickSpacing"); tickSpacingToMaxLiquidityPerTick(TickMath.MIN_TICK_SPACING); - snapEnd(); + vm.stopSnapshotGas(); } function testTick_tickSpacingToMaxLiquidityPerTick_gasCost60TickSpacing() public { - snapStart("tickSpacingToMaxLiquidityPerTick_gasCost60TickSpacing"); + vm.startSnapshotGas("tickSpacingToMaxLiquidityPerTick_gasCost60TickSpacing"); tickSpacingToMaxLiquidityPerTick(60); - snapEnd(); + vm.stopSnapshotGas(); } function testTick_tickSpacingToMaxLiquidityPerTick_gasCostMaxTickSpacing() public { - snapStart("tickSpacingToMaxLiquidityPerTick_gasCostMaxTickSpacing"); + vm.startSnapshotGas("tickSpacingToMaxLiquidityPerTick_gasCostMaxTickSpacing"); tickSpacingToMaxLiquidityPerTick(TickMath.MAX_TICK_SPACING); - snapEnd(); + vm.stopSnapshotGas(); } function testTick_getFeeGrowthInside_returnsAllForTwoUninitializedTicksIfTickIsInside() public { diff --git a/test/libraries/BitMath.t.sol b/test/libraries/BitMath.t.sol index dcc0295a0..aedb50aa2 100644 --- a/test/libraries/BitMath.t.sol +++ b/test/libraries/BitMath.t.sol @@ -1,11 +1,10 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.20; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {Test} from "forge-std/Test.sol"; import {BitMath} from "../../src/libraries/BitMath.sol"; -contract TestBitMath is Test, GasSnapshot { +contract TestBitMath is Test { function test_mostSignificantBit_revertsWhenZero() public { vm.expectRevert(); BitMath.mostSignificantBit(0); @@ -43,17 +42,17 @@ contract TestBitMath is Test, GasSnapshot { } function test_mostSignificantBit_gas() public { - snapStart("BitMathMostSignificantBitSmallNumber"); + vm.startSnapshotGas("BitMathMostSignificantBitSmallNumber"); BitMath.mostSignificantBit(3568); - snapEnd(); + vm.stopSnapshotGas(); - snapStart("BitMathMostSignificantBitMaxUint128"); + vm.startSnapshotGas("BitMathMostSignificantBitMaxUint128"); BitMath.mostSignificantBit(type(uint128).max); - snapEnd(); + vm.stopSnapshotGas(); - snapStart("BitMathMostSignificantBitMaxUint256"); + vm.startSnapshotGas("BitMathMostSignificantBitMaxUint256"); BitMath.mostSignificantBit(type(uint256).max); - snapEnd(); + vm.stopSnapshotGas(); } function test_leastSignificantBit_revertsWhenZero() public { @@ -93,17 +92,17 @@ contract TestBitMath is Test, GasSnapshot { } function test_leastSignificantBit_gas() public { - snapStart("BitMathLeastSignificantBitSmallNumber"); + vm.startSnapshotGas("BitMathLeastSignificantBitSmallNumber"); BitMath.leastSignificantBit(3568); - snapEnd(); + vm.stopSnapshotGas(); - snapStart("BitMathLeastSignificantBitMaxUint128"); + vm.startSnapshotGas("BitMathLeastSignificantBitMaxUint128"); BitMath.leastSignificantBit(type(uint128).max); - snapEnd(); + vm.stopSnapshotGas(); - snapStart("BitMathLeastSignificantBitMaxUint256"); + vm.startSnapshotGas("BitMathLeastSignificantBitMaxUint256"); BitMath.leastSignificantBit(type(uint256).max); - snapEnd(); + vm.stopSnapshotGas(); } function mostSignificantBitReference(uint256 x) private pure returns (uint256) { diff --git a/test/libraries/Hooks.t.sol b/test/libraries/Hooks.t.sol index eacc1ea6c..6d7da20a1 100644 --- a/test/libraries/Hooks.t.sol +++ b/test/libraries/Hooks.t.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.20; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {Test} from "forge-std/Test.sol"; import {Vm} from "forge-std/Vm.sol"; import {Hooks} from "../../src/libraries/Hooks.sol"; @@ -24,8 +23,9 @@ import {BaseTestHooks} from "../../src/test/BaseTestHooks.sol"; import {EmptyRevertContract} from "../../src/test/EmptyRevertContract.sol"; import {StateLibrary} from "../../src/libraries/StateLibrary.sol"; import {Constants} from "../utils/Constants.sol"; +import {CustomRevert} from "../../src/libraries/CustomRevert.sol"; -contract HooksTest is Test, Deployers, GasSnapshot { +contract HooksTest is Test, Deployers { using Hooks for IHooks; using StateLibrary for IPoolManager; @@ -1011,9 +1011,11 @@ contract HooksTest is Test, Deployers, GasSnapshot { vm.expectRevert( abi.encodeWithSelector( - Hooks.Wrap__FailedHookCall.selector, + CustomRevert.WrappedError.selector, address(revertingHook), - abi.encodeWithSelector(BaseTestHooks.HookNotImplemented.selector) + IHooks.beforeSwap.selector, + abi.encodeWithSelector(BaseTestHooks.HookNotImplemented.selector), + abi.encodeWithSelector(Hooks.HookCallFailed.selector) ) ); swapRouter.swap(key, swapParams, testSettings, new bytes(0)); @@ -1036,7 +1038,13 @@ contract HooksTest is Test, Deployers, GasSnapshot { PoolSwapTest.TestSettings({takeClaims: false, settleUsingBurn: false}); vm.expectRevert( - abi.encodeWithSelector(Hooks.Wrap__FailedHookCall.selector, address(revertingHook), new bytes(0)) + abi.encodeWithSelector( + CustomRevert.WrappedError.selector, + address(beforeSwapFlag), + IHooks.beforeSwap.selector, + "", + abi.encodeWithSelector(Hooks.HookCallFailed.selector) + ) ); swapRouter.swap(key, swapParams, testSettings, new bytes(0)); } diff --git a/test/libraries/Pool.t.sol b/test/libraries/Pool.t.sol index 0ffa73f09..e93e9f1df 100644 --- a/test/libraries/Pool.t.sol +++ b/test/libraries/Pool.t.sol @@ -15,9 +15,8 @@ import {Slot0} from "../../src/types/Slot0.sol"; import {SafeCast} from "../../src/libraries/SafeCast.sol"; import {ProtocolFeeLibrary} from "../../src/libraries/ProtocolFeeLibrary.sol"; import {LPFeeLibrary} from "../../src/libraries/LPFeeLibrary.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; -contract PoolTest is Test, GasSnapshot { +contract PoolTest is Test { using Pool for Pool.State; using LPFeeLibrary for uint24; using ProtocolFeeLibrary for *; @@ -120,9 +119,12 @@ contract PoolTest is Test, GasSnapshot { assertEq(slot0.protocolFee(), 0); slot0 = slot0.setProtocolFee(protocolFee); assertEq(slot0.protocolFee(), protocolFee); + state.slot0 = slot0; + + uint16 expectedProtocolFee = params.zeroForOne ? protocolFee0 : protocolFee1; uint24 _lpFee = params.lpFeeOverride.isOverride() ? params.lpFeeOverride.removeOverrideFlag() : lpFee; - uint24 swapFee = protocolFee == 0 ? _lpFee : uint16(protocolFee).calculateSwapFee(_lpFee); + uint24 swapFee = expectedProtocolFee == 0 ? _lpFee : expectedProtocolFee.calculateSwapFee(_lpFee); if (params.amountSpecified >= 0 && swapFee == MAX_LP_FEE) { vm.expectRevert(Pool.InvalidFeeForExactOut.selector); diff --git a/test/libraries/ProtocolFeeLibrary.t.sol b/test/libraries/ProtocolFeeLibrary.t.sol index ba341a4d6..7e04681d1 100644 --- a/test/libraries/ProtocolFeeLibrary.t.sol +++ b/test/libraries/ProtocolFeeLibrary.t.sol @@ -2,11 +2,10 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {LPFeeLibrary} from "../../src/libraries/LPFeeLibrary.sol"; import {ProtocolFeeLibrary} from "../../src/libraries/ProtocolFeeLibrary.sol"; -contract ProtocolFeeLibraryTest is Test, GasSnapshot { +contract ProtocolFeeLibraryTest is Test { function test_getZeroForOneFee() public pure { uint24 fee = uint24(ProtocolFeeLibrary.MAX_PROTOCOL_FEE - 1) << 12 | ProtocolFeeLibrary.MAX_PROTOCOL_FEE; assertEq(ProtocolFeeLibrary.getZeroForOneFee(fee), uint24(ProtocolFeeLibrary.MAX_PROTOCOL_FEE)); @@ -71,18 +70,18 @@ contract ProtocolFeeLibraryTest is Test, GasSnapshot { protocolFee = uint16(bound(protocolFee, 0, ProtocolFeeLibrary.MAX_PROTOCOL_FEE)); lpFee = uint24(bound(lpFee, 0, LPFeeLibrary.MAX_LP_FEE)); uint24 swapFee = ProtocolFeeLibrary.calculateSwapFee(protocolFee, lpFee); - // if lp fee is not the max, the swap fee should never be the max since the protocol fee is taken off first and then the lp fee is taken from the remaining amount if (lpFee < LPFeeLibrary.MAX_LP_FEE) { - assertLt(swapFee, LPFeeLibrary.MAX_LP_FEE); + assertLe(swapFee, LPFeeLibrary.MAX_LP_FEE); } else { - // otherwise it is equal to max, and can therefore never be larger + // if lp fee is equal to max, swap fee can never be larger assertEq(swapFee, LPFeeLibrary.MAX_LP_FEE); } - assertGe(swapFee, lpFee); + // protocolFee + lpFee(1_000_000 - protocolFee) / 1_000_000 (rounded up) + uint256 expectedSwapFee = protocolFee + (1e6 - protocolFee) * uint256(lpFee) / 1e6; + if (((1e6 - protocolFee) * uint256(lpFee)) % 1e6 != 0) expectedSwapFee++; - uint256 expectedSwapFee = - protocolFee + lpFee * uint256(LPFeeLibrary.MAX_LP_FEE - protocolFee) / LPFeeLibrary.MAX_LP_FEE; + assertGe(swapFee, lpFee); assertEq(swapFee, uint24(expectedSwapFee)); } } diff --git a/test/libraries/SqrtPriceMath.t.sol b/test/libraries/SqrtPriceMath.t.sol index 396132616..b916e345a 100644 --- a/test/libraries/SqrtPriceMath.t.sol +++ b/test/libraries/SqrtPriceMath.t.sol @@ -3,11 +3,10 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; import {Vm} from "forge-std/Vm.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {SqrtPriceMath} from "../../src/libraries/SqrtPriceMath.sol"; import {Constants} from "../../test/utils/Constants.sol"; -contract SqrtPriceMathTest is Test, GasSnapshot { +contract SqrtPriceMathTest is Test { function test_getNextSqrtPriceFromInput_revertsIfPriceIsZero() public { vm.expectRevert(SqrtPriceMath.InvalidPriceOrLiquidity.selector); SqrtPriceMath.getNextSqrtPriceFromInput(0, 1, 0.1 ether, false); @@ -97,17 +96,17 @@ contract SqrtPriceMathTest is Test, GasSnapshot { function test_getNextSqrtPriceFromInput_zeroForOneEqualsTrueGas() public { uint160 sqrtP = Constants.SQRT_PRICE_1_1; - snapStart("getNextSqrtPriceFromInput_zeroForOneEqualsTrueGas"); + vm.startSnapshotGas("getNextSqrtPriceFromInput_zeroForOneEqualsTrueGas"); SqrtPriceMath.getNextSqrtPriceFromInput(sqrtP, uint128(1 ether), 0.1 ether, true); - snapEnd(); + vm.stopSnapshotGas(); } function test_getNextSqrtPriceFromInput_zeroForOneEqualsFalseGas() public { uint160 sqrtP = Constants.SQRT_PRICE_1_1; - snapStart("getNextSqrtPriceFromInput_zeroForOneEqualsFalseGas"); + vm.startSnapshotGas("getNextSqrtPriceFromInput_zeroForOneEqualsFalseGas"); SqrtPriceMath.getNextSqrtPriceFromInput(sqrtP, uint128(1 ether), 0.1 ether, false); - snapEnd(); + vm.stopSnapshotGas(); } function test_getNextSqrtPriceFromOutput_revertsIfPriceIsZero() public { @@ -227,17 +226,17 @@ contract SqrtPriceMathTest is Test, GasSnapshot { function test_getNextSqrtPriceFromOutput_zeroForOneEqualsTrueGas() public { uint160 sqrtP = Constants.SQRT_PRICE_1_1; - snapStart("getNextSqrtPriceFromOutput_zeroForOneEqualsTrueGas"); + vm.startSnapshotGas("getNextSqrtPriceFromOutput_zeroForOneEqualsTrueGas"); SqrtPriceMath.getNextSqrtPriceFromOutput(sqrtP, uint128(1 ether), 0.1 ether, true); - snapEnd(); + vm.stopSnapshotGas(); } function test_getNextSqrtPriceFromOutput_zeroForOneEqualsFalseGas() public { uint160 sqrtP = Constants.SQRT_PRICE_1_1; - snapStart("getNextSqrtPriceFromOutput_zeroForOneEqualsFalseGas"); + vm.startSnapshotGas("getNextSqrtPriceFromOutput_zeroForOneEqualsFalseGas"); SqrtPriceMath.getNextSqrtPriceFromOutput(sqrtP, uint128(1 ether), 0.1 ether, false); - snapEnd(); + vm.stopSnapshotGas(); } function test_getAmount0Delta_returns0IfLiquidityIs0() public pure { @@ -285,15 +284,15 @@ contract SqrtPriceMathTest is Test, GasSnapshot { } function test_getAmount0Delta_gasCostForAmount0WhereRoundUpIsTrue() public { - snapStart("getAmount0Delta_gasCostForAmount0WhereRoundUpIsTrue"); + vm.startSnapshotGas("getAmount0Delta_gasCostForAmount0WhereRoundUpIsTrue"); SqrtPriceMath.getAmount0Delta(Constants.SQRT_PRICE_121_100, Constants.SQRT_PRICE_1_1, uint128(1 ether), true); - snapEnd(); + vm.stopSnapshotGas(); } function test_getAmount0Delta_gasCostForAmount0WhereRoundUpIsFalse() public { - snapStart("getAmount0Delta_gasCostForAmount0WhereRoundUpIsFalse"); + vm.startSnapshotGas("getAmount0Delta_gasCostForAmount0WhereRoundUpIsFalse"); SqrtPriceMath.getAmount0Delta(Constants.SQRT_PRICE_121_100, Constants.SQRT_PRICE_1_1, uint128(1 ether), false); - snapEnd(); + vm.stopSnapshotGas(); } function test_getAmount1Delta_returns0IfLiquidityIs0() public pure { @@ -323,15 +322,15 @@ contract SqrtPriceMathTest is Test, GasSnapshot { } function test_getAmount1Delta_gasCostForAmount1WhereRoundUpIsTrue() public { - snapStart("getAmount1Delta_gasCostForAmount1WhereRoundUpIsTrue"); + vm.startSnapshotGas("getAmount1Delta_gasCostForAmount1WhereRoundUpIsTrue"); SqrtPriceMath.getAmount1Delta(Constants.SQRT_PRICE_121_100, Constants.SQRT_PRICE_1_1, uint128(1 ether), true); - snapEnd(); + vm.stopSnapshotGas(); } function test_getAmount1Delta_gasCostForAmount1WhereRoundUpIsFalse() public { - snapStart("getAmount1Delta_gasCostForAmount1WhereRoundUpIsFalse"); + vm.startSnapshotGas("getAmount1Delta_gasCostForAmount1WhereRoundUpIsFalse"); SqrtPriceMath.getAmount1Delta(Constants.SQRT_PRICE_121_100, Constants.SQRT_PRICE_1_1, uint128(1 ether), false); - snapEnd(); + vm.stopSnapshotGas(); } function test_swapComputation_sqrtPTimessqrtQOverflows() public pure { diff --git a/test/libraries/StateLibrary.t.sol b/test/libraries/StateLibrary.t.sol index 4f6294465..65de841a2 100644 --- a/test/libraries/StateLibrary.t.sol +++ b/test/libraries/StateLibrary.t.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.19; import "forge-std/Test.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {IHooks} from "../../src/interfaces/IHooks.sol"; import {Hooks} from "../../src/libraries/Hooks.sol"; import {TickMath} from "../../src/libraries/TickMath.sol"; @@ -20,7 +19,7 @@ import {FixedPoint128} from "../../src/libraries/FixedPoint128.sol"; import {StateLibrary} from "../../src/libraries/StateLibrary.sol"; import {Fuzzers} from "../../src/test/Fuzzers.sol"; -contract StateLibraryTest is Test, Deployers, Fuzzers, GasSnapshot { +contract StateLibraryTest is Test, Deployers, Fuzzers { using FixedPointMathLib for uint256; PoolId poolId; @@ -50,7 +49,7 @@ contract StateLibraryTest is Test, Deployers, Fuzzers, GasSnapshot { uint256 swapAmount = 100 ether; swap(key, true, -int256(swapAmount), ZERO_BYTES); (uint160 sqrtPriceX96, int24 tick, uint24 protocolFee, uint24 swapFee) = StateLibrary.getSlot0(manager, poolId); - snapLastCall("extsload getSlot0"); + vm.snapshotGasLastCall("extsload getSlot0"); assertEq(tick, -139); // magic number verified against a native getter @@ -64,7 +63,7 @@ contract StateLibraryTest is Test, Deployers, Fuzzers, GasSnapshot { modifyLiquidityRouter.modifyLiquidity(key, IPoolManager.ModifyLiquidityParams(-60, 60, 10 ether, 0), ZERO_BYTES); (uint128 liquidityGrossLower, int128 liquidityNetLower) = StateLibrary.getTickLiquidity(manager, poolId, -60); - snapLastCall("extsload getTickLiquidity"); + vm.snapshotGasLastCall("extsload getTickLiquidity"); assertEq(liquidityGrossLower, 10 ether); assertEq(liquidityNetLower, 10 ether); @@ -183,7 +182,7 @@ contract StateLibraryTest is Test, Deployers, Fuzzers, GasSnapshot { swap(key, true, -int256(swapAmount), ZERO_BYTES); (feeGrowthGlobal0, feeGrowthGlobal1) = StateLibrary.getFeeGrowthGlobals(manager, poolId); - snapLastCall("extsload getFeeGrowthGlobals"); + vm.snapshotGasLastCall("extsload getFeeGrowthGlobals"); uint256 feeGrowthGlobalCalc = swapAmount.mulWadDown(0.003e18).mulDivDown(FixedPoint128.Q128, liquidity); assertEq(feeGrowthGlobal0, feeGrowthGlobalCalc); @@ -219,7 +218,7 @@ contract StateLibraryTest is Test, Deployers, Fuzzers, GasSnapshot { ); uint128 liquidity = StateLibrary.getLiquidity(manager, poolId); - snapLastCall("extsload getLiquidity"); + vm.snapshotGasLastCall("extsload getLiquidity"); assertEq(liquidity, 20 ether); } @@ -247,7 +246,7 @@ contract StateLibraryTest is Test, Deployers, Fuzzers, GasSnapshot { (int16 wordPos, uint8 bitPos) = TickBitmap.position(tickLower / key.tickSpacing); uint256 tickBitmap = StateLibrary.getTickBitmap(manager, poolId, wordPos); - snapLastCall("extsload getTickBitmap"); + vm.snapshotGasLastCall("extsload getTickBitmap"); assertNotEq(tickBitmap, 0); assertEq(tickBitmap, 1 << bitPos); @@ -295,7 +294,7 @@ contract StateLibraryTest is Test, Deployers, Fuzzers, GasSnapshot { (uint128 liquidity, uint256 feeGrowthInside0X128, uint256 feeGrowthInside1X128) = StateLibrary.getPositionInfo(manager, poolId, positionId); - snapLastCall("extsload getPositionInfo"); + vm.snapshotGasLastCall("extsload getPositionInfo"); assertEq(liquidity, 10_000 ether); @@ -363,7 +362,7 @@ contract StateLibraryTest is Test, Deployers, Fuzzers, GasSnapshot { int24 tick = -60; (uint256 feeGrowthOutside0X128, uint256 feeGrowthOutside1X128) = StateLibrary.getTickFeeGrowthOutside(manager, poolId, tick); - snapLastCall("extsload getTickFeeGrowthOutside"); + vm.snapshotGasLastCall("extsload getTickFeeGrowthOutside"); // magic number verified against a native getter on PoolManager assertEq(feeGrowthOutside0X128, 3076214778951936192155253373200636); @@ -395,7 +394,7 @@ contract StateLibraryTest is Test, Deployers, Fuzzers, GasSnapshot { int24 tick = -60; (uint128 liquidityGross, int128 liquidityNet, uint256 feeGrowthOutside0X128, uint256 feeGrowthOutside1X128) = StateLibrary.getTickInfo(manager, poolId, tick); - snapLastCall("extsload getTickInfo"); + vm.snapshotGasLastCall("extsload getTickInfo"); (uint128 liquidityGross_, int128 liquidityNet_) = StateLibrary.getTickLiquidity(manager, poolId, tick); (uint256 feeGrowthOutside0X128_, uint256 feeGrowthOutside1X128_) = @@ -430,7 +429,7 @@ contract StateLibraryTest is Test, Deployers, Fuzzers, GasSnapshot { // calculated live (uint256 feeGrowthInside0X128, uint256 feeGrowthInside1X128) = StateLibrary.getFeeGrowthInside(manager, poolId, -60, 60); - snapLastCall("extsload getFeeGrowthInside"); + vm.snapshotGasLastCall("extsload getFeeGrowthInside"); // poke the LP so that fees are updated modifyLiquidityRouter.modifyLiquidity(key, IPoolManager.ModifyLiquidityParams(-60, 60, 0, 0), ZERO_BYTES); @@ -489,7 +488,7 @@ contract StateLibraryTest is Test, Deployers, Fuzzers, GasSnapshot { keccak256(abi.encodePacked(address(modifyLiquidityRouter), int24(-60), int24(60), bytes32(0))); uint128 liquidity = StateLibrary.getPositionLiquidity(manager, poolId, positionId); - snapLastCall("extsload getPositionLiquidity"); + vm.snapshotGasLastCall("extsload getPositionLiquidity"); assertEq(liquidity, 10_000 ether); } diff --git a/test/libraries/SwapMath.t.sol b/test/libraries/SwapMath.t.sol index 8335725b8..4f70ef0a0 100644 --- a/test/libraries/SwapMath.t.sol +++ b/test/libraries/SwapMath.t.sol @@ -5,10 +5,9 @@ import {Test} from "forge-std/Test.sol"; import {Vm} from "forge-std/Vm.sol"; import {SqrtPriceMath} from "../../src/libraries/SqrtPriceMath.sol"; import {SwapMath} from "../../src/libraries/SwapMath.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {Constants} from "../utils/Constants.sol"; -contract SwapMathTest is Test, GasSnapshot { +contract SwapMathTest is Test { function test_fuzz_getSqrtPriceTarget(bool zeroForOne, uint160 sqrtPriceNextX96, uint160 sqrtPriceLimitX96) public pure @@ -241,50 +240,50 @@ contract SwapMathTest is Test, GasSnapshot { } function test_computeSwapStep_swapOneForZero_exactInCapped() public { - snapStart("SwapMath_oneForZero_exactInCapped"); + vm.startSnapshotGas("SwapMath_oneForZero_exactInCapped"); SwapMath.computeSwapStep(Constants.SQRT_PRICE_1_1, Constants.SQRT_PRICE_101_100, 2 ether, (1 ether) * -1, 600); - snapEnd(); + vm.stopSnapshotGas(); } function test_computeSwapStep_swapZeroForOne_exactInCapped() public { - snapStart("SwapMath_zeroForOne_exactInCapped"); + vm.startSnapshotGas("SwapMath_zeroForOne_exactInCapped"); SwapMath.computeSwapStep(Constants.SQRT_PRICE_1_1, Constants.SQRT_PRICE_99_100, 2 ether, (1 ether) * -1, 600); - snapEnd(); + vm.stopSnapshotGas(); } function test_computeSwapStep_swapOneForZero_exactOutCapped() public { - snapStart("SwapMath_oneForZero_exactOutCapped"); + vm.startSnapshotGas("SwapMath_oneForZero_exactOutCapped"); SwapMath.computeSwapStep(Constants.SQRT_PRICE_1_1, Constants.SQRT_PRICE_101_100, 2 ether, 1 ether, 600); - snapEnd(); + vm.stopSnapshotGas(); } function test_computeSwapStep_swapZeroForOne_exactOutCapped() public { - snapStart("SwapMath_zeroForOne_exactOutCapped"); + vm.startSnapshotGas("SwapMath_zeroForOne_exactOutCapped"); SwapMath.computeSwapStep(Constants.SQRT_PRICE_1_1, Constants.SQRT_PRICE_99_100, 2 ether, 1 ether, 600); - snapEnd(); + vm.stopSnapshotGas(); } function test_computeSwapStep_swapOneForZero_exactInPartial() public { - snapStart("SwapMath_oneForZero_exactInPartial"); + vm.startSnapshotGas("SwapMath_oneForZero_exactInPartial"); SwapMath.computeSwapStep(Constants.SQRT_PRICE_1_1, Constants.SQRT_PRICE_1010_100, 2 ether, 1_000 * -1, 600); - snapEnd(); + vm.stopSnapshotGas(); } function test_computeSwapStep_swapZeroForOne_exactInPartial() public { - snapStart("SwapMath_zeroForOne_exactInPartial"); + vm.startSnapshotGas("SwapMath_zeroForOne_exactInPartial"); SwapMath.computeSwapStep(Constants.SQRT_PRICE_1_1, Constants.SQRT_PRICE_99_1000, 2 ether, 1_000 * -1, 600); - snapEnd(); + vm.stopSnapshotGas(); } function test_computeSwapStep_swapOneForZero_exactOutPartial() public { - snapStart("SwapMath_oneForZero_exactOutPartial"); + vm.startSnapshotGas("SwapMath_oneForZero_exactOutPartial"); SwapMath.computeSwapStep(Constants.SQRT_PRICE_1_1, Constants.SQRT_PRICE_1010_100, 2 ether, 1_000, 600); - snapEnd(); + vm.stopSnapshotGas(); } function test_computeSwapStep_swapZeroForOne_exactOutPartial() public { - snapStart("SwapMath_zeroForOne_exactOutPartial"); + vm.startSnapshotGas("SwapMath_zeroForOne_exactOutPartial"); SwapMath.computeSwapStep(Constants.SQRT_PRICE_1_1, Constants.SQRT_PRICE_99_1000, 2 ether, 1_000, 600); - snapEnd(); + vm.stopSnapshotGas(); } } diff --git a/test/libraries/TickBitmap.t.sol b/test/libraries/TickBitmap.t.sol index 570addf81..a79f13d44 100644 --- a/test/libraries/TickBitmap.t.sol +++ b/test/libraries/TickBitmap.t.sol @@ -3,11 +3,10 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; import {Vm} from "forge-std/Vm.sol"; -import {GasSnapshot} from "lib/forge-gas-snapshot/src/GasSnapshot.sol"; import {TickBitmap} from "../../src/libraries/TickBitmap.sol"; import {TickMath} from "../../src/libraries/TickMath.sol"; -contract TickBitmapTest is Test, GasSnapshot { +contract TickBitmapTest is Test { using TickBitmap for mapping(int16 => uint256); int24 constant INITIALIZED_TICK = 70; @@ -95,21 +94,21 @@ contract TickBitmapTest is Test, GasSnapshot { } function test_flipTick_flippingFirstTickInWordToInitialized_gas() public { - snapStart("flipTick_flippingFirstTickInWordToInitialized"); + vm.startSnapshotGas("flipTick_flippingFirstTickInWordToInitialized"); flipTick(TICK_IN_UNINITIALZIED_WORD); - snapEnd(); + vm.stopSnapshotGas(); } function test_flipTick_flippingSecondTickInWordToInitialized_gas() public { - snapStart("flipTick_flippingSecondTickInWordToInitialized"); + vm.startSnapshotGas("flipTick_flippingSecondTickInWordToInitialized"); flipTick(INITIALIZED_TICK + 1); - snapEnd(); + vm.stopSnapshotGas(); } function test_flipTick_flippingATickThatResultsInDeletingAWord_gas() public { - snapStart("flipTick_flippingATickThatResultsInDeletingAWord"); + vm.startSnapshotGas("flipTick_flippingATickThatResultsInDeletingAWord"); flipTick(SOLO_INITIALIZED_TICK_IN_WORD); - snapEnd(); + vm.stopSnapshotGas(); } function test_fuzz_flipTick(int24 tick, int24 tickSpacing) public { @@ -198,21 +197,21 @@ contract TickBitmapTest is Test, GasSnapshot { } function test_nextInitializedTickWithinOneWord_lteFalse_onBoundary_gas() public { - snapStart("nextInitializedTickWithinOneWord_lteFalse_onBoundary"); + vm.startSnapshotGas("nextInitializedTickWithinOneWord_lteFalse_onBoundary"); bitmap.nextInitializedTickWithinOneWord(255, 1, false); - snapEnd(); + vm.stopSnapshotGas(); } function test_nextInitializedTickWithinOneWord_lteFalse_justBelowBoundary_gas() public { - snapStart("nextInitializedTickWithinOneWord_lteFalse_justBelowBoundary"); + vm.startSnapshotGas("nextInitializedTickWithinOneWord_lteFalse_justBelowBoundary"); bitmap.nextInitializedTickWithinOneWord(254, 1, false); - snapEnd(); + vm.stopSnapshotGas(); } function test_nextInitializedTickWithinOneWord_lteFalse_forEntireWord_gas() public { - snapStart("nextInitializedTickWithinOneWord_lteFalse_forEntireWord"); + vm.startSnapshotGas("nextInitializedTickWithinOneWord_lteFalse_forEntireWord"); bitmap.nextInitializedTickWithinOneWord(768, 1, false); - snapEnd(); + vm.stopSnapshotGas(); } function test_nextInitializedTickWithinOneWord_lteTrue_returnsSameTickIfInitialized() public view { @@ -277,21 +276,21 @@ contract TickBitmapTest is Test, GasSnapshot { } function test_nextInitializedTickWithinOneWord_lteTrue_onBoundary_gas() public { - snapStart("nextInitializedTickWithinOneWord_lteTrue_onBoundary_gas"); + vm.startSnapshotGas("nextInitializedTickWithinOneWord_lteTrue_onBoundary_gas"); bitmap.nextInitializedTickWithinOneWord(256, 1, true); - snapEnd(); + vm.stopSnapshotGas(); } function test_nextInitializedTickWithinOneWord_lteTrue_justBelowBoundary_gas() public { - snapStart("nextInitializedTickWithinOneWord_lteTrue_justBelowBoundary"); + vm.startSnapshotGas("nextInitializedTickWithinOneWord_lteTrue_justBelowBoundary"); bitmap.nextInitializedTickWithinOneWord(255, 1, true); - snapEnd(); + vm.stopSnapshotGas(); } function test_nextInitializedTickWithinOneWord_lteTrue_forEntireWord_gas() public { - snapStart("nextInitializedTickWithinOneWord_lteTrue_forEntireWord"); + vm.startSnapshotGas("nextInitializedTickWithinOneWord_lteTrue_forEntireWord"); bitmap.nextInitializedTickWithinOneWord(1024, 1, true); - snapEnd(); + vm.stopSnapshotGas(); } function test_fuzz_nextInitializedTickWithinOneWord(int24 tick, bool lte) public view { diff --git a/test/libraries/TickMath.t.sol b/test/libraries/TickMath.t.sol index 98f9c1481..5ad9212dd 100644 --- a/test/libraries/TickMath.t.sol +++ b/test/libraries/TickMath.t.sol @@ -1,14 +1,13 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.20; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {Test} from "forge-std/Test.sol"; import {Vm} from "forge-std/Vm.sol"; import {TickMathTest} from "src/test/TickMathTest.sol"; import {TickMath} from "src/libraries/TickMath.sol"; import {JavascriptFfi} from "test/utils/JavascriptFfi.sol"; -contract TickMathTestTest is Test, JavascriptFfi, GasSnapshot { +contract TickMathTestTest is Test, JavascriptFfi { int24 constant MIN_TICK = TickMath.MIN_TICK; int24 constant MAX_TICK = TickMath.MAX_TICK; @@ -225,24 +224,24 @@ contract TickMathTestTest is Test, JavascriptFfi, GasSnapshot { /// @notice Benchmark the gas cost of `getSqrtPriceAtTick` function test_getSqrtPriceAtTick_gasCost() public { - snapStart("TickMathGetSqrtPriceAtTick"); + vm.startSnapshotGas("TickMathGetSqrtPriceAtTick"); unchecked { for (int24 tick = -50; tick < 50;) { TickMath.getSqrtPriceAtTick(tick++); } } - snapEnd(); + vm.stopSnapshotGas(); } /// @notice Benchmark the gas cost of `getTickAtSqrtPrice` function test_getTickAtSqrtPrice_gasCost() public { - snapStart("TickMathGetTickAtSqrtPrice"); + vm.startSnapshotGas("TickMathGetTickAtSqrtPrice"); unchecked { uint160 sqrtPriceX96 = 1 << 33; for (uint256 i; i++ < 100; sqrtPriceX96 <<= 1) { TickMath.getTickAtSqrtPrice(sqrtPriceX96); } } - snapEnd(); + vm.stopSnapshotGas(); } } diff --git a/test/types/Currency.t.sol b/test/types/Currency.t.sol index 1ca8e02d2..88f897e1e 100644 --- a/test/types/Currency.t.sol +++ b/test/types/Currency.t.sol @@ -3,10 +3,11 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; import {stdError} from "forge-std/StdError.sol"; -import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; +import {MockERC20, ERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; import {Currency, CurrencyLibrary} from "../../src/types/Currency.sol"; import {CurrencyTest} from "../../src/test/CurrencyTest.sol"; import {EmptyRevertContract} from "../../src/test/EmptyRevertContract.sol"; +import {CustomRevert} from "../../src/libraries/CustomRevert.sol"; contract TestCurrency is Test { uint256 constant initialERC20Balance = 1000 ether; @@ -123,9 +124,11 @@ contract TestCurrency is Test { // the token reverts with no data, so our custom error will be emitted instead vm.expectRevert( abi.encodeWithSelector( - CurrencyLibrary.Wrap__ERC20TransferFailed.selector, - Currency.unwrap(Currency.wrap(address(emptyRevertingToken))), - new bytes(0) + CustomRevert.WrappedError.selector, + address(emptyRevertingToken), + ERC20.transfer.selector, + "", + abi.encodeWithSelector(CurrencyLibrary.ERC20TransferFailed.selector) ) ); currencyTest.transfer(Currency.wrap(address(emptyRevertingToken)), otherAddress, 100); @@ -141,7 +144,13 @@ contract TestCurrency is Test { assertEq(address(currencyTest).balance, contractBalanceBefore - amount); } else { vm.expectRevert( - abi.encodeWithSelector(CurrencyLibrary.Wrap__NativeTransferFailed.selector, otherAddress, new bytes(0)) + abi.encodeWithSelector( + CustomRevert.WrappedError.selector, + otherAddress, + bytes4(0), + new bytes(0), + abi.encodeWithSelector(CurrencyLibrary.NativeTransferFailed.selector) + ) ); currencyTest.transfer(nativeCurrency, otherAddress, amount); assertEq(otherAddress.balance, balanceBefore); @@ -161,9 +170,11 @@ contract TestCurrency is Test { // the token reverts with an overflow error message, so this is bubbled up vm.expectRevert( abi.encodeWithSelector( - CurrencyLibrary.Wrap__ERC20TransferFailed.selector, + CustomRevert.WrappedError.selector, Currency.unwrap(erc20Currency), - stdError.arithmeticError + ERC20.transfer.selector, + stdError.arithmeticError, + abi.encodeWithSelector(CurrencyLibrary.ERC20TransferFailed.selector) ) ); currencyTest.transfer(erc20Currency, otherAddress, amount); diff --git a/test/utils/Deployers.sol b/test/utils/Deployers.sol index f15b42461..88559148b 100644 --- a/test/utils/Deployers.sol +++ b/test/utils/Deployers.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.20; +import "forge-std/Test.sol"; import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; import {Hooks} from "../../src/libraries/Hooks.sol"; import {Currency, CurrencyLibrary} from "../../src/types/Currency.sol"; @@ -25,9 +26,8 @@ import {PoolClaimsTest} from "../../src/test/PoolClaimsTest.sol"; import {ActionsRouter} from "../../src/test/ActionsRouter.sol"; import {LiquidityAmounts} from "../../test/utils/LiquidityAmounts.sol"; import {StateLibrary} from "../../src/libraries/StateLibrary.sol"; -import {ProtocolFeeControllerTest} from "../../src/test/ProtocolFeeControllerTest.sol"; -contract Deployers { +contract Deployers is Test { using LPFeeLibrary for uint24; using StateLibrary for IPoolManager; @@ -63,7 +63,7 @@ contract Deployers { PoolClaimsTest claimsRouter; PoolNestedActionsTest nestedActionRouter; - ProtocolFeeControllerTest feeController; + address feeController; PoolKey key; PoolKey nativeKey; @@ -74,8 +74,17 @@ contract Deployers { uint160 hookPermissionCount = 14; uint160 clearAllHookPermissionsMask = ~uint160(0) << (hookPermissionCount); + modifier noIsolate() { + if (msg.sender != address(this)) { + (bool success,) = address(this).call(msg.data); + require(success); + } else { + _; + } + } + function deployFreshManager() internal virtual { - manager = new PoolManager(); + manager = new PoolManager(address(this)); } function deployFreshManagerAndRouters() internal { @@ -88,7 +97,7 @@ contract Deployers { takeRouter = new PoolTakeTest(manager); claimsRouter = new PoolClaimsTest(manager); nestedActionRouter = new PoolNestedActionsTest(manager); - feeController = new ProtocolFeeControllerTest(); + feeController = makeAddr("feeController"); actionsRouter = new ActionsRouter(manager); manager.setProtocolFeeController(feeController); diff --git a/test/utils/NestedActions.t.sol b/test/utils/NestedActions.t.sol index 90c3bdbb0..033526097 100644 --- a/test/utils/NestedActions.t.sol +++ b/test/utils/NestedActions.t.sol @@ -3,11 +3,10 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; import {Deployers} from "test/utils/Deployers.sol"; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {Action} from "src/test/PoolNestedActionsTest.sol"; import {IHooks} from "src/interfaces/IHooks.sol"; -contract NestedActions is Test, Deployers, GasSnapshot { +contract NestedActions is Test, Deployers { Action[] actions; function setUp() public { diff --git a/test/utils/SwapHelper.t.sol b/test/utils/SwapHelper.t.sol index 67f5557dd..a6dd00533 100644 --- a/test/utils/SwapHelper.t.sol +++ b/test/utils/SwapHelper.t.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.20; -import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {Test} from "forge-std/Test.sol"; import {Vm} from "forge-std/Vm.sol"; import {Hooks} from "../../src/libraries/Hooks.sol"; @@ -22,7 +21,7 @@ import {BalanceDelta} from "../../src/types/BalanceDelta.sol"; import {Constants} from "../utils/Constants.sol"; /// @notice Testing Deployers.swap() and Deployers.swapNativeInput() -contract SwapHelperTest is Test, Deployers, GasSnapshot { +contract SwapHelperTest is Test, Deployers { using Hooks for IHooks; MockHooks mockHooks;