From ea853f27f96ed44dd39d1edd3386f1cdd73494bf Mon Sep 17 00:00:00 2001 From: chefburger Date: Wed, 15 May 2024 16:49:54 +0800 Subject: [PATCH] feat: enable hooks to return deltas to influence pool behavior --- .../BinHookTest#testBurnSucceedsWithHook.snap | 1 - ...inHookTest#testDonateSucceedsWithHook.snap | 1 - ...okTest#testInitializeSucceedsWithHook.snap | 1 - .../BinHookTest#testMintSucceedsWithHook.snap | 1 - .../BinHookTest#testSwapSucceedsWithHook.snap | 1 - ...oolManagerTest#testBurnNativeCurrency.snap | 1 - ...olManagerTest#testExtLoadPoolActiveId.snap | 1 - ...anagerTest#testFuzzUpdateDynamicLPFee.snap | 1 - ...oolManagerTest#testFuzz_SetMaxBinStep.snap | 1 - ...BinPoolManagerTest#testGasBurnHalfBin.snap | 1 - ...inPoolManagerTest#testGasBurnNineBins.snap | 1 - .../BinPoolManagerTest#testGasBurnOneBin.snap | 1 - .../BinPoolManagerTest#testGasDonate.snap | 1 - ...nPoolManagerTest#testGasMintNneBins-1.snap | 1 - ...nPoolManagerTest#testGasMintNneBins-2.snap | 1 - ...inPoolManagerTest#testGasMintOneBin-1.snap | 1 - ...inPoolManagerTest#testGasMintOneBin-2.snap | 1 - ...olManagerTest#testGasSwapMultipleBins.snap | 1 - ...nagerTest#testGasSwapOverBigBinIdGate.snap | 1 - ...nPoolManagerTest#testGasSwapSingleBin.snap | 1 - ...oolManagerTest#testMintNativeCurrency.snap | 1 - .../BinPoolManagerTest#testNoOpGas_Burn.snap | 1 - ...BinPoolManagerTest#testNoOpGas_Donate.snap | 1 - ...oolManagerTest#testNoOpGas_Initialize.snap | 1 - .../BinPoolManagerTest#testNoOpGas_Mint.snap | 1 - .../BinPoolManagerTest#testNoOpGas_Swap.snap | 1 - ...BinPoolManagerTest#testSetProtocolFee.snap | 1 - ...athTest#leastSignificantBitMaxUint128.snap | 1 - ...athTest#leastSignificantBitMaxUint256.snap | 1 - ...thTest#leastSignificantBitSmallNumber.snap | 1 - ...MathTest#mostSignificantBitMaxUint128.snap | 1 - ...MathTest#mostSignificantBitMaxUint256.snap | 1 - ...athTest#mostSignificantBitSmallNumber.snap | 1 - ...oolManagerTest#addLiquidity_fromEmpty.snap | 1 - ...ManagerTest#addLiquidity_fromNonEmpty.snap | 1 - ...lManagerTest#addLiquidity_nativeToken.snap | 1 - .../CLPoolManagerTest#donateBothTokens.snap | 1 - .../CLPoolManagerTest#gasDonateOneToken.snap | 1 - ...oolManagerTest#initializeWithoutHooks.snap | 1 - ...anagerTest#removeLiquidity_toNonEmpty.snap | 1 - ...PoolManagerTest#swap_againstLiquidity.snap | 1 - ...gerTest#swap_leaveSurplusTokenInVault.snap | 1 - ...oolManagerTest#swap_runOutOfLiquidity.snap | 1 - .../CLPoolManagerTest#swap_simple.snap | 1 - ...nagerTest#swap_useSurplusTokenAsInput.snap | 1 - .../CLPoolManagerTest#swap_withHooks.snap | 1 - .../CLPoolManagerTest#swap_withNative.snap | 1 - ...anagerTest#testFuzzUpdateDynamicLPFee.snap | 1 - ...CLPoolManagerTest#testNoOp_gas_Donate.snap | 1 - ...olManagerTest#testNoOp_gas_Initialize.snap | 1 - ...nagerTest#testNoOp_gas_ModifyPosition.snap | 1 - .../CLPoolManagerTest#testNoOp_gas_Swap.snap | 1 - ...olParametersHelperTest#getTickSpacing.snap | 1 - .../CLPositionTest#Position_update_add.snap | 1 - ...CLPositionTest#Position_update_remove.snap | 1 - .forge-snapshots/ExtsloadTest#extsload.snap | 1 - .../ExtsloadTest#extsloadInBatch.snap | 1 - .../LiquidityMathTest#addDeltaNegtive.snap | 1 - .../LiquidityMathTest#addDeltaPositive.snap | 1 - ..._gasCostForAmount0WhereRoundUpIsFalse.snap | 1 - ...a_gasCostForAmount0WhereRoundUpIsTrue.snap | 1 - ..._gasCostForAmount1WhereRoundUpIsFalse.snap | 1 - ...a_gasCostForAmount1WhereRoundUpIsTrue.snap | 1 - ...tPriceFromInput_zeroForOneEqualsFalse.snap | 1 - ...rtPriceFromInput_zeroForOneEqualsTrue.snap | 1 - ...PriceFromOutput_zeroForOneEqualsFalse.snap | 1 - ...tPriceFromOutput_zeroForOneEqualsTrue.snap | 1 - ...pMathTest#SwapOneForZeroExactInCapped.snap | 1 - ...MathTest#SwapOneForZeroExactInPartial.snap | 1 - ...MathTest#SwapOneForZeroExactOutCapped.snap | 1 - ...athTest#SwapOneForZeroExactOutPartial.snap | 1 - ...pMathTest#SwapZeroForOneExactInCapped.snap | 1 - ...MathTest#SwapZeroForOneExactInPartial.snap | 1 - ...MathTest#SwapZeroForOneExactOutCapped.snap | 1 - ...athTest#SwapZeroForOneExactOutPartial.snap | 1 - .forge-snapshots/TickTest#checkTicks.snap | 1 - .../TickTest#getFeeGrowthInside.snap | 1 - ...Test#tickSpacingToMaxLiquidityPerTick.snap | 1 - .forge-snapshots/TickTest#update.snap | 1 - .forge-snapshots/VaultTest#Vault.snap | 1 - .forge-snapshots/VaultTest#collectFee.snap | 1 - ...VaultTest#lockSettledWhenAddLiquidity.snap | 1 - .../VaultTest#lockSettledWhenFlashloan.snap | 1 - ...VaultTest#lockSettledWhenMultiHopSwap.snap | 1 - .../VaultTest#lockSettledWhenSwap.snap | 1 - .../VaultTest#registerPoolManager.snap | 1 - .forge-snapshots/VaultTest#testLock_NoOp.snap | 1 - ...Test#testSettleAndMintRefund_WithMint.snap | 1 - ...t#testSettleAndMintRefund_WithoutMint.snap | 1 - ...ippingATickThatResultsInDeletingAWord.snap | 1 - ...fFlippingFirstTickInWordToInitialized.snap | 1 - ...FlippingSecondTickInWordToInitialized.snap | 1 - ...OneWord_lteFalse_gasCostForEntireWord.snap | 1 - ...ord_lteFalse_gasCostJustBelowBoundary.snap | 1 - ...hinOneWord_lteFalse_gasCostOnBoundary.snap | 1 - ...nOneWord_lteTrue_gasCostForEntireWord.snap | 1 - ...Word_lteTrue_gasCostJustBelowBoundary.snap | 1 - ...thinOneWord_lteTrue_gasCostOnBoundary.snap | 1 - src/libraries/Hooks.sol | 19 ++- src/pool-bin/BinPoolManager.sol | 90 ++++------ src/pool-bin/interfaces/IBinHooks.sol | 17 +- src/pool-bin/interfaces/IBinPoolManager.sol | 3 + src/pool-bin/libraries/BinHooks.sol | 157 ++++++++++++++++++ src/pool-bin/libraries/BinPool.sol | 6 +- src/pool-cl/CLPoolManager.sol | 95 +++-------- src/pool-cl/interfaces/ICLHooks.sol | 17 +- src/pool-cl/interfaces/ICLPoolManager.sol | 13 +- src/pool-cl/libraries/CLHooks.sol | 141 ++++++++++++++++ src/pool-cl/libraries/CLPool.sol | 16 +- src/types/BalanceDelta.sol | 9 +- test/libraries/Hooks/Hooks.t.sol | 17 -- test/pool-bin/BinPoolManager.t.sol | 71 -------- test/pool-bin/helpers/BaseBinTestHook.sol | 15 +- test/pool-bin/helpers/BinLiquidityHelper.sol | 9 - test/pool-bin/helpers/BinSwapHelper.sol | 9 - test/pool-cl/CLPoolManager.t.sol | 66 -------- test/pool-cl/helpers/BaseCLTestHook.sol | 15 +- test/pool-cl/helpers/CLPoolManagerRouter.sol | 24 --- test/pool-cl/libraries/CLPool.t.sol | 3 +- 119 files changed, 424 insertions(+), 486 deletions(-) delete mode 100644 .forge-snapshots/BinHookTest#testBurnSucceedsWithHook.snap delete mode 100644 .forge-snapshots/BinHookTest#testDonateSucceedsWithHook.snap delete mode 100644 .forge-snapshots/BinHookTest#testInitializeSucceedsWithHook.snap delete mode 100644 .forge-snapshots/BinHookTest#testMintSucceedsWithHook.snap delete mode 100644 .forge-snapshots/BinHookTest#testSwapSucceedsWithHook.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testExtLoadPoolActiveId.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testFuzzUpdateDynamicLPFee.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testFuzz_SetMaxBinStep.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testGasDonate.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testNoOpGas_Burn.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testNoOpGas_Donate.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testNoOpGas_Initialize.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testNoOpGas_Mint.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testNoOpGas_Swap.snap delete mode 100644 .forge-snapshots/BinPoolManagerTest#testSetProtocolFee.snap delete mode 100644 .forge-snapshots/BitMathTest#leastSignificantBitMaxUint128.snap delete mode 100644 .forge-snapshots/BitMathTest#leastSignificantBitMaxUint256.snap delete mode 100644 .forge-snapshots/BitMathTest#leastSignificantBitSmallNumber.snap delete mode 100644 .forge-snapshots/BitMathTest#mostSignificantBitMaxUint128.snap delete mode 100644 .forge-snapshots/BitMathTest#mostSignificantBitMaxUint256.snap delete mode 100644 .forge-snapshots/BitMathTest#mostSignificantBitSmallNumber.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#donateBothTokens.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#initializeWithoutHooks.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#swap_simple.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#swap_withHooks.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#swap_withNative.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#testFuzzUpdateDynamicLPFee.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#testNoOp_gas_Donate.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#testNoOp_gas_Initialize.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#testNoOp_gas_ModifyPosition.snap delete mode 100644 .forge-snapshots/CLPoolManagerTest#testNoOp_gas_Swap.snap delete mode 100644 .forge-snapshots/CLPoolParametersHelperTest#getTickSpacing.snap delete mode 100644 .forge-snapshots/CLPositionTest#Position_update_add.snap delete mode 100644 .forge-snapshots/CLPositionTest#Position_update_remove.snap delete mode 100644 .forge-snapshots/ExtsloadTest#extsload.snap delete mode 100644 .forge-snapshots/ExtsloadTest#extsloadInBatch.snap delete mode 100644 .forge-snapshots/LiquidityMathTest#addDeltaNegtive.snap delete mode 100644 .forge-snapshots/LiquidityMathTest#addDeltaPositive.snap delete mode 100644 .forge-snapshots/SqrtPriceMathTest#getAmount0Delta_gasCostForAmount0WhereRoundUpIsFalse.snap delete mode 100644 .forge-snapshots/SqrtPriceMathTest#getAmount0Delta_gasCostForAmount0WhereRoundUpIsTrue.snap delete mode 100644 .forge-snapshots/SqrtPriceMathTest#getAmount1Delta_gasCostForAmount1WhereRoundUpIsFalse.snap delete mode 100644 .forge-snapshots/SqrtPriceMathTest#getAmount1Delta_gasCostForAmount1WhereRoundUpIsTrue.snap delete mode 100644 .forge-snapshots/SqrtPriceMathTest#getNextSqrtPriceFromInput_zeroForOneEqualsFalse.snap delete mode 100644 .forge-snapshots/SqrtPriceMathTest#getNextSqrtPriceFromInput_zeroForOneEqualsTrue.snap delete mode 100644 .forge-snapshots/SqrtPriceMathTest#getNextSqrtPriceFromOutput_zeroForOneEqualsFalse.snap delete mode 100644 .forge-snapshots/SqrtPriceMathTest#getNextSqrtPriceFromOutput_zeroForOneEqualsTrue.snap delete mode 100644 .forge-snapshots/SwapMathTest#SwapOneForZeroExactInCapped.snap delete mode 100644 .forge-snapshots/SwapMathTest#SwapOneForZeroExactInPartial.snap delete mode 100644 .forge-snapshots/SwapMathTest#SwapOneForZeroExactOutCapped.snap delete mode 100644 .forge-snapshots/SwapMathTest#SwapOneForZeroExactOutPartial.snap delete mode 100644 .forge-snapshots/SwapMathTest#SwapZeroForOneExactInCapped.snap delete mode 100644 .forge-snapshots/SwapMathTest#SwapZeroForOneExactInPartial.snap delete mode 100644 .forge-snapshots/SwapMathTest#SwapZeroForOneExactOutCapped.snap delete mode 100644 .forge-snapshots/SwapMathTest#SwapZeroForOneExactOutPartial.snap delete mode 100644 .forge-snapshots/TickTest#checkTicks.snap delete mode 100644 .forge-snapshots/TickTest#getFeeGrowthInside.snap delete mode 100644 .forge-snapshots/TickTest#tickSpacingToMaxLiquidityPerTick.snap delete mode 100644 .forge-snapshots/TickTest#update.snap delete mode 100644 .forge-snapshots/VaultTest#Vault.snap delete mode 100644 .forge-snapshots/VaultTest#collectFee.snap delete mode 100644 .forge-snapshots/VaultTest#lockSettledWhenAddLiquidity.snap delete mode 100644 .forge-snapshots/VaultTest#lockSettledWhenFlashloan.snap delete mode 100644 .forge-snapshots/VaultTest#lockSettledWhenMultiHopSwap.snap delete mode 100644 .forge-snapshots/VaultTest#lockSettledWhenSwap.snap delete mode 100644 .forge-snapshots/VaultTest#registerPoolManager.snap delete mode 100644 .forge-snapshots/VaultTest#testLock_NoOp.snap delete mode 100644 .forge-snapshots/VaultTest#testSettleAndMintRefund_WithMint.snap delete mode 100644 .forge-snapshots/VaultTest#testSettleAndMintRefund_WithoutMint.snap delete mode 100644 .forge-snapshots/flipTick_gasCostOfFlippingATickThatResultsInDeletingAWord.snap delete mode 100644 .forge-snapshots/flipTick_gasCostOfFlippingFirstTickInWordToInitialized.snap delete mode 100644 .forge-snapshots/flipTick_gasCostOfFlippingSecondTickInWordToInitialized.snap delete mode 100644 .forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_gasCostForEntireWord.snap delete mode 100644 .forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_gasCostJustBelowBoundary.snap delete mode 100644 .forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_gasCostOnBoundary.snap delete mode 100644 .forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_gasCostForEntireWord.snap delete mode 100644 .forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_gasCostJustBelowBoundary.snap delete mode 100644 .forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_gasCostOnBoundary.snap create mode 100644 src/pool-bin/libraries/BinHooks.sol create mode 100644 src/pool-cl/libraries/CLHooks.sol diff --git a/.forge-snapshots/BinHookTest#testBurnSucceedsWithHook.snap b/.forge-snapshots/BinHookTest#testBurnSucceedsWithHook.snap deleted file mode 100644 index 5ef512ea..00000000 --- a/.forge-snapshots/BinHookTest#testBurnSucceedsWithHook.snap +++ /dev/null @@ -1 +0,0 @@ -181124 \ No newline at end of file diff --git a/.forge-snapshots/BinHookTest#testDonateSucceedsWithHook.snap b/.forge-snapshots/BinHookTest#testDonateSucceedsWithHook.snap deleted file mode 100644 index f9e66567..00000000 --- a/.forge-snapshots/BinHookTest#testDonateSucceedsWithHook.snap +++ /dev/null @@ -1 +0,0 @@ -185453 \ No newline at end of file diff --git a/.forge-snapshots/BinHookTest#testInitializeSucceedsWithHook.snap b/.forge-snapshots/BinHookTest#testInitializeSucceedsWithHook.snap deleted file mode 100644 index bfcb7cad..00000000 --- a/.forge-snapshots/BinHookTest#testInitializeSucceedsWithHook.snap +++ /dev/null @@ -1 +0,0 @@ -137037 \ No newline at end of file diff --git a/.forge-snapshots/BinHookTest#testMintSucceedsWithHook.snap b/.forge-snapshots/BinHookTest#testMintSucceedsWithHook.snap deleted file mode 100644 index 22fed2fe..00000000 --- a/.forge-snapshots/BinHookTest#testMintSucceedsWithHook.snap +++ /dev/null @@ -1 +0,0 @@ -329719 \ No newline at end of file diff --git a/.forge-snapshots/BinHookTest#testSwapSucceedsWithHook.snap b/.forge-snapshots/BinHookTest#testSwapSucceedsWithHook.snap deleted file mode 100644 index fa139b82..00000000 --- a/.forge-snapshots/BinHookTest#testSwapSucceedsWithHook.snap +++ /dev/null @@ -1 +0,0 @@ -192675 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap b/.forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap deleted file mode 100644 index 24bc5c20..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap +++ /dev/null @@ -1 +0,0 @@ -142017 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testExtLoadPoolActiveId.snap b/.forge-snapshots/BinPoolManagerTest#testExtLoadPoolActiveId.snap deleted file mode 100644 index 49b43c45..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testExtLoadPoolActiveId.snap +++ /dev/null @@ -1 +0,0 @@ -1866 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testFuzzUpdateDynamicLPFee.snap b/.forge-snapshots/BinPoolManagerTest#testFuzzUpdateDynamicLPFee.snap deleted file mode 100644 index 3d7fbe59..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testFuzzUpdateDynamicLPFee.snap +++ /dev/null @@ -1 +0,0 @@ -32585 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testFuzz_SetMaxBinStep.snap b/.forge-snapshots/BinPoolManagerTest#testFuzz_SetMaxBinStep.snap deleted file mode 100644 index 13505f4e..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testFuzz_SetMaxBinStep.snap +++ /dev/null @@ -1 +0,0 @@ -30350 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap b/.forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap deleted file mode 100644 index 3a5c6070..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap +++ /dev/null @@ -1 +0,0 @@ -158185 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap b/.forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap deleted file mode 100644 index 767b7892..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap +++ /dev/null @@ -1 +0,0 @@ -303813 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap b/.forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap deleted file mode 100644 index df816042..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap +++ /dev/null @@ -1 +0,0 @@ -139378 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasDonate.snap b/.forge-snapshots/BinPoolManagerTest#testGasDonate.snap deleted file mode 100644 index 11a442d2..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testGasDonate.snap +++ /dev/null @@ -1 +0,0 @@ -125193 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap b/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap deleted file mode 100644 index 1030999b..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap +++ /dev/null @@ -1 +0,0 @@ -1014201 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap b/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap deleted file mode 100644 index 13aed349..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap +++ /dev/null @@ -1 +0,0 @@ -342215 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap b/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap deleted file mode 100644 index 5cfb45a7..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap +++ /dev/null @@ -1 +0,0 @@ -380533 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap b/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap deleted file mode 100644 index c53d4dde..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap +++ /dev/null @@ -1 +0,0 @@ -149294 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap b/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap deleted file mode 100644 index 9901ae99..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap +++ /dev/null @@ -1 +0,0 @@ -187651 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap b/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap deleted file mode 100644 index 8248c717..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap +++ /dev/null @@ -1 +0,0 @@ -193636 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap b/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap deleted file mode 100644 index 45aff27a..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap +++ /dev/null @@ -1 +0,0 @@ -146078 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap b/.forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap deleted file mode 100644 index 1bd2a1ee..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap +++ /dev/null @@ -1 +0,0 @@ -327426 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Burn.snap b/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Burn.snap deleted file mode 100644 index 0e7b8511..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Burn.snap +++ /dev/null @@ -1 +0,0 @@ -76619 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Donate.snap b/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Donate.snap deleted file mode 100644 index 03115631..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Donate.snap +++ /dev/null @@ -1 +0,0 @@ -54134 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Initialize.snap b/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Initialize.snap deleted file mode 100644 index 83c8f740..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Initialize.snap +++ /dev/null @@ -1 +0,0 @@ -64662 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Mint.snap b/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Mint.snap deleted file mode 100644 index e65039fd..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Mint.snap +++ /dev/null @@ -1 +0,0 @@ -69634 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Swap.snap b/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Swap.snap deleted file mode 100644 index acd8adaa..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testNoOpGas_Swap.snap +++ /dev/null @@ -1 +0,0 @@ -57563 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testSetProtocolFee.snap b/.forge-snapshots/BinPoolManagerTest#testSetProtocolFee.snap deleted file mode 100644 index 12ede85c..00000000 --- a/.forge-snapshots/BinPoolManagerTest#testSetProtocolFee.snap +++ /dev/null @@ -1 +0,0 @@ -34422 \ No newline at end of file diff --git a/.forge-snapshots/BitMathTest#leastSignificantBitMaxUint128.snap b/.forge-snapshots/BitMathTest#leastSignificantBitMaxUint128.snap deleted file mode 100644 index 9d3f4170..00000000 --- a/.forge-snapshots/BitMathTest#leastSignificantBitMaxUint128.snap +++ /dev/null @@ -1 +0,0 @@ -455 \ No newline at end of file diff --git a/.forge-snapshots/BitMathTest#leastSignificantBitMaxUint256.snap b/.forge-snapshots/BitMathTest#leastSignificantBitMaxUint256.snap deleted file mode 100644 index 2da43253..00000000 --- a/.forge-snapshots/BitMathTest#leastSignificantBitMaxUint256.snap +++ /dev/null @@ -1 +0,0 @@ -457 \ No newline at end of file diff --git a/.forge-snapshots/BitMathTest#leastSignificantBitSmallNumber.snap b/.forge-snapshots/BitMathTest#leastSignificantBitSmallNumber.snap deleted file mode 100644 index 13ef0a79..00000000 --- a/.forge-snapshots/BitMathTest#leastSignificantBitSmallNumber.snap +++ /dev/null @@ -1 +0,0 @@ -453 \ No newline at end of file diff --git a/.forge-snapshots/BitMathTest#mostSignificantBitMaxUint128.snap b/.forge-snapshots/BitMathTest#mostSignificantBitMaxUint128.snap deleted file mode 100644 index c0db21d8..00000000 --- a/.forge-snapshots/BitMathTest#mostSignificantBitMaxUint128.snap +++ /dev/null @@ -1 +0,0 @@ -392 \ No newline at end of file diff --git a/.forge-snapshots/BitMathTest#mostSignificantBitMaxUint256.snap b/.forge-snapshots/BitMathTest#mostSignificantBitMaxUint256.snap deleted file mode 100644 index 8d4011ad..00000000 --- a/.forge-snapshots/BitMathTest#mostSignificantBitMaxUint256.snap +++ /dev/null @@ -1 +0,0 @@ -412 \ No newline at end of file diff --git a/.forge-snapshots/BitMathTest#mostSignificantBitSmallNumber.snap b/.forge-snapshots/BitMathTest#mostSignificantBitSmallNumber.snap deleted file mode 100644 index 194ba8cc..00000000 --- a/.forge-snapshots/BitMathTest#mostSignificantBitSmallNumber.snap +++ /dev/null @@ -1 +0,0 @@ -320 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap b/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap deleted file mode 100644 index 6f174376..00000000 --- a/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap +++ /dev/null @@ -1 +0,0 @@ -401400 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap b/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap deleted file mode 100644 index 8500a53f..00000000 --- a/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap +++ /dev/null @@ -1 +0,0 @@ -182388 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap b/.forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap deleted file mode 100644 index e2ea1fdb..00000000 --- a/.forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap +++ /dev/null @@ -1 +0,0 @@ -247527 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#donateBothTokens.snap b/.forge-snapshots/CLPoolManagerTest#donateBothTokens.snap deleted file mode 100644 index 8d19448a..00000000 --- a/.forge-snapshots/CLPoolManagerTest#donateBothTokens.snap +++ /dev/null @@ -1 +0,0 @@ -175562 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap b/.forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap deleted file mode 100644 index 4a0b0e1b..00000000 --- a/.forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap +++ /dev/null @@ -1 +0,0 @@ -116944 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#initializeWithoutHooks.snap b/.forge-snapshots/CLPoolManagerTest#initializeWithoutHooks.snap deleted file mode 100644 index a047ff13..00000000 --- a/.forge-snapshots/CLPoolManagerTest#initializeWithoutHooks.snap +++ /dev/null @@ -1 +0,0 @@ -59393 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap b/.forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap deleted file mode 100644 index 231b27c4..00000000 --- a/.forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap +++ /dev/null @@ -1 +0,0 @@ -128973 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap b/.forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap deleted file mode 100644 index 9a2af0bc..00000000 --- a/.forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap +++ /dev/null @@ -1 +0,0 @@ -148772 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap b/.forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap deleted file mode 100644 index 9b016f69..00000000 --- a/.forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap +++ /dev/null @@ -1 +0,0 @@ -177222 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap b/.forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap deleted file mode 100644 index 43f2e4ad..00000000 --- a/.forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap +++ /dev/null @@ -1 +0,0 @@ -25086624 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_simple.snap b/.forge-snapshots/CLPoolManagerTest#swap_simple.snap deleted file mode 100644 index 061f91d4..00000000 --- a/.forge-snapshots/CLPoolManagerTest#swap_simple.snap +++ /dev/null @@ -1 +0,0 @@ -78867 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap b/.forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap deleted file mode 100644 index f71d0575..00000000 --- a/.forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap +++ /dev/null @@ -1 +0,0 @@ -158439 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_withHooks.snap b/.forge-snapshots/CLPoolManagerTest#swap_withHooks.snap deleted file mode 100644 index a19d1d77..00000000 --- a/.forge-snapshots/CLPoolManagerTest#swap_withHooks.snap +++ /dev/null @@ -1 +0,0 @@ -95374 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_withNative.snap b/.forge-snapshots/CLPoolManagerTest#swap_withNative.snap deleted file mode 100644 index bff11caf..00000000 --- a/.forge-snapshots/CLPoolManagerTest#swap_withNative.snap +++ /dev/null @@ -1 +0,0 @@ -78870 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#testFuzzUpdateDynamicLPFee.snap b/.forge-snapshots/CLPoolManagerTest#testFuzzUpdateDynamicLPFee.snap deleted file mode 100644 index 40100785..00000000 --- a/.forge-snapshots/CLPoolManagerTest#testFuzzUpdateDynamicLPFee.snap +++ /dev/null @@ -1 +0,0 @@ -32293 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Donate.snap b/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Donate.snap deleted file mode 100644 index 890d0b3f..00000000 --- a/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Donate.snap +++ /dev/null @@ -1 +0,0 @@ -53970 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Initialize.snap b/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Initialize.snap deleted file mode 100644 index 21de32ba..00000000 --- a/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Initialize.snap +++ /dev/null @@ -1 +0,0 @@ -65115 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_ModifyPosition.snap b/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_ModifyPosition.snap deleted file mode 100644 index 62af65f1..00000000 --- a/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_ModifyPosition.snap +++ /dev/null @@ -1 +0,0 @@ -60222 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Swap.snap b/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Swap.snap deleted file mode 100644 index f2a6d359..00000000 --- a/.forge-snapshots/CLPoolManagerTest#testNoOp_gas_Swap.snap +++ /dev/null @@ -1 +0,0 @@ -56919 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolParametersHelperTest#getTickSpacing.snap b/.forge-snapshots/CLPoolParametersHelperTest#getTickSpacing.snap deleted file mode 100644 index 6d58c4e5..00000000 --- a/.forge-snapshots/CLPoolParametersHelperTest#getTickSpacing.snap +++ /dev/null @@ -1 +0,0 @@ -109 \ No newline at end of file diff --git a/.forge-snapshots/CLPositionTest#Position_update_add.snap b/.forge-snapshots/CLPositionTest#Position_update_add.snap deleted file mode 100644 index 40efa8ca..00000000 --- a/.forge-snapshots/CLPositionTest#Position_update_add.snap +++ /dev/null @@ -1 +0,0 @@ -1427 \ No newline at end of file diff --git a/.forge-snapshots/CLPositionTest#Position_update_remove.snap b/.forge-snapshots/CLPositionTest#Position_update_remove.snap deleted file mode 100644 index 870e31e0..00000000 --- a/.forge-snapshots/CLPositionTest#Position_update_remove.snap +++ /dev/null @@ -1 +0,0 @@ -1697 \ No newline at end of file diff --git a/.forge-snapshots/ExtsloadTest#extsload.snap b/.forge-snapshots/ExtsloadTest#extsload.snap deleted file mode 100644 index 2531cd46..00000000 --- a/.forge-snapshots/ExtsloadTest#extsload.snap +++ /dev/null @@ -1 +0,0 @@ -7468 \ No newline at end of file diff --git a/.forge-snapshots/ExtsloadTest#extsloadInBatch.snap b/.forge-snapshots/ExtsloadTest#extsloadInBatch.snap deleted file mode 100644 index 8f979894..00000000 --- a/.forge-snapshots/ExtsloadTest#extsloadInBatch.snap +++ /dev/null @@ -1 +0,0 @@ -11374 \ No newline at end of file diff --git a/.forge-snapshots/LiquidityMathTest#addDeltaNegtive.snap b/.forge-snapshots/LiquidityMathTest#addDeltaNegtive.snap deleted file mode 100644 index d2c5ed21..00000000 --- a/.forge-snapshots/LiquidityMathTest#addDeltaNegtive.snap +++ /dev/null @@ -1 +0,0 @@ -116 \ No newline at end of file diff --git a/.forge-snapshots/LiquidityMathTest#addDeltaPositive.snap b/.forge-snapshots/LiquidityMathTest#addDeltaPositive.snap deleted file mode 100644 index 95c8a676..00000000 --- a/.forge-snapshots/LiquidityMathTest#addDeltaPositive.snap +++ /dev/null @@ -1 +0,0 @@ -113 \ No newline at end of file diff --git a/.forge-snapshots/SqrtPriceMathTest#getAmount0Delta_gasCostForAmount0WhereRoundUpIsFalse.snap b/.forge-snapshots/SqrtPriceMathTest#getAmount0Delta_gasCostForAmount0WhereRoundUpIsFalse.snap deleted file mode 100644 index 1dd3380c..00000000 --- a/.forge-snapshots/SqrtPriceMathTest#getAmount0Delta_gasCostForAmount0WhereRoundUpIsFalse.snap +++ /dev/null @@ -1 +0,0 @@ -516 \ No newline at end of file diff --git a/.forge-snapshots/SqrtPriceMathTest#getAmount0Delta_gasCostForAmount0WhereRoundUpIsTrue.snap b/.forge-snapshots/SqrtPriceMathTest#getAmount0Delta_gasCostForAmount0WhereRoundUpIsTrue.snap deleted file mode 100644 index b7f636c1..00000000 --- a/.forge-snapshots/SqrtPriceMathTest#getAmount0Delta_gasCostForAmount0WhereRoundUpIsTrue.snap +++ /dev/null @@ -1 +0,0 @@ -665 \ No newline at end of file diff --git a/.forge-snapshots/SqrtPriceMathTest#getAmount1Delta_gasCostForAmount1WhereRoundUpIsFalse.snap b/.forge-snapshots/SqrtPriceMathTest#getAmount1Delta_gasCostForAmount1WhereRoundUpIsFalse.snap deleted file mode 100644 index 1fc188de..00000000 --- a/.forge-snapshots/SqrtPriceMathTest#getAmount1Delta_gasCostForAmount1WhereRoundUpIsFalse.snap +++ /dev/null @@ -1 +0,0 @@ -525 \ No newline at end of file diff --git a/.forge-snapshots/SqrtPriceMathTest#getAmount1Delta_gasCostForAmount1WhereRoundUpIsTrue.snap b/.forge-snapshots/SqrtPriceMathTest#getAmount1Delta_gasCostForAmount1WhereRoundUpIsTrue.snap deleted file mode 100644 index 929530e8..00000000 --- a/.forge-snapshots/SqrtPriceMathTest#getAmount1Delta_gasCostForAmount1WhereRoundUpIsTrue.snap +++ /dev/null @@ -1 +0,0 @@ -653 \ No newline at end of file diff --git a/.forge-snapshots/SqrtPriceMathTest#getNextSqrtPriceFromInput_zeroForOneEqualsFalse.snap b/.forge-snapshots/SqrtPriceMathTest#getNextSqrtPriceFromInput_zeroForOneEqualsFalse.snap deleted file mode 100644 index 7dfce351..00000000 --- a/.forge-snapshots/SqrtPriceMathTest#getNextSqrtPriceFromInput_zeroForOneEqualsFalse.snap +++ /dev/null @@ -1 +0,0 @@ -594 \ No newline at end of file diff --git a/.forge-snapshots/SqrtPriceMathTest#getNextSqrtPriceFromInput_zeroForOneEqualsTrue.snap b/.forge-snapshots/SqrtPriceMathTest#getNextSqrtPriceFromInput_zeroForOneEqualsTrue.snap deleted file mode 100644 index 19e03cff..00000000 --- a/.forge-snapshots/SqrtPriceMathTest#getNextSqrtPriceFromInput_zeroForOneEqualsTrue.snap +++ /dev/null @@ -1 +0,0 @@ -776 \ No newline at end of file diff --git a/.forge-snapshots/SqrtPriceMathTest#getNextSqrtPriceFromOutput_zeroForOneEqualsFalse.snap b/.forge-snapshots/SqrtPriceMathTest#getNextSqrtPriceFromOutput_zeroForOneEqualsFalse.snap deleted file mode 100644 index f8f45074..00000000 --- a/.forge-snapshots/SqrtPriceMathTest#getNextSqrtPriceFromOutput_zeroForOneEqualsFalse.snap +++ /dev/null @@ -1 +0,0 @@ -878 \ No newline at end of file diff --git a/.forge-snapshots/SqrtPriceMathTest#getNextSqrtPriceFromOutput_zeroForOneEqualsTrue.snap b/.forge-snapshots/SqrtPriceMathTest#getNextSqrtPriceFromOutput_zeroForOneEqualsTrue.snap deleted file mode 100644 index 4c9bbbfa..00000000 --- a/.forge-snapshots/SqrtPriceMathTest#getNextSqrtPriceFromOutput_zeroForOneEqualsTrue.snap +++ /dev/null @@ -1 +0,0 @@ -468 \ No newline at end of file diff --git a/.forge-snapshots/SwapMathTest#SwapOneForZeroExactInCapped.snap b/.forge-snapshots/SwapMathTest#SwapOneForZeroExactInCapped.snap deleted file mode 100644 index 9eca385b..00000000 --- a/.forge-snapshots/SwapMathTest#SwapOneForZeroExactInCapped.snap +++ /dev/null @@ -1 +0,0 @@ -2237 \ No newline at end of file diff --git a/.forge-snapshots/SwapMathTest#SwapOneForZeroExactInPartial.snap b/.forge-snapshots/SwapMathTest#SwapOneForZeroExactInPartial.snap deleted file mode 100644 index 7c98c788..00000000 --- a/.forge-snapshots/SwapMathTest#SwapOneForZeroExactInPartial.snap +++ /dev/null @@ -1 +0,0 @@ -3022 \ No newline at end of file diff --git a/.forge-snapshots/SwapMathTest#SwapOneForZeroExactOutCapped.snap b/.forge-snapshots/SwapMathTest#SwapOneForZeroExactOutCapped.snap deleted file mode 100644 index d8f80992..00000000 --- a/.forge-snapshots/SwapMathTest#SwapOneForZeroExactOutCapped.snap +++ /dev/null @@ -1 +0,0 @@ -1994 \ No newline at end of file diff --git a/.forge-snapshots/SwapMathTest#SwapOneForZeroExactOutPartial.snap b/.forge-snapshots/SwapMathTest#SwapOneForZeroExactOutPartial.snap deleted file mode 100644 index 7c98c788..00000000 --- a/.forge-snapshots/SwapMathTest#SwapOneForZeroExactOutPartial.snap +++ /dev/null @@ -1 +0,0 @@ -3022 \ No newline at end of file diff --git a/.forge-snapshots/SwapMathTest#SwapZeroForOneExactInCapped.snap b/.forge-snapshots/SwapMathTest#SwapZeroForOneExactInCapped.snap deleted file mode 100644 index ee99c5c7..00000000 --- a/.forge-snapshots/SwapMathTest#SwapZeroForOneExactInCapped.snap +++ /dev/null @@ -1 +0,0 @@ -2227 \ No newline at end of file diff --git a/.forge-snapshots/SwapMathTest#SwapZeroForOneExactInPartial.snap b/.forge-snapshots/SwapMathTest#SwapZeroForOneExactInPartial.snap deleted file mode 100644 index e0f118c0..00000000 --- a/.forge-snapshots/SwapMathTest#SwapZeroForOneExactInPartial.snap +++ /dev/null @@ -1 +0,0 @@ -3175 \ No newline at end of file diff --git a/.forge-snapshots/SwapMathTest#SwapZeroForOneExactOutCapped.snap b/.forge-snapshots/SwapMathTest#SwapZeroForOneExactOutCapped.snap deleted file mode 100644 index a43f9e1b..00000000 --- a/.forge-snapshots/SwapMathTest#SwapZeroForOneExactOutCapped.snap +++ /dev/null @@ -1 +0,0 @@ -1984 \ No newline at end of file diff --git a/.forge-snapshots/SwapMathTest#SwapZeroForOneExactOutPartial.snap b/.forge-snapshots/SwapMathTest#SwapZeroForOneExactOutPartial.snap deleted file mode 100644 index e0f118c0..00000000 --- a/.forge-snapshots/SwapMathTest#SwapZeroForOneExactOutPartial.snap +++ /dev/null @@ -1 +0,0 @@ -3175 \ No newline at end of file diff --git a/.forge-snapshots/TickTest#checkTicks.snap b/.forge-snapshots/TickTest#checkTicks.snap deleted file mode 100644 index 0dbf139f..00000000 --- a/.forge-snapshots/TickTest#checkTicks.snap +++ /dev/null @@ -1 +0,0 @@ -350 \ No newline at end of file diff --git a/.forge-snapshots/TickTest#getFeeGrowthInside.snap b/.forge-snapshots/TickTest#getFeeGrowthInside.snap deleted file mode 100644 index 6b7fd1d0..00000000 --- a/.forge-snapshots/TickTest#getFeeGrowthInside.snap +++ /dev/null @@ -1 +0,0 @@ -51477 \ No newline at end of file diff --git a/.forge-snapshots/TickTest#tickSpacingToMaxLiquidityPerTick.snap b/.forge-snapshots/TickTest#tickSpacingToMaxLiquidityPerTick.snap deleted file mode 100644 index 04170a36..00000000 --- a/.forge-snapshots/TickTest#tickSpacingToMaxLiquidityPerTick.snap +++ /dev/null @@ -1 +0,0 @@ -1151 \ No newline at end of file diff --git a/.forge-snapshots/TickTest#update.snap b/.forge-snapshots/TickTest#update.snap deleted file mode 100644 index 7b7e6841..00000000 --- a/.forge-snapshots/TickTest#update.snap +++ /dev/null @@ -1 +0,0 @@ -134819 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#Vault.snap b/.forge-snapshots/VaultTest#Vault.snap deleted file mode 100644 index b70512a0..00000000 --- a/.forge-snapshots/VaultTest#Vault.snap +++ /dev/null @@ -1 +0,0 @@ -7437 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#collectFee.snap b/.forge-snapshots/VaultTest#collectFee.snap deleted file mode 100644 index 206f0c3a..00000000 --- a/.forge-snapshots/VaultTest#collectFee.snap +++ /dev/null @@ -1 +0,0 @@ -53360 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#lockSettledWhenAddLiquidity.snap b/.forge-snapshots/VaultTest#lockSettledWhenAddLiquidity.snap deleted file mode 100644 index af78ee04..00000000 --- a/.forge-snapshots/VaultTest#lockSettledWhenAddLiquidity.snap +++ /dev/null @@ -1 +0,0 @@ -159328 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#lockSettledWhenFlashloan.snap b/.forge-snapshots/VaultTest#lockSettledWhenFlashloan.snap deleted file mode 100644 index 4fdddea1..00000000 --- a/.forge-snapshots/VaultTest#lockSettledWhenFlashloan.snap +++ /dev/null @@ -1 +0,0 @@ -103575 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#lockSettledWhenMultiHopSwap.snap b/.forge-snapshots/VaultTest#lockSettledWhenMultiHopSwap.snap deleted file mode 100644 index 584d5812..00000000 --- a/.forge-snapshots/VaultTest#lockSettledWhenMultiHopSwap.snap +++ /dev/null @@ -1 +0,0 @@ -118251 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#lockSettledWhenSwap.snap b/.forge-snapshots/VaultTest#lockSettledWhenSwap.snap deleted file mode 100644 index edf15509..00000000 --- a/.forge-snapshots/VaultTest#lockSettledWhenSwap.snap +++ /dev/null @@ -1 +0,0 @@ -118250 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#registerPoolManager.snap b/.forge-snapshots/VaultTest#registerPoolManager.snap deleted file mode 100644 index d3457db4..00000000 --- a/.forge-snapshots/VaultTest#registerPoolManager.snap +++ /dev/null @@ -1 +0,0 @@ -47916 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#testLock_NoOp.snap b/.forge-snapshots/VaultTest#testLock_NoOp.snap deleted file mode 100644 index 924fa5c1..00000000 --- a/.forge-snapshots/VaultTest#testLock_NoOp.snap +++ /dev/null @@ -1 +0,0 @@ -32989 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#testSettleAndMintRefund_WithMint.snap b/.forge-snapshots/VaultTest#testSettleAndMintRefund_WithMint.snap deleted file mode 100644 index b18d08ba..00000000 --- a/.forge-snapshots/VaultTest#testSettleAndMintRefund_WithMint.snap +++ /dev/null @@ -1 +0,0 @@ -100035 \ No newline at end of file diff --git a/.forge-snapshots/VaultTest#testSettleAndMintRefund_WithoutMint.snap b/.forge-snapshots/VaultTest#testSettleAndMintRefund_WithoutMint.snap deleted file mode 100644 index 372de2e1..00000000 --- a/.forge-snapshots/VaultTest#testSettleAndMintRefund_WithoutMint.snap +++ /dev/null @@ -1 +0,0 @@ -55142 \ No newline at end of file diff --git a/.forge-snapshots/flipTick_gasCostOfFlippingATickThatResultsInDeletingAWord.snap b/.forge-snapshots/flipTick_gasCostOfFlippingATickThatResultsInDeletingAWord.snap deleted file mode 100644 index 3819e938..00000000 --- a/.forge-snapshots/flipTick_gasCostOfFlippingATickThatResultsInDeletingAWord.snap +++ /dev/null @@ -1 +0,0 @@ -5409 \ No newline at end of file diff --git a/.forge-snapshots/flipTick_gasCostOfFlippingFirstTickInWordToInitialized.snap b/.forge-snapshots/flipTick_gasCostOfFlippingFirstTickInWordToInitialized.snap deleted file mode 100644 index 0cd31fe2..00000000 --- a/.forge-snapshots/flipTick_gasCostOfFlippingFirstTickInWordToInitialized.snap +++ /dev/null @@ -1 +0,0 @@ -22506 \ No newline at end of file diff --git a/.forge-snapshots/flipTick_gasCostOfFlippingSecondTickInWordToInitialized.snap b/.forge-snapshots/flipTick_gasCostOfFlippingSecondTickInWordToInitialized.snap deleted file mode 100644 index 38966a2c..00000000 --- a/.forge-snapshots/flipTick_gasCostOfFlippingSecondTickInWordToInitialized.snap +++ /dev/null @@ -1 +0,0 @@ -5515 \ No newline at end of file diff --git a/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_gasCostForEntireWord.snap b/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_gasCostForEntireWord.snap deleted file mode 100644 index 13f668d1..00000000 --- a/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_gasCostForEntireWord.snap +++ /dev/null @@ -1 +0,0 @@ -2592 \ No newline at end of file diff --git a/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_gasCostJustBelowBoundary.snap b/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_gasCostJustBelowBoundary.snap deleted file mode 100644 index 13f668d1..00000000 --- a/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_gasCostJustBelowBoundary.snap +++ /dev/null @@ -1 +0,0 @@ -2592 \ No newline at end of file diff --git a/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_gasCostOnBoundary.snap b/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_gasCostOnBoundary.snap deleted file mode 100644 index 13f668d1..00000000 --- a/.forge-snapshots/nextInitializedTickWithinOneWord_lteFalse_gasCostOnBoundary.snap +++ /dev/null @@ -1 +0,0 @@ -2592 \ No newline at end of file diff --git a/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_gasCostForEntireWord.snap b/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_gasCostForEntireWord.snap deleted file mode 100644 index 0c52fc6d..00000000 --- a/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_gasCostForEntireWord.snap +++ /dev/null @@ -1 +0,0 @@ -2591 \ No newline at end of file diff --git a/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_gasCostJustBelowBoundary.snap b/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_gasCostJustBelowBoundary.snap deleted file mode 100644 index 7b34ebbf..00000000 --- a/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_gasCostJustBelowBoundary.snap +++ /dev/null @@ -1 +0,0 @@ -2900 \ No newline at end of file diff --git a/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_gasCostOnBoundary.snap b/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_gasCostOnBoundary.snap deleted file mode 100644 index 0c52fc6d..00000000 --- a/.forge-snapshots/nextInitializedTickWithinOneWord_lteTrue_gasCostOnBoundary.snap +++ /dev/null @@ -1 +0,0 @@ -2591 \ No newline at end of file diff --git a/src/libraries/Hooks.sol b/src/libraries/Hooks.sol index 279998e3..71138982 100644 --- a/src/libraries/Hooks.sol +++ b/src/libraries/Hooks.sol @@ -15,8 +15,13 @@ library Hooks { bytes4 constant NO_OP_SELECTOR = bytes4(keccak256(abi.encodePacked("NoOp"))); - /// @notice Hook has no-op defined, but lacking before* call - error NoOpHookMissingBeforeCall(); + /// @notice Hook permissions contain conflict + /// 1. has no-op defined, but lacking before* call + /// 2. has before swap returns delta, but lacking beforeSwap call + /// 3. has after swap returns delta, but lacking afterSwap call + /// 4. has add liquidity returns delta, but lacking add liquidity call + /// 5. has remove liquidity returns delta, but lacking remove liquidity call + error HookPermissionsValidationError(); /// @notice Hook config validation failed /// 1. either registration bitmap mismatch @@ -27,6 +32,9 @@ library Hooks { /// @notice Hook did not return its selector error InvalidHookResponse(); + /// @notice Hook delta exceeds swap amount + error HookDeltaExceedsSwapAmount(); + /// @notice Utility function intended to be used in pool initialization to ensure /// the hook contract's hooks registration bitmap match the configration in the pool key function validateHookConfig(PoolKey memory poolKey) internal view { @@ -56,11 +64,4 @@ library Hooks { function shouldCall(bytes32 parameters, uint8 offset, IHooks hook) internal view returns (bool) { return hasOffsetEnabled(parameters, offset) && address(hook) != msg.sender; } - - /// @dev Verify hook return value matches no-op when these 2 conditions are met - /// 1) Hook have permission for no-op - /// 2) Return value is no-op selector - function isValidNoOpCall(bytes32 parameters, uint8 noOpOffset, bytes4 selector) internal pure returns (bool) { - return hasOffsetEnabled(parameters, noOpOffset) && selector == NO_OP_SELECTOR; - } } diff --git a/src/pool-bin/BinPoolManager.sol b/src/pool-bin/BinPoolManager.sol index 90027597..d8989dfa 100644 --- a/src/pool-bin/BinPoolManager.sol +++ b/src/pool-bin/BinPoolManager.sol @@ -18,6 +18,7 @@ import {BinPosition} from "./libraries/BinPosition.sol"; import {LPFeeLibrary} from "../libraries/LPFeeLibrary.sol"; import {PackedUint128Math} from "./libraries/math/PackedUint128Math.sol"; import {Extsload} from "../Extsload.sol"; +import {BinHooks} from "./libraries/BinHooks.sol"; import "./interfaces/IBinHooks.sol"; /// @notice Holds the state for all bin pools @@ -100,7 +101,7 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload { IBinHooks hooks = IBinHooks(address(key.hooks)); Hooks.validateHookConfig(key); - _validateHookNoOp(key); + BinHooks.validate(key); /// @notice init value for dynamic lp fee is 0, but hook can still set it in afterInitialize uint24 lpFee = key.fee.getInitialLPFee(); @@ -135,27 +136,19 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload { whenNotPaused returns (BalanceDelta delta) { + if (amountIn == 0) revert InsufficientAmountIn(); + PoolId id = key.toId(); _checkPoolInitialized(id); - IBinHooks hooks = IBinHooks(address(key.hooks)); - if (key.parameters.shouldCall(HOOKS_BEFORE_SWAP_OFFSET, hooks)) { - bytes4 selector = hooks.beforeSwap(msg.sender, key, swapForY, amountIn, hookData); - if (key.parameters.isValidNoOpCall(HOOKS_NO_OP_OFFSET, selector)) { - // Sentinel return value used to signify that a NoOp occurred. - return BalanceDeltaLibrary.MAXIMUM_DELTA; - } else if (selector != IBinHooks.beforeSwap.selector) { - revert Hooks.InvalidHookResponse(); - } - } + (uint128 amountToSwap, int128 hookDeltaSpecified) = BinHooks.beforeSwap(key, swapForY, amountIn, hookData); /// @dev fix stack too deep { BinPool.SwapState memory state; - (delta, state) = - pools[id].swap(BinPool.SwapParams({swapForY: swapForY, binStep: key.parameters.getBinStep()}), amountIn); - - vault.accountPoolBalanceDelta(key, delta, msg.sender); + (delta, state) = pools[id].swap( + BinPool.SwapParams({swapForY: swapForY, binStep: key.parameters.getBinStep()}), amountToSwap + ); unchecked { if (state.feeForProtocol > 0) { @@ -170,11 +163,14 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload { ); } - if (key.parameters.shouldCall(HOOKS_AFTER_SWAP_OFFSET, hooks)) { - if (hooks.afterSwap(msg.sender, key, swapForY, amountIn, delta, hookData) != IBinHooks.afterSwap.selector) { - revert Hooks.InvalidHookResponse(); - } + BalanceDelta hookDelta; + (delta, hookDelta) = BinHooks.afterSwap(key, swapForY, amountIn, delta, hookData, hookDeltaSpecified); + + if (hookDelta != BalanceDeltaLibrary.ZERO_DELTA) { + vault.accountPoolBalanceDelta(key, hookDelta, address(key.hooks)); } + + vault.accountPoolBalanceDelta(key, delta, msg.sender); } /// @inheritdoc IBinPoolManager @@ -240,11 +236,7 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload { IBinHooks hooks = IBinHooks(address(key.hooks)); if (key.parameters.shouldCall(HOOKS_BEFORE_MINT_OFFSET, hooks)) { - bytes4 selector = hooks.beforeMint(msg.sender, key, params, hookData); - if (key.parameters.isValidNoOpCall(HOOKS_NO_OP_OFFSET, selector)) { - // Sentinel return value used to signify that a NoOp occurred. - return (BalanceDeltaLibrary.MAXIMUM_DELTA, mintArray); - } else if (selector != IBinHooks.beforeMint.selector) { + if (hooks.beforeMint(msg.sender, key, params, hookData) != IBinHooks.beforeMint.selector) { revert Hooks.InvalidHookResponse(); } } @@ -260,8 +252,6 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload { }) ); - vault.accountPoolBalanceDelta(key, delta, msg.sender); - unchecked { if (feeForProtocol > 0) { protocolFeesAccrued[key.currency0] += feeForProtocol.decodeX(); @@ -272,11 +262,13 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload { /// @notice Make sure the first event is noted, so that later events from afterHook won't get mixed up with this one emit Mint(id, msg.sender, mintArray.ids, mintArray.amounts, compositionFee, feeForProtocol); - if (key.parameters.shouldCall(HOOKS_AFTER_MINT_OFFSET, hooks)) { - if (hooks.afterMint(msg.sender, key, params, delta, hookData) != IBinHooks.afterMint.selector) { - revert Hooks.InvalidHookResponse(); - } + BalanceDelta hookDelta; + (delta, hookDelta) = BinHooks.afterMint(key, params, delta, hookData); + + if (hookDelta != BalanceDeltaLibrary.ZERO_DELTA) { + vault.accountPoolBalanceDelta(key, hookDelta, address(key.hooks)); } + vault.accountPoolBalanceDelta(key, delta, msg.sender); } /// @inheritdoc IBinPoolManager @@ -291,11 +283,7 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload { IBinHooks hooks = IBinHooks(address(key.hooks)); if (key.parameters.shouldCall(HOOKS_BEFORE_BURN_OFFSET, hooks)) { - bytes4 selector = hooks.beforeBurn(msg.sender, key, params, hookData); - if (key.parameters.isValidNoOpCall(HOOKS_NO_OP_OFFSET, selector)) { - // Sentinel return value used to signify that a NoOp occurred. - return BalanceDeltaLibrary.MAXIMUM_DELTA; - } else if (selector != IBinHooks.beforeBurn.selector) { + if (hooks.beforeBurn(msg.sender, key, params, hookData) != IBinHooks.beforeBurn.selector) { revert Hooks.InvalidHookResponse(); } } @@ -305,16 +293,16 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload { (delta, binIds, amountRemoved) = pools[id].burn(BinPool.BurnParams({from: msg.sender, ids: params.ids, amountsToBurn: params.amountsToBurn})); - vault.accountPoolBalanceDelta(key, delta, msg.sender); - /// @notice Make sure the first event is noted, so that later events from afterHook won't get mixed up with this one emit Burn(id, msg.sender, binIds, amountRemoved); - if (key.parameters.shouldCall(HOOKS_AFTER_BURN_OFFSET, hooks)) { - if (hooks.afterBurn(msg.sender, key, params, delta, hookData) != IBinHooks.afterBurn.selector) { - revert Hooks.InvalidHookResponse(); - } + BalanceDelta hookDelta; + (delta, hookDelta) = BinHooks.afterBurn(key, params, delta, hookData); + + if (hookDelta != BalanceDeltaLibrary.ZERO_DELTA) { + vault.accountPoolBalanceDelta(key, hookDelta, address(key.hooks)); } + vault.accountPoolBalanceDelta(key, delta, msg.sender); } function donate(PoolKey memory key, uint128 amount0, uint128 amount1, bytes calldata hookData) @@ -329,11 +317,7 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload { IBinHooks hooks = IBinHooks(address(key.hooks)); if (key.parameters.shouldCall(HOOKS_BEFORE_DONATE_OFFSET, hooks)) { - bytes4 selector = hooks.beforeDonate(msg.sender, key, amount0, amount1, hookData); - if (key.parameters.isValidNoOpCall(HOOKS_NO_OP_OFFSET, selector)) { - // Sentinel return value used to signify that a NoOp occurred. - return (BalanceDeltaLibrary.MAXIMUM_DELTA, binId); - } else if (selector != IBinHooks.beforeDonate.selector) { + if (hooks.beforeDonate(msg.sender, key, amount0, amount1, hookData) != IBinHooks.beforeDonate.selector) { revert Hooks.InvalidHookResponse(); } } @@ -377,18 +361,4 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload { function _checkPoolInitialized(PoolId id) internal view { if (pools[id].isNotInitialized()) revert PoolNotInitialized(); } - - function _validateHookNoOp(PoolKey memory key) internal pure { - // if no-op is active for hook, there must be a before* hook active too - if (key.parameters.hasOffsetEnabled(HOOKS_NO_OP_OFFSET)) { - if ( - !key.parameters.hasOffsetEnabled(HOOKS_BEFORE_MINT_OFFSET) - && !key.parameters.hasOffsetEnabled(HOOKS_BEFORE_BURN_OFFSET) - && !key.parameters.hasOffsetEnabled(HOOKS_BEFORE_SWAP_OFFSET) - && !key.parameters.hasOffsetEnabled(HOOKS_BEFORE_DONATE_OFFSET) - ) { - revert Hooks.NoOpHookMissingBeforeCall(); - } - } - } } diff --git a/src/pool-bin/interfaces/IBinHooks.sol b/src/pool-bin/interfaces/IBinHooks.sol index c8d06524..e9d0e078 100644 --- a/src/pool-bin/interfaces/IBinHooks.sol +++ b/src/pool-bin/interfaces/IBinHooks.sol @@ -16,7 +16,10 @@ uint8 constant HOOKS_BEFORE_SWAP_OFFSET = 6; uint8 constant HOOKS_AFTER_SWAP_OFFSET = 7; uint8 constant HOOKS_BEFORE_DONATE_OFFSET = 8; uint8 constant HOOKS_AFTER_DONATE_OFFSET = 9; -uint8 constant HOOKS_NO_OP_OFFSET = 10; +uint8 constant HOOKS_BEFORE_SWAP_RETURNS_DELTA_OFFSET = 10; +uint8 constant HOOKS_AFTER_SWAP_RETURNS_DELTA_OFFSET = 11; +uint8 constant HOOKS_AFTER_MINT_RETURNS_DELTA_OFFSET = 12; +uint8 constant HOOKS_AFTER_BURN_RETURNS_DELTA_OFFSET = 13; /// @notice The PoolManager contract decides whether to invoke specific hook by inspecting the first 16 /// bits of bytes32 PoolKey.parameters. For example a 1 bit in the first bit will cause the beforeInitialize @@ -63,13 +66,14 @@ interface IBinHooks is IHooks { /// @param delta The amount owed to the locker (negative) or owed to the pool (positive) /// @param hookData Arbitrary data handed into the PoolManager by the liquidty provider to be be passed on to the hook /// @return bytes4 The function selector for the hook + /// @return BalanceDelta The hook's delta in token0 and token1. function afterMint( address sender, PoolKey calldata key, IBinPoolManager.MintParams calldata params, BalanceDelta delta, bytes calldata hookData - ) external returns (bytes4); + ) external returns (bytes4, BalanceDelta); /// @notice The hook called before removing liquidity /// @param sender The initial msg.sender for the modify position call @@ -91,13 +95,14 @@ interface IBinHooks is IHooks { /// @param delta The amount owed to the locker (negative) or owed to the pool (positive) /// @param hookData Arbitrary data handed into the PoolManager by the liquidty provider to be be passed on to the hook /// @return bytes4 The function selector for the hook + /// @return BalanceDelta The hook's delta in token0 and token1. function afterBurn( address sender, PoolKey calldata key, IBinPoolManager.BurnParams calldata params, BalanceDelta delta, bytes calldata hookData - ) external returns (bytes4); + ) external returns (bytes4, BalanceDelta); /// @notice The hook called before a swap /// @param sender The initial msg.sender for the swap call @@ -106,9 +111,10 @@ interface IBinHooks is IHooks { /// @param amountIn Amount of tokenX or tokenY in /// @param hookData Arbitrary data handed into the PoolManager by the swapper to be be passed on to the hook /// @return bytes4 The function selector for the hook + /// @return int128 The hook's delta in specified currency function beforeSwap(address sender, PoolKey calldata key, bool swapForY, uint128 amountIn, bytes calldata hookData) external - returns (bytes4); + returns (bytes4, int128); /// @notice The hook called after a swap /// @param sender The initial msg.sender for the swap call @@ -118,6 +124,7 @@ interface IBinHooks is IHooks { /// @param delta The amount owed to the locker (negative) or owed to the pool (positive) /// @param hookData Arbitrary data handed into the PoolManager by the swapper to be be passed on to the hook /// @return bytes4 The function selector for the hook + /// @return int128 The hook's delta in unspecified currency function afterSwap( address sender, PoolKey calldata key, @@ -125,7 +132,7 @@ interface IBinHooks is IHooks { uint128 amountIn, BalanceDelta delta, bytes calldata hookData - ) external returns (bytes4); + ) external returns (bytes4, int128); /// @notice The hook called before donate /// @param sender The initial msg.sender for the donate call diff --git a/src/pool-bin/interfaces/IBinPoolManager.sol b/src/pool-bin/interfaces/IBinPoolManager.sol index 457d0fb8..e0e41c12 100644 --- a/src/pool-bin/interfaces/IBinPoolManager.sol +++ b/src/pool-bin/interfaces/IBinPoolManager.sol @@ -24,6 +24,9 @@ interface IBinPoolManager is IProtocolFees, IPoolManager, IExtsload { /// @notice Error thrown when owner set max bin step too small error MaxBinStepTooSmall(uint16 maxBinStep); + /// @notice Error thrown when amountIn is 0 + error InsufficientAmountIn(); + /// @notice Returns the constant representing the max bin step /// @return maxBinStep a value of 100 would represent a 1% price jump between bin (limit can be raised by owner) function MAX_BIN_STEP() external view returns (uint16); diff --git a/src/pool-bin/libraries/BinHooks.sol b/src/pool-bin/libraries/BinHooks.sol new file mode 100644 index 00000000..4b7ae778 --- /dev/null +++ b/src/pool-bin/libraries/BinHooks.sol @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (C) 2024 PancakeSwap +pragma solidity ^0.8.24; + +import "../interfaces/IBinHooks.sol"; +import {PoolKey} from "../../types/PoolKey.sol"; +import {IBinPoolManager} from "../interfaces/IBinPoolManager.sol"; +import {Hooks} from "../../libraries/Hooks.sol"; +import {BalanceDelta, BalanceDeltaLibrary, toBalanceDelta} from "../../types/BalanceDelta.sol"; + +library BinHooks { + using Hooks for bytes32; + + function validate(PoolKey memory key) internal pure { + if ( + key.parameters.hasOffsetEnabled(HOOKS_BEFORE_SWAP_RETURNS_DELTA_OFFSET) + && !key.parameters.hasOffsetEnabled(HOOKS_BEFORE_SWAP_OFFSET) + ) { + revert Hooks.HookPermissionsValidationError(); + } + + if ( + key.parameters.hasOffsetEnabled(HOOKS_AFTER_SWAP_RETURNS_DELTA_OFFSET) + && !key.parameters.hasOffsetEnabled(HOOKS_AFTER_SWAP_OFFSET) + ) { + revert Hooks.HookPermissionsValidationError(); + } + + if ( + key.parameters.hasOffsetEnabled(HOOKS_AFTER_MINT_RETURNS_DELTA_OFFSET) + && !key.parameters.hasOffsetEnabled(HOOKS_AFTER_MINT_OFFSET) + ) { + revert Hooks.HookPermissionsValidationError(); + } + + if ( + key.parameters.hasOffsetEnabled(HOOKS_AFTER_BURN_RETURNS_DELTA_OFFSET) + && !key.parameters.hasOffsetEnabled(HOOKS_AFTER_BURN_OFFSET) + ) { + revert Hooks.HookPermissionsValidationError(); + } + } + + function afterMint( + PoolKey memory key, + IBinPoolManager.MintParams memory params, + BalanceDelta delta, + bytes calldata hookData + ) internal returns (BalanceDelta callerDelta, BalanceDelta hookDelta) { + IBinHooks hooks = IBinHooks(address(key.hooks)); + callerDelta = delta; + + if (key.parameters.shouldCall(HOOKS_AFTER_MINT_OFFSET, hooks)) { + bytes4 selector; + (selector, hookDelta) = hooks.afterMint(msg.sender, key, params, delta, hookData); + + if (selector != IBinHooks.afterMint.selector) { + revert Hooks.InvalidHookResponse(); + } + + if ( + key.parameters.hasOffsetEnabled(HOOKS_AFTER_MINT_RETURNS_DELTA_OFFSET) + && hookDelta != BalanceDeltaLibrary.ZERO_DELTA + ) { + callerDelta = callerDelta - hookDelta; + } + } + } + + function afterBurn( + PoolKey memory key, + IBinPoolManager.BurnParams memory params, + BalanceDelta delta, + bytes calldata hookData + ) internal returns (BalanceDelta callerDelta, BalanceDelta hookDelta) { + IBinHooks hooks = IBinHooks(address(key.hooks)); + callerDelta = delta; + + if (key.parameters.shouldCall(HOOKS_AFTER_BURN_OFFSET, hooks)) { + bytes4 selector; + (selector, hookDelta) = hooks.afterBurn(msg.sender, key, params, delta, hookData); + + if (selector != IBinHooks.afterBurn.selector) { + revert Hooks.InvalidHookResponse(); + } + + if ( + key.parameters.hasOffsetEnabled(HOOKS_AFTER_BURN_RETURNS_DELTA_OFFSET) + && hookDelta != BalanceDeltaLibrary.ZERO_DELTA + ) { + callerDelta = callerDelta - hookDelta; + } + } + } + + function beforeSwap(PoolKey memory key, bool swapForY, uint128 amountIn, bytes calldata hookData) + internal + returns (uint128 amountToSwap, int128 hookDeltaSpecified) + { + IBinHooks hooks = IBinHooks(address(key.hooks)); + amountToSwap = amountIn; + + /// @notice If the hook is not registered, return the original amount to swap + if (!key.parameters.shouldCall(HOOKS_BEFORE_SWAP_OFFSET, hooks)) { + return (amountToSwap, hookDeltaSpecified); + } + + bytes4 selector; + (selector, hookDeltaSpecified) = hooks.beforeSwap(msg.sender, key, swapForY, amountIn, hookData); + if (selector != IBinHooks.beforeSwap.selector) { + revert Hooks.InvalidHookResponse(); + } + + // Update the swap amount according to the hook's return + if (key.parameters.hasOffsetEnabled(HOOKS_BEFORE_SWAP_RETURNS_DELTA_OFFSET) && hookDeltaSpecified != 0) { + /// @dev default overflow check make sure the swap amount is always valid + if (hookDeltaSpecified > 0) { + amountToSwap += uint128(hookDeltaSpecified); + } else { + amountToSwap -= uint128(-hookDeltaSpecified); + } + } + } + + function afterSwap( + PoolKey memory key, + bool swapForY, + uint128 amountIn, + BalanceDelta delta, + bytes calldata hookData, + int128 hookDeltaSpecified + ) internal returns (BalanceDelta swapperDelta, BalanceDelta hookDelta) { + IBinHooks hooks = IBinHooks(address(key.hooks)); + + int128 hookDeltaUnspecified; + if (key.parameters.shouldCall(HOOKS_AFTER_SWAP_OFFSET, hooks)) { + bytes4 selector; + (selector, hookDeltaUnspecified) = hooks.afterSwap(msg.sender, key, swapForY, amountIn, delta, hookData); + if (selector != IBinHooks.afterSwap.selector) { + revert Hooks.InvalidHookResponse(); + } + + if (!key.parameters.hasOffsetEnabled(HOOKS_AFTER_SWAP_RETURNS_DELTA_OFFSET)) { + hookDeltaUnspecified = 0; + } + } + + if (hookDeltaUnspecified != 0 || hookDeltaSpecified != 0) { + hookDelta = swapForY + ? toBalanceDelta(hookDeltaSpecified, hookDeltaUnspecified) + : toBalanceDelta(hookDeltaUnspecified, hookDeltaSpecified); + + // the caller has to pay for (or receive) the hook's delta + swapperDelta = delta - hookDelta; + } + } +} diff --git a/src/pool-bin/libraries/BinPool.sol b/src/pool-bin/libraries/BinPool.sol index b6c36d31..77642604 100644 --- a/src/pool-bin/libraries/BinPool.sol +++ b/src/pool-bin/libraries/BinPool.sol @@ -38,7 +38,6 @@ library BinPool { error BinPool__InvalidBurnInput(); error BinPool__BurnZeroAmount(uint24 id); error BinPool__ZeroAmountsOut(uint24 id); - error BinPool__InsufficientAmountIn(); error BinPool__OutOfLiquidity(); error BinPool__InsufficientAmountOut(); error BinPool__NoLiquidityToReceiveFees(); @@ -202,8 +201,6 @@ library BinPool { internal returns (BalanceDelta result, SwapState memory swapState) { - if (amountIn == 0) revert BinPool__InsufficientAmountIn(); - Slot0 memory slot0Cache = self.slot0; swapState.activeId = slot0Cache.activeId; bool swapForY = params.swapForY; @@ -216,6 +213,9 @@ library BinPool { /// @dev swap fee includes protocolFee (charged first) and lpFee swapState.swapFee = swapState.protocolFee.calculateSwapFee(slot0Cache.lpFee); + /// @notice early return if hook has updated amountIn to 0 + if (amountIn == 0) return (result, swapState); + while (true) { bytes32 binReserves = self.reserveOfBin[swapState.activeId]; if (!binReserves.isEmpty(!swapForY)) { diff --git a/src/pool-cl/CLPoolManager.sol b/src/pool-cl/CLPoolManager.sol index 54b0b572..55a7ba98 100644 --- a/src/pool-cl/CLPoolManager.sol +++ b/src/pool-cl/CLPoolManager.sol @@ -20,6 +20,7 @@ import {BalanceDelta, BalanceDeltaLibrary} from "../types/BalanceDelta.sol"; import {Extsload} from "../Extsload.sol"; import {SafeCast} from "../libraries/SafeCast.sol"; import {CLPoolGetters} from "./libraries/CLPoolGetters.sol"; +import {CLHooks} from "./libraries/CLHooks.sol"; contract CLPoolManager is ICLPoolManager, ProtocolFees, Extsload { using SafeCast for int256; @@ -97,7 +98,7 @@ contract CLPoolManager is ICLPoolManager, ProtocolFees, Extsload { ICLHooks hooks = ICLHooks(address(key.hooks)); Hooks.validateHookConfig(key); - _validateHookNoOp(key); + CLHooks.validate(key); /// @notice init value for dynamic lp fee is 0, but hook can still set it in afterInitialize uint24 lpFee = key.fee.getInitialLPFee(); @@ -144,22 +145,16 @@ contract CLPoolManager is ICLPoolManager, ProtocolFees, Extsload { _checkPoolInitialized(id); ICLHooks hooks = ICLHooks(address(key.hooks)); - if (params.liquidityDelta > 0 && key.parameters.shouldCall(HOOKS_BEFORE_ADD_LIQUIDITY_OFFSET, hooks)) { - bytes4 selector = hooks.beforeAddLiquidity(msg.sender, key, params, hookData); - if (key.parameters.isValidNoOpCall(HOOKS_NO_OP_OFFSET, selector)) { - // Sentinel return value used to signify that a NoOp occurred. - return (BalanceDeltaLibrary.MAXIMUM_DELTA, BalanceDeltaLibrary.ZERO_DELTA); - } else if (selector != ICLHooks.beforeAddLiquidity.selector) { + if (hooks.beforeAddLiquidity(msg.sender, key, params, hookData) != ICLHooks.beforeAddLiquidity.selector) { revert Hooks.InvalidHookResponse(); } } else if (params.liquidityDelta <= 0 && key.parameters.shouldCall(HOOKS_BEFORE_REMOVE_LIQUIDITY_OFFSET, hooks)) { - bytes4 selector = hooks.beforeRemoveLiquidity(msg.sender, key, params, hookData); - if (key.parameters.isValidNoOpCall(HOOKS_NO_OP_OFFSET, selector)) { - // Sentinel return value used to signify that a NoOp occurred. - return (BalanceDeltaLibrary.MAXIMUM_DELTA, BalanceDeltaLibrary.ZERO_DELTA); - } else if (selector != ICLHooks.beforeRemoveLiquidity.selector) { + if ( + hooks.beforeRemoveLiquidity(msg.sender, key, params, hookData) + != ICLHooks.beforeRemoveLiquidity.selector + ) { revert Hooks.InvalidHookResponse(); } } @@ -174,26 +169,16 @@ contract CLPoolManager is ICLPoolManager, ProtocolFees, Extsload { }) ); - vault.accountPoolBalanceDelta(key, delta + feeDelta, msg.sender); - /// @notice Make sure the first event is noted, so that later events from afterHook won't get mixed up with this one emit ModifyLiquidity(id, msg.sender, params.tickLower, params.tickUpper, params.liquidityDelta); - if (params.liquidityDelta > 0 && key.parameters.shouldCall(HOOKS_AFTER_ADD_LIQUIDITY_OFFSET, hooks)) { - if ( - hooks.afterAddLiquidity(msg.sender, key, params, delta, hookData) != ICLHooks.afterAddLiquidity.selector - ) { - revert Hooks.InvalidHookResponse(); - } - } else if (params.liquidityDelta <= 0 && key.parameters.shouldCall(HOOKS_AFTER_REMOVE_LIQUIDITY_OFFSET, hooks)) - { - if ( - hooks.afterRemoveLiquidity(msg.sender, key, params, delta, hookData) - != ICLHooks.afterRemoveLiquidity.selector - ) { - revert Hooks.InvalidHookResponse(); - } + BalanceDelta hookDelta; + (delta, hookDelta) = CLHooks.afterModifyLiquidity(key, params, delta + feeDelta, hookData); + + if (hookDelta != BalanceDeltaLibrary.ZERO_DELTA) { + vault.accountPoolBalanceDelta(key, hookDelta, address(key.hooks)); } + vault.accountPoolBalanceDelta(key, delta, msg.sender); } /// @inheritdoc ICLPoolManager @@ -204,35 +189,22 @@ contract CLPoolManager is ICLPoolManager, ProtocolFees, Extsload { whenNotPaused returns (BalanceDelta delta) { + if (params.amountSpecified == 0) revert SwapAmountCannotBeZero(); + PoolId id = key.toId(); _checkPoolInitialized(id); - ICLHooks hooks = ICLHooks(address(key.hooks)); - - if (key.parameters.shouldCall(HOOKS_BEFORE_SWAP_OFFSET, hooks)) { - bytes4 selector = hooks.beforeSwap(msg.sender, key, params, hookData); - if (key.parameters.isValidNoOpCall(HOOKS_NO_OP_OFFSET, selector)) { - // Sentinel return value used to signify that a NoOp occurred. - return BalanceDeltaLibrary.MAXIMUM_DELTA; - } else if (selector != ICLHooks.beforeSwap.selector) { - revert Hooks.InvalidHookResponse(); - } - } - + (int256 amountToSwap, int128 hookDeltaSpecified) = CLHooks.beforeSwap(key, params, hookData); CLPool.SwapState memory state; (delta, state) = pools[id].swap( CLPool.SwapParams({ tickSpacing: key.parameters.getTickSpacing(), zeroForOne: params.zeroForOne, - amountSpecified: params.amountSpecified, + amountSpecified: amountToSwap, sqrtPriceLimitX96: params.sqrtPriceLimitX96 }) ); - /// @dev delta already includes protocol fee - /// all tokens go into the vault - vault.accountPoolBalanceDelta(key, delta, msg.sender); - unchecked { if (state.feeForProtocol > 0) { protocolFeesAccrued[params.zeroForOne ? key.currency0 : key.currency1] += state.feeForProtocol; @@ -252,11 +224,16 @@ contract CLPoolManager is ICLPoolManager, ProtocolFees, Extsload { state.protocolFee ); - if (key.parameters.shouldCall(HOOKS_AFTER_SWAP_OFFSET, hooks)) { - if (hooks.afterSwap(msg.sender, key, params, delta, hookData) != ICLHooks.afterSwap.selector) { - revert Hooks.InvalidHookResponse(); - } + BalanceDelta hookDelta; + (delta, hookDelta) = CLHooks.afterSwap(key, params, delta, hookData, hookDeltaSpecified); + + if (hookDelta != BalanceDeltaLibrary.ZERO_DELTA) { + vault.accountPoolBalanceDelta(key, hookDelta, address(key.hooks)); } + + /// @dev delta already includes protocol fee + /// all tokens go into the vault + vault.accountPoolBalanceDelta(key, delta, msg.sender); } /// @inheritdoc ICLPoolManager @@ -272,11 +249,7 @@ contract CLPoolManager is ICLPoolManager, ProtocolFees, Extsload { ICLHooks hooks = ICLHooks(address(key.hooks)); if (key.parameters.shouldCall(HOOKS_BEFORE_DONATE_OFFSET, hooks)) { - bytes4 selector = hooks.beforeDonate(msg.sender, key, amount0, amount1, hookData); - if (key.parameters.isValidNoOpCall(HOOKS_NO_OP_OFFSET, selector)) { - // Sentinel return value used to signify that a NoOp occurred. - return BalanceDeltaLibrary.MAXIMUM_DELTA; - } else if (selector != ICLHooks.beforeDonate.selector) { + if (hooks.beforeDonate(msg.sender, key, amount0, amount1, hookData) != ICLHooks.beforeDonate.selector) { revert Hooks.InvalidHookResponse(); } } @@ -329,20 +302,6 @@ contract CLPoolManager is ICLPoolManager, ProtocolFees, Extsload { if (pools[id].isNotInitialized()) revert PoolNotInitialized(); } - function _validateHookNoOp(PoolKey memory key) internal pure { - // if no-op is active for hook, there must be a before* hook active too - if (key.parameters.hasOffsetEnabled(HOOKS_NO_OP_OFFSET)) { - if ( - !key.parameters.hasOffsetEnabled(HOOKS_BEFORE_ADD_LIQUIDITY_OFFSET) - && !key.parameters.hasOffsetEnabled(HOOKS_BEFORE_REMOVE_LIQUIDITY_OFFSET) - && !key.parameters.hasOffsetEnabled(HOOKS_BEFORE_SWAP_OFFSET) - && !key.parameters.hasOffsetEnabled(HOOKS_BEFORE_DONATE_OFFSET) - ) { - revert Hooks.NoOpHookMissingBeforeCall(); - } - } - } - /// @notice not accept ether // receive() external payable {} // fallback() external payable {} diff --git a/src/pool-cl/interfaces/ICLHooks.sol b/src/pool-cl/interfaces/ICLHooks.sol index 1b14f0c9..126ba12c 100644 --- a/src/pool-cl/interfaces/ICLHooks.sol +++ b/src/pool-cl/interfaces/ICLHooks.sol @@ -17,7 +17,10 @@ uint8 constant HOOKS_BEFORE_SWAP_OFFSET = 6; uint8 constant HOOKS_AFTER_SWAP_OFFSET = 7; uint8 constant HOOKS_BEFORE_DONATE_OFFSET = 8; uint8 constant HOOKS_AFTER_DONATE_OFFSET = 9; -uint8 constant HOOKS_NO_OP_OFFSET = 10; +uint8 constant HOOKS_BEFORE_SWAP_RETURNS_DELTA_OFFSET = 10; +uint8 constant HOOKS_AFTER_SWAP_RETURNS_DELTA_OFFSET = 11; +uint8 constant HOOKS_AFTER_ADD_LIQUIDIY_RETURNS_DELTA_OFFSET = 12; +uint8 constant HOOKS_AFTER_REMOVE_LIQUIDIY_RETURNS_DELTA_OFFSET = 13; /// @notice The PoolManager contract decides whether to invoke specific hooks by inspecting the leading bits /// of the hooks contract address. For example, a 1 bit in the first bit of the address will @@ -69,13 +72,14 @@ interface ICLHooks is IHooks { /// @param params The parameters for adding liquidity /// @param hookData Arbitrary data handed into the PoolManager by the liquidty provider to be be passed on to the hook /// @return bytes4 The function selector for the hook + /// @return BalanceDelta The hook's delta in token0 and token1. function afterAddLiquidity( address sender, PoolKey calldata key, ICLPoolManager.ModifyLiquidityParams calldata params, BalanceDelta delta, bytes calldata hookData - ) external returns (bytes4); + ) external returns (bytes4, BalanceDelta); /// @notice The hook called before liquidity is removed /// @param sender The initial msg.sender for the remove liquidity call @@ -96,13 +100,14 @@ interface ICLHooks is IHooks { /// @param params The parameters for removing liquidity /// @param hookData Arbitrary data handed into the PoolManager by the liquidty provider to be be passed on to the hook /// @return bytes4 The function selector for the hook + /// @return BalanceDelta The hook's delta in token0 and token1. function afterRemoveLiquidity( address sender, PoolKey calldata key, ICLPoolManager.ModifyLiquidityParams calldata params, BalanceDelta delta, bytes calldata hookData - ) external returns (bytes4); + ) external returns (bytes4, BalanceDelta); /// @notice The hook called before a swap /// @param sender The initial msg.sender for the swap call @@ -110,12 +115,13 @@ interface ICLHooks is IHooks { /// @param params The parameters for the swap /// @param hookData Arbitrary data handed into the PoolManager by the swapper to be be passed on to the hook /// @return bytes4 The function selector for the hook + /// @return int128 The hook's delta in specified currency function beforeSwap( address sender, PoolKey calldata key, ICLPoolManager.SwapParams calldata params, bytes calldata hookData - ) external returns (bytes4); + ) external returns (bytes4, int128); /// @notice The hook called after a swap /// @param sender The initial msg.sender for the swap call @@ -124,13 +130,14 @@ interface ICLHooks is IHooks { /// @param delta The amount owed to the locker (positive) or owed to the pool (negative) /// @param hookData Arbitrary data handed into the PoolManager by the swapper to be be passed on to the hook /// @return bytes4 The function selector for the hook + /// @return int128 The hook's delta in unspecified currency function afterSwap( address sender, PoolKey calldata key, ICLPoolManager.SwapParams calldata params, BalanceDelta delta, bytes calldata hookData - ) external returns (bytes4); + ) external returns (bytes4, int128); /// @notice The hook called before donate /// @param sender The initial msg.sender for the donate call diff --git a/src/pool-cl/interfaces/ICLPoolManager.sol b/src/pool-cl/interfaces/ICLPoolManager.sol index ff92ac4f..8054d525 100644 --- a/src/pool-cl/interfaces/ICLPoolManager.sol +++ b/src/pool-cl/interfaces/ICLPoolManager.sol @@ -21,6 +21,8 @@ interface ICLPoolManager is IProtocolFees, IPoolManager, IExtsload { error TickSpacingTooSmall(); /// @notice Error thrown when add liquidity is called when paused() error PoolPaused(); + /// @notice Thrown when trying to swap amount of 0 + error SwapAmountCannotBeZero(); /// @notice Emitted when a new pool is initialized /// @param id The abi encoded hash of the pool key struct for the new pool @@ -119,8 +121,8 @@ interface ICLPoolManager is IProtocolFees, IPoolManager, IExtsload { } /// @notice Modify the position for the given pool - /// @return delta The balance delta of the liquidity change - /// @return feeDelta The balance delta of the fees generated in the liquidity range + /// @return delta The balance delta of the caller of modifyLiquidity. This is the total of both principal and fee deltas. + /// @return feeDelta The balance delta of the fees generated in the liquidity range. Returned for informational purposes. function modifyLiquidity(PoolKey memory key, ModifyLiquidityParams memory params, bytes calldata hookData) external returns (BalanceDelta delta, BalanceDelta feeDelta); @@ -132,6 +134,13 @@ interface ICLPoolManager is IProtocolFees, IPoolManager, IExtsload { } /// @notice Swap against the given pool + /// @param key The pool to swap in + /// @param params The parameters for swapping + /// @param hookData Any data to pass to the callback + /// @return delta The balance delta of the address swapping + /// @dev Swapping on low liquidity pools may cause unexpected swap amounts when liquidity available is less than amountSpecified. + /// Additionally note that if interacting with hooks that have the BEFORE_SWAP_RETURNS_DELTA_FLAG or AFTER_SWAP_RETURNS_DELTA_FLAG + /// the hook may alter the swap input/output. Integrators should perform checks on the returned swapDelta. function swap(PoolKey memory key, SwapParams memory params, bytes calldata hookData) external returns (BalanceDelta); diff --git a/src/pool-cl/libraries/CLHooks.sol b/src/pool-cl/libraries/CLHooks.sol new file mode 100644 index 00000000..abefad84 --- /dev/null +++ b/src/pool-cl/libraries/CLHooks.sol @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (C) 2024 PancakeSwap +pragma solidity ^0.8.24; + +import "../interfaces/ICLHooks.sol"; +import {PoolKey} from "../../types/PoolKey.sol"; +import {ICLPoolManager} from "../interfaces/ICLPoolManager.sol"; +import {Hooks} from "../../libraries/Hooks.sol"; +import {BalanceDelta, BalanceDeltaLibrary, toBalanceDelta} from "../../types/BalanceDelta.sol"; + +library CLHooks { + using Hooks for bytes32; + + function validate(PoolKey memory key) internal pure { + if ( + key.parameters.hasOffsetEnabled(HOOKS_BEFORE_SWAP_RETURNS_DELTA_OFFSET) + && !key.parameters.hasOffsetEnabled(HOOKS_BEFORE_SWAP_OFFSET) + ) { + revert Hooks.HookPermissionsValidationError(); + } + + if ( + key.parameters.hasOffsetEnabled(HOOKS_AFTER_SWAP_RETURNS_DELTA_OFFSET) + && !key.parameters.hasOffsetEnabled(HOOKS_AFTER_SWAP_OFFSET) + ) { + revert Hooks.HookPermissionsValidationError(); + } + + if ( + key.parameters.hasOffsetEnabled(HOOKS_AFTER_ADD_LIQUIDIY_RETURNS_DELTA_OFFSET) + && !key.parameters.hasOffsetEnabled(HOOKS_AFTER_ADD_LIQUIDITY_OFFSET) + ) { + revert Hooks.HookPermissionsValidationError(); + } + + if ( + key.parameters.hasOffsetEnabled(HOOKS_AFTER_REMOVE_LIQUIDIY_RETURNS_DELTA_OFFSET) + && !key.parameters.hasOffsetEnabled(HOOKS_AFTER_REMOVE_LIQUIDITY_OFFSET) + ) { + revert Hooks.HookPermissionsValidationError(); + } + } + + function afterModifyLiquidity( + PoolKey memory key, + ICLPoolManager.ModifyLiquidityParams memory params, + BalanceDelta delta, + bytes calldata hookData + ) internal returns (BalanceDelta callerDelta, BalanceDelta hookDelta) { + ICLHooks hooks = ICLHooks(address(key.hooks)); + callerDelta = delta; + + if (params.liquidityDelta > 0 && key.parameters.shouldCall(HOOKS_AFTER_ADD_LIQUIDITY_OFFSET, hooks)) { + bytes4 selector; + (selector, hookDelta) = hooks.afterAddLiquidity(msg.sender, key, params, delta, hookData); + + if (selector != ICLHooks.afterAddLiquidity.selector) { + revert Hooks.InvalidHookResponse(); + } + + if ( + key.parameters.hasOffsetEnabled(HOOKS_AFTER_ADD_LIQUIDIY_RETURNS_DELTA_OFFSET) + && hookDelta != BalanceDeltaLibrary.ZERO_DELTA + ) { + callerDelta = callerDelta - hookDelta; + } + } else if (params.liquidityDelta < 0 && key.parameters.shouldCall(HOOKS_AFTER_REMOVE_LIQUIDITY_OFFSET, hooks)) { + bytes4 selector; + (selector, hookDelta) = hooks.afterRemoveLiquidity(msg.sender, key, params, delta, hookData); + + if (selector != ICLHooks.afterRemoveLiquidity.selector) { + revert Hooks.InvalidHookResponse(); + } + + if ( + key.parameters.hasOffsetEnabled(HOOKS_AFTER_REMOVE_LIQUIDIY_RETURNS_DELTA_OFFSET) + && hookDelta != BalanceDeltaLibrary.ZERO_DELTA + ) { + callerDelta = callerDelta - hookDelta; + } + } + } + + function beforeSwap(PoolKey memory key, ICLPoolManager.SwapParams memory params, bytes calldata hookData) + internal + returns (int256 amountToSwap, int128 hookDeltaSpecified) + { + ICLHooks hooks = ICLHooks(address(key.hooks)); + amountToSwap = params.amountSpecified; + + /// @notice If the hook is not registered, return the original amount to swap + if (!key.parameters.shouldCall(HOOKS_BEFORE_SWAP_OFFSET, hooks)) { + return (amountToSwap, hookDeltaSpecified); + } + + bytes4 selector; + (selector, hookDeltaSpecified) = hooks.beforeSwap(msg.sender, key, params, hookData); + if (selector != ICLHooks.beforeSwap.selector) { + revert Hooks.InvalidHookResponse(); + } + + // Update the swap amount according to the hook's return, and check that the swap type doesnt change (exact input/output) + if (key.parameters.hasOffsetEnabled(HOOKS_BEFORE_SWAP_RETURNS_DELTA_OFFSET) && hookDeltaSpecified != 0) { + bool exactInput = amountToSwap > 0; + amountToSwap += hookDeltaSpecified; + if (exactInput ? amountToSwap < 0 : amountToSwap > 0) revert Hooks.HookDeltaExceedsSwapAmount(); + } + } + + function afterSwap( + PoolKey memory key, + ICLPoolManager.SwapParams memory params, + BalanceDelta delta, + bytes calldata hookData, + int128 hookDeltaSpecified + ) internal returns (BalanceDelta swapperDelta, BalanceDelta hookDelta) { + ICLHooks hooks = ICLHooks(address(key.hooks)); + + int128 hookDeltaUnspecified; + if (key.parameters.shouldCall(HOOKS_AFTER_SWAP_OFFSET, hooks)) { + bytes4 selector; + (selector, hookDeltaUnspecified) = hooks.afterSwap(msg.sender, key, params, delta, hookData); + if (selector != ICLHooks.afterSwap.selector) { + revert Hooks.InvalidHookResponse(); + } + + if (!key.parameters.hasOffsetEnabled(HOOKS_AFTER_SWAP_RETURNS_DELTA_OFFSET)) { + hookDeltaUnspecified = 0; + } + } + + if (hookDeltaUnspecified != 0 || hookDeltaSpecified != 0) { + hookDelta = (params.amountSpecified > 0 == params.zeroForOne) + ? toBalanceDelta(hookDeltaSpecified, hookDeltaUnspecified) + : toBalanceDelta(hookDeltaUnspecified, hookDeltaSpecified); + + // the caller has to pay for (or receive) the hook's delta + swapperDelta = delta - hookDelta; + } + } +} diff --git a/src/pool-cl/libraries/CLPool.sol b/src/pool-cl/libraries/CLPool.sol index 5f10defd..a301e2ae 100644 --- a/src/pool-cl/libraries/CLPool.sol +++ b/src/pool-cl/libraries/CLPool.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.24; import {CLPosition} from "./CLPosition.sol"; import {TickMath} from "./TickMath.sol"; -import {BalanceDelta, toBalanceDelta} from "../../types/BalanceDelta.sol"; +import {BalanceDelta, BalanceDeltaLibrary, toBalanceDelta} from "../../types/BalanceDelta.sol"; import {Tick} from "./Tick.sol"; import {TickBitmap} from "./TickBitmap.sol"; import {SqrtPriceMath} from "./SqrtPriceMath.sol"; @@ -33,9 +33,6 @@ library CLPool { /// @notice Thrown when trying to interact with a non-initialized pool error PoolNotInitialized(); - /// @notice Thrown when trying to swap amount of 0 - error SwapAmountCannotBeZero(); - /// @notice Thrown when trying to swap with max lp fee and specifying an output amount error InvalidFeeForExactOut(); @@ -198,12 +195,12 @@ library CLPool { internal returns (BalanceDelta balanceDelta, SwapState memory state) { - if (params.amountSpecified == 0) revert SwapAmountCannotBeZero(); - + // cache variables for gas optimization Slot0 memory slot0Start = self.slot0; - // Declare zeroForOne and sqrtPriceLimitX96 upfront for gas optmization bool zeroForOne = params.zeroForOne; uint160 sqrtPriceLimitX96 = params.sqrtPriceLimitX96; + + // check price limit if ( zeroForOne ? (sqrtPriceLimitX96 >= slot0Start.sqrtPriceX96 || sqrtPriceLimitX96 <= TickMath.MIN_SQRT_RATIO) @@ -212,10 +209,12 @@ library CLPool { revert InvalidSqrtPriceLimit(slot0Start.sqrtPriceX96, sqrtPriceLimitX96); } + // cache variables for gas optimization // liquidity at the beginning of the swap uint128 liquidityStart = self.liquidity; bool exactInput = params.amountSpecified > 0; + // init swap state { uint16 protocolFee = zeroForOne ? slot0Start.protocolFee.getZeroForOneFee() : slot0Start.protocolFee.getOneForZeroFee(); @@ -239,6 +238,9 @@ library CLPool { revert InvalidFeeForExactOut(); } + /// @notice early return if hook has updated amountSpecified to 0 + if (params.amountSpecified == 0) return (BalanceDeltaLibrary.ZERO_DELTA, state); + StepComputations memory step; // continue swapping as long as we haven't used the entire input/output and haven't reached the price limit while (state.amountSpecifiedRemaining != 0 && state.sqrtPriceX96 != sqrtPriceLimitX96) { diff --git a/src/types/BalanceDelta.sol b/src/types/BalanceDelta.sol index 32c5918c..6e837712 100644 --- a/src/types/BalanceDelta.sol +++ b/src/types/BalanceDelta.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.24; type BalanceDelta is int256; -using {add as +, sub as -, eq as ==} for BalanceDelta global; +using {add as +, sub as -, eq as ==, neq as !=} for BalanceDelta global; using BalanceDeltaLibrary for BalanceDelta global; function toBalanceDelta(int128 _amount0, int128 _amount1) pure returns (BalanceDelta balanceDelta) { @@ -26,10 +26,11 @@ function eq(BalanceDelta a, BalanceDelta b) pure returns (bool) { return a.amount0() == b.amount0() && a.amount1() == b.amount1(); } -library BalanceDeltaLibrary { - // Sentinel return value used to signify that a NoOp occurred. - BalanceDelta public constant MAXIMUM_DELTA = BalanceDelta.wrap(int256(type(uint256).max)); +function neq(BalanceDelta a, BalanceDelta b) pure returns (bool) { + return a.amount0() != b.amount0() || a.amount1() != b.amount1(); +} +library BalanceDeltaLibrary { // Sentinel return value used for feeDelta to signify that a NoOp occurred. BalanceDelta public constant ZERO_DELTA = BalanceDelta.wrap(0); diff --git a/test/libraries/Hooks/Hooks.t.sol b/test/libraries/Hooks/Hooks.t.sol index 25bece44..2133d1a0 100644 --- a/test/libraries/Hooks/Hooks.t.sol +++ b/test/libraries/Hooks/Hooks.t.sol @@ -90,21 +90,4 @@ contract HooksTest is Test { assertEq(Hooks.hasOffsetEnabled(bytes32(uint256(0xaaaa)), 14), false); assertEq(Hooks.hasOffsetEnabled(bytes32(uint256(0xaaaa)), 15), true); } - - function testIsValidNoOpCall(bytes32 parameters, uint8 noOpOffset, bytes4 selector) public { - // make sure enough true cases are covered - noOpOffset = uint8(bound(noOpOffset, 0, 15)); - if (uint32(selector) > type(uint32).max / 2) { - selector = Hooks.NO_OP_SELECTOR; - } - - bool expectRet; - assembly { - expectRet := and(shr(noOpOffset, parameters), 1) - } - expectRet = expectRet && selector == Hooks.NO_OP_SELECTOR; - - bool actualRet = Hooks.isValidNoOpCall(parameters, noOpOffset, selector); - assertEq(expectRet, actualRet); - } } diff --git a/test/pool-bin/BinPoolManager.t.sol b/test/pool-bin/BinPoolManager.t.sol index 9e9aa38e..e5c10ae7 100644 --- a/test/pool-bin/BinPoolManager.t.sol +++ b/test/pool-bin/BinPoolManager.t.sol @@ -227,77 +227,6 @@ contract BinPoolManagerTest is Test, GasSnapshot, BinTestHelper { poolManager.initialize(key, activeId, ""); } - function testInitialize_NoOpMissingBeforeCall() public { - // 0000 0100 0000 0000 // only noOp - uint16 bitMap = 0x0400; - - BinNoOpTestHook noOpHook = new BinNoOpTestHook(); - noOpHook.setHooksRegistrationBitmap(bitMap); - - key = PoolKey({ - currency0: Currency.wrap(makeAddr("token0")), - currency1: Currency.wrap(makeAddr("token1")), - hooks: IHooks(address(noOpHook)), - poolManager: IPoolManager(address(poolManager)), - fee: uint24(3000), - parameters: bytes32(uint256(bitMap)).setBinStep(1) - }); - - // no op permission set, but no before call - vm.expectRevert(Hooks.NoOpHookMissingBeforeCall.selector); - poolManager.initialize(key, activeId, ""); - } - - function testNoOp_Gas() public { - // 0000 0101 0101 0100 // noOp, beforeMint, beforeBurn, beforeSwap, beforeDonate - uint16 bitMap = 0x0554; - - // pre-req create pool - BinNoOpTestHook noOpHook = new BinNoOpTestHook(); - noOpHook.setHooksRegistrationBitmap(bitMap); - key = PoolKey({ - currency0: Currency.wrap(makeAddr("token0")), - currency1: Currency.wrap(makeAddr("token1")), - hooks: IHooks(address(noOpHook)), - poolManager: IPoolManager(address(poolManager)), - fee: uint24(3000), - parameters: bytes32(uint256(bitMap)).setBinStep(1) - }); - - snapStart("BinPoolManagerTest#testNoOpGas_Initialize"); - poolManager.initialize(key, activeId, ""); - snapEnd(); - - BalanceDelta delta; - - // Action 1: mint, params doesn't matter for noOp - IBinPoolManager.MintParams memory mintParams; - snapStart("BinPoolManagerTest#testNoOpGas_Mint"); - delta = binLiquidityHelper.mint{value: 1 ether}(key, mintParams, ""); - snapEnd(); - assertTrue(delta == BalanceDeltaLibrary.MAXIMUM_DELTA); - - // Action 2: Burn, params doesn't matter for noOp - IBinPoolManager.BurnParams memory burnParams; - snapStart("BinPoolManagerTest#testNoOpGas_Burn"); - delta = binLiquidityHelper.burn(key, burnParams, ""); - snapEnd(); - assertTrue(delta == BalanceDeltaLibrary.MAXIMUM_DELTA); - - // Action 3: Swap - BinSwapHelper.TestSettings memory testSettings; - snapStart("BinPoolManagerTest#testNoOpGas_Swap"); - delta = binSwapHelper.swap(key, false, 1e17, testSettings, ""); - snapEnd(); - assertTrue(delta == BalanceDeltaLibrary.MAXIMUM_DELTA); - - // Action 4: Donate - snapStart("BinPoolManagerTest#testNoOpGas_Donate"); - delta = binDonateHelper.donate(key, 10 ether, 10 ether, ""); - snapEnd(); - assertTrue(delta == BalanceDeltaLibrary.MAXIMUM_DELTA); - } - function testGasMintOneBin() public { poolManager.initialize(key, activeId, new bytes(0)); diff --git a/test/pool-bin/helpers/BaseBinTestHook.sol b/test/pool-bin/helpers/BaseBinTestHook.sol index 3b1085c9..d380fb6f 100644 --- a/test/pool-bin/helpers/BaseBinTestHook.sol +++ b/test/pool-bin/helpers/BaseBinTestHook.sol @@ -1,19 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.24; -import { - HOOKS_BEFORE_INITIALIZE_OFFSET, - HOOKS_AFTER_INITIALIZE_OFFSET, - HOOKS_BEFORE_MINT_OFFSET, - HOOKS_AFTER_MINT_OFFSET, - HOOKS_BEFORE_BURN_OFFSET, - HOOKS_AFTER_BURN_OFFSET, - HOOKS_BEFORE_SWAP_OFFSET, - HOOKS_AFTER_SWAP_OFFSET, - HOOKS_BEFORE_DONATE_OFFSET, - HOOKS_AFTER_DONATE_OFFSET, - HOOKS_NO_OP_OFFSET -} from "../../../src/pool-bin/interfaces/IBinHooks.sol"; +import "../../../src/pool-bin/interfaces/IBinHooks.sol"; import {PoolKey} from "../../../src/types/PoolKey.sol"; import {BalanceDelta} from "../../../src/types/BalanceDelta.sol"; import {IBinHooks} from "../../../src/pool-bin/interfaces/IBinHooks.sol"; @@ -120,7 +108,6 @@ contract BaseBinTestHook is IBinHooks { | (permissions.afterSwap ? 1 << HOOKS_AFTER_SWAP_OFFSET : 0) | (permissions.beforeDonate ? 1 << HOOKS_BEFORE_DONATE_OFFSET : 0) | (permissions.afterDonate ? 1 << HOOKS_AFTER_DONATE_OFFSET : 0) - | (permissions.noOp ? 1 << HOOKS_NO_OP_OFFSET : 0) ); } } diff --git a/test/pool-bin/helpers/BinLiquidityHelper.sol b/test/pool-bin/helpers/BinLiquidityHelper.sol index b1c86634..19082de6 100644 --- a/test/pool-bin/helpers/BinLiquidityHelper.sol +++ b/test/pool-bin/helpers/BinLiquidityHelper.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.24; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IVault} from "../../../src/interfaces/IVault.sol"; -import {HOOKS_NO_OP_OFFSET} from "../../../src/pool-bin/interfaces/IBinHooks.sol"; import {IBinPoolManager} from "../../../src/pool-bin/interfaces/IBinPoolManager.sol"; import {BalanceDelta, BalanceDeltaLibrary} from "../../../src/types/BalanceDelta.sol"; import {CurrencyLibrary, Currency} from "../../../src/types/Currency.sol"; @@ -86,14 +85,6 @@ contract BinLiquidityHelper { (delta,) = binManager.mint(data.key, data.params, data.hookData); } - if (delta == BalanceDeltaLibrary.MAXIMUM_DELTA) { - // check if the hook has permission to no-op, if true, return early - if (!key.parameters.shouldCall(HOOKS_NO_OP_OFFSET, key.hooks)) { - revert HookMissingNoOpPermission(); - } - return abi.encode(delta); - } - if (delta.amount0() > 0) { if (key.currency0.isNative()) { vault.settle{value: uint128(delta.amount0())}(key.currency0); diff --git a/test/pool-bin/helpers/BinSwapHelper.sol b/test/pool-bin/helpers/BinSwapHelper.sol index 9a764e1e..6c7b55e5 100644 --- a/test/pool-bin/helpers/BinSwapHelper.sol +++ b/test/pool-bin/helpers/BinSwapHelper.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.24; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IVault} from "../../../src/interfaces/IVault.sol"; -import {HOOKS_NO_OP_OFFSET} from "../../../src/pool-bin/interfaces/IBinHooks.sol"; import {IBinPoolManager} from "../../../src/pool-bin/interfaces/IBinPoolManager.sol"; import {BalanceDelta, BalanceDeltaLibrary} from "../../../src/types/BalanceDelta.sol"; import {CurrencyLibrary, Currency} from "../../../src/types/Currency.sol"; @@ -61,14 +60,6 @@ contract BinSwapHelper { BalanceDelta delta = binManager.swap(data.key, data.swapForY, data.amountIn, data.hookData); - if (delta == BalanceDeltaLibrary.MAXIMUM_DELTA) { - // check if the hook has permission to no-op, if true, return early - if (!data.key.parameters.shouldCall(HOOKS_NO_OP_OFFSET, data.key.hooks)) { - revert HookMissingNoOpPermission(); - } - return abi.encode(delta); - } - if (data.swapForY) { if (delta.amount0() > 0) { if (data.testSettings.settleUsingTransfer) { diff --git a/test/pool-cl/CLPoolManager.t.sol b/test/pool-cl/CLPoolManager.t.sol index 5c8a4253..f61cc59a 100644 --- a/test/pool-cl/CLPoolManager.t.sol +++ b/test/pool-cl/CLPoolManager.t.sol @@ -627,24 +627,6 @@ contract CLPoolManagerTest is Test, Deployers, TokenFixture, GasSnapshot { poolManager.initialize(key, SQRT_RATIO_1_1, ZERO_BYTES); } - function test_initialize_failsNoOpMissingBeforeCall() public { - uint16 bitMap = 0x0400; // 0000 0100 0000 0000 (only noOp) - - CLNoOpTestHook noOpHook = new CLNoOpTestHook(); - noOpHook.setHooksRegistrationBitmap(bitMap); - PoolKey memory key = PoolKey({ - currency0: currency0, - currency1: currency1, - fee: 3000, - hooks: IHooks(noOpHook), - poolManager: poolManager, - parameters: bytes32(uint256((60 << 16) | noOpHook.getHooksRegistrationBitmap())) - }); - - vm.expectRevert(Hooks.NoOpHookMissingBeforeCall.selector); - poolManager.initialize(key, TickMath.MIN_SQRT_RATIO, new bytes(0)); - } - // ************** *************** // // ************** modifyPosition *************** // // ************** *************** // @@ -2476,54 +2458,6 @@ contract CLPoolManagerTest is Test, Deployers, TokenFixture, GasSnapshot { assertEq(swapFee, _swapFee); } - function testNoOp_gas() public { - uint16 bitMap = 0x0550; // 0000 0101 0101 0000 (only noOp, beforeRemoveLiquidity, beforeSwap, beforeDonate) - - // pre-req create pool - CLNoOpTestHook noOpHook = new CLNoOpTestHook(); - noOpHook.setHooksRegistrationBitmap(bitMap); - PoolKey memory key = PoolKey({ - currency0: currency0, - currency1: currency1, - fee: 3000, - hooks: IHooks(noOpHook), - poolManager: poolManager, - parameters: bytes32(uint256((60 << 16) | noOpHook.getHooksRegistrationBitmap())) - }); - - snapStart("CLPoolManagerTest#testNoOp_gas_Initialize"); - poolManager.initialize(key, TickMath.MIN_SQRT_RATIO, new bytes(0)); - snapEnd(); - - BalanceDelta delta; - BalanceDelta feeDelta; - - // Action 1: modify - ICLPoolManager.ModifyLiquidityParams memory params; - snapStart("CLPoolManagerTest#testNoOp_gas_ModifyPosition"); - (delta, feeDelta) = router.modifyPosition(key, params, ZERO_BYTES); - snapEnd(); - assertTrue(delta == BalanceDeltaLibrary.MAXIMUM_DELTA); - assertTrue(feeDelta == BalanceDeltaLibrary.ZERO_DELTA); - - // Action 2: swap - snapStart("CLPoolManagerTest#testNoOp_gas_Swap"); - delta = router.swap( - key, - ICLPoolManager.SwapParams(true, 10000, SQRT_RATIO_1_2), - CLPoolManagerRouter.SwapTestSettings(true, true), - ZERO_BYTES - ); - snapEnd(); - assertTrue(delta == BalanceDeltaLibrary.MAXIMUM_DELTA); - - // Action 3: donate - snapStart("CLPoolManagerTest#testNoOp_gas_Donate"); - delta = router.donate(key, 100, 100, ZERO_BYTES); - snapEnd(); - assertTrue(delta == BalanceDeltaLibrary.MAXIMUM_DELTA); - } - function testModifyLiquidity_Add_WhenPaused() public { Currency currency0 = Currency.wrap(address(new ERC20PresetFixedSupply("C0", "C0", 1e10 ether, address(this)))); Currency currency1 = Currency.wrap(address(new ERC20PresetFixedSupply("C1", "C1", 1e10 ether, address(this)))); diff --git a/test/pool-cl/helpers/BaseCLTestHook.sol b/test/pool-cl/helpers/BaseCLTestHook.sol index ebc52da4..2d17c547 100644 --- a/test/pool-cl/helpers/BaseCLTestHook.sol +++ b/test/pool-cl/helpers/BaseCLTestHook.sol @@ -1,19 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.24; -import { - HOOKS_BEFORE_INITIALIZE_OFFSET, - HOOKS_AFTER_INITIALIZE_OFFSET, - HOOKS_BEFORE_ADD_LIQUIDITY_OFFSET, - HOOKS_AFTER_ADD_LIQUIDITY_OFFSET, - HOOKS_BEFORE_REMOVE_LIQUIDITY_OFFSET, - HOOKS_AFTER_REMOVE_LIQUIDITY_OFFSET, - HOOKS_BEFORE_SWAP_OFFSET, - HOOKS_AFTER_SWAP_OFFSET, - HOOKS_BEFORE_DONATE_OFFSET, - HOOKS_AFTER_DONATE_OFFSET, - HOOKS_NO_OP_OFFSET -} from "../../../src/pool-cl/interfaces/ICLHooks.sol"; +import "../../../src/pool-cl/interfaces/ICLHooks.sol"; import {PoolKey} from "../../../src/types/PoolKey.sol"; import {BalanceDelta} from "../../../src/types/BalanceDelta.sol"; import {ICLHooks} from "../../../src/pool-cl/interfaces/ICLHooks.sol"; @@ -134,7 +122,6 @@ contract BaseCLTestHook is ICLHooks { | (permissions.afterSwap ? 1 << HOOKS_AFTER_SWAP_OFFSET : 0) | (permissions.beforeDonate ? 1 << HOOKS_BEFORE_DONATE_OFFSET : 0) | (permissions.afterDonate ? 1 << HOOKS_AFTER_DONATE_OFFSET : 0) - | (permissions.noOp ? 1 << HOOKS_NO_OP_OFFSET : 0) ); } } diff --git a/test/pool-cl/helpers/CLPoolManagerRouter.sol b/test/pool-cl/helpers/CLPoolManagerRouter.sol index 5820f15e..8d3f701c 100644 --- a/test/pool-cl/helpers/CLPoolManagerRouter.sol +++ b/test/pool-cl/helpers/CLPoolManagerRouter.sol @@ -9,7 +9,6 @@ import {ICLPoolManager} from "../../../src/pool-cl/interfaces/ICLPoolManager.sol import {console2} from "forge-std/console2.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {BalanceDelta, BalanceDeltaLibrary} from "../../../src/types/BalanceDelta.sol"; -import {HOOKS_NO_OP_OFFSET} from "../../../src/pool-cl/interfaces/ICLHooks.sol"; import {Hooks} from "../../../src/libraries/Hooks.sol"; contract CLPoolManagerRouter { @@ -62,13 +61,6 @@ contract CLPoolManagerRouter { ModifyPositionCallbackData memory data = abi.decode(rawData, (ModifyPositionCallbackData)); (BalanceDelta delta, BalanceDelta feeDelta) = poolManager.modifyLiquidity(data.key, data.params, data.hookData); - if (delta == BalanceDeltaLibrary.MAXIMUM_DELTA) { - // check if the hook has permission to no-op, if true, return early - if (!data.key.parameters.shouldCall(HOOKS_NO_OP_OFFSET, data.key.hooks)) { - revert HookMissingNoOpPermission(); - } - return abi.encode(delta, feeDelta); - } // For now assume to always settle feeDelta in the same way as delta BalanceDelta totalDelta = delta + feeDelta; @@ -139,14 +131,6 @@ contract CLPoolManagerRouter { BalanceDelta delta = poolManager.swap(data.key, data.params, data.hookData); - if (delta == BalanceDeltaLibrary.MAXIMUM_DELTA) { - // check if the hook has permission to no-op, if true, return early - if (!data.key.parameters.shouldCall(HOOKS_NO_OP_OFFSET, data.key.hooks)) { - revert HookMissingNoOpPermission(); - } - return abi.encode(delta); - } - if (data.params.zeroForOne) { if (delta.amount0() > 0) { if (data.testSettings.settleUsingTransfer) { @@ -231,14 +215,6 @@ contract CLPoolManagerRouter { BalanceDelta delta = poolManager.donate(data.key, data.amount0, data.amount1, data.hookData); - if (delta == BalanceDeltaLibrary.MAXIMUM_DELTA) { - // check if the hook has permission to no-op, if true, return early - if (!data.key.parameters.shouldCall(HOOKS_NO_OP_OFFSET, data.key.hooks)) { - revert HookMissingNoOpPermission(); - } - return abi.encode(delta); - } - if (delta.amount0() > 0) { if (data.key.currency0.isNative()) { vault.settle{value: uint128(delta.amount0())}(data.key.currency0); diff --git a/test/pool-cl/libraries/CLPool.t.sol b/test/pool-cl/libraries/CLPool.t.sol index 5f5160e7..965f9113 100644 --- a/test/pool-cl/libraries/CLPool.t.sol +++ b/test/pool-cl/libraries/CLPool.t.sol @@ -15,6 +15,7 @@ import {LiquidityAmounts} from "../helpers/LiquidityAmounts.sol"; import {LPFeeLibrary} from "../../../src/libraries/LPFeeLibrary.sol"; import {FullMath} from "../../../src/pool-cl/libraries/FullMath.sol"; import {FixedPoint128} from "../../../src/pool-cl/libraries/FixedPoint128.sol"; +import {ICLPoolManager} from "../../../src/pool-cl/interfaces/ICLPoolManager.sol"; contract PoolTest is Test { using CLPool for CLPool.State; @@ -101,7 +102,7 @@ contract PoolTest is Test { CLPool.Slot0 memory slot0 = state.slot0; if (swapParams.amountSpecified == 0) { - vm.expectRevert(CLPool.SwapAmountCannotBeZero.selector); + vm.expectRevert(ICLPoolManager.SwapAmountCannotBeZero.selector); } else if (swapParams.zeroForOne) { if (swapParams.sqrtPriceLimitX96 >= slot0.sqrtPriceX96) { vm.expectRevert(