Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Middleware remove #145

Open
wants to merge 88 commits into
base: base-middleware
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
62f093a
discover deltas bug
Jun1on Jul 10, 2024
fcd3b34
forbid after remove returns delta
Jun1on Jul 10, 2024
bb2641c
override deltas edge case with internal delegatecall
Jun1on Jul 11, 2024
266c61e
fix bugs
Jun1on Jul 11, 2024
43717e8
add frontrun protection
Jun1on Jul 12, 2024
8f41cf5
fix bug
Jun1on Jul 12, 2024
802f466
remove unused struct
Jun1on Jul 14, 2024
feb48f2
use msg.data instead of params
Jun1on Jul 15, 2024
26524f4
add FailedImplementationCall error
Jun1on Jul 15, 2024
f3cc913
fix removeLiquidity in tests
Jun1on Jul 15, 2024
c7353bb
increase foundry gas_limit
Jun1on Jul 16, 2024
33b1775
update to solidity ^0.8.24
Jun1on Jul 16, 2024
23a8644
enforce implementations to be mined
Jun1on Jul 17, 2024
3cb9689
enforece remove implementations to be mined
Jun1on Jul 17, 2024
a54a92e
fix breaking ci (#157)
snreynolds Jul 17, 2024
087a262
Update core in periphery (#156)
hensha256 Jul 17, 2024
f242024
Clean up repo (#159)
hensha256 Jul 18, 2024
4ecb379
add posm to issue template (#166)
snreynolds Jul 19, 2024
9d1b36e
fix PR comments
Jun1on Jul 18, 2024
7602a8a
discover deltas bug
Jun1on Jul 10, 2024
368e318
override deltas edge case with internal delegatecall
Jun1on Jul 11, 2024
5e66d57
update imports
Jun1on Jul 19, 2024
17885b9
fix conflict
Jun1on Jul 19, 2024
a9cfd38
Shared actions router (#160)
hensha256 Jul 22, 2024
e5db8e2
create variant that bans deltas
Jun1on Jul 22, 2024
1abe26d
add position manager [wip] (#141)
snreynolds Jul 23, 2024
675e85b
separate middleware if they return deltas
Jun1on Jul 23, 2024
845aa81
add more tests and fix bug
Jun1on Jul 23, 2024
b98912f
add useless variables
Jun1on Jul 23, 2024
f1a680f
force MiddlewareRemove to return delta
Jun1on Jul 23, 2024
6f094c3
fix import (#190)
dianakocsis Jul 24, 2024
181b9ea
fix failing test
Jun1on Jul 24, 2024
e13ba65
reduce gas limit to 5M
Jun1on Jul 24, 2024
a266de8
posm: Native Token (#189)
saucepoint Jul 24, 2024
800e169
add natspec
Jun1on Jul 24, 2024
d3ee037
add state view contract (#187)
snreynolds Jul 24, 2024
6c4a6b6
Safe transfer ETH in posm (#193)
hensha256 Jul 24, 2024
511ce32
Test folder cleanup (#191)
hensha256 Jul 24, 2024
51f9aae
add return value griefing test
Jun1on Jul 24, 2024
dcadfc7
use using, fix import (#195)
snreynolds Jul 25, 2024
ffde495
Update core... again (#198)
hensha256 Jul 25, 2024
1c1d153
CurrencySettler -> DeltaResolver (#186)
hensha256 Jul 25, 2024
f3fc0ac
fix overflow griefing
Jun1on Jul 25, 2024
98e7fa5
uncomment
Jun1on Jul 25, 2024
d7c5302
feat: store PoolPositionId (#196)
snreynolds Jul 25, 2024
1d1d91e
Reentrancy lock posm (#204)
hensha256 Jul 25, 2024
cb902e1
clean up with baseremove
Jun1on Jul 25, 2024
2a9026f
update against latest core (#206)
snreynolds Jul 25, 2024
b973438
remove isApprovedOrOwner from increase (#207)
dianakocsis Jul 26, 2024
540664f
test override
Jun1on Jul 26, 2024
10f748e
use position key helper instead of manually hashing (#213)
saucepoint Jul 27, 2024
2603731
feat: Use permit2 transferFrom (#208)
snreynolds Jul 29, 2024
de79c94
Routing (#58)
ewilz Jul 29, 2024
9c134d1
Support native routing (#224)
hensha256 Jul 30, 2024
a96a8f6
posm : use actions router, remove return vals (#214)
snreynolds Jul 30, 2024
f37734c
rename lib (#228)
hensha256 Jul 30, 2024
b065dcd
Add transfer support (#218)
snreynolds Jul 31, 2024
463d030
some posm tests (#194)
saucepoint Jul 31, 2024
db359ca
Decode posm params in calldata (#226)
hensha256 Jul 31, 2024
0f03176
test SafeCallback (#220)
saucepoint Jul 31, 2024
f38a66f
fix testing compiler warnings (#232)
snreynolds Jul 31, 2024
b54c7bc
remove matching flags requirement
Jun1on Jul 31, 2024
e12bd98
Merge remote-tracking branch 'origin/main' into middleware-remove
Jun1on Jul 31, 2024
eda7534
clean imports
Jun1on Jul 31, 2024
e77f698
Slippage checks routing (#233)
hensha256 Aug 1, 2024
c77742c
Optimise actions encoding (#234)
hensha256 Aug 1, 2024
1f473ec
Make _handleAction virtual in position manager (#240)
qiwu7 Aug 1, 2024
256f7a7
clean imports
Jun1on Aug 1, 2024
598b02e
chore: remove recipient from QuoteParams (#241)
ConjunctiveNormalForm Aug 1, 2024
2e1cf9b
add gas snapshots
Jun1on Aug 1, 2024
c9cbfe2
make function abstract
Jun1on Aug 1, 2024
fff8413
Multi CurrencyDeltas Library (#245)
saucepoint Aug 2, 2024
83ca829
posm slippage (#225)
saucepoint Aug 2, 2024
a421a06
Router settle with balance (#235)
hensha256 Aug 2, 2024
a44f768
posm: Clear (#243)
saucepoint Aug 2, 2024
1bbeef5
Decode router params calldata (#230)
hensha256 Aug 2, 2024
8011598
use helper function and optimize gas
Jun1on Aug 2, 2024
f8f6deb
move files from contracts to src
Jun1on Aug 2, 2024
92d6f70
create HookFees library
Jun1on Aug 2, 2024
8c91ab3
Merge branch 'main' into middleware-remove
Jun1on Aug 2, 2024
8d99c45
Merge remote-tracking branch 'origin/base-middleware' into middleware…
Jun1on Aug 2, 2024
b230ee2
fix conflicts
Jun1on Aug 2, 2024
3eab6cb
store fee in factory
Jun1on Aug 2, 2024
e52fb04
remove BaseMiddlewareFactory
Jun1on Aug 2, 2024
fb02259
Create ABOUT_MIDDLEWARE.md
Jun1on Aug 2, 2024
5e7e959
require success on override
Jun1on Aug 5, 2024
2b62627
update docs
Jun1on Aug 5, 2024
564f941
add fuzz test
Jun1on Aug 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .forge-snapshots/FullRangeAddInitialLiquidity.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
311181
310035
2 changes: 1 addition & 1 deletion .forge-snapshots/FullRangeAddLiquidity.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
122990
121849
2 changes: 1 addition & 1 deletion .forge-snapshots/FullRangeFirstSwap.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
80220
78755
2 changes: 1 addition & 1 deletion .forge-snapshots/FullRangeInitialize.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1015181
1008752
2 changes: 1 addition & 1 deletion .forge-snapshots/FullRangeRemoveLiquidity.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
110566
109419
2 changes: 1 addition & 1 deletion .forge-snapshots/FullRangeRemoveLiquidityAndRebalance.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
240044
238654
2 changes: 1 addition & 1 deletion .forge-snapshots/FullRangeSecondSwap.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
45930
44465
2 changes: 1 addition & 1 deletion .forge-snapshots/FullRangeSwap.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
79351
77891
2 changes: 1 addition & 1 deletion .forge-snapshots/TWAMMSubmitOrder.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
122336
121999
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ jobs:
with:
version: nightly

- name: Run tests
- name: Check format
run: forge fmt --check
9 changes: 0 additions & 9 deletions contracts/interfaces/IBaseHook.sol

This file was deleted.

2 changes: 1 addition & 1 deletion contracts/interfaces/IMiddlewareFactory.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
pragma solidity ^0.8.24;

interface IMiddlewareFactory {
event MiddlewareCreated(address implementation, address middleware);
Expand Down
31 changes: 20 additions & 11 deletions contracts/middleware/BaseMiddleware.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,37 @@ pragma solidity ^0.8.24;

import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {BeforeSwapDelta} from "@uniswap/v4-core/src/types/BeforeSwapDelta.sol";
import {Proxy} from "@openzeppelin/contracts/proxy/Proxy.sol";

contract BaseMiddleware is Proxy {
/**
* @notice Proxy contract that forwards calls to an implementation contract.
* @dev Inheret this contract and implement hook functions to create a middleware.
*/
abstract contract BaseMiddleware is Proxy {
/// @notice The address of the pool manager
IPoolManager public immutable poolManager;
/// @dev Use in middleware implementations to access the pool manager
IPoolManager public immutable manager;

/// @notice The address of the implementation contract. All calls to this contract will be forwarded to implementation.
address public immutable implementation;

constructor(IPoolManager _poolManager, address _impl) {
poolManager = _poolManager;
error FlagsMismatch();

constructor(IPoolManager _manager, address _impl) {
_ensureValidFlags(_impl);
manager = _manager;
implementation = _impl;
}

function _implementation() internal view override returns (address) {
return implementation;
}

// yo i wanna delete this function but how do i remove this warning
receive() external payable {
_delegate(_implementation());
/// @notice Ensure that the implementation contract has the correct hook flags.
/// @dev Override to enforce hook flags.
function _ensureValidFlags(address _impl) internal view virtual {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason the implementation needs to have the same flags as the middleware?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, will remove this actually

if (uint160(address(this)) & Hooks.ALL_HOOK_MASK != uint160(_impl) & Hooks.ALL_HOOK_MASK) {
revert FlagsMismatch();
}
}
}
18 changes: 6 additions & 12 deletions contracts/middleware/BaseMiddlewareFactory.sol
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
pragma solidity ^0.8.24;

import {IMiddlewareFactory} from "../interfaces/IMiddlewareFactory.sol";
import {BaseMiddleware} from "./BaseMiddleware.sol";
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
import {IBaseHook} from "../interfaces/IBaseHook.sol";

contract BaseMiddlewareFactory is IMiddlewareFactory {
abstract contract BaseMiddlewareFactory is IMiddlewareFactory {
mapping(address => address) private _implementations;

IPoolManager public immutable poolManager;
IPoolManager public immutable manager;

constructor(IPoolManager _poolManager) {
poolManager = _poolManager;
constructor(IPoolManager _manager) {
manager = _manager;
}

function getImplementation(address middleware) external view override returns (address implementation) {
Expand All @@ -23,12 +20,9 @@ contract BaseMiddlewareFactory is IMiddlewareFactory {

function createMiddleware(address implementation, bytes32 salt) external override returns (address middleware) {
middleware = _deployMiddleware(implementation, salt);
Hooks.validateHookPermissions(IHooks(middleware), IBaseHook(implementation).getHookPermissions());
_implementations[middleware] = implementation;
emit MiddlewareCreated(implementation, middleware);
}

function _deployMiddleware(address implementation, bytes32 salt) internal virtual returns (address middleware) {
return address(new BaseMiddleware{salt: salt}(poolManager, implementation));
}
function _deployMiddleware(address implementation, bytes32 salt) internal virtual returns (address middleware) {}
}
64 changes: 64 additions & 0 deletions contracts/middleware/BaseRemove.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {BalanceDelta, BalanceDeltaLibrary} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {Proxy} from "@openzeppelin/contracts/proxy/Proxy.sol";
import {BaseMiddleware} from "./BaseMiddleware.sol";
import {BaseHook} from "../BaseHook.sol";
import {BalanceDeltaLibrary} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
import {TransientStateLibrary} from "@uniswap/v4-core/src/libraries/TransientStateLibrary.sol";

abstract contract BaseRemove is BaseMiddleware {
using TransientStateLibrary for IPoolManager;

error HookPermissionForbidden(address hooks);
error HookModifiedDeltas();
error FailedImplementationCall();

bytes internal constant ZERO_BYTES = bytes("");
uint256 public constant GAS_LIMIT = 5_000_000;
uint256 public constant MAX_BIPS = 10_000;

// use this hookdata to override checks to save gas. keccak256("override") - 1
bytes32 constant OVERRIDE_BYTES = 0x23b70c8dec38c3dec67a5596870027b04c4058cb3ac57b4e589bf628ac6669e7;

uint256 public immutable maxFeeBips;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why declare this variable in this contract? seems like its never used here, and actually the implementing contract would set this value?

Copy link
Contributor Author

@Jun1on Jun1on Jul 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i was thinking it was better for standardization. if a third party calls a middleware and wants to read its maxFee, it would return zero.


constructor(IPoolManager _manager, address _impl) BaseMiddleware(_manager, _impl) {}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add natspec!, this would be a good spot to document the hookData param as well

function beforeRemoveLiquidity(
address sender,
PoolKey calldata key,
IPoolManager.ModifyLiquidityParams calldata params,
bytes calldata hookData
) external returns (bytes4) {
if (bytes32(hookData) == OVERRIDE_BYTES) {
(bool success, bytes memory returnData) = address(implementation).delegatecall(
abi.encodeWithSelector(this.beforeRemoveLiquidity.selector, sender, key, params, hookData[32:])
);
return BaseHook.beforeRemoveLiquidity.selector;
return abi.decode(returnData, (bytes4));
Jun1on marked this conversation as resolved.
Show resolved Hide resolved
}
address(this).delegatecall{gas: GAS_LIMIT}(
abi.encodeWithSelector(this._beforeRemoveLiquidity.selector, msg.data)
);
return BaseHook.beforeRemoveLiquidity.selector;
Jun1on marked this conversation as resolved.
Show resolved Hide resolved
}

function _beforeRemoveLiquidity(bytes calldata data) external {
(bool success, bytes memory returnData) = address(implementation).delegatecall(data);
if (!success) {
revert FailedImplementationCall();
}
(bytes4 selector) = abi.decode(returnData, (bytes4));
if (selector != BaseHook.beforeRemoveLiquidity.selector) {
revert Hooks.InvalidHookResponse();
}
if (manager.getNonzeroDeltaCount() != 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

technically nonzeroDeltaCount could be nonzero so long as its the same value that it was before the delegatecall to the impl

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right. while i initially thought of only the user case where someone removes liquidity through posm, someone could purpousely make nonzeroDeltaCount != 0 to circumvent the hook.

revert HookModifiedDeltas();
}
}
}
128 changes: 128 additions & 0 deletions contracts/middleware/MiddlewareRemove.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {BalanceDelta, BalanceDeltaLibrary} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {Proxy} from "@openzeppelin/contracts/proxy/Proxy.sol";
import {BaseRemove} from "./BaseRemove.sol";
import {BaseHook} from "../BaseHook.sol";
import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
import {CustomRevert} from "@uniswap/v4-core/src/libraries/CustomRevert.sol";
import {NonZeroDeltaCount} from "@uniswap/v4-core/src/libraries/NonZeroDeltaCount.sol";
import {TransientStateLibrary} from "@uniswap/v4-core/src/libraries/TransientStateLibrary.sol";

contract MiddlewareRemove is BaseRemove {
using CustomRevert for bytes4;
using Hooks for IHooks;
using TransientStateLibrary for IPoolManager;

error HookModifiedDeltasBeforeRemove();
error HookTookTooMuchFee();
error HookInvalidDeltasAfterRemove();
error MaxFeeBipsTooHigh();

constructor(IPoolManager _manager, address _impl, uint256 _maxFeeBips) BaseRemove(_manager, _impl) {
if (_maxFeeBips > MAX_BIPS) revert MaxFeeBipsTooHigh();
maxFeeBips = _maxFeeBips;
}

function afterRemoveLiquidity(
address sender,
PoolKey calldata key,
IPoolManager.ModifyLiquidityParams calldata params,
BalanceDelta delta,
bytes calldata hookData
) external returns (bytes4, BalanceDelta) {
if (bytes32(hookData) == OVERRIDE_BYTES) {
(, bytes memory returnData) = address(implementation).delegatecall(
abi.encodeWithSelector(this.afterRemoveLiquidity.selector, sender, key, params, delta, hookData[32:])
);
return abi.decode(returnData, (bytes4, BalanceDelta));
}
(bool success, bytes memory returnData) = address(this).delegatecall{gas: GAS_LIMIT}(
Jun1on marked this conversation as resolved.
Show resolved Hide resolved
abi.encodeWithSelector(this._callAndEnsureValidDeltas.selector, sender, key, params, delta, hookData)
);
if (success) {
return (BaseHook.afterRemoveLiquidity.selector, abi.decode(returnData, (BalanceDelta)));
} else {
return (BaseHook.afterRemoveLiquidity.selector, BalanceDeltaLibrary.ZERO_DELTA);
}
}

function _callAndEnsureValidDeltas(
address sender,
PoolKey calldata key,
IPoolManager.ModifyLiquidityParams calldata params,
BalanceDelta delta,
bytes calldata hookData
) external returns (BalanceDelta) {
(bool success, bytes memory returnData) = address(implementation).delegatecall(
abi.encodeWithSelector(this.afterRemoveLiquidity.selector, sender, key, params, delta, hookData)
);
if (!success) {
revert FailedImplementationCall();
}
(bytes4 selector, BalanceDelta returnDelta) = abi.decode(returnData, (bytes4, BalanceDelta));
if (selector != BaseHook.afterRemoveLiquidity.selector) {
revert Hooks.InvalidHookResponse();
}
uint256 nonzeroDeltaCount = manager.getNonzeroDeltaCount();
if (nonzeroDeltaCount == 0 && returnDelta == BalanceDeltaLibrary.ZERO_DELTA) {
return returnDelta;
}
if (
returnDelta.amount0() > int256(uint256(int256(delta.amount0())) * maxFeeBips / MAX_BIPS)
|| returnDelta.amount1() > int256(uint256(int256(delta.amount1())) * maxFeeBips / MAX_BIPS)
) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

throw this in a library to make this code path more readable! and since you are doing this calculation twice.. maybe something like:

feeTake0, feeTaken1 = returnDelta.calculateFeesFrom(delta)
if (maxFee0 > feeTaken0 || maxFee1 > feeTaken1) revert HookTookTooMuchFee();

revert HookTookTooMuchFee();
}
// error on overflow
returnDelta - delta;
uint256 nonzeroHookDeltaCount;
int256 hookDelta = manager.currencyDelta(address(this), key.currency0);
if (hookDelta != 0) {
if (-hookDelta != returnDelta.amount0()) {
revert HookInvalidDeltasAfterRemove();
}
nonzeroHookDeltaCount++;
if (nonzeroHookDeltaCount == nonzeroDeltaCount) {
return returnDelta;
}
}
hookDelta = manager.currencyDelta(address(this), key.currency1);
if (hookDelta != 0) {
if (-hookDelta != returnDelta.amount1()) {
revert HookInvalidDeltasAfterRemove();
}
nonzeroHookDeltaCount++;
if (nonzeroHookDeltaCount == nonzeroDeltaCount) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this not the same code twice? also Im confused what this is checking? put into helper to reduce code repetition

return returnDelta;
}
}

// weird edge case in case the hook settled the caller's deltas
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you planning on removing? i think we should probably be ok with a hook settling a callers deltas (thats safe behavior)

// can prob delete this
// if (manager.currencyDelta(sender, key.currency0) != 0) {
// nonzeroHookDeltaCount++;
// }
// if (manager.currencyDelta(sender, key.currency1) != 0) {
// nonzeroHookDeltaCount++;
// }
// if (nonzeroHookDeltaCount == nonzeroDeltaCount) {
// return returnDelta;
// }

revert HookInvalidDeltasAfterRemove();
}

function _ensureValidFlags(address _impl) internal view virtual override {
if (uint160(address(this)) & Hooks.ALL_HOOK_MASK != uint160(_impl) & Hooks.ALL_HOOK_MASK) {
revert FlagsMismatch();
}
if (!IHooks(address(this)).hasPermission(Hooks.AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG)) {
HookPermissionForbidden.selector.revertWith(address(this));
}
}
}
Loading
Loading