diff --git a/.forge-snapshots/addLiquidity with empty hook.snap b/.forge-snapshots/addLiquidity with empty hook.snap index b8989b888..019c77f29 100644 --- a/.forge-snapshots/addLiquidity with empty hook.snap +++ b/.forge-snapshots/addLiquidity with empty hook.snap @@ -1 +1 @@ -265373 \ No newline at end of file +265381 \ No newline at end of file diff --git a/.forge-snapshots/addLiquidity with native token.snap b/.forge-snapshots/addLiquidity with native token.snap index d447a901c..d072cabb1 100644 --- a/.forge-snapshots/addLiquidity with native token.snap +++ b/.forge-snapshots/addLiquidity with native token.snap @@ -1 +1 @@ -140136 \ No newline at end of file +140224 \ No newline at end of file diff --git a/.forge-snapshots/addLiquidity.snap b/.forge-snapshots/addLiquidity.snap index a4f8803b5..267b1c2f5 100644 --- a/.forge-snapshots/addLiquidity.snap +++ b/.forge-snapshots/addLiquidity.snap @@ -1 +1 @@ -145453 \ No newline at end of file +145541 \ No newline at end of file diff --git a/.forge-snapshots/donate gas with 1 token.snap b/.forge-snapshots/donate gas with 1 token.snap index 5999220c5..0715154f4 100644 --- a/.forge-snapshots/donate gas with 1 token.snap +++ b/.forge-snapshots/donate gas with 1 token.snap @@ -1 +1 @@ -101049 \ No newline at end of file +101137 \ No newline at end of file diff --git a/.forge-snapshots/donate gas with 2 tokens.snap b/.forge-snapshots/donate gas with 2 tokens.snap index bef388da8..0bc63eb2a 100644 --- a/.forge-snapshots/donate gas with 2 tokens.snap +++ b/.forge-snapshots/donate gas with 2 tokens.snap @@ -1 +1 @@ -132039 \ No newline at end of file +132127 \ No newline at end of file diff --git a/.forge-snapshots/initialize.snap b/.forge-snapshots/initialize.snap index 662b3527e..9576f45df 100644 --- a/.forge-snapshots/initialize.snap +++ b/.forge-snapshots/initialize.snap @@ -1 +1 @@ -51180 \ No newline at end of file +51268 \ No newline at end of file diff --git a/.forge-snapshots/poolManager bytecode size.snap b/.forge-snapshots/poolManager bytecode size.snap index 6a63e7beb..2654fd3e0 100644 --- a/.forge-snapshots/poolManager bytecode size.snap +++ b/.forge-snapshots/poolManager bytecode size.snap @@ -1 +1 @@ -22965 \ No newline at end of file +23083 \ No newline at end of file diff --git a/.forge-snapshots/removeLiquidity with empty hook.snap b/.forge-snapshots/removeLiquidity with empty hook.snap index 60c50e8f3..a7b4c4134 100644 --- a/.forge-snapshots/removeLiquidity with empty hook.snap +++ b/.forge-snapshots/removeLiquidity with empty hook.snap @@ -1 +1 @@ -55984 \ No newline at end of file +56072 \ No newline at end of file diff --git a/.forge-snapshots/removeLiquidity with native token.snap b/.forge-snapshots/removeLiquidity with native token.snap index 91d24dd8f..5710db49c 100644 --- a/.forge-snapshots/removeLiquidity with native token.snap +++ b/.forge-snapshots/removeLiquidity with native token.snap @@ -1 +1 @@ -148170 \ No newline at end of file +148258 \ No newline at end of file diff --git a/.forge-snapshots/removeLiquidity.snap b/.forge-snapshots/removeLiquidity.snap index b5f49cf1d..1bcdd5bfe 100644 --- a/.forge-snapshots/removeLiquidity.snap +++ b/.forge-snapshots/removeLiquidity.snap @@ -1 +1 @@ -149634 \ No newline at end of file +149722 \ No newline at end of file diff --git a/.forge-snapshots/simple swap with native.snap b/.forge-snapshots/simple swap with native.snap index 11e0aff71..92d965caa 100644 --- a/.forge-snapshots/simple swap with native.snap +++ b/.forge-snapshots/simple swap with native.snap @@ -1 +1 @@ -132814 \ No newline at end of file +132902 \ No newline at end of file diff --git a/.forge-snapshots/simple swap.snap b/.forge-snapshots/simple swap.snap index 51754821b..e03d94df2 100644 --- a/.forge-snapshots/simple swap.snap +++ b/.forge-snapshots/simple swap.snap @@ -1 +1 @@ -146690 \ No newline at end of file +146778 \ No newline at end of file diff --git a/.forge-snapshots/swap against liquidity with native token.snap b/.forge-snapshots/swap against liquidity with native token.snap index 3ea3bdda3..3039612cb 100644 --- a/.forge-snapshots/swap against liquidity with native token.snap +++ b/.forge-snapshots/swap against liquidity with native token.snap @@ -1 +1 @@ -72273 \ No newline at end of file +72361 \ No newline at end of file diff --git a/.forge-snapshots/swap against liquidity.snap b/.forge-snapshots/swap against liquidity.snap index bb8dceb17..13788d81c 100644 --- a/.forge-snapshots/swap against liquidity.snap +++ b/.forge-snapshots/swap against liquidity.snap @@ -1 +1 @@ -60276 \ No newline at end of file +60364 \ No newline at end of file diff --git a/.forge-snapshots/swap burn 6909 for input.snap b/.forge-snapshots/swap burn 6909 for input.snap index 2c5d23970..07f2cf54d 100644 --- a/.forge-snapshots/swap burn 6909 for input.snap +++ b/.forge-snapshots/swap burn 6909 for input.snap @@ -1 +1 @@ -80306 \ No newline at end of file +80394 \ No newline at end of file diff --git a/.forge-snapshots/swap burn native 6909 for input.snap b/.forge-snapshots/swap burn native 6909 for input.snap index 7cf446276..505243eb6 100644 --- a/.forge-snapshots/swap burn native 6909 for input.snap +++ b/.forge-snapshots/swap burn native 6909 for input.snap @@ -1 +1 @@ -76303 \ No newline at end of file +76391 \ No newline at end of file diff --git a/.forge-snapshots/swap mint native output as 6909.snap b/.forge-snapshots/swap mint native output as 6909.snap index ef5b6e1ca..cad93df0b 100644 --- a/.forge-snapshots/swap mint native output as 6909.snap +++ b/.forge-snapshots/swap mint native output as 6909.snap @@ -1 +1 @@ -138654 \ No newline at end of file +138742 \ No newline at end of file diff --git a/.forge-snapshots/swap mint output as 6909.snap b/.forge-snapshots/swap mint output as 6909.snap index b4ba009f6..134896538 100644 --- a/.forge-snapshots/swap mint output as 6909.snap +++ b/.forge-snapshots/swap mint output as 6909.snap @@ -1 +1 @@ -155505 \ No newline at end of file +155593 \ No newline at end of file diff --git a/.forge-snapshots/swap skips hook call if hook is caller.snap b/.forge-snapshots/swap skips hook call if hook is caller.snap new file mode 100644 index 000000000..41ac906bf --- /dev/null +++ b/.forge-snapshots/swap skips hook call if hook is caller.snap @@ -0,0 +1 @@ +156254 \ No newline at end of file diff --git a/.forge-snapshots/swap with dynamic fee.snap b/.forge-snapshots/swap with dynamic fee.snap index 34409c289..1456957a2 100644 --- a/.forge-snapshots/swap with dynamic fee.snap +++ b/.forge-snapshots/swap with dynamic fee.snap @@ -1 +1 @@ -89580 \ No newline at end of file +89668 \ No newline at end of file diff --git a/.forge-snapshots/swap with hooks.snap b/.forge-snapshots/swap with hooks.snap index 14da3b121..2f3e10ebe 100644 --- a/.forge-snapshots/swap with hooks.snap +++ b/.forge-snapshots/swap with hooks.snap @@ -1 +1 @@ -60254 \ No newline at end of file +60342 \ No newline at end of file diff --git a/.forge-snapshots/update dynamic fee in before swap.snap b/.forge-snapshots/update dynamic fee in before swap.snap index ac74b3045..f44d09345 100644 --- a/.forge-snapshots/update dynamic fee in before swap.snap +++ b/.forge-snapshots/update dynamic fee in before swap.snap @@ -1 +1 @@ -140246 \ No newline at end of file +140294 \ No newline at end of file diff --git a/src/libraries/Hooks.sol b/src/libraries/Hooks.sol index 6fed8bea9..895876a2a 100644 --- a/src/libraries/Hooks.sol +++ b/src/libraries/Hooks.sol @@ -96,7 +96,6 @@ library Hooks { /// @notice performs a hook call using the given calldata on the given hook function callHook(IHooks self, bytes memory data) internal { - if (msg.sender == address(self)) return; (bytes4 expectedSelector, bytes4 selector) = _callHook(self, data); if (selector != expectedSelector) { @@ -104,9 +103,17 @@ library Hooks { } } + /// @notice modifier to prevent calling a hook if they initiated the action + modifier noSelfCall(IHooks self) { + if (msg.sender != address(self)) { + _; + } + } + /// @notice calls beforeInitialize hook if permissioned and validates return value function beforeInitialize(IHooks self, PoolKey memory key, uint160 sqrtPriceX96, bytes calldata hookData) internal + noSelfCall(self) { if (self.hasPermission(BEFORE_INITIALIZE_FLAG)) { self.callHook( @@ -118,6 +125,7 @@ library Hooks { /// @notice calls afterInitialize hook if permissioned and validates return value function afterInitialize(IHooks self, PoolKey memory key, uint160 sqrtPriceX96, int24 tick, bytes calldata hookData) internal + noSelfCall(self) { if (self.hasPermission(AFTER_INITIALIZE_FLAG)) { self.callHook( @@ -132,7 +140,7 @@ library Hooks { PoolKey memory key, IPoolManager.ModifyLiquidityParams memory params, bytes calldata hookData - ) internal { + ) internal noSelfCall(self) { if (params.liquidityDelta > 0 && self.hasPermission(BEFORE_ADD_LIQUIDITY_FLAG)) { self.callHook(abi.encodeWithSelector(IHooks.beforeAddLiquidity.selector, msg.sender, key, params, hookData)); } else if (params.liquidityDelta <= 0 && self.hasPermission(BEFORE_REMOVE_LIQUIDITY_FLAG)) { @@ -149,7 +157,7 @@ library Hooks { IPoolManager.ModifyLiquidityParams memory params, BalanceDelta delta, bytes calldata hookData - ) internal { + ) internal noSelfCall(self) { if (params.liquidityDelta > 0 && self.hasPermission(AFTER_ADD_LIQUIDITY_FLAG)) { self.callHook( abi.encodeWithSelector(IHooks.afterAddLiquidity.selector, msg.sender, key, params, delta, hookData) @@ -164,6 +172,7 @@ library Hooks { /// @notice calls beforeSwap hook if permissioned and validates return value function beforeSwap(IHooks self, PoolKey memory key, IPoolManager.SwapParams memory params, bytes calldata hookData) internal + noSelfCall(self) { if (self.hasPermission(BEFORE_SWAP_FLAG)) { self.callHook(abi.encodeWithSelector(IHooks.beforeSwap.selector, msg.sender, key, params, hookData)); @@ -177,7 +186,7 @@ library Hooks { IPoolManager.SwapParams memory params, BalanceDelta delta, bytes calldata hookData - ) internal { + ) internal noSelfCall(self) { if (self.hasPermission(AFTER_SWAP_FLAG)) { self.callHook(abi.encodeWithSelector(IHooks.afterSwap.selector, msg.sender, key, params, delta, hookData)); } @@ -186,6 +195,7 @@ library Hooks { /// @notice calls beforeDonate hook if permissioned and validates return value function beforeDonate(IHooks self, PoolKey memory key, uint256 amount0, uint256 amount1, bytes calldata hookData) internal + noSelfCall(self) { if (self.hasPermission(BEFORE_DONATE_FLAG)) { self.callHook( @@ -197,6 +207,7 @@ library Hooks { /// @notice calls afterDonate hook if permissioned and validates return value function afterDonate(IHooks self, PoolKey memory key, uint256 amount0, uint256 amount1, bytes calldata hookData) internal + noSelfCall(self) { if (self.hasPermission(AFTER_DONATE_FLAG)) { self.callHook( diff --git a/test/SkipCallsTestHook.t.sol b/test/SkipCallsTestHook.t.sol index d12609b0f..317e2aaf4 100644 --- a/test/SkipCallsTestHook.t.sol +++ b/test/SkipCallsTestHook.t.sol @@ -160,6 +160,22 @@ contract SkipCallsTest is Test, Deployers, GasSnapshot { assertEq(skipCallsTestHook.counter(), 2); } + function test_gas_beforeSwap_skipIfCalledByHook() public { + SkipCallsTestHook skipCallsTestHook = SkipCallsTestHook( + address(uint160(type(uint160).max & clearAllHookPermisssionsMask | Hooks.BEFORE_SWAP_FLAG)) + ); + + deploy(skipCallsTestHook); + approveAndAddLiquidity(skipCallsTestHook); + assertEq(skipCallsTestHook.counter(), 0); + + // swaps and increments counter + snapStart("swap skips hook call if hook is caller"); + swapRouter.swap(key, swapParams, testSettings, abi.encode(address(this))); + snapEnd(); + assertEq(skipCallsTestHook.counter(), 1); + } + function test_afterSwap_skipIfCalledByHook() public { SkipCallsTestHook skipCallsTestHook = SkipCallsTestHook( address(uint160(type(uint160).max & clearAllHookPermisssionsMask | Hooks.AFTER_SWAP_FLAG))