@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.
@@ -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
+ ]
@@ -13,9 +13,9 @@
13
13
  "internalType": "contract IDeployedCoinVersionLookup"
14
14
  },
15
15
  {
16
- "name": "trustedMessageSenders_",
17
- "type": "address[]",
18
- "internalType": "address[]"
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 = 200
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.1",
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
- getDefaultTrustedMessageSenders(),
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
- /// @notice Mapping of trusted message senders - these are addresses that are trusted to provide a
64
- /// an original msg.sender
65
- mapping(address => bool) internal trustedMessageSender;
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 trustedMessageSenders_ The addresses of the trusted message senders - these are addresses that are trusted to provide a
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
- address[] memory trustedMessageSenders_,
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
- for (uint256 i = 0; i < trustedMessageSenders_.length; i++) {
95
- trustedMessageSender[trustedMessageSenders_[i]] = true;
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 trustedMessageSender[sender];
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 = trustedMessageSender[sender];
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
- address[] memory trustedMessageSenders,
90
+ ITrustedMsgSenderProviderLookup trustedMsgSenderLookup,
90
91
  address upgradeGate
91
92
  ) internal returns (address hookAddress, bytes32 salt) {
92
- bytes memory hookCreationCode = makeHookCreationCode(poolManager, coinVersionLookup, trustedMessageSenders, upgradeGate);
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
- address[] memory trustedMessageSenders,
135
+ ITrustedMsgSenderProviderLookup trustedMsgSenderLookup,
135
136
  address upgradeGate
136
137
  ) internal pure returns (bytes memory) {
137
- return abi.encode(poolManager, coinVersionLookup, trustedMessageSenders, upgradeGate);
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
- address[] memory trustedMessageSenders,
144
+ ITrustedMsgSenderProviderLookup trustedMsgSenderLookup,
144
145
  address upgradeGate
145
146
  ) internal pure returns (bytes memory) {
146
- return abi.encodePacked(type(ZoraV4CoinHook).creationCode, hookConstructorArgs(poolManager, coinVersionLookup, trustedMessageSenders, upgradeGate));
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
- address[] memory trustedMessageSenders,
155
+ ITrustedMsgSenderProviderLookup trustedMsgSenderLookup,
155
156
  address upgradeGate,
156
157
  bytes32 salt
157
158
  ) internal returns (IHooks hook) {
158
- bytes memory creationCode = makeHookCreationCode(poolManager, coinVersionLookup, trustedMessageSenders, upgradeGate);
159
+ bytes memory creationCode = makeHookCreationCode(poolManager, coinVersionLookup, trustedMsgSenderLookup, upgradeGate);
159
160
  return deployHookWithSalt(creationCode, salt);
160
161
  }
161
162