mirror of
https://github.com/lux-amm/v4-core.git
synced 2026-10-30 20:54:53 +00:00
1047 lines
54 KiB
Solidity
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));
|
|
}
|
|
}
|