diff --git a/.forge-snapshots/HooksShouldCallBeforeSwap.snap b/.forge-snapshots/HooksShouldCallBeforeSwap.snap index 3e932fe8f..d2c5ed212 100644 --- a/.forge-snapshots/HooksShouldCallBeforeSwap.snap +++ b/.forge-snapshots/HooksShouldCallBeforeSwap.snap @@ -1 +1 @@ -34 \ No newline at end of file +116 \ No newline at end of file diff --git a/.forge-snapshots/before swap hook, already cached dynamic fee.snap b/.forge-snapshots/before swap hook, already cached dynamic fee.snap index 932655da6..44d36db5e 100644 --- a/.forge-snapshots/before swap hook, already cached dynamic fee.snap +++ b/.forge-snapshots/before swap hook, already cached dynamic fee.snap @@ -1 +1 @@ -192918 \ No newline at end of file +194519 \ No newline at end of file diff --git a/.forge-snapshots/cached dynamic fee, no hooks.snap b/.forge-snapshots/cached dynamic fee, no hooks.snap index 18c4ddb93..ecc6dc509 100644 --- a/.forge-snapshots/cached dynamic fee, no hooks.snap +++ b/.forge-snapshots/cached dynamic fee, no hooks.snap @@ -1 +1 @@ -148280 \ No newline at end of file +146864 \ 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 90e7d69c3..d09eb4748 100644 --- a/.forge-snapshots/donate gas with 1 token.snap +++ b/.forge-snapshots/donate gas with 1 token.snap @@ -1 +1 @@ -139280 \ No newline at end of file +137968 \ 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 b9ab45c61..ef8943ef6 100644 --- a/.forge-snapshots/donate gas with 2 tokens.snap +++ b/.forge-snapshots/donate gas with 2 tokens.snap @@ -1 +1 @@ -186702 \ No newline at end of file +185390 \ No newline at end of file diff --git a/.forge-snapshots/initialize.snap b/.forge-snapshots/initialize.snap index c63109919..1e8ddbbcd 100644 --- a/.forge-snapshots/initialize.snap +++ b/.forge-snapshots/initialize.snap @@ -1 +1 @@ -75775 \ No newline at end of file +74268 \ No newline at end of file diff --git a/.forge-snapshots/mint with empty hook.snap b/.forge-snapshots/mint with empty hook.snap index 41a0ed1c7..f796eec15 100644 --- a/.forge-snapshots/mint with empty hook.snap +++ b/.forge-snapshots/mint with empty hook.snap @@ -1 +1 @@ -318670 \ No newline at end of file +323262 \ No newline at end of file diff --git a/.forge-snapshots/mint with native token.snap b/.forge-snapshots/mint with native token.snap index 163d757d5..1817e9ba2 100644 --- a/.forge-snapshots/mint with native token.snap +++ b/.forge-snapshots/mint with native token.snap @@ -1 +1 @@ -201474 \ No newline at end of file +200100 \ No newline at end of file diff --git a/.forge-snapshots/mint.snap b/.forge-snapshots/mint.snap index 20733ca89..ef066c96f 100644 --- a/.forge-snapshots/mint.snap +++ b/.forge-snapshots/mint.snap @@ -1 +1 @@ -201394 \ No newline at end of file +200042 \ No newline at end of file diff --git a/.forge-snapshots/mintWithEmptyHookEOAInitiated.snap b/.forge-snapshots/mintWithEmptyHookEOAInitiated.snap index 8a480b14a..d22631db9 100644 --- a/.forge-snapshots/mintWithEmptyHookEOAInitiated.snap +++ b/.forge-snapshots/mintWithEmptyHookEOAInitiated.snap @@ -1 +1 @@ -250566 \ No newline at end of file +255158 \ No newline at end of file diff --git a/.forge-snapshots/modify position with noop.snap b/.forge-snapshots/modify position with noop.snap index 71005f950..6ecd69a39 100644 --- a/.forge-snapshots/modify position with noop.snap +++ b/.forge-snapshots/modify position with noop.snap @@ -1 +1 @@ -56582 \ No newline at end of file +58201 \ No newline at end of file diff --git a/.forge-snapshots/poolManager bytecode size.snap b/.forge-snapshots/poolManager bytecode size.snap index 523760de1..533a9d3f2 100644 --- a/.forge-snapshots/poolManager bytecode size.snap +++ b/.forge-snapshots/poolManager bytecode size.snap @@ -1 +1 @@ -24030 \ No newline at end of file +23592 \ 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 a50ed13b7..e66e1bc95 100644 --- a/.forge-snapshots/simple swap with native.snap +++ b/.forge-snapshots/simple swap with native.snap @@ -1 +1 @@ -197165 \ No newline at end of file +195835 \ No newline at end of file diff --git a/.forge-snapshots/simple swap.snap b/.forge-snapshots/simple swap.snap index b894092bb..e388485d4 100644 --- a/.forge-snapshots/simple swap.snap +++ b/.forge-snapshots/simple swap.snap @@ -1 +1 @@ -205733 \ No newline at end of file +204403 \ No newline at end of file diff --git a/.forge-snapshots/simpleSwapEOAInitiated.snap b/.forge-snapshots/simpleSwapEOAInitiated.snap index b48be94ff..90ceff1c6 100644 --- a/.forge-snapshots/simpleSwapEOAInitiated.snap +++ b/.forge-snapshots/simpleSwapEOAInitiated.snap @@ -1 +1 @@ -176999 \ No newline at end of file +175669 \ No newline at end of file diff --git a/.forge-snapshots/simpleSwapNativeEOAInitiated.snap b/.forge-snapshots/simpleSwapNativeEOAInitiated.snap index 7afcfdb27..a32a609e5 100644 --- a/.forge-snapshots/simpleSwapNativeEOAInitiated.snap +++ b/.forge-snapshots/simpleSwapNativeEOAInitiated.snap @@ -1 +1 @@ -173661 \ No newline at end of file +172331 \ 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 b9d2fc13c..3838ae2e8 100644 --- a/.forge-snapshots/swap against liquidity with native token.snap +++ b/.forge-snapshots/swap against liquidity with native token.snap @@ -1 +1 @@ -127793 \ No newline at end of file +126463 \ No newline at end of file diff --git a/.forge-snapshots/swap against liquidity.snap b/.forge-snapshots/swap against liquidity.snap index 3780a96f4..9ce2e3bf8 100644 --- a/.forge-snapshots/swap against liquidity.snap +++ b/.forge-snapshots/swap against liquidity.snap @@ -1 +1 @@ -115284 \ No newline at end of file +113954 \ No newline at end of file diff --git a/.forge-snapshots/swap burn claim for input.snap b/.forge-snapshots/swap burn claim for input.snap index 34d25aec6..9390d2181 100644 --- a/.forge-snapshots/swap burn claim for input.snap +++ b/.forge-snapshots/swap burn claim for input.snap @@ -1 +1 @@ -134457 \ No newline at end of file +133127 \ No newline at end of file diff --git a/.forge-snapshots/swap mint output as claim.snap b/.forge-snapshots/swap mint output as claim.snap index d5ab856f8..12d1a218c 100644 --- a/.forge-snapshots/swap mint output as claim.snap +++ b/.forge-snapshots/swap mint output as claim.snap @@ -1 +1 @@ -217926 \ No newline at end of file +216596 \ 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 cb5df9a3e..da2a04f8e 100644 --- a/.forge-snapshots/swap with dynamic fee.snap +++ b/.forge-snapshots/swap with dynamic fee.snap @@ -1 +1 @@ -192160 \ No newline at end of file +193620 \ No newline at end of file diff --git a/.forge-snapshots/swap with hooks.snap b/.forge-snapshots/swap with hooks.snap index 81bb0fc29..54570960b 100644 --- a/.forge-snapshots/swap with hooks.snap +++ b/.forge-snapshots/swap with hooks.snap @@ -1 +1 @@ -115262 \ No newline at end of file +113932 \ No newline at end of file diff --git a/.forge-snapshots/swap with noop.snap b/.forge-snapshots/swap with noop.snap index 27088e368..876b81885 100644 --- a/.forge-snapshots/swap with noop.snap +++ b/.forge-snapshots/swap with noop.snap @@ -1 +1 @@ -49888 \ No newline at end of file +51546 \ 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 bf6b54800..4d31f4eaa 100644 --- a/.forge-snapshots/update dynamic fee in before swap.snap +++ b/.forge-snapshots/update dynamic fee in before swap.snap @@ -1 +1 @@ -198762 \ No newline at end of file +200363 \ No newline at end of file diff --git a/lib/forge-gas-snapshot b/lib/forge-gas-snapshot index 4f472f5d7..1a5804e00 160000 --- a/lib/forge-gas-snapshot +++ b/lib/forge-gas-snapshot @@ -1 +1 @@ -Subproject commit 4f472f5d7a63afa35d67ae0e2d1a2e2c353801cf +Subproject commit 1a5804e001531d580813d94e1a0f2853467202e6 diff --git a/lib/forge-std b/lib/forge-std index 6d27cc06f..2f1126975 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit 6d27cc06fb2668965cbbc533d6ac3385c91a19a3 +Subproject commit 2f112697506eab12d433a65fdc31a639548fe365 diff --git a/src/PoolManager.sol b/src/PoolManager.sol index 295694cca..e0c30663c 100644 --- a/src/PoolManager.sol +++ b/src/PoolManager.sol @@ -100,7 +100,7 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, Claims { function _checkLocker(address caller, address locker, IHooks hook) internal pure { if (caller == locker) return; - if (caller == address(hook) && hook.hasPermissionToAccessLock()) return; + if (caller == address(hook) && hook.hasPermission(Hooks.ACCESS_LOCK_FLAG)) return; revert LockedBy(locker, address(hook)); } @@ -119,14 +119,7 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, Claims { if (key.currency0 >= key.currency1) revert CurrenciesOutOfOrderOrEqual(); if (!key.hooks.isValidHookAddress(key.fee)) revert Hooks.HookAddressNotValid(address(key.hooks)); - (bool set) = Lockers.setCurrentHook(key.hooks); - - if (key.hooks.shouldCallBeforeInitialize()) { - if (key.hooks.beforeInitialize(msg.sender, key, sqrtPriceX96, hookData) != IHooks.beforeInitialize.selector) - { - revert Hooks.InvalidHookResponse(); - } - } + key.hooks.beforeInitialize(key, sqrtPriceX96, hookData); PoolId id = key.toId(); (, uint16 protocolFee) = _fetchProtocolFee(key); @@ -134,17 +127,7 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, Claims { tick = pools[id].initialize(sqrtPriceX96, protocolFee, swapFee); - if (key.hooks.shouldCallAfterInitialize()) { - if ( - key.hooks.afterInitialize(msg.sender, key, sqrtPriceX96, tick, hookData) - != IHooks.afterInitialize.selector - ) { - revert Hooks.InvalidHookResponse(); - } - } - - // We only want to clear the current hook if it was set in setCurrentHook in this execution frame. - if (set) Lockers.clearCurrentHook(); + key.hooks.afterInitialize(key, sqrtPriceX96, tick, hookData); // On intitalize we emit the key's fee, which tells us all fee settings a pool can have: either a static swap fee or dynamic swap fee and if the hook has enabled swap or withdraw fees. emit Initialize(id, key.currency0, key.currency1, key.fee, key.tickSpacing, key.hooks); @@ -199,21 +182,11 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, Claims { IPoolManager.ModifyPositionParams memory params, bytes calldata hookData ) external override noDelegateCall onlyByLocker returns (BalanceDelta delta) { - (bool set) = Lockers.setCurrentHook(key.hooks); - PoolId id = key.toId(); _checkPoolInitialized(id); - if (key.hooks.shouldCallBeforeModifyPosition()) { - bytes4 selector = key.hooks.beforeModifyPosition(msg.sender, key, params, hookData); - // Sentinel return value used to signify that a NoOp occurred. - if (key.hooks.isValidNoOpCall(selector)) { - // We only want to clear the current hook if it was set in setCurrentHook in this execution frame. - if (set) Lockers.clearCurrentHook(); - return BalanceDeltaLibrary.MAXIMUM_DELTA; - } else if (selector != IHooks.beforeModifyPosition.selector) { - revert Hooks.InvalidHookResponse(); - } + if (!key.hooks.beforeModifyPosition(key, params, hookData)) { + return BalanceDeltaLibrary.MAXIMUM_DELTA; } delta = pools[id].modifyPosition( @@ -228,17 +201,7 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, Claims { _accountPoolBalanceDelta(key, delta); - if (key.hooks.shouldCallAfterModifyPosition()) { - if ( - key.hooks.afterModifyPosition(msg.sender, key, params, delta, hookData) - != IHooks.afterModifyPosition.selector - ) { - revert Hooks.InvalidHookResponse(); - } - } - - // We only want to clear the current hook if it was set in setCurrentHook in this execution frame. - if (set) Lockers.clearCurrentHook(); + key.hooks.afterModifyPosition(key, params, delta, hookData); emit ModifyPosition(id, msg.sender, params.tickLower, params.tickUpper, params.liquidityDelta); } @@ -251,21 +214,11 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, Claims { onlyByLocker returns (BalanceDelta delta) { - (bool set) = Lockers.setCurrentHook(key.hooks); - PoolId id = key.toId(); _checkPoolInitialized(id); - if (key.hooks.shouldCallBeforeSwap()) { - bytes4 selector = key.hooks.beforeSwap(msg.sender, key, params, hookData); - // Sentinel return value used to signify that a NoOp occurred. - if (key.hooks.isValidNoOpCall(selector)) { - // We only want to clear the current hook if it was set in setCurrentHook in this execution frame. - if (set) Lockers.clearCurrentHook(); - return BalanceDeltaLibrary.MAXIMUM_DELTA; - } else if (selector != IHooks.beforeSwap.selector) { - revert Hooks.InvalidHookResponse(); - } + if (!key.hooks.beforeSwap(key, params, hookData)) { + return BalanceDeltaLibrary.MAXIMUM_DELTA; } uint256 feeForProtocol; @@ -289,14 +242,7 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, Claims { } } - if (key.hooks.shouldCallAfterSwap()) { - if (key.hooks.afterSwap(msg.sender, key, params, delta, hookData) != IHooks.afterSwap.selector) { - revert Hooks.InvalidHookResponse(); - } - } - - // We only want to clear the current hook if it was set in setCurrentHook in this execution frame. - if (set) Lockers.clearCurrentHook(); + key.hooks.afterSwap(key, params, delta, hookData); emit Swap( id, msg.sender, delta.amount0(), delta.amount1(), state.sqrtPriceX96, state.liquidity, state.tick, swapFee @@ -311,35 +257,18 @@ contract PoolManager is IPoolManager, Fees, NoDelegateCall, Claims { onlyByLocker returns (BalanceDelta delta) { - (bool set) = Lockers.setCurrentHook(key.hooks); - PoolId id = key.toId(); _checkPoolInitialized(id); - if (key.hooks.shouldCallBeforeDonate()) { - bytes4 selector = key.hooks.beforeDonate(msg.sender, key, amount0, amount1, hookData); - // Sentinel return value used to signify that a NoOp occurred. - if (key.hooks.isValidNoOpCall(selector)) { - // We only want to clear the current hook if it was set in setCurrentHook in this execution frame. - if (set) Lockers.clearCurrentHook(); - return BalanceDeltaLibrary.MAXIMUM_DELTA; - } else if (selector != IHooks.beforeDonate.selector) { - revert Hooks.InvalidHookResponse(); - } + if (!key.hooks.beforeDonate(key, amount0, amount1, hookData)) { + return BalanceDeltaLibrary.MAXIMUM_DELTA; } delta = pools[id].donate(amount0, amount1); _accountPoolBalanceDelta(key, delta); - if (key.hooks.shouldCallAfterDonate()) { - if (key.hooks.afterDonate(msg.sender, key, amount0, amount1, hookData) != IHooks.afterDonate.selector) { - revert Hooks.InvalidHookResponse(); - } - } - - // We only want to clear the current hook if it was set in setCurrentHook in this execution frame. - if (set) Lockers.clearCurrentHook(); + key.hooks.afterDonate(key, amount0, amount1, hookData); } /// @inheritdoc IPoolManager diff --git a/src/libraries/Hooks.sol b/src/libraries/Hooks.sol index d2bdc8b3a..09c68e608 100644 --- a/src/libraries/Hooks.sol +++ b/src/libraries/Hooks.sol @@ -1,8 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; +import {PoolKey} from "../types/PoolKey.sol"; import {IHooks} from "../interfaces/IHooks.sol"; -import {FeeLibrary} from "../libraries/FeeLibrary.sol"; +import {FeeLibrary} from "./FeeLibrary.sol"; +import {BalanceDelta} from "../types/BalanceDelta.sol"; +import {IPoolManager} from "../interfaces/IPoolManager.sol"; +import {Lockers} from "./Lockers.sol"; /// @notice V4 decides whether to invoke specific hooks by inspecting the leading bits of the address that /// the hooks contract is deployed to. @@ -10,6 +14,7 @@ import {FeeLibrary} from "../libraries/FeeLibrary.sol"; /// has leading bits '1001' which would cause the 'before initialize' and 'after modify position' hooks to be used. library Hooks { using FeeLibrary for uint24; + using Hooks for IHooks; uint256 internal constant BEFORE_INITIALIZE_FLAG = 1 << 159; uint256 internal constant AFTER_INITIALIZE_FLAG = 1 << 158; @@ -44,21 +49,25 @@ library Hooks { /// @notice Hook did not return its selector error InvalidHookResponse(); + /// @notice thrown when a hook call fails + error FailedHookCall(); + /// @notice Utility function intended to be used in hook constructors to ensure /// the deployed hooks address causes the intended hooks to be called /// @param permissions The hooks that are intended to be called /// @dev permissions param is memory as the function will be called from constructors function validateHookPermissions(IHooks self, Permissions memory permissions) internal pure { if ( - permissions.beforeInitialize != shouldCallBeforeInitialize(self) - || permissions.afterInitialize != shouldCallAfterInitialize(self) - || permissions.beforeModifyPosition != shouldCallBeforeModifyPosition(self) - || permissions.afterModifyPosition != shouldCallAfterModifyPosition(self) - || permissions.beforeSwap != shouldCallBeforeSwap(self) - || permissions.afterSwap != shouldCallAfterSwap(self) - || permissions.beforeDonate != shouldCallBeforeDonate(self) - || permissions.afterDonate != shouldCallAfterDonate(self) || permissions.noOp != hasPermissionToNoOp(self) - || permissions.accessLock != hasPermissionToAccessLock(self) + permissions.beforeInitialize != self.hasPermission(BEFORE_INITIALIZE_FLAG) + || permissions.afterInitialize != self.hasPermission(AFTER_INITIALIZE_FLAG) + || permissions.beforeModifyPosition != self.hasPermission(BEFORE_MODIFY_POSITION_FLAG) + || permissions.afterModifyPosition != self.hasPermission(AFTER_MODIFY_POSITION_FLAG) + || permissions.beforeSwap != self.hasPermission(BEFORE_SWAP_FLAG) + || permissions.afterSwap != self.hasPermission(AFTER_SWAP_FLAG) + || permissions.beforeDonate != self.hasPermission(BEFORE_DONATE_FLAG) + || permissions.afterDonate != self.hasPermission(AFTER_DONATE_FLAG) + || permissions.noOp != self.hasPermission(NO_OP_FLAG) + || permissions.accessLock != self.hasPermission(ACCESS_LOCK_FLAG) ) { revert HookAddressNotValid(address(self)); } @@ -69,8 +78,8 @@ library Hooks { function isValidHookAddress(IHooks hook, uint24 fee) internal pure returns (bool) { // if NoOp is allowed, at least one of beforeModifyPosition, beforeSwap and beforeDonate should be allowed if ( - hasPermissionToNoOp(hook) && !shouldCallBeforeModifyPosition(hook) && !shouldCallBeforeSwap(hook) - && !shouldCallBeforeDonate(hook) + hook.hasPermission(NO_OP_FLAG) && !hook.hasPermission(BEFORE_MODIFY_POSITION_FLAG) + && !hook.hasPermission(BEFORE_SWAP_FLAG) && !hook.hasPermission(BEFORE_DONATE_FLAG) ) { return false; } @@ -81,47 +90,165 @@ library Hooks { : (uint160(address(hook)) >= ACCESS_LOCK_FLAG || fee.isDynamicFee()); } - function shouldCallBeforeInitialize(IHooks self) internal pure returns (bool) { - return uint256(uint160(address(self))) & BEFORE_INITIALIZE_FLAG != 0; + /// @notice performs a hook call using the given calldata on the given hook + /// @return expectedSelector The selector that the hook is expected to return + /// @return selector The selector that the hook actually returned + function _callHook(IHooks self, bytes memory data) private returns (bytes4 expectedSelector, bytes4 selector) { + bool set = Lockers.setCurrentHook(self); + + assembly { + expectedSelector := mload(add(data, 0x20)) + } + + (bool success, bytes memory result) = address(self).call(data); + if (!success) _revert(result); + + selector = abi.decode(result, (bytes4)); + + // We only want to clear the current hook if it was set in setCurrentHook in this execution frame. + if (set) Lockers.clearCurrentHook(); + } + + /// @notice performs a hook call using the given calldata on the given hook + function callHook(IHooks self, bytes memory data) internal { + (bytes4 expectedSelector, bytes4 selector) = _callHook(self, data); + + if (selector != expectedSelector) { + revert InvalidHookResponse(); + } + } + + /// @notice performs a hook call using the given calldata on the given hook + /// @return shouldExecute Whether the operation should be executed or nooped + function callHookNoopable(IHooks self, bytes memory data) internal returns (bool shouldExecute) { + (bytes4 expectedSelector, bytes4 selector) = _callHook(self, data); + + if (selector == expectedSelector) { + shouldExecute = true; + } else if (selector == NO_OP_SELECTOR && self.hasPermission(NO_OP_FLAG)) { + shouldExecute = false; + } else { + revert InvalidHookResponse(); + } } - function shouldCallAfterInitialize(IHooks self) internal pure returns (bool) { - return uint256(uint160(address(self))) & AFTER_INITIALIZE_FLAG != 0; + /// @notice calls beforeInitialize hook if permissioned and validates return value + function beforeInitialize(IHooks self, PoolKey memory key, uint160 sqrtPriceX96, bytes calldata hookData) + internal + { + if (self.hasPermission(BEFORE_INITIALIZE_FLAG)) { + self.callHook( + abi.encodeWithSelector(IHooks.beforeInitialize.selector, msg.sender, key, sqrtPriceX96, hookData) + ); + } } - function shouldCallBeforeModifyPosition(IHooks self) internal pure returns (bool) { - return uint256(uint160(address(self))) & BEFORE_MODIFY_POSITION_FLAG != 0; + /// @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 + { + if (self.hasPermission(AFTER_INITIALIZE_FLAG)) { + self.callHook( + abi.encodeWithSelector(IHooks.afterInitialize.selector, msg.sender, key, sqrtPriceX96, tick, hookData) + ); + } } - function shouldCallAfterModifyPosition(IHooks self) internal pure returns (bool) { - return uint256(uint160(address(self))) & AFTER_MODIFY_POSITION_FLAG != 0; + /// @notice calls beforeModifyPosition hook if permissioned and validates return value + function beforeModifyPosition( + IHooks self, + PoolKey memory key, + IPoolManager.ModifyPositionParams memory params, + bytes calldata hookData + ) internal returns (bool shouldExecute) { + if (self.hasPermission(BEFORE_MODIFY_POSITION_FLAG)) { + shouldExecute = self.callHookNoopable( + abi.encodeWithSelector(IHooks.beforeModifyPosition.selector, msg.sender, key, params, hookData) + ); + } else { + return true; + } } - function shouldCallBeforeSwap(IHooks self) internal pure returns (bool) { - return uint256(uint160(address(self))) & BEFORE_SWAP_FLAG != 0; + /// @notice calls afterModifyPosition hook if permissioned and validates return value + function afterModifyPosition( + IHooks self, + PoolKey memory key, + IPoolManager.ModifyPositionParams memory params, + BalanceDelta delta, + bytes calldata hookData + ) internal { + if (key.hooks.hasPermission(AFTER_MODIFY_POSITION_FLAG)) { + self.callHook( + abi.encodeWithSelector(IHooks.afterModifyPosition.selector, msg.sender, key, params, delta, hookData) + ); + } } - function shouldCallAfterSwap(IHooks self) internal pure returns (bool) { - return uint256(uint160(address(self))) & AFTER_SWAP_FLAG != 0; + /// @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 + returns (bool shouldExecute) + { + if (key.hooks.hasPermission(BEFORE_SWAP_FLAG)) { + shouldExecute = self.callHookNoopable( + abi.encodeWithSelector(IHooks.beforeSwap.selector, msg.sender, key, params, hookData) + ); + } else { + return true; + } } - function shouldCallBeforeDonate(IHooks self) internal pure returns (bool) { - return uint256(uint160(address(self))) & BEFORE_DONATE_FLAG != 0; + /// @notice calls afterSwap hook if permissioned and validates return value + function afterSwap( + IHooks self, + PoolKey memory key, + IPoolManager.SwapParams memory params, + BalanceDelta delta, + bytes calldata hookData + ) internal { + if (key.hooks.hasPermission(AFTER_SWAP_FLAG)) { + self.callHook(abi.encodeWithSelector(IHooks.afterSwap.selector, msg.sender, key, params, delta, hookData)); + } } - function shouldCallAfterDonate(IHooks self) internal pure returns (bool) { - return uint256(uint160(address(self))) & AFTER_DONATE_FLAG != 0; + /// @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 + returns (bool shouldExecute) + { + if (key.hooks.hasPermission(BEFORE_DONATE_FLAG)) { + shouldExecute = self.callHookNoopable( + abi.encodeWithSelector(IHooks.beforeDonate.selector, msg.sender, key, amount0, amount1, hookData) + ); + } else { + return true; + } } - function hasPermissionToAccessLock(IHooks self) internal pure returns (bool) { - return uint256(uint160(address(self))) & ACCESS_LOCK_FLAG != 0; + /// @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 + { + if (key.hooks.hasPermission(AFTER_DONATE_FLAG)) { + self.callHook( + abi.encodeWithSelector(IHooks.afterDonate.selector, msg.sender, key, amount0, amount1, hookData) + ); + } } - function hasPermissionToNoOp(IHooks self) internal pure returns (bool) { - return uint256(uint160(address(self))) & NO_OP_FLAG != 0; + function hasPermission(IHooks self, uint256 flag) internal pure returns (bool) { + return uint256(uint160(address(self))) & flag != 0; } - function isValidNoOpCall(IHooks self, bytes4 selector) internal pure returns (bool) { - return hasPermissionToNoOp(self) && selector == NO_OP_SELECTOR; + /// @notice bubble up revert if present. Else throw FailedHookCall + function _revert(bytes memory result) private pure { + if (result.length > 0) { + assembly { + revert(add(0x20, result), mload(result)) + } + } else { + revert FailedHookCall(); + } } } diff --git a/src/test/HooksTest.sol b/src/test/HooksTest.sol index a99ec9e9b..a2c23aec2 100644 --- a/src/test/HooksTest.sol +++ b/src/test/HooksTest.sol @@ -16,40 +16,40 @@ contract HooksTest { } function shouldCallBeforeInitialize(address hookAddress) external pure returns (bool) { - return IHooks(hookAddress).shouldCallBeforeInitialize(); + return IHooks(hookAddress).hasPermission(Hooks.BEFORE_INITIALIZE_FLAG); } function shouldCallAfterInitialize(address hookAddress) external pure returns (bool) { - return IHooks(hookAddress).shouldCallAfterInitialize(); + return IHooks(hookAddress).hasPermission(Hooks.AFTER_INITIALIZE_FLAG); } function shouldCallBeforeSwap(address hookAddress) external pure returns (bool) { - return IHooks(hookAddress).shouldCallBeforeSwap(); + return IHooks(hookAddress).hasPermission(Hooks.BEFORE_SWAP_FLAG); } function shouldCallAfterSwap(address hookAddress) external pure returns (bool) { - return IHooks(hookAddress).shouldCallAfterSwap(); + return IHooks(hookAddress).hasPermission(Hooks.AFTER_SWAP_FLAG); } function shouldCallBeforeModifyPosition(address hookAddress) external pure returns (bool) { - return IHooks(hookAddress).shouldCallBeforeModifyPosition(); + return IHooks(hookAddress).hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG); } function shouldCallAfterModifyPosition(address hookAddress) external pure returns (bool) { - return IHooks(hookAddress).shouldCallAfterModifyPosition(); + return IHooks(hookAddress).hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG); } function shouldCallBeforeDonate(address hookAddress) external pure returns (bool) { - return IHooks(hookAddress).shouldCallBeforeDonate(); + return IHooks(hookAddress).hasPermission(Hooks.BEFORE_DONATE_FLAG); } function shouldCallAfterDonate(address hookAddress) external pure returns (bool) { - return IHooks(hookAddress).shouldCallAfterDonate(); + return IHooks(hookAddress).hasPermission(Hooks.AFTER_DONATE_FLAG); } function getGasCostOfShouldCall(address hookAddress) external view returns (uint256) { uint256 gasBefore = gasleft(); - IHooks(hookAddress).shouldCallBeforeSwap(); + IHooks(hookAddress).hasPermission(Hooks.BEFORE_SWAP_FLAG); return gasBefore - gasleft(); } diff --git a/src/test/PoolDonateTest.sol b/src/test/PoolDonateTest.sol index 06b6c848f..efbbd6176 100644 --- a/src/test/PoolDonateTest.sol +++ b/src/test/PoolDonateTest.sol @@ -59,10 +59,10 @@ contract PoolDonateTest is PoolTestBase, Test { (,, uint256 reserveAfter0, int256 deltaAfter0) = _fetchBalances(data.key.currency0, data.sender); (,, uint256 reserveAfter1, int256 deltaAfter1) = _fetchBalances(data.key.currency1, data.sender); - if (!data.key.hooks.hasPermissionToAccessLock()) { + if (!data.key.hooks.hasPermission(Hooks.ACCESS_LOCK_FLAG)) { assertEq(reserveBefore0, reserveAfter0); assertEq(reserveBefore1, reserveAfter1); - if (!data.key.hooks.hasPermissionToNoOp()) { + if (!data.key.hooks.hasPermission(Hooks.NO_OP_FLAG)) { assertEq(deltaAfter0, int256(data.amount0)); assertEq(deltaAfter1, int256(data.amount1)); } @@ -70,7 +70,7 @@ contract PoolDonateTest is PoolTestBase, Test { if (delta == BalanceDeltaLibrary.MAXIMUM_DELTA) { // Check that this hook is allowed to NoOp, then we can return as we dont need to settle - assertTrue(data.key.hooks.hasPermissionToNoOp(), "Invalid NoOp returned"); + assertTrue(data.key.hooks.hasPermission(Hooks.NO_OP_FLAG), "Invalid NoOp returned"); return abi.encode(delta); } diff --git a/src/test/PoolInitializeTest.sol b/src/test/PoolInitializeTest.sol index 65a29b2bd..772ae5a85 100644 --- a/src/test/PoolInitializeTest.sol +++ b/src/test/PoolInitializeTest.sol @@ -44,7 +44,7 @@ contract PoolInitializeTest is Test, PoolTestBase { int256 delta1 = manager.currencyDelta(address(this), data.key.currency1); uint256 nonZeroDC = manager.getLockNonzeroDeltaCount(); - if (!data.key.hooks.hasPermissionToAccessLock()) { + if (!data.key.hooks.hasPermission(Hooks.ACCESS_LOCK_FLAG)) { assertEq(delta0, 0, "delta0"); assertEq(delta1, 0, "delta1"); assertEq(nonZeroDC, 0, "NonzeroDeltaCount"); diff --git a/src/test/PoolModifyPositionTest.sol b/src/test/PoolModifyPositionTest.sol index c3b7a2365..0a5852529 100644 --- a/src/test/PoolModifyPositionTest.sol +++ b/src/test/PoolModifyPositionTest.sol @@ -53,12 +53,12 @@ contract PoolModifyPositionTest is Test, PoolTestBase { (,,, int256 delta1) = _fetchBalances(data.key.currency1, data.sender); // These assertions only apply in non lock-accessing pools. - if (!data.key.hooks.hasPermissionToAccessLock()) { + if (!data.key.hooks.hasPermission(Hooks.ACCESS_LOCK_FLAG)) { if (data.params.liquidityDelta > 0) { - assert(delta0 > 0 || delta1 > 0 || data.key.hooks.hasPermissionToNoOp()); + assert(delta0 > 0 || delta1 > 0 || data.key.hooks.hasPermission(Hooks.NO_OP_FLAG)); assert(!(delta0 < 0 || delta1 < 0)); } else { - assert(delta0 < 0 || delta1 < 0 || data.key.hooks.hasPermissionToNoOp()); + assert(delta0 < 0 || delta1 < 0 || data.key.hooks.hasPermission(Hooks.NO_OP_FLAG)); assert(!(delta0 > 0 || delta1 > 0)); } } diff --git a/src/test/PoolSwapTest.sol b/src/test/PoolSwapTest.sol index 805c34557..872720be3 100644 --- a/src/test/PoolSwapTest.sol +++ b/src/test/PoolSwapTest.sol @@ -68,13 +68,13 @@ contract PoolSwapTest is Test, PoolTestBase { (,, uint256 reserveAfter0, int256 deltaAfter0) = _fetchBalances(data.key.currency0, data.sender); (,, uint256 reserveAfter1, int256 deltaAfter1) = _fetchBalances(data.key.currency1, data.sender); - if (!data.key.hooks.hasPermissionToAccessLock()) { + if (!data.key.hooks.hasPermission(Hooks.ACCESS_LOCK_FLAG)) { // Hanndle assertions when the hook cannot access the lock. // IE if the hook can access the lock, the reserves before and after are not necessarily the same. Hook can "take". assertEq(reserveBefore0, reserveAfter0); assertEq(reserveBefore1, reserveAfter1); - if (!data.key.hooks.hasPermissionToNoOp()) { + if (!data.key.hooks.hasPermission(Hooks.NO_OP_FLAG)) { if (data.params.zeroForOne) { if (data.params.amountSpecified > 0) { // exact input, 0 for 1 @@ -101,7 +101,7 @@ contract PoolSwapTest is Test, PoolTestBase { if (delta == BalanceDeltaLibrary.MAXIMUM_DELTA) { // Check that this hook is allowed to NoOp, then we can return as we dont need to settle - assertTrue(data.key.hooks.hasPermissionToNoOp(), "Invalid NoOp returned"); + assertTrue(data.key.hooks.hasPermission(Hooks.NO_OP_FLAG), "Invalid NoOp returned"); return abi.encode(delta); } diff --git a/test/Hooks.t.sol b/test/Hooks.t.sol index c768c5187..b6cc5d12a 100644 --- a/test/Hooks.t.sol +++ b/test/Hooks.t.sol @@ -25,6 +25,7 @@ import {BalanceDelta} from "../src/types/BalanceDelta.sol"; contract HooksTest is Test, Deployers, GasSnapshot { using PoolIdLibrary for PoolKey; + using Hooks for IHooks; address payable ALL_HOOKS_ADDRESS = payable(0xfF00000000000000000000000000000000000000); MockHooks mockHooks; @@ -154,16 +155,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: false }) ); - assertFalse(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertFalse(Hooks.shouldCallAfterInitialize(hookAddr)); - assertFalse(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallBeforeSwap(hookAddr)); - assertFalse(Hooks.shouldCallAfterSwap(hookAddr)); - assertFalse(Hooks.shouldCallBeforeDonate(hookAddr)); - assertFalse(Hooks.shouldCallAfterDonate(hookAddr)); - assertFalse(Hooks.hasPermissionToNoOp(hookAddr)); - assertFalse(Hooks.hasPermissionToAccessLock(hookAddr)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function testValidateHookAddressBeforeInitialize(uint160 addr) public { @@ -185,16 +186,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: false }) ); - assertTrue(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertFalse(Hooks.shouldCallAfterInitialize(hookAddr)); - assertFalse(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallBeforeSwap(hookAddr)); - assertFalse(Hooks.shouldCallAfterSwap(hookAddr)); - assertFalse(Hooks.shouldCallBeforeDonate(hookAddr)); - assertFalse(Hooks.shouldCallAfterDonate(hookAddr)); - assertFalse(Hooks.hasPermissionToNoOp(hookAddr)); - assertFalse(Hooks.hasPermissionToAccessLock(hookAddr)); + assertTrue(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function testValidateHookAddressAfterInitialize(uint160 addr) public { @@ -216,16 +217,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: false }) ); - assertFalse(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertTrue(Hooks.shouldCallAfterInitialize(hookAddr)); - assertFalse(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallBeforeSwap(hookAddr)); - assertFalse(Hooks.shouldCallAfterSwap(hookAddr)); - assertFalse(Hooks.shouldCallBeforeDonate(hookAddr)); - assertFalse(Hooks.shouldCallAfterDonate(hookAddr)); - assertFalse(Hooks.hasPermissionToNoOp(hookAddr)); - assertFalse(Hooks.hasPermissionToAccessLock(hookAddr)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function testValidateHookAddressBeforeAndAfterInitialize(uint160 addr) public { @@ -246,16 +247,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: false }) ); - assertTrue(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertTrue(Hooks.shouldCallAfterInitialize(hookAddr)); - assertFalse(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallBeforeSwap(hookAddr)); - assertFalse(Hooks.shouldCallAfterSwap(hookAddr)); - assertFalse(Hooks.shouldCallBeforeDonate(hookAddr)); - assertFalse(Hooks.shouldCallAfterDonate(hookAddr)); - assertFalse(Hooks.hasPermissionToNoOp(hookAddr)); - assertFalse(Hooks.hasPermissionToAccessLock(hookAddr)); + assertTrue(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function testValidateHookAddressBeforeModify(uint160 addr) public { @@ -276,16 +277,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: false }) ); - assertFalse(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertFalse(Hooks.shouldCallAfterInitialize(hookAddr)); - assertTrue(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallBeforeSwap(hookAddr)); - assertFalse(Hooks.shouldCallAfterSwap(hookAddr)); - assertFalse(Hooks.shouldCallBeforeDonate(hookAddr)); - assertFalse(Hooks.shouldCallAfterDonate(hookAddr)); - assertFalse(Hooks.hasPermissionToNoOp(hookAddr)); - assertFalse(Hooks.hasPermissionToAccessLock(hookAddr)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function testValidateHookAddressAfterModify(uint160 addr) public { @@ -306,16 +307,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: false }) ); - assertFalse(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertFalse(Hooks.shouldCallAfterInitialize(hookAddr)); - assertFalse(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertTrue(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallBeforeSwap(hookAddr)); - assertFalse(Hooks.shouldCallAfterSwap(hookAddr)); - assertFalse(Hooks.shouldCallBeforeDonate(hookAddr)); - assertFalse(Hooks.shouldCallAfterDonate(hookAddr)); - assertFalse(Hooks.hasPermissionToNoOp(hookAddr)); - assertFalse(Hooks.hasPermissionToAccessLock(hookAddr)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function testValidateHookAddressBeforeAndAfterModify(uint160 addr) public { @@ -337,16 +338,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: false }) ); - assertFalse(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertFalse(Hooks.shouldCallAfterInitialize(hookAddr)); - assertTrue(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertTrue(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallBeforeSwap(hookAddr)); - assertFalse(Hooks.shouldCallAfterSwap(hookAddr)); - assertFalse(Hooks.shouldCallBeforeDonate(hookAddr)); - assertFalse(Hooks.shouldCallAfterDonate(hookAddr)); - assertFalse(Hooks.hasPermissionToNoOp(hookAddr)); - assertFalse(Hooks.hasPermissionToAccessLock(hookAddr)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function testValidateHookAddressBeforeInitializeAfterModify(uint160 addr) public { @@ -368,16 +369,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: false }) ); - assertTrue(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertFalse(Hooks.shouldCallAfterInitialize(hookAddr)); - assertFalse(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertTrue(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallBeforeSwap(hookAddr)); - assertFalse(Hooks.shouldCallAfterSwap(hookAddr)); - assertFalse(Hooks.shouldCallBeforeDonate(hookAddr)); - assertFalse(Hooks.shouldCallAfterDonate(hookAddr)); - assertFalse(Hooks.hasPermissionToNoOp(hookAddr)); - assertFalse(Hooks.hasPermissionToAccessLock(hookAddr)); + assertTrue(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function testValidateHookAddressBeforeSwap(uint160 addr) public { @@ -398,16 +399,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: false }) ); - assertFalse(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertFalse(Hooks.shouldCallAfterInitialize(hookAddr)); - assertFalse(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertTrue(Hooks.shouldCallBeforeSwap(hookAddr)); - assertFalse(Hooks.shouldCallAfterSwap(hookAddr)); - assertFalse(Hooks.shouldCallBeforeDonate(hookAddr)); - assertFalse(Hooks.shouldCallAfterDonate(hookAddr)); - assertFalse(Hooks.hasPermissionToNoOp(hookAddr)); - assertFalse(Hooks.hasPermissionToAccessLock(hookAddr)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function testValidateHookAddressAfterSwap(uint160 addr) public { @@ -428,16 +429,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: false }) ); - assertFalse(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertFalse(Hooks.shouldCallAfterInitialize(hookAddr)); - assertFalse(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallBeforeSwap(hookAddr)); - assertTrue(Hooks.shouldCallAfterSwap(hookAddr)); - assertFalse(Hooks.shouldCallBeforeDonate(hookAddr)); - assertFalse(Hooks.shouldCallAfterDonate(hookAddr)); - assertFalse(Hooks.hasPermissionToNoOp(hookAddr)); - assertFalse(Hooks.hasPermissionToAccessLock(hookAddr)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function testValidateHookAddressBeforeAndAfterSwap(uint160 addr) public { @@ -458,16 +459,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: false }) ); - assertFalse(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertFalse(Hooks.shouldCallAfterInitialize(hookAddr)); - assertFalse(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertTrue(Hooks.shouldCallBeforeSwap(hookAddr)); - assertTrue(Hooks.shouldCallAfterSwap(hookAddr)); - assertFalse(Hooks.shouldCallBeforeDonate(hookAddr)); - assertFalse(Hooks.shouldCallAfterDonate(hookAddr)); - assertFalse(Hooks.hasPermissionToNoOp(hookAddr)); - assertFalse(Hooks.hasPermissionToAccessLock(hookAddr)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function testValidateHookAddressBeforeDonate(uint160 addr) public { @@ -488,16 +489,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: false }) ); - assertFalse(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertFalse(Hooks.shouldCallAfterInitialize(hookAddr)); - assertFalse(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallBeforeSwap(hookAddr)); - assertFalse(Hooks.shouldCallAfterSwap(hookAddr)); - assertTrue(Hooks.shouldCallBeforeDonate(hookAddr)); - assertFalse(Hooks.shouldCallAfterDonate(hookAddr)); - assertFalse(Hooks.hasPermissionToNoOp(hookAddr)); - assertFalse(Hooks.hasPermissionToAccessLock(hookAddr)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function testValidateHookAddressAfterDonate(uint160 addr) public { @@ -518,16 +519,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: false }) ); - assertFalse(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertFalse(Hooks.shouldCallAfterInitialize(hookAddr)); - assertFalse(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallBeforeSwap(hookAddr)); - assertFalse(Hooks.shouldCallAfterSwap(hookAddr)); - assertFalse(Hooks.shouldCallBeforeDonate(hookAddr)); - assertTrue(Hooks.shouldCallAfterDonate(hookAddr)); - assertFalse(Hooks.hasPermissionToNoOp(hookAddr)); - assertFalse(Hooks.hasPermissionToAccessLock(hookAddr)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function testValidateHookAddressBeforeAndAfterDonate(uint160 addr) public { @@ -548,16 +549,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: false }) ); - assertFalse(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertFalse(Hooks.shouldCallAfterInitialize(hookAddr)); - assertFalse(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallBeforeSwap(hookAddr)); - assertFalse(Hooks.shouldCallAfterSwap(hookAddr)); - assertTrue(Hooks.shouldCallBeforeDonate(hookAddr)); - assertTrue(Hooks.shouldCallAfterDonate(hookAddr)); - assertFalse(Hooks.hasPermissionToNoOp(hookAddr)); - assertFalse(Hooks.hasPermissionToAccessLock(hookAddr)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function test_validateHookAddress_accessLock(uint160 addr) public { @@ -578,16 +579,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: true }) ); - assertFalse(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertFalse(Hooks.shouldCallAfterInitialize(hookAddr)); - assertFalse(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallBeforeSwap(hookAddr)); - assertFalse(Hooks.shouldCallAfterSwap(hookAddr)); - assertFalse(Hooks.shouldCallBeforeDonate(hookAddr)); - assertFalse(Hooks.shouldCallAfterDonate(hookAddr)); - assertFalse(Hooks.hasPermissionToNoOp(hookAddr)); - assertTrue(Hooks.hasPermissionToAccessLock(hookAddr)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function testValidateHookAddressAllHooks(uint160 addr) public { @@ -609,16 +610,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: true }) ); - assertTrue(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertTrue(Hooks.shouldCallAfterInitialize(hookAddr)); - assertTrue(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertTrue(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertTrue(Hooks.shouldCallBeforeSwap(hookAddr)); - assertTrue(Hooks.shouldCallAfterSwap(hookAddr)); - assertTrue(Hooks.shouldCallBeforeDonate(hookAddr)); - assertTrue(Hooks.shouldCallAfterDonate(hookAddr)); - assertTrue(Hooks.hasPermissionToNoOp(hookAddr)); - assertTrue(Hooks.hasPermissionToAccessLock(hookAddr)); + assertTrue(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function testValidateHookAddressNoOp(uint160 addr) public { @@ -646,16 +647,16 @@ contract HooksTest is Test, Deployers, GasSnapshot { accessLock: false }) ); - assertFalse(Hooks.shouldCallBeforeInitialize(hookAddr)); - assertFalse(Hooks.shouldCallAfterInitialize(hookAddr)); - assertTrue(Hooks.shouldCallBeforeModifyPosition(hookAddr)); - assertFalse(Hooks.shouldCallAfterModifyPosition(hookAddr)); - assertTrue(Hooks.shouldCallBeforeSwap(hookAddr)); - assertFalse(Hooks.shouldCallAfterSwap(hookAddr)); - assertTrue(Hooks.shouldCallBeforeDonate(hookAddr)); - assertFalse(Hooks.shouldCallAfterDonate(hookAddr)); - assertTrue(Hooks.hasPermissionToNoOp(hookAddr)); - assertFalse(Hooks.hasPermissionToAccessLock(hookAddr)); + assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.BEFORE_MODIFY_POSITION_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_MODIFY_POSITION_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.BEFORE_SWAP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.BEFORE_DONATE_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.AFTER_DONATE_FLAG)); + assertTrue(hookAddr.hasPermission(Hooks.NO_OP_FLAG)); + assertFalse(hookAddr.hasPermission(Hooks.ACCESS_LOCK_FLAG)); } function testValidateHookAddressFailsAllHooks(uint152 addr, uint8 mask) public { @@ -705,7 +706,7 @@ contract HooksTest is Test, Deployers, GasSnapshot { function testGas() public { snapStart("HooksShouldCallBeforeSwap"); - Hooks.shouldCallBeforeSwap(IHooks(address(0))); + IHooks(address(0)).hasPermission(Hooks.BEFORE_SWAP_FLAG); snapEnd(); }