@zoralabs/coins 2.3.1 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build$colon$js.log +115 -116
- package/CHANGELOG.md +24 -0
- package/abis/BaseTest.json +3 -3
- package/abis/FeeEstimatorHook.json +23 -0
- package/abis/ITrustedMsgSenderProviderLookup.json +21 -0
- package/abis/IZoraV4CoinHook.json +5 -0
- package/abis/TrustedMsgSenderProviderLookup.json +215 -0
- package/abis/VmContractHelper242.json +233 -0
- package/abis/ZoraV4CoinHook.json +21 -3
- package/foundry.toml +5 -1
- package/package.json +3 -3
- package/script/DeployTrustedMsgSenderLookup.s.sol +20 -0
- package/src/deployment/CoinsDeployerBase.sol +22 -1
- package/src/hooks/ZoraV4CoinHook.sol +19 -55
- package/src/interfaces/ITrustedMsgSenderProviderLookup.sol +18 -0
- package/src/interfaces/IZoraV4CoinHook.sol +3 -0
- package/src/libs/HooksDeployment.sol +9 -8
- package/src/libs/V4Liquidity.sol +50 -6
- package/src/utils/TrustedMsgSenderProviderLookup.sol +73 -0
- package/src/version/ContractVersionBase.sol +1 -1
- package/test/CreatorCoinRewards.t.sol +4 -0
- package/test/HooksDeployment.t.sol +58 -6
- package/test/LiquidityMigration.t.sol +6 -2
- package/test/TrustedMsgSenderProviderLookup.t.sol +112 -0
- package/test/Upgrades.t.sol +15 -10
- package/test/utils/BaseTest.sol +35 -9
- package/test/utils/FeeEstimatorHook.sol +3 -1
- package/test/utils/TrustedSenderTestHelper.sol +18 -0
- /package/abis/{VmContractHelper239.json → VmContractHelper235.json} +0 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"type": "function",
|
|
4
|
+
"name": "deployCode",
|
|
5
|
+
"inputs": [
|
|
6
|
+
{
|
|
7
|
+
"name": "_artifact",
|
|
8
|
+
"type": "string",
|
|
9
|
+
"internalType": "string"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"name": "_value",
|
|
13
|
+
"type": "uint256",
|
|
14
|
+
"internalType": "uint256"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "_salt",
|
|
18
|
+
"type": "bytes32",
|
|
19
|
+
"internalType": "bytes32"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"outputs": [
|
|
23
|
+
{
|
|
24
|
+
"name": "",
|
|
25
|
+
"type": "address",
|
|
26
|
+
"internalType": "address"
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"stateMutability": "nonpayable"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"type": "function",
|
|
33
|
+
"name": "deployCode",
|
|
34
|
+
"inputs": [
|
|
35
|
+
{
|
|
36
|
+
"name": "_artifact",
|
|
37
|
+
"type": "string",
|
|
38
|
+
"internalType": "string"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name": "_args",
|
|
42
|
+
"type": "bytes",
|
|
43
|
+
"internalType": "bytes"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "_salt",
|
|
47
|
+
"type": "bytes32",
|
|
48
|
+
"internalType": "bytes32"
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"outputs": [
|
|
52
|
+
{
|
|
53
|
+
"name": "",
|
|
54
|
+
"type": "address",
|
|
55
|
+
"internalType": "address"
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"stateMutability": "nonpayable"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"type": "function",
|
|
62
|
+
"name": "deployCode",
|
|
63
|
+
"inputs": [
|
|
64
|
+
{
|
|
65
|
+
"name": "_artifact",
|
|
66
|
+
"type": "string",
|
|
67
|
+
"internalType": "string"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "_value",
|
|
71
|
+
"type": "uint256",
|
|
72
|
+
"internalType": "uint256"
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"outputs": [
|
|
76
|
+
{
|
|
77
|
+
"name": "",
|
|
78
|
+
"type": "address",
|
|
79
|
+
"internalType": "address"
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
"stateMutability": "nonpayable"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"type": "function",
|
|
86
|
+
"name": "deployCode",
|
|
87
|
+
"inputs": [
|
|
88
|
+
{
|
|
89
|
+
"name": "_artifact",
|
|
90
|
+
"type": "string",
|
|
91
|
+
"internalType": "string"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"name": "_salt",
|
|
95
|
+
"type": "bytes32",
|
|
96
|
+
"internalType": "bytes32"
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
"outputs": [
|
|
100
|
+
{
|
|
101
|
+
"name": "",
|
|
102
|
+
"type": "address",
|
|
103
|
+
"internalType": "address"
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
"stateMutability": "nonpayable"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"type": "function",
|
|
110
|
+
"name": "deployCode",
|
|
111
|
+
"inputs": [
|
|
112
|
+
{
|
|
113
|
+
"name": "_artifact",
|
|
114
|
+
"type": "string",
|
|
115
|
+
"internalType": "string"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"name": "_args",
|
|
119
|
+
"type": "bytes",
|
|
120
|
+
"internalType": "bytes"
|
|
121
|
+
}
|
|
122
|
+
],
|
|
123
|
+
"outputs": [
|
|
124
|
+
{
|
|
125
|
+
"name": "",
|
|
126
|
+
"type": "address",
|
|
127
|
+
"internalType": "address"
|
|
128
|
+
}
|
|
129
|
+
],
|
|
130
|
+
"stateMutability": "nonpayable"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"type": "function",
|
|
134
|
+
"name": "deployCode",
|
|
135
|
+
"inputs": [
|
|
136
|
+
{
|
|
137
|
+
"name": "_artifact",
|
|
138
|
+
"type": "string",
|
|
139
|
+
"internalType": "string"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"name": "_args",
|
|
143
|
+
"type": "bytes",
|
|
144
|
+
"internalType": "bytes"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"name": "_value",
|
|
148
|
+
"type": "uint256",
|
|
149
|
+
"internalType": "uint256"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"name": "_salt",
|
|
153
|
+
"type": "bytes32",
|
|
154
|
+
"internalType": "bytes32"
|
|
155
|
+
}
|
|
156
|
+
],
|
|
157
|
+
"outputs": [
|
|
158
|
+
{
|
|
159
|
+
"name": "",
|
|
160
|
+
"type": "address",
|
|
161
|
+
"internalType": "address"
|
|
162
|
+
}
|
|
163
|
+
],
|
|
164
|
+
"stateMutability": "nonpayable"
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"type": "function",
|
|
168
|
+
"name": "deployCode",
|
|
169
|
+
"inputs": [
|
|
170
|
+
{
|
|
171
|
+
"name": "_artifact",
|
|
172
|
+
"type": "string",
|
|
173
|
+
"internalType": "string"
|
|
174
|
+
}
|
|
175
|
+
],
|
|
176
|
+
"outputs": [
|
|
177
|
+
{
|
|
178
|
+
"name": "",
|
|
179
|
+
"type": "address",
|
|
180
|
+
"internalType": "address"
|
|
181
|
+
}
|
|
182
|
+
],
|
|
183
|
+
"stateMutability": "nonpayable"
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"type": "function",
|
|
187
|
+
"name": "deployCode",
|
|
188
|
+
"inputs": [
|
|
189
|
+
{
|
|
190
|
+
"name": "_artifact",
|
|
191
|
+
"type": "string",
|
|
192
|
+
"internalType": "string"
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"name": "_args",
|
|
196
|
+
"type": "bytes",
|
|
197
|
+
"internalType": "bytes"
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"name": "_value",
|
|
201
|
+
"type": "uint256",
|
|
202
|
+
"internalType": "uint256"
|
|
203
|
+
}
|
|
204
|
+
],
|
|
205
|
+
"outputs": [
|
|
206
|
+
{
|
|
207
|
+
"name": "",
|
|
208
|
+
"type": "address",
|
|
209
|
+
"internalType": "address"
|
|
210
|
+
}
|
|
211
|
+
],
|
|
212
|
+
"stateMutability": "nonpayable"
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"type": "function",
|
|
216
|
+
"name": "getCode",
|
|
217
|
+
"inputs": [
|
|
218
|
+
{
|
|
219
|
+
"name": "_artifact",
|
|
220
|
+
"type": "string",
|
|
221
|
+
"internalType": "string"
|
|
222
|
+
}
|
|
223
|
+
],
|
|
224
|
+
"outputs": [
|
|
225
|
+
{
|
|
226
|
+
"name": "",
|
|
227
|
+
"type": "bytes",
|
|
228
|
+
"internalType": "bytes"
|
|
229
|
+
}
|
|
230
|
+
],
|
|
231
|
+
"stateMutability": "nonpayable"
|
|
232
|
+
}
|
|
233
|
+
]
|
package/abis/ZoraV4CoinHook.json
CHANGED
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
"internalType": "contract IDeployedCoinVersionLookup"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
|
-
"name": "
|
|
17
|
-
"type": "address
|
|
18
|
-
"internalType": "
|
|
16
|
+
"name": "trustedMsgSenderLookup_",
|
|
17
|
+
"type": "address",
|
|
18
|
+
"internalType": "contract ITrustedMsgSenderProviderLookup"
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"name": "upgradeGate_",
|
|
@@ -1037,6 +1037,19 @@
|
|
|
1037
1037
|
],
|
|
1038
1038
|
"stateMutability": "view"
|
|
1039
1039
|
},
|
|
1040
|
+
{
|
|
1041
|
+
"type": "function",
|
|
1042
|
+
"name": "getTrustedMsgSenderLookup",
|
|
1043
|
+
"inputs": [],
|
|
1044
|
+
"outputs": [
|
|
1045
|
+
{
|
|
1046
|
+
"name": "",
|
|
1047
|
+
"type": "address",
|
|
1048
|
+
"internalType": "contract ITrustedMsgSenderProviderLookup"
|
|
1049
|
+
}
|
|
1050
|
+
],
|
|
1051
|
+
"stateMutability": "view"
|
|
1052
|
+
},
|
|
1040
1053
|
{
|
|
1041
1054
|
"type": "function",
|
|
1042
1055
|
"name": "initializeFromMigration",
|
|
@@ -1845,6 +1858,11 @@
|
|
|
1845
1858
|
}
|
|
1846
1859
|
]
|
|
1847
1860
|
},
|
|
1861
|
+
{
|
|
1862
|
+
"type": "error",
|
|
1863
|
+
"name": "TrustedMsgSenderLookupCannotBeZeroAddress",
|
|
1864
|
+
"inputs": []
|
|
1865
|
+
},
|
|
1848
1866
|
{
|
|
1849
1867
|
"type": "error",
|
|
1850
1868
|
"name": "UpgradeGateCannotBeZeroAddress",
|
package/foundry.toml
CHANGED
|
@@ -5,7 +5,7 @@ libs = ["node_modules"]
|
|
|
5
5
|
via_ir = true
|
|
6
6
|
optimizer = true
|
|
7
7
|
solc_version = '0.8.28'
|
|
8
|
-
optimizer_runs =
|
|
8
|
+
optimizer_runs = 100
|
|
9
9
|
dynamic_test_linking = true
|
|
10
10
|
fs_permissions = [
|
|
11
11
|
{ access = "readwrite", path = "./addresses" },
|
|
@@ -16,6 +16,10 @@ fs_permissions = [
|
|
|
16
16
|
{ access = "read", path = "../shared-contracts/deterministicConfig" }
|
|
17
17
|
]
|
|
18
18
|
|
|
19
|
+
[profile.dev]
|
|
20
|
+
via_ir = true
|
|
21
|
+
optimizer = false
|
|
22
|
+
|
|
19
23
|
[profile.ci.fuzz]
|
|
20
24
|
runs = 100
|
|
21
25
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zoralabs/coins",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"tsx": "^3.13.0",
|
|
36
36
|
"typescript": "^5.2.2",
|
|
37
37
|
"viem": "^2.21.18",
|
|
38
|
-
"@zoralabs/shared-contracts": "^0.0.5",
|
|
39
38
|
"@zoralabs/shared-scripts": "^0.0.0",
|
|
40
|
-
"@zoralabs/tsconfig": "^0.0.1"
|
|
39
|
+
"@zoralabs/tsconfig": "^0.0.1",
|
|
40
|
+
"@zoralabs/shared-contracts": "^0.0.5"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "forge build",
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
|
+
|
|
4
|
+
import {CoinsDeployerBase} from "../src/deployment/CoinsDeployerBase.sol";
|
|
5
|
+
|
|
6
|
+
contract DeployTrustedMsgSenderLookup is CoinsDeployerBase {
|
|
7
|
+
function run() public {
|
|
8
|
+
CoinsDeployment memory deployment = readDeployment();
|
|
9
|
+
|
|
10
|
+
vm.startBroadcast();
|
|
11
|
+
|
|
12
|
+
// Deploy the trusted message sender lookup contract
|
|
13
|
+
deployment = deployTrustedMsgSenderLookup(deployment);
|
|
14
|
+
|
|
15
|
+
vm.stopBroadcast();
|
|
16
|
+
|
|
17
|
+
// Save the updated deployment json
|
|
18
|
+
saveDeployment(deployment);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -19,6 +19,8 @@ import {CreatorCoin} from "../CreatorCoin.sol";
|
|
|
19
19
|
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
|
|
20
20
|
import {HookUpgradeGate} from "../hooks/HookUpgradeGate.sol";
|
|
21
21
|
import {BuySupplyWithV4SwapHook} from "../hooks/deployment/BuySupplyWithV4SwapHook.sol";
|
|
22
|
+
import {TrustedMsgSenderProviderLookup} from "../utils/TrustedMsgSenderProviderLookup.sol";
|
|
23
|
+
import {ITrustedMsgSenderProviderLookup} from "../interfaces/ITrustedMsgSenderProviderLookup.sol";
|
|
22
24
|
|
|
23
25
|
contract CoinsDeployerBase is ProxyDeployerScript {
|
|
24
26
|
address internal constant PROTOCOL_REWARDS = 0x7777777F279eba3d3Ad8F4E708545291A6fDBA8B;
|
|
@@ -39,6 +41,8 @@ contract CoinsDeployerBase is ProxyDeployerScript {
|
|
|
39
41
|
address buySupplyWithSwapRouterHook;
|
|
40
42
|
address zoraV4CoinHook;
|
|
41
43
|
address hookUpgradeGate;
|
|
44
|
+
// trusted sender lookup
|
|
45
|
+
address trustedMsgSenderLookup;
|
|
42
46
|
// Hook deployment salt (for deterministic deployment)
|
|
43
47
|
bytes32 zoraV4CoinHookSalt;
|
|
44
48
|
bool isDev;
|
|
@@ -70,6 +74,7 @@ contract CoinsDeployerBase is ProxyDeployerScript {
|
|
|
70
74
|
vm.serializeAddress(objectKey, "CREATOR_COIN_IMPL", deployment.creatorCoinImpl);
|
|
71
75
|
vm.serializeAddress(objectKey, "HOOK_UPGRADE_GATE", deployment.hookUpgradeGate);
|
|
72
76
|
vm.serializeAddress(objectKey, "ZORA_HOOK_REGISTRY", deployment.zoraHookRegistry);
|
|
77
|
+
vm.serializeAddress(objectKey, "TRUSTED_MSG_SENDER_LOOKUP", deployment.trustedMsgSenderLookup);
|
|
73
78
|
string memory result = vm.serializeAddress(objectKey, "COIN_V4_IMPL", deployment.coinV4Impl);
|
|
74
79
|
|
|
75
80
|
vm.writeJson(result, addressesFile(deployment.isDev));
|
|
@@ -98,6 +103,7 @@ contract CoinsDeployerBase is ProxyDeployerScript {
|
|
|
98
103
|
deployment.creatorCoinImpl = readAddressOrDefaultToZero(json, "CREATOR_COIN_IMPL");
|
|
99
104
|
deployment.hookUpgradeGate = readAddressOrDefaultToZero(json, "HOOK_UPGRADE_GATE");
|
|
100
105
|
deployment.zoraHookRegistry = readAddressOrDefaultToZero(json, "ZORA_HOOK_REGISTRY");
|
|
106
|
+
deployment.trustedMsgSenderLookup = readAddressOrDefaultToZero(json, "TRUSTED_MSG_SENDER_LOOKUP");
|
|
101
107
|
}
|
|
102
108
|
|
|
103
109
|
function deployCoinV4Impl() internal returns (ContentCoin) {
|
|
@@ -139,14 +145,23 @@ contract CoinsDeployerBase is ProxyDeployerScript {
|
|
|
139
145
|
return deployment;
|
|
140
146
|
}
|
|
141
147
|
|
|
148
|
+
function deployTrustedMsgSenderLookup(CoinsDeployment memory deployment) internal returns (CoinsDeployment memory) {
|
|
149
|
+
// Deploy the contract directly using constructor
|
|
150
|
+
deployment.trustedMsgSenderLookup = address(new TrustedMsgSenderProviderLookup(getDefaultTrustedMessageSenders(), getProxyAdmin()));
|
|
151
|
+
|
|
152
|
+
return deployment;
|
|
153
|
+
}
|
|
154
|
+
|
|
142
155
|
function deployZoraV4CoinHook(CoinsDeployment memory deployment) internal returns (IHooks hook, bytes32 salt) {
|
|
156
|
+
require(deployment.trustedMsgSenderLookup != address(0), "Trusted message sender lookup not deployed");
|
|
157
|
+
|
|
143
158
|
return
|
|
144
159
|
HooksDeployment.deployHookWithExistingOrNewSalt(
|
|
145
160
|
HooksDeployment.FOUNDRY_SCRIPT_ADDRESS,
|
|
146
161
|
HooksDeployment.makeHookCreationCode(
|
|
147
162
|
getUniswapV4PoolManager(),
|
|
148
163
|
deployment.zoraFactory,
|
|
149
|
-
|
|
164
|
+
ITrustedMsgSenderProviderLookup(deployment.trustedMsgSenderLookup),
|
|
150
165
|
deployment.hookUpgradeGate
|
|
151
166
|
),
|
|
152
167
|
deployment.zoraV4CoinHookSalt
|
|
@@ -175,6 +190,9 @@ contract CoinsDeployerBase is ProxyDeployerScript {
|
|
|
175
190
|
function deployImpls(CoinsDeployment memory deployment) internal returns (CoinsDeployment memory) {
|
|
176
191
|
// Deploy implementation contracts
|
|
177
192
|
|
|
193
|
+
// Deploy trusted message sender lookup first
|
|
194
|
+
deployment = deployTrustedMsgSenderLookup(deployment);
|
|
195
|
+
|
|
178
196
|
// Deploy hook first, then use its address for coin v4 impl
|
|
179
197
|
console.log("deploying content coin hook");
|
|
180
198
|
(IHooks zoraV4CoinHook, bytes32 usedSalt) = deployZoraV4CoinHook(deployment);
|
|
@@ -191,6 +209,9 @@ contract CoinsDeployerBase is ProxyDeployerScript {
|
|
|
191
209
|
}
|
|
192
210
|
|
|
193
211
|
function deployHooks(CoinsDeployment memory deployment) internal returns (CoinsDeployment memory) {
|
|
212
|
+
// Deploy trusted message sender lookup first
|
|
213
|
+
deployment = deployTrustedMsgSenderLookup(deployment);
|
|
214
|
+
|
|
194
215
|
// Deploy hook first, then use its address for coin v4 impl
|
|
195
216
|
(IHooks zoraV4CoinHook, bytes32 usedSalt) = deployZoraV4CoinHook(deployment);
|
|
196
217
|
deployment.zoraV4CoinHook = address(zoraV4CoinHook);
|
|
@@ -16,6 +16,7 @@ import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
|
|
|
16
16
|
import {SwapParams} from "@uniswap/v4-core/src/types/PoolOperation.sol";
|
|
17
17
|
import {IZoraV4CoinHook} from "../interfaces/IZoraV4CoinHook.sol";
|
|
18
18
|
import {IMsgSender} from "../interfaces/IMsgSender.sol";
|
|
19
|
+
import {ITrustedMsgSenderProviderLookup} from "../interfaces/ITrustedMsgSenderProviderLookup.sol";
|
|
19
20
|
import {IHasSwapPath} from "../interfaces/ICoin.sol";
|
|
20
21
|
import {LpPosition} from "../types/LpPosition.sol";
|
|
21
22
|
import {V4Liquidity} from "../libs/V4Liquidity.sol";
|
|
@@ -60,9 +61,10 @@ contract ZoraV4CoinHook is
|
|
|
60
61
|
{
|
|
61
62
|
using BalanceDeltaLibrary for BalanceDelta;
|
|
62
63
|
|
|
63
|
-
/// @
|
|
64
|
-
///
|
|
65
|
-
|
|
64
|
+
/// @dev DEPRECATED: This mapping is kept for storage compatibility. It doesn't matter that storage slots moved around
|
|
65
|
+
/// between versions since the contracts are immutable, but in some tests we do etching to test if a new hook fixes some bugs, so we want to maintain the storage slot order.
|
|
66
|
+
/// This slot previously held the mappings of trusted message senders.
|
|
67
|
+
mapping(address => bool) internal legacySlot0;
|
|
66
68
|
|
|
67
69
|
/// @notice Mapping of pool keys to coins.
|
|
68
70
|
mapping(bytes32 => IZoraV4CoinHook.PoolCoin) internal poolCoins;
|
|
@@ -73,27 +75,34 @@ contract ZoraV4CoinHook is
|
|
|
73
75
|
/// @notice The upgrade gate contract - used to verify allowed upgrade paths
|
|
74
76
|
IHooksUpgradeGate internal immutable upgradeGate;
|
|
75
77
|
|
|
78
|
+
/// @notice The trusted message sender lookup contract - used to determine if an address is trusted
|
|
79
|
+
ITrustedMsgSenderProviderLookup internal immutable trustedMsgSenderLookup;
|
|
80
|
+
|
|
76
81
|
/// @notice The constructor for the ZoraV4CoinHook.
|
|
77
82
|
/// @param poolManager_ The Uniswap V4 pool manager
|
|
78
83
|
/// @param coinVersionLookup_ The coin version lookup contract - used to determine if an address is a coin and what version it is.
|
|
79
|
-
/// @param
|
|
84
|
+
/// @param trustedMsgSenderLookup_ The trusted message sender lookup contract - used to determine if an address is trusted
|
|
80
85
|
/// @param upgradeGate_ The upgrade gate contract for managing hook upgrades
|
|
81
86
|
constructor(
|
|
82
87
|
IPoolManager poolManager_,
|
|
83
88
|
IDeployedCoinVersionLookup coinVersionLookup_,
|
|
84
|
-
|
|
89
|
+
ITrustedMsgSenderProviderLookup trustedMsgSenderLookup_,
|
|
85
90
|
IHooksUpgradeGate upgradeGate_
|
|
86
91
|
) BaseHook(poolManager_) {
|
|
87
92
|
require(address(coinVersionLookup_) != address(0), CoinVersionLookupCannotBeZeroAddress());
|
|
88
93
|
|
|
89
94
|
require(address(upgradeGate_) != address(0), UpgradeGateCannotBeZeroAddress());
|
|
90
95
|
|
|
96
|
+
require(address(trustedMsgSenderLookup_) != address(0), TrustedMsgSenderLookupCannotBeZeroAddress());
|
|
97
|
+
|
|
91
98
|
coinVersionLookup = coinVersionLookup_;
|
|
92
99
|
upgradeGate = upgradeGate_;
|
|
100
|
+
trustedMsgSenderLookup = trustedMsgSenderLookup_;
|
|
101
|
+
}
|
|
93
102
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
103
|
+
/// @notice Returns the trusted message sender lookup contract
|
|
104
|
+
function getTrustedMsgSenderLookup() external view returns (ITrustedMsgSenderProviderLookup) {
|
|
105
|
+
return trustedMsgSenderLookup;
|
|
97
106
|
}
|
|
98
107
|
|
|
99
108
|
/// @notice Returns the uniswap v4 hook settings / permissions.
|
|
@@ -120,7 +129,7 @@ contract ZoraV4CoinHook is
|
|
|
120
129
|
|
|
121
130
|
/// @inheritdoc IZoraV4CoinHook
|
|
122
131
|
function isTrustedMessageSender(address sender) external view returns (bool) {
|
|
123
|
-
return
|
|
132
|
+
return trustedMsgSenderLookup.isTrustedMsgSenderProvider(sender);
|
|
124
133
|
}
|
|
125
134
|
|
|
126
135
|
/// @inheritdoc IZoraV4CoinHook
|
|
@@ -256,51 +265,6 @@ contract ZoraV4CoinHook is
|
|
|
256
265
|
|
|
257
266
|
// Store the positions and mint the initial liquidity into the new pool
|
|
258
267
|
_initializeForPositions(newKey, coin, positions);
|
|
259
|
-
|
|
260
|
-
// Handle any remaining token balances by adding them to the last position
|
|
261
|
-
// This ensures no tokens are left unminted during the migration process
|
|
262
|
-
_mintExtraLiquidityAtLastPosition(sqrtPriceX96, newKey);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/// @notice Internal fn to add any remaining token balances to the last liquidity position.
|
|
266
|
-
/// @param sqrtPriceX96 The sqrt price x96.
|
|
267
|
-
/// @param poolKey The pool key.
|
|
268
|
-
function _mintExtraLiquidityAtLastPosition(uint160 sqrtPriceX96, PoolKey memory poolKey) internal {
|
|
269
|
-
// Check if there are any leftover token balances in the hook after migration
|
|
270
|
-
// These could result from rounding or partial liquidity transfers
|
|
271
|
-
uint256 currency0Balance = poolKey.currency0.balanceOfSelf();
|
|
272
|
-
uint256 currency1Balance = poolKey.currency1.balanceOfSelf();
|
|
273
|
-
|
|
274
|
-
// Get the stored positions for this pool to access the last position
|
|
275
|
-
LpPosition[] storage positions = poolCoins[CoinCommon.hashPoolKey(poolKey)].positions;
|
|
276
|
-
|
|
277
|
-
// Only proceed if there are actually leftover tokens to mint
|
|
278
|
-
if (currency0Balance > 0 || currency1Balance > 0) {
|
|
279
|
-
// Get reference to the last position where we'll add the extra liquidity
|
|
280
|
-
LpPosition storage lastPosition = positions[positions.length - 1];
|
|
281
|
-
|
|
282
|
-
// Calculate how much liquidity we can create with the remaining token balances
|
|
283
|
-
// This uses the current pool price and the last position's tick range
|
|
284
|
-
uint128 newLiquidity = LiquidityAmounts.getLiquidityForAmounts(
|
|
285
|
-
sqrtPriceX96,
|
|
286
|
-
TickMath.getSqrtPriceAtTick(lastPosition.tickLower),
|
|
287
|
-
TickMath.getSqrtPriceAtTick(lastPosition.tickUpper),
|
|
288
|
-
currency0Balance,
|
|
289
|
-
currency1Balance
|
|
290
|
-
);
|
|
291
|
-
|
|
292
|
-
// Create a temporary array with just the last position to mint the extra liquidity
|
|
293
|
-
LpPosition[] memory newPositions = new LpPosition[](1);
|
|
294
|
-
newPositions[0] = lastPosition;
|
|
295
|
-
newPositions[0].liquidity = newLiquidity; // Set the calculated liquidity amount
|
|
296
|
-
|
|
297
|
-
// Mint the extra liquidity into the pool using the V4 liquidity manager
|
|
298
|
-
V4Liquidity.lockAndMint(poolManager, poolKey, newPositions);
|
|
299
|
-
|
|
300
|
-
// Update our internal tracking of the last position's liquidity
|
|
301
|
-
// This keeps our records in sync with the actual pool state
|
|
302
|
-
positions[positions.length - 1].liquidity += newPositions[0].liquidity;
|
|
303
|
-
}
|
|
304
268
|
}
|
|
305
269
|
|
|
306
270
|
/// @notice Saves the positions for the coin and mints them into the pool
|
|
@@ -403,7 +367,7 @@ contract ZoraV4CoinHook is
|
|
|
403
367
|
/// @return swapper The original message sender.
|
|
404
368
|
/// @return senderIsTrusted Whether the sender is a trusted message sender.
|
|
405
369
|
function _getOriginalMsgSender(address sender) internal view returns (address swapper, bool senderIsTrusted) {
|
|
406
|
-
senderIsTrusted =
|
|
370
|
+
senderIsTrusted = trustedMsgSenderLookup.isTrustedMsgSenderProvider(sender);
|
|
407
371
|
|
|
408
372
|
// If getter function reverts, we return a 0 address by default and continue execution.
|
|
409
373
|
try IMsgSender(sender).msgSender() returns (address _swapper) {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// SPDX-License-Identifier: ZORA-DELAYED-OSL-v1
|
|
2
|
+
// This software is licensed under the Zora Delayed Open Source License.
|
|
3
|
+
// Under this license, you may use, copy, modify, and distribute this software for
|
|
4
|
+
// non-commercial purposes only. Commercial use and competitive products are prohibited
|
|
5
|
+
// until the "Open Date" (3 years from first public distribution or earlier at Zora's discretion),
|
|
6
|
+
// at which point this software automatically becomes available under the MIT License.
|
|
7
|
+
// Full license terms available at: https://docs.zora.co/coins/license
|
|
8
|
+
pragma solidity ^0.8.23;
|
|
9
|
+
|
|
10
|
+
/// @title ITrustedMsgSenderProviderLookup
|
|
11
|
+
/// @notice Interface for contracts that can determine if an address is a trusted message sender
|
|
12
|
+
/// @dev This interface allows the hook to delegate the trusted sender check to an external contract
|
|
13
|
+
interface ITrustedMsgSenderProviderLookup {
|
|
14
|
+
/// @notice Checks if an address is a trusted message sender provider
|
|
15
|
+
/// @param sender The address to check
|
|
16
|
+
/// @return true if the sender is trusted, false otherwise
|
|
17
|
+
function isTrustedMsgSenderProvider(address sender) external view returns (bool);
|
|
18
|
+
}
|
|
@@ -44,6 +44,9 @@ interface IZoraV4CoinHook is IUpgradeableV4Hook {
|
|
|
44
44
|
/// @notice Upgrade gate cannot be the zero address.
|
|
45
45
|
error UpgradeGateCannotBeZeroAddress();
|
|
46
46
|
|
|
47
|
+
/// @notice Trusted message sender lookup cannot be the zero address.
|
|
48
|
+
error TrustedMsgSenderLookupCannotBeZeroAddress();
|
|
49
|
+
|
|
47
50
|
/// @notice Thrown when a pool is not initialized for the hook.
|
|
48
51
|
/// @param key The pool key struct to identify the pool.
|
|
49
52
|
error NoCoinForHook(PoolKey key);
|
|
@@ -14,6 +14,7 @@ import {HookMiner} from "@uniswap/v4-periphery/src/utils/HookMiner.sol";
|
|
|
14
14
|
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
|
15
15
|
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
|
|
16
16
|
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
|
|
17
|
+
import {ITrustedMsgSenderProviderLookup} from "../interfaces/ITrustedMsgSenderProviderLookup.sol";
|
|
17
18
|
|
|
18
19
|
Vm constant vm = Vm(address(bytes20(uint160(uint256(keccak256("hevm cheat code"))))));
|
|
19
20
|
|
|
@@ -86,10 +87,10 @@ library HooksDeployment {
|
|
|
86
87
|
address deployer,
|
|
87
88
|
address poolManager,
|
|
88
89
|
address coinVersionLookup,
|
|
89
|
-
|
|
90
|
+
ITrustedMsgSenderProviderLookup trustedMsgSenderLookup,
|
|
90
91
|
address upgradeGate
|
|
91
92
|
) internal returns (address hookAddress, bytes32 salt) {
|
|
92
|
-
bytes memory hookCreationCode = makeHookCreationCode(poolManager, coinVersionLookup,
|
|
93
|
+
bytes memory hookCreationCode = makeHookCreationCode(poolManager, coinVersionLookup, trustedMsgSenderLookup, upgradeGate);
|
|
93
94
|
(salt, ) = mineAndCacheSalt(deployer, hookCreationCode);
|
|
94
95
|
hookAddress = HookMinerWithCreationCodeArgs.deterministicHookAddress(deployer, salt, hookCreationCode);
|
|
95
96
|
}
|
|
@@ -131,19 +132,19 @@ library HooksDeployment {
|
|
|
131
132
|
function hookConstructorArgs(
|
|
132
133
|
address poolManager,
|
|
133
134
|
address coinVersionLookup,
|
|
134
|
-
|
|
135
|
+
ITrustedMsgSenderProviderLookup trustedMsgSenderLookup,
|
|
135
136
|
address upgradeGate
|
|
136
137
|
) internal pure returns (bytes memory) {
|
|
137
|
-
return abi.encode(poolManager, coinVersionLookup,
|
|
138
|
+
return abi.encode(poolManager, coinVersionLookup, trustedMsgSenderLookup, upgradeGate);
|
|
138
139
|
}
|
|
139
140
|
|
|
140
141
|
function makeHookCreationCode(
|
|
141
142
|
address poolManager,
|
|
142
143
|
address coinVersionLookup,
|
|
143
|
-
|
|
144
|
+
ITrustedMsgSenderProviderLookup trustedMsgSenderLookup,
|
|
144
145
|
address upgradeGate
|
|
145
146
|
) internal pure returns (bytes memory) {
|
|
146
|
-
return abi.encodePacked(type(ZoraV4CoinHook).creationCode, hookConstructorArgs(poolManager, coinVersionLookup,
|
|
147
|
+
return abi.encodePacked(type(ZoraV4CoinHook).creationCode, hookConstructorArgs(poolManager, coinVersionLookup, trustedMsgSenderLookup, upgradeGate));
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
/// @notice Deploys or returns existing ContentCoinHook using deterministic deployment. Ensures that if a hooks is already
|
|
@@ -151,11 +152,11 @@ library HooksDeployment {
|
|
|
151
152
|
function deployZoraV4CoinHook(
|
|
152
153
|
address poolManager,
|
|
153
154
|
address coinVersionLookup,
|
|
154
|
-
|
|
155
|
+
ITrustedMsgSenderProviderLookup trustedMsgSenderLookup,
|
|
155
156
|
address upgradeGate,
|
|
156
157
|
bytes32 salt
|
|
157
158
|
) internal returns (IHooks hook) {
|
|
158
|
-
bytes memory creationCode = makeHookCreationCode(poolManager, coinVersionLookup,
|
|
159
|
+
bytes memory creationCode = makeHookCreationCode(poolManager, coinVersionLookup, trustedMsgSenderLookup, upgradeGate);
|
|
159
160
|
return deployHookWithSalt(creationCode, salt);
|
|
160
161
|
}
|
|
161
162
|
|