forked from Uniswap/v4-core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Hooks.sol
101 lines (85 loc) · 4.53 KB
/
Hooks.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.19;
import {IHooks} from "../interfaces/IHooks.sol";
import {Fees} from "../libraries/Fees.sol";
/// @notice V4 decides whether to invoke specific hooks by inspecting the leading bits of the address that
/// the hooks contract is deployed to.
/// For example, a hooks contract deployed to address: 0x9000000000000000000000000000000000000000
/// has leading bits '1001' which would cause the 'before initialize' and 'after swap' hooks to be used.
library Hooks {
using Fees for uint24;
uint256 internal constant BEFORE_INITIALIZE_FLAG = 1 << 159;
uint256 internal constant AFTER_INITIALIZE_FLAG = 1 << 158;
uint256 internal constant BEFORE_MODIFY_POSITION_FLAG = 1 << 157;
uint256 internal constant AFTER_MODIFY_POSITION_FLAG = 1 << 156;
uint256 internal constant BEFORE_SWAP_FLAG = 1 << 155;
uint256 internal constant AFTER_SWAP_FLAG = 1 << 154;
uint256 internal constant BEFORE_DONATE_FLAG = 1 << 153;
uint256 internal constant AFTER_DONATE_FLAG = 1 << 152;
struct Calls {
bool beforeInitialize;
bool afterInitialize;
bool beforeModifyPosition;
bool afterModifyPosition;
bool beforeSwap;
bool afterSwap;
bool beforeDonate;
bool afterDonate;
}
/// @notice Thrown if the address will not lead to the specified hook calls being called
/// @param hooks The address of the hooks contract
error HookAddressNotValid(address hooks);
/// @notice Hook did not return its selector
error InvalidHookResponse();
/// @notice Utility function intended to be used in hook constructors to ensure
/// the deployed hooks address causes the intended hooks to be called
/// @param calls The hooks that are intended to be called
/// @dev calls param is memory as the function will be called from constructors
function validateHookAddress(IHooks self, Calls memory calls) internal pure {
if (
calls.beforeInitialize != shouldCallBeforeInitialize(self)
|| calls.afterInitialize != shouldCallAfterInitialize(self)
|| calls.beforeModifyPosition != shouldCallBeforeModifyPosition(self)
|| calls.afterModifyPosition != shouldCallAfterModifyPosition(self)
|| calls.beforeSwap != shouldCallBeforeSwap(self) || calls.afterSwap != shouldCallAfterSwap(self)
|| calls.beforeDonate != shouldCallBeforeDonate(self) || calls.afterDonate != shouldCallAfterDonate(self)
) {
revert HookAddressNotValid(address(self));
}
}
/// @notice Ensures that the hook address includes at least one hook flag or dynamic fees, or is the 0 address
/// @param hook The hook to verify
function isValidHookAddress(IHooks hook, uint24 fee) internal pure returns (bool) {
// If there is no hook contract set, then fee cannot be dynamic and there cannot be a hook fee on swap or withdrawal.
return address(hook) == address(0)
? !fee.isDynamicFee() && !fee.hasHookSwapFee() && !fee.hasHookWithdrawFee()
: (
uint160(address(hook)) >= AFTER_DONATE_FLAG || fee.isDynamicFee() || fee.hasHookSwapFee()
|| fee.hasHookWithdrawFee()
);
}
function shouldCallBeforeInitialize(IHooks self) internal pure returns (bool) {
return uint256(uint160(address(self))) & BEFORE_INITIALIZE_FLAG != 0;
}
function shouldCallAfterInitialize(IHooks self) internal pure returns (bool) {
return uint256(uint160(address(self))) & AFTER_INITIALIZE_FLAG != 0;
}
function shouldCallBeforeModifyPosition(IHooks self) internal pure returns (bool) {
return uint256(uint160(address(self))) & BEFORE_MODIFY_POSITION_FLAG != 0;
}
function shouldCallAfterModifyPosition(IHooks self) internal pure returns (bool) {
return uint256(uint160(address(self))) & AFTER_MODIFY_POSITION_FLAG != 0;
}
function shouldCallBeforeSwap(IHooks self) internal pure returns (bool) {
return uint256(uint160(address(self))) & BEFORE_SWAP_FLAG != 0;
}
function shouldCallAfterSwap(IHooks self) internal pure returns (bool) {
return uint256(uint160(address(self))) & AFTER_SWAP_FLAG != 0;
}
function shouldCallBeforeDonate(IHooks self) internal pure returns (bool) {
return uint256(uint160(address(self))) & BEFORE_DONATE_FLAG != 0;
}
function shouldCallAfterDonate(IHooks self) internal pure returns (bool) {
return uint256(uint160(address(self))) & AFTER_DONATE_FLAG != 0;
}
}