-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathVioletHooksExample.sol
159 lines (141 loc) · 5.41 KB
/
VioletHooksExample.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {BaseHook} from "v4-periphery/BaseHook.sol";
import {Hooks} from "@uniswap/v4-core/contracts/libraries/Hooks.sol";
import {IPoolManager} from "@uniswap/v4-core/contracts/interfaces/IPoolManager.sol";
import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol";
import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/contracts/types/PoolId.sol";
import {BalanceDelta} from "@uniswap/v4-core/contracts/types/BalanceDelta.sol";
import {IVioletID, VioletIDHelpers} from "./VioletIDHelpers.sol";
error UnauthorizedSender(address sender);
contract VioletHooksExample is BaseHook, VioletIDHelpers {
using PoolIdLibrary for PoolKey;
/**
* @dev Mapping from Pools to the required/blocked statusCombinationIds.
* A statusCombinationId represents the combination of multiple status IDs
* on the VioletID Registry. It is used to check if an address holds
* multiple statuses all at once.
*/
mapping(PoolId => uint256 statusCombinationId)
public requiredVioletIdStatusCombination;
mapping(PoolId => uint256 statusCombinationId)
public blockedVioletIdStatusCombination;
/**
* @dev Whitelist of senders (Swap Router, Position Manager contract...).
* This is important since we want to make sure that the sender's contract is properly
* forwarding the address of the end user who initiated the transaction.
* The assumption here is that users are not calling the PoolManager themselves directly.
* See README.md for more details.
*/
mapping(address => bool) public authorizedSender;
constructor(
IPoolManager _poolManager,
IVioletID _violetID
) BaseHook(_poolManager) VioletIDHelpers(_violetID) {}
function getHooksCalls() public pure override returns (Hooks.Calls memory) {
return
Hooks.Calls({
beforeInitialize: false,
afterInitialize: false,
beforeModifyPosition: true,
afterModifyPosition: false,
beforeSwap: true,
afterSwap: false,
beforeDonate: true,
afterDonate: false
});
}
/**
* @notice Grab the compliance requirements for a given pool and compare
* the VioletID statuses of the user against them.
* Requirements can be adjusted for each pool such that:
* - Only addresses with specific status(es) can interact with a pool
* - And/or only addresses without specific status(es) can interact with a pool
* @dev A status combination ID is a single number representing multiple statuses.
*/
modifier verifyComplianceOfUser(address user, PoolKey calldata key) {
PoolId poolId = key.toId();
// Checks that `user` has the statuses required to interact with the specified pool
uint256 requiredStatusCombinationId = requiredVioletIdStatusCombination[
poolId
];
if (requiredStatusCombinationId != 0) {
checkForRequiredVioletIDStatuses(user, requiredStatusCombinationId);
}
// Checks that `user` does NOT have the statuses barred from interacting with the specified pool
uint256 blockedStatusCombinationId = blockedVioletIdStatusCombination[
poolId
];
if (blockedStatusCombinationId != 0) {
checkForBlockedVioletIdStatuses(user, blockedStatusCombinationId);
}
_;
}
modifier isAuthorizedSender(address sender) {
if (!authorizedSender[sender]) revert UnauthorizedSender(sender);
_;
}
function beforeSwap(
address sender,
PoolKey calldata key,
IPoolManager.SwapParams calldata,
bytes calldata hookData
)
external
view
override
isAuthorizedSender(sender)
verifyComplianceOfUser(address(abi.decode(hookData, (address))), key)
returns (bytes4)
{
return BaseHook.beforeSwap.selector;
}
function beforeModifyPosition(
address sender,
PoolKey calldata key,
IPoolManager.ModifyPositionParams calldata,
bytes calldata hookData
)
external
view
override
isAuthorizedSender(sender)
verifyComplianceOfUser(address(abi.decode(hookData, (address))), key)
returns (bytes4)
{
return BaseHook.beforeModifyPosition.selector;
}
function beforeDonate(
address sender,
PoolKey calldata key,
uint256,
uint256,
bytes calldata hookData
)
external
view
override
isAuthorizedSender(sender)
verifyComplianceOfUser(address(abi.decode(hookData, (address))), key)
returns (bytes4)
{
return BaseHook.beforeDonate.selector;
}
// ↓↓↓↓↓ ADMIN FUNCTIONS ↓↓↓↓↓
// Obviously these functions would normally be permissioned.
function setRequiredVioletIdStatuses(
PoolId poolId,
uint256 statusCombinationId
) external {
requiredVioletIdStatusCombination[poolId] = statusCombinationId;
}
function setBlockedVioletIdStatuses(
PoolId poolId,
uint256 statusCombinationId
) external {
blockedVioletIdStatusCombination[poolId] = statusCombinationId;
}
function updateSenderWhitelist(address sender, bool isAuthorized) external {
authorizedSender[sender] = isAuthorized;
}
}