Files

1047 lines
54 KiB
Solidity

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import {Test} from "forge-std/Test.sol";
import {Vm} from "forge-std/Vm.sol";
import {Hooks} from "../../src/libraries/Hooks.sol";
import {LPFeeLibrary} from "../../src/libraries/LPFeeLibrary.sol";
import {MockHooks} from "../../src/test/MockHooks.sol";
import {IPoolManager} from "../../src/interfaces/IPoolManager.sol";
import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol";
import {IHooks} from "../../src/interfaces/IHooks.sol";
import {Currency} from "../../src/types/Currency.sol";
import {PoolManager} from "../../src/PoolManager.sol";
import {PoolSwapTest} from "../../src/test/PoolSwapTest.sol";
import {PoolDonateTest} from "../../src/test/PoolDonateTest.sol";
import {Deployers} from "test/utils/Deployers.sol";
import {ProtocolFees} from "../../src/ProtocolFees.sol";
import {PoolId} from "../../src/types/PoolId.sol";
import {PoolKey} from "../../src/types/PoolKey.sol";
import {ModifyLiquidityParams, SwapParams} from "../../src/types/PoolOperation.sol";
import {IERC20Minimal} from "../../src/interfaces/external/IERC20Minimal.sol";
import {BalanceDelta} from "../../src/types/BalanceDelta.sol";
import {BaseTestHooks} from "../../src/test/BaseTestHooks.sol";
import {EmptyRevertContract} from "../../src/test/EmptyRevertContract.sol";
import {StateLibrary} from "../../src/libraries/StateLibrary.sol";
import {Constants} from "../utils/Constants.sol";
import {CustomRevert} from "../../src/libraries/CustomRevert.sol";
contract HooksTest is Test, Deployers {
using Hooks for IHooks;
using StateLibrary for IPoolManager;
MockHooks mockHooks;
BaseTestHooks revertingHookImpl;
function setUp() public {
MockHooks impl = new MockHooks();
vm.etch(Constants.ALL_HOOKS, address(impl).code);
mockHooks = MockHooks(Constants.ALL_HOOKS);
revertingHookImpl = new BaseTestHooks();
initializeManagerRoutersAndPoolsWithLiq(mockHooks);
}
function test_initialize_succeedsWithHook() public {
manager.initialize(uninitializedKey, SQRT_PRICE_1_1);
(uint160 sqrtPriceX96,,,) = manager.getSlot0(uninitializedKey.toId());
assertEq(sqrtPriceX96, SQRT_PRICE_1_1);
assertEq(mockHooks.beforeInitializeData(), new bytes(123));
assertEq(mockHooks.afterInitializeData(), new bytes(123));
}
function test_beforeInitialize_invalidReturn() public {
mockHooks.setReturnValue(mockHooks.beforeInitialize.selector, bytes4(0xdeadbeef));
vm.expectRevert(Hooks.InvalidHookResponse.selector);
manager.initialize(uninitializedKey, SQRT_PRICE_1_1);
}
function test_afterInitialize_invalidReturn() public {
mockHooks.setReturnValue(mockHooks.afterInitialize.selector, bytes4(0xdeadbeef));
vm.expectRevert(Hooks.InvalidHookResponse.selector);
manager.initialize(uninitializedKey, SQRT_PRICE_1_1);
}
function test_beforeAfterAddLiquidity_beforeAfterRemoveLiquidity_succeedsWithHook() public {
MockERC20(Currency.unwrap(key.currency0)).mint(address(this), 1e18);
MockERC20(Currency.unwrap(key.currency0)).approve(address(modifyLiquidityRouter), 1e18);
modifyLiquidityRouter.modifyLiquidity(key, ModifyLiquidityParams(0, 60, 1e18, 0), new bytes(111));
assertEq(mockHooks.beforeAddLiquidityData(), new bytes(111));
assertEq(mockHooks.afterAddLiquidityData(), new bytes(111));
modifyLiquidityRouter.modifyLiquidity(key, ModifyLiquidityParams(0, 60, -1e18, 0), new bytes(222));
assertEq(mockHooks.beforeRemoveLiquidityData(), new bytes(222));
assertEq(mockHooks.afterRemoveLiquidityData(), new bytes(222));
}
function test_beforeAfterAddLiquidity_calledWithPositiveLiquidityDelta() public {
MockERC20(Currency.unwrap(key.currency0)).mint(address(this), 1e18);
MockERC20(Currency.unwrap(key.currency0)).approve(address(modifyLiquidityRouter), 1e18);
modifyLiquidityRouter.modifyLiquidity(key, ModifyLiquidityParams(0, 60, 100, 0), new bytes(111));
assertEq(mockHooks.beforeAddLiquidityData(), new bytes(111));
assertEq(mockHooks.afterAddLiquidityData(), new bytes(111));
}
function test_beforeAfterRemoveLiquidity_calledWithZeroLiquidityDelta() public {
MockERC20(Currency.unwrap(key.currency0)).mint(address(this), 1e18);
MockERC20(Currency.unwrap(key.currency0)).approve(address(modifyLiquidityRouter), 1e18);
modifyLiquidityRouter.modifyLiquidity(key, ModifyLiquidityParams(0, 60, 1e18, 0), new bytes(111));
assertEq(mockHooks.beforeAddLiquidityData(), new bytes(111));
assertEq(mockHooks.afterAddLiquidityData(), new bytes(111));
modifyLiquidityRouter.modifyLiquidity(key, ModifyLiquidityParams(0, 60, 0, 0), new bytes(222));
assertEq(mockHooks.beforeAddLiquidityData(), new bytes(111));
assertEq(mockHooks.afterAddLiquidityData(), new bytes(111));
assertEq(mockHooks.beforeRemoveLiquidityData(), new bytes(222));
assertEq(mockHooks.afterRemoveLiquidityData(), new bytes(222));
}
function test_beforeAfterRemoveLiquidity_calledWithPositiveLiquidityDelta() public {
modifyLiquidityRouter.modifyLiquidity(key, ModifyLiquidityParams(0, 60, 1e18, 0), new bytes(111));
MockERC20(Currency.unwrap(key.currency0)).mint(address(this), 1e18);
MockERC20(Currency.unwrap(key.currency0)).approve(address(modifyLiquidityRouter), 1e18);
modifyLiquidityRouter.modifyLiquidity(key, ModifyLiquidityParams(0, 60, -1e18, 0), new bytes(111));
assertEq(mockHooks.beforeRemoveLiquidityData(), new bytes(111));
assertEq(mockHooks.afterRemoveLiquidityData(), new bytes(111));
}
function test_beforeAddLiquidity_invalidReturn() public {
mockHooks.setReturnValue(mockHooks.beforeAddLiquidity.selector, bytes4(0xdeadbeef));
MockERC20(Currency.unwrap(key.currency0)).mint(address(this), 1e18);
MockERC20(Currency.unwrap(key.currency0)).approve(address(modifyLiquidityRouter), 1e18);
vm.expectRevert(Hooks.InvalidHookResponse.selector);
modifyLiquidityRouter.modifyLiquidity(key, LIQUIDITY_PARAMS, ZERO_BYTES);
}
function test_beforeRemoveLiquidity_invalidReturn() public {
mockHooks.setReturnValue(mockHooks.beforeRemoveLiquidity.selector, bytes4(0xdeadbeef));
MockERC20(Currency.unwrap(key.currency0)).mint(address(this), 1e18);
MockERC20(Currency.unwrap(key.currency0)).approve(address(modifyLiquidityRouter), 1e18);
modifyLiquidityRouter.modifyLiquidity(key, LIQUIDITY_PARAMS, ZERO_BYTES);
vm.expectRevert(Hooks.InvalidHookResponse.selector);
modifyLiquidityRouter.modifyLiquidity(key, REMOVE_LIQUIDITY_PARAMS, ZERO_BYTES);
}
function test_afterAddLiquidity_invalidReturn() public {
mockHooks.setReturnValue(mockHooks.afterAddLiquidity.selector, bytes4(0xdeadbeef));
MockERC20(Currency.unwrap(key.currency0)).mint(address(this), 1e18);
MockERC20(Currency.unwrap(key.currency0)).approve(address(modifyLiquidityRouter), 1e18);
vm.expectRevert(Hooks.InvalidHookResponse.selector);
modifyLiquidityRouter.modifyLiquidity(key, LIQUIDITY_PARAMS, ZERO_BYTES);
}
function test_afterRemoveLiquidity_invalidReturn() public {
mockHooks.setReturnValue(mockHooks.afterRemoveLiquidity.selector, bytes4(0xdeadbeef));
MockERC20(Currency.unwrap(key.currency0)).mint(address(this), 1e18);
MockERC20(Currency.unwrap(key.currency0)).approve(address(modifyLiquidityRouter), 1e18);
modifyLiquidityRouter.modifyLiquidity(key, LIQUIDITY_PARAMS, ZERO_BYTES);
vm.expectRevert(Hooks.InvalidHookResponse.selector);
modifyLiquidityRouter.modifyLiquidity(key, REMOVE_LIQUIDITY_PARAMS, ZERO_BYTES);
}
function test_swap_succeedsWithHook() public {
SwapParams memory swapParams =
SwapParams({zeroForOne: true, amountSpecified: 100, sqrtPriceLimitX96: SQRT_PRICE_1_2});
PoolSwapTest.TestSettings memory testSettings =
PoolSwapTest.TestSettings({takeClaims: false, settleUsingBurn: false});
swapRouter.swap(key, swapParams, testSettings, new bytes(222));
assertEq(mockHooks.beforeSwapData(), new bytes(222));
assertEq(mockHooks.afterSwapData(), new bytes(222));
}
function test_beforeSwap_invalidReturn() public {
mockHooks.setReturnValue(mockHooks.beforeSwap.selector, bytes4(0xdeadbeef));
vm.expectRevert(Hooks.InvalidHookResponse.selector);
swapRouter.swap(
key, SwapParams(false, 100, SQRT_PRICE_1_1 + 60), PoolSwapTest.TestSettings(true, true), ZERO_BYTES
);
}
function test_afterSwap_invalidReturn() public {
mockHooks.setReturnValue(mockHooks.afterSwap.selector, bytes4(0xdeadbeef));
vm.expectRevert(Hooks.InvalidHookResponse.selector);
swapRouter.swap(
key, SwapParams(false, 100, SQRT_PRICE_1_1 + 60), PoolSwapTest.TestSettings(true, true), ZERO_BYTES
);
}
function test_donate_succeedsWithHook() public {
donateRouter.donate(key, 100, 200, new bytes(333));
assertEq(mockHooks.beforeDonateData(), new bytes(333));
assertEq(mockHooks.afterDonateData(), new bytes(333));
}
function test_beforeDonate_invalidReturn() public {
mockHooks.setReturnValue(mockHooks.beforeDonate.selector, bytes4(0xdeadbeef));
vm.expectRevert(Hooks.InvalidHookResponse.selector);
donateRouter.donate(key, 100, 200, ZERO_BYTES);
}
function test_afterDonate_invalidReturn() public {
mockHooks.setReturnValue(mockHooks.beforeDonate.selector, bytes4(0xdeadbeef));
vm.expectRevert(Hooks.InvalidHookResponse.selector);
donateRouter.donate(key, 100, 200, ZERO_BYTES);
}
// hook validation
function test_fuzz_validateHookPermissions_noHooks(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr = IHooks(address(preAddr));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: false,
afterSwap: false,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_beforeInitialize(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr = IHooks(address(uint160(preAddr | Hooks.BEFORE_INITIALIZE_FLAG)));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: true,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: false,
afterSwap: false,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertTrue(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_afterInitialize(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr = IHooks(address(uint160(preAddr | Hooks.AFTER_INITIALIZE_FLAG)));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: true,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: false,
afterSwap: false,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_beforeAndAfterInitialize(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr = IHooks(address(uint160(preAddr | Hooks.BEFORE_INITIALIZE_FLAG | Hooks.AFTER_INITIALIZE_FLAG)));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: true,
afterInitialize: true,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: false,
afterSwap: false,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertTrue(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_beforeAddLiquidity(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr = IHooks(address(uint160(preAddr | Hooks.BEFORE_ADD_LIQUIDITY_FLAG)));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: true,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: false,
afterSwap: false,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_afterAddLiquidity(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr = IHooks(address(uint160(preAddr | Hooks.AFTER_ADD_LIQUIDITY_FLAG)));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: true,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: false,
afterSwap: false,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_beforeAndAfterAddLiquidity(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr =
IHooks(address(uint160(preAddr | Hooks.BEFORE_ADD_LIQUIDITY_FLAG | Hooks.AFTER_ADD_LIQUIDITY_FLAG)));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: true,
afterAddLiquidity: true,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: false,
afterSwap: false,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_beforeRemoveLiquidity(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr = IHooks(address(uint160(preAddr | Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG)));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: true,
afterRemoveLiquidity: false,
beforeSwap: false,
afterSwap: false,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_afterRemoveLiquidity(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr = IHooks(address(uint160(preAddr | Hooks.AFTER_REMOVE_LIQUIDITY_FLAG)));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: true,
beforeSwap: false,
afterSwap: false,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_beforeAfterRemoveLiquidity(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr =
IHooks(address(uint160(preAddr | Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG | Hooks.AFTER_REMOVE_LIQUIDITY_FLAG)));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: true,
afterRemoveLiquidity: true,
beforeSwap: false,
afterSwap: false,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_beforeInitializeAfterAddLiquidity(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr =
IHooks(address(uint160(preAddr | Hooks.BEFORE_INITIALIZE_FLAG | Hooks.AFTER_ADD_LIQUIDITY_FLAG)));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: true,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: true,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: false,
afterSwap: false,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertTrue(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_beforeSwap(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr = IHooks(address(uint160(preAddr | Hooks.BEFORE_SWAP_FLAG)));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: true,
afterSwap: false,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_afterSwap(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr = IHooks(address(uint160(preAddr | Hooks.AFTER_SWAP_FLAG)));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: false,
afterSwap: true,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_beforeAndAfterSwap(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr = IHooks(address(uint160(preAddr | Hooks.BEFORE_SWAP_FLAG | Hooks.AFTER_SWAP_FLAG)));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: true,
afterSwap: true,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_beforeDonate(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr = IHooks(address(uint160(preAddr | Hooks.BEFORE_DONATE_FLAG)));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: false,
afterSwap: false,
beforeDonate: true,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_afterDonate(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr = IHooks(address(uint160(preAddr | Hooks.AFTER_DONATE_FLAG)));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: false,
afterSwap: false,
beforeDonate: false,
afterDonate: true,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_beforeAndAfterDonate(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr = IHooks(address(uint160(preAddr | Hooks.BEFORE_DONATE_FLAG | Hooks.AFTER_DONATE_FLAG)));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: false,
afterSwap: false,
beforeDonate: true,
afterDonate: true,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertFalse(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookPermissions_allHooks(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
uint160 allHookBitsFlipped = uint160((1 << hookPermissionCount) - 1);
IHooks hookAddr = IHooks(address(uint160(preAddr) | allHookBitsFlipped));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: true,
afterInitialize: true,
beforeAddLiquidity: true,
afterAddLiquidity: true,
beforeRemoveLiquidity: true,
afterRemoveLiquidity: true,
beforeSwap: true,
afterSwap: true,
beforeDonate: true,
afterDonate: true,
beforeSwapReturnDelta: true,
afterSwapReturnDelta: true,
afterAddLiquidityReturnDelta: true,
afterRemoveLiquidityReturnDelta: true
})
);
assertTrue(hookAddr.hasPermission(Hooks.BEFORE_INITIALIZE_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.AFTER_INITIALIZE_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.BEFORE_ADD_LIQUIDITY_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_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.BEFORE_SWAP_RETURNS_DELTA_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG));
assertTrue(hookAddr.hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG));
}
function test_fuzz_validateHookAddress_failsAllHooks(uint160 addr, uint16 mask) public {
uint160 preAddr = addr & clearAllHookPermissionsMask;
// Set the upper `hooksPermissionCount` number of bits to get the full mask in uint16.
uint16 allHooksMask = uint16(~uint16(0));
// We want any combination except all hooks.
vm.assume(mask < (allHooksMask >> (16 - hookPermissionCount)));
IHooks hookAddr = IHooks(address(uint160(preAddr) | uint160(mask)));
vm.expectRevert(abi.encodeWithSelector(Hooks.HookAddressNotValid.selector, (address(hookAddr))));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: true,
afterInitialize: true,
beforeAddLiquidity: true,
afterAddLiquidity: true,
beforeRemoveLiquidity: true,
afterRemoveLiquidity: true,
beforeSwap: true,
afterSwap: true,
beforeDonate: true,
afterDonate: true,
beforeSwapReturnDelta: true,
afterSwapReturnDelta: true,
afterAddLiquidityReturnDelta: true,
afterRemoveLiquidityReturnDelta: true
})
);
}
function test_fuzz_validateHookAddress_failsNoHooks(uint160 addr, uint16 mask) public {
// we only want hookPermissionCount of mask
mask = mask >> (16 - hookPermissionCount);
uint160 preAddr = addr & clearAllHookPermissionsMask;
// We want any combination except no hooks.
vm.assume(mask != 0);
IHooks hookAddr = IHooks(address(preAddr | uint160(mask)));
vm.expectRevert(abi.encodeWithSelector(Hooks.HookAddressNotValid.selector, (address(hookAddr))));
Hooks.validateHookPermissions(
hookAddr,
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: false,
afterSwap: false,
beforeDonate: false,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
})
);
}
function test_isValidHookAddress_valid_anyFlags() public pure {
assertTrue(Hooks.isValidHookAddress(IHooks(0x0000000000000000000000000000000000002000), 3000));
assertTrue(Hooks.isValidHookAddress(IHooks(0x0000000000000000000000000000000000001000), 3000));
assertTrue(Hooks.isValidHookAddress(IHooks(0x0000000000000000000000000000000000000800), 3000));
assertTrue(Hooks.isValidHookAddress(IHooks(0x0000000000000000000000000000000000000400), 3000));
assertTrue(Hooks.isValidHookAddress(IHooks(0x0000000000000000000000000000000000000200), 3000));
assertTrue(Hooks.isValidHookAddress(IHooks(0x0000000000000000000000000000000000000100), 3000));
assertTrue(Hooks.isValidHookAddress(IHooks(0x0000000000000000000000000000000000000080), 3000));
assertTrue(Hooks.isValidHookAddress(IHooks(0x0000000000000000000000000000000000000040), 3000));
assertTrue(Hooks.isValidHookAddress(IHooks(0x0000000000000000000000000000000000000020), 3000));
assertTrue(Hooks.isValidHookAddress(IHooks(0x0000000000000000000000000000000000000010), 3000));
assertTrue(Hooks.isValidHookAddress(IHooks(0xF00040A85D5Af5BF1d1762f925BdAddc42013C00), 3000));
}
function test_isValidHookAddress_zeroAddress_fixedFee() public pure {
assertTrue(Hooks.isValidHookAddress(IHooks(address(0)), 3000));
}
function testIsValidHookAddress_invalid_zeroAddressWithDynamicFee() public pure {
assertFalse(Hooks.isValidHookAddress(IHooks(address(0)), LPFeeLibrary.DYNAMIC_FEE_FLAG));
}
function test_fuzz_isValidHookAddress_invalid_returnsDeltaWithoutHookFlag(uint160 addr) public view {
uint160 preAddr = addr & clearAllHookPermissionsMask;
IHooks hookAddr = IHooks(address(uint160(preAddr | Hooks.BEFORE_SWAP_RETURNS_DELTA_FLAG)));
assertFalse(Hooks.isValidHookAddress(hookAddr, 3000));
hookAddr = IHooks(address(uint160(preAddr | Hooks.AFTER_SWAP_RETURNS_DELTA_FLAG)));
assertFalse(Hooks.isValidHookAddress(hookAddr, 3000));
hookAddr = IHooks(address(uint160(preAddr | Hooks.AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG)));
assertFalse(Hooks.isValidHookAddress(hookAddr, 3000));
hookAddr = IHooks(address(uint160(preAddr | Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG)));
assertFalse(Hooks.isValidHookAddress(hookAddr, 3000));
}
function test_isValidHookAddress_valid_noFlagsWithDynamicFee() public pure {
assertTrue(
Hooks.isValidHookAddress(IHooks(0x1000000000000000000000000000000000000000), LPFeeLibrary.DYNAMIC_FEE_FLAG)
);
}
function test_isValidHookAddress_invalid_noFlagsNoDynamicFee() public pure {
assertFalse(Hooks.isValidHookAddress(IHooks(0x1000000000000000000000000000000000000000), 3000));
assertFalse(Hooks.isValidHookAddress(IHooks(0x0001000000000000000000000000000000004000), 3000));
assertFalse(Hooks.isValidHookAddress(IHooks(0x003840A85D5AF5bf1D1762F925BDaDdc42010000), 3000));
// not dynamic as another bit is dirty in the fee
assertFalse(
Hooks.isValidHookAddress(
IHooks(0x1000000000000000000000000000000000000000), LPFeeLibrary.DYNAMIC_FEE_FLAG | uint24(3000)
)
);
}
function test_callHook_revertsWithBubbleUp() public {
// This test executes _callHook through beforeSwap.
address beforeSwapFlag = address(uint160(Hooks.BEFORE_SWAP_FLAG));
vm.etch(beforeSwapFlag, address(revertingHookImpl).code);
BaseTestHooks revertingHook = BaseTestHooks(beforeSwapFlag);
PoolKey memory key = PoolKey(currency0, currency1, 0, 60, IHooks(revertingHook));
manager.initialize(key, SQRT_PRICE_1_1);
SwapParams memory swapParams =
SwapParams({zeroForOne: true, amountSpecified: 100, sqrtPriceLimitX96: SQRT_PRICE_1_2});
PoolSwapTest.TestSettings memory testSettings =
PoolSwapTest.TestSettings({takeClaims: false, settleUsingBurn: false});
vm.expectRevert(
abi.encodeWithSelector(
CustomRevert.WrappedError.selector,
address(revertingHook),
IHooks.beforeSwap.selector,
abi.encodeWithSelector(BaseTestHooks.HookNotImplemented.selector),
abi.encodeWithSelector(Hooks.HookCallFailed.selector)
)
);
swapRouter.swap(key, swapParams, testSettings, new bytes(0));
}
function test_callHook_revertsWithInternalErrorFailedHookCall() public {
// This test executes _callHook through beforeSwap.
EmptyRevertContract emptyRevertingHookImpl = new EmptyRevertContract();
address beforeSwapFlag = address(uint160(Hooks.BEFORE_SWAP_FLAG));
vm.etch(beforeSwapFlag, address(emptyRevertingHookImpl).code);
EmptyRevertContract revertingHook = EmptyRevertContract(beforeSwapFlag);
PoolKey memory key = PoolKey(currency0, currency1, 0, 60, IHooks(address(revertingHook)));
manager.initialize(key, SQRT_PRICE_1_1);
SwapParams memory swapParams =
SwapParams({zeroForOne: true, amountSpecified: 100, sqrtPriceLimitX96: SQRT_PRICE_1_2});
PoolSwapTest.TestSettings memory testSettings =
PoolSwapTest.TestSettings({takeClaims: false, settleUsingBurn: false});
vm.expectRevert(
abi.encodeWithSelector(
CustomRevert.WrappedError.selector,
address(beforeSwapFlag),
IHooks.beforeSwap.selector,
"",
abi.encodeWithSelector(Hooks.HookCallFailed.selector)
)
);
swapRouter.swap(key, swapParams, testSettings, new bytes(0));
}
}