@zoralabs/coins 2.1.1 → 2.2.1

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.
Files changed (97) hide show
  1. package/.turbo/turbo-build$colon$js.log +152 -0
  2. package/CHANGELOG.md +60 -0
  3. package/abis/BaseCoin.json +26 -0
  4. package/abis/BaseTest.json +2 -7
  5. package/abis/CoinConstants.json +0 -104
  6. package/abis/ContentCoin.json +26 -0
  7. package/abis/CreatorCoin.json +30 -4
  8. package/abis/FeeEstimatorHook.json +0 -5
  9. package/abis/ICoin.json +26 -0
  10. package/abis/ICoinV3.json +26 -0
  11. package/abis/ICreatorCoin.json +39 -0
  12. package/abis/IERC721.json +36 -36
  13. package/abis/IHasCoinType.json +15 -0
  14. package/abis/IHasTotalSupplyForPositions.json +15 -0
  15. package/abis/IZoraFactory.json +52 -0
  16. package/abis/IZoraHookRegistry.json +188 -0
  17. package/abis/VmContractHelper227.json +233 -0
  18. package/abis/ZoraFactoryImpl.json +32 -6
  19. package/abis/ZoraHookRegistry.json +375 -0
  20. package/abis/{CreatorCoinHook.json → ZoraV4CoinHook.json} +1 -1
  21. package/addresses/8453.json +2 -1
  22. package/dist/index.cjs +72 -10
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.js +72 -10
  25. package/dist/index.js.map +1 -1
  26. package/dist/wagmiGenerated.d.ts +90 -10
  27. package/dist/wagmiGenerated.d.ts.map +1 -1
  28. package/foundry.toml +4 -1
  29. package/package/wagmiGenerated.ts +72 -10
  30. package/package.json +7 -5
  31. package/script/PrintRegisterUpgradePath.s.sol +0 -7
  32. package/script/TestBackingCoinSwap.s.sol +0 -1
  33. package/script/TestV4Swap.s.sol +0 -1
  34. package/script/UpgradeFactoryImpl.s.sol +1 -1
  35. package/src/BaseCoin.sol +15 -12
  36. package/src/ContentCoin.sol +10 -0
  37. package/src/CreatorCoin.sol +28 -7
  38. package/src/ZoraFactoryImpl.sol +62 -23
  39. package/src/deployment/CoinsDeployerBase.sol +24 -58
  40. package/src/hook-registry/ZoraHookRegistry.sol +93 -0
  41. package/src/hooks/{BaseZoraV4CoinHook.sol → ZoraV4CoinHook.sol} +13 -8
  42. package/src/interfaces/ICoin.sol +19 -1
  43. package/src/interfaces/ICreatorCoin.sol +4 -0
  44. package/src/interfaces/IZoraFactory.sol +32 -10
  45. package/src/interfaces/IZoraHookRegistry.sol +47 -0
  46. package/src/libs/CoinConstants.sol +0 -32
  47. package/src/libs/CoinRewardsV4.sol +53 -15
  48. package/src/libs/CreatorCoinConstants.sol +0 -1
  49. package/src/libs/HooksDeployment.sol +13 -65
  50. package/src/libs/MarketConstants.sol +10 -12
  51. package/src/libs/V4Liquidity.sol +30 -0
  52. package/src/version/ContractVersionBase.sol +1 -1
  53. package/test/CoinUniV4.t.sol +33 -30
  54. package/test/ContentCoinRewards.t.sol +320 -0
  55. package/test/CreatorCoin.t.sol +1 -1
  56. package/test/CreatorCoinRewards.t.sol +375 -0
  57. package/test/DeploymentHooks.t.sol +10 -10
  58. package/test/Factory.t.sol +24 -7
  59. package/test/HooksDeployment.t.sol +4 -4
  60. package/test/LiquidityMigration.t.sol +4 -9
  61. package/test/Upgrades.t.sol +44 -48
  62. package/test/ZoraHookRegistry.t.sol +266 -0
  63. package/test/utils/BaseTest.sol +25 -42
  64. package/test/utils/FeeEstimatorHook.sol +4 -6
  65. package/test/utils/RewardTestHelpers.sol +106 -0
  66. package/.turbo/turbo-build.log +0 -199
  67. package/abis/AutoSwapperTest.json +0 -618
  68. package/abis/BadImpl.json +0 -15
  69. package/abis/BaseZoraV4CoinHook.json +0 -1664
  70. package/abis/CoinTest.json +0 -819
  71. package/abis/CoinUniV4Test.json +0 -1128
  72. package/abis/ContentCoinHook.json +0 -1733
  73. package/abis/CreatorCoinTest.json +0 -887
  74. package/abis/Deploy.json +0 -9
  75. package/abis/DeployHooks.json +0 -9
  76. package/abis/DeployScript.json +0 -35
  77. package/abis/DeployedCoinVersionLookupTest.json +0 -740
  78. package/abis/DifferentNamespaceVersionLookup.json +0 -39
  79. package/abis/FactoryTest.json +0 -748
  80. package/abis/FakeHookNoInterface.json +0 -21
  81. package/abis/GenerateDeterministicParams.json +0 -9
  82. package/abis/HooksDeploymentTest.json +0 -645
  83. package/abis/HooksTest.json +0 -709
  84. package/abis/InvalidLiquidityMigrationReceiver.json +0 -21
  85. package/abis/LiquidityMigrationReceiver.json +0 -103
  86. package/abis/LiquidityMigrationTest.json +0 -889
  87. package/abis/MockBadFactory.json +0 -15
  88. package/abis/MultiOwnableTest.json +0 -766
  89. package/abis/PrintUpgradeCommand.json +0 -9
  90. package/abis/TestDeployedCoinVersionLookupImplementation.json +0 -39
  91. package/abis/TestV4Swap.json +0 -9
  92. package/abis/UpgradeFactoryImpl.json +0 -9
  93. package/abis/UpgradeHooks.json +0 -35
  94. package/abis/UpgradesTest.json +0 -723
  95. package/src/hooks/ContentCoinHook.sol +0 -27
  96. package/src/hooks/CreatorCoinHook.sol +0 -27
  97. package/src/libs/CreatorCoinRewards.sol +0 -34
@@ -13,7 +13,7 @@ import {IWETH} from "../src/interfaces/IWETH.sol";
13
13
  import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
14
14
  import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
15
15
  import {BuySupplyWithSwapRouterHook} from "../src/hooks/deployment/BuySupplyWithSwapRouterHook.sol";
16
- import {ContentCoinHook} from "../src/hooks/ContentCoinHook.sol";
16
+ import {ZoraV4CoinHook} from "../src/hooks/ZoraV4CoinHook.sol";
17
17
  import {console} from "forge-std/console.sol";
18
18
  import {IDeployedCoinVersionLookup} from "../src/interfaces/IDeployedCoinVersionLookup.sol";
19
19
  import {IHooksUpgradeGate} from "../src/interfaces/IHooksUpgradeGate.sol";
@@ -43,7 +43,7 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
43
43
 
44
44
  factoryProxy = ZoraFactoryImpl(0x777777751622c0d3258f214F9DF38E35BF45baF3);
45
45
 
46
- ZoraFactoryImpl newImpl = new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(contentCoinHook), address(creatorCoinHook));
46
+ ZoraFactoryImpl newImpl = new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(hook), address(zoraHookRegistry));
47
47
 
48
48
  vm.prank(factoryProxy.owner());
49
49
  factoryProxy.upgradeToAndCall(address(newImpl), "");
@@ -58,7 +58,7 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
58
58
 
59
59
  factoryProxy = ZoraFactoryImpl(0x777777751622c0d3258f214F9DF38E35BF45baF3);
60
60
 
61
- ZoraFactoryImpl newImpl = new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(contentCoinHook), address(creatorCoinHook));
61
+ ZoraFactoryImpl newImpl = new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(hook), address(zoraHookRegistry));
62
62
 
63
63
  vm.prank(factoryProxy.owner());
64
64
  factoryProxy.upgradeToAndCall(address(newImpl), "");
@@ -70,29 +70,25 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
70
70
  factoryProxy.upgradeToAndCall(address(badImpl), "");
71
71
  }
72
72
 
73
- function test_canUpgradeToSameContractName() public {
74
- // this test that we can upgrade to the same contract name, when we have already upgraded to a version that has a contract name
75
- vm.createSelectFork("base", 29675508);
73
+ // This fork test needs to be updated after hook registry + new factory is deployed
74
+ // function test_canUpgradeToSameContractName() public {
75
+ // // this test that we can upgrade to the same contract name, when we have already upgraded to a version that has a contract name
76
+ // vm.createSelectFork("base", 29675508);
76
77
 
77
- factoryProxy = ZoraFactoryImpl(0x777777751622c0d3258f214F9DF38E35BF45baF3);
78
+ // factoryProxy = ZoraFactoryImpl(0x777777751622c0d3258f214F9DF38E35BF45baF3);
78
79
 
79
- ZoraFactoryImpl newImpl = new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(contentCoinHook), address(creatorCoinHook));
80
+ // ZoraFactoryImpl newImpl = new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(hook), address(zoraHookRegistry));
80
81
 
81
- vm.prank(factoryProxy.owner());
82
- factoryProxy.upgradeToAndCall(address(newImpl), "");
82
+ // vm.prank(factoryProxy.owner());
83
+ // factoryProxy.upgradeToAndCall(address(newImpl), "");
83
84
 
84
- ZoraFactoryImpl newImpl2 = new ZoraFactoryImpl(
85
- factoryProxy.coinV4Impl(),
86
- factoryProxy.creatorCoinImpl(),
87
- address(contentCoinHook),
88
- address(creatorCoinHook)
89
- );
85
+ // ZoraFactoryImpl newImpl2 = new ZoraFactoryImpl(factoryProxy.coinV4Impl(), factoryProxy.creatorCoinImpl(), address(hook), address(zoraHookRegistry));
90
86
 
91
- vm.prank(factoryProxy.owner());
92
- factoryProxy.upgradeToAndCall(address(newImpl2), "");
87
+ // vm.prank(factoryProxy.owner());
88
+ // factoryProxy.upgradeToAndCall(address(newImpl2), "");
93
89
 
94
- assertEq(factoryProxy.implementation(), address(newImpl2));
95
- }
90
+ // assertEq(factoryProxy.implementation(), address(newImpl2));
91
+ // }
96
92
 
97
93
  function test_canUpgradeAndSwap() public {
98
94
  vm.createSelectFork("base");
@@ -179,32 +175,6 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
179
175
  vm.stopPrank();
180
176
  }
181
177
 
182
- function test_canCanFixBrokenContentCoinAndSwap() public {
183
- vm.createSelectFork("base", 31835069);
184
-
185
- address trader = 0xf69fEc6d858c77e969509843852178bd24CAd2B6;
186
-
187
- address contentCoin = 0x4E93A01c90f812284F71291a8d1415a904957156;
188
-
189
- address creatorCoin = ICoin(contentCoin).currency();
190
-
191
- uint256 amountIn = IERC20(creatorCoin).balanceOf(trader);
192
-
193
- require(amountIn > 0, "no balance");
194
-
195
- // this swap should revert because the content coin is broken
196
- _swapSomeCurrencyForCoinAndExpectRevert(ICoin(contentCoin), creatorCoin, uint128(amountIn), trader);
197
-
198
- bytes memory creationCode = HooksDeployment.contentCoinCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
199
-
200
- (IHooks newHook, ) = HooksDeployment.deployHookWithExistingOrNewSalt(address(this), creationCode, bytes32(0));
201
-
202
- // etch new hook into the content coin, it shouldn't revert anymore when swapping
203
- vm.etch(address(ICoin(contentCoin).hooks()), address(newHook).code);
204
-
205
- _swapSomeCurrencyForCoin(ICoin(contentCoin), creatorCoin, uint128(amountIn), trader);
206
- }
207
-
208
178
  function test_canUpgradeBrokenContentCoinAndSwap() public {
209
179
  vm.createSelectFork("base", 32613149);
210
180
 
@@ -216,7 +186,7 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
216
186
 
217
187
  uint256 amountIn = 0.000111 ether;
218
188
 
219
- bytes memory creationCode = HooksDeployment.contentCoinCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
189
+ bytes memory creationCode = HooksDeployment.makeHookCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
220
190
 
221
191
  (IHooks newHook, ) = HooksDeployment.deployHookWithExistingOrNewSalt(address(this), creationCode, bytes32(0));
222
192
 
@@ -268,7 +238,7 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
268
238
 
269
239
  address existingHook = address(creatorCoin.hooks());
270
240
 
271
- bytes memory creationCode = HooksDeployment.creatorCoinCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
241
+ bytes memory creationCode = HooksDeployment.makeHookCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
272
242
 
273
243
  (IHooks newHook, ) = HooksDeployment.deployHookWithExistingOrNewSalt(address(this), creationCode, bytes32(0));
274
244
 
@@ -319,4 +289,30 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
319
289
  // now try to swap some currency for the creator coin - it should succeed
320
290
  _swapSomeCurrencyForCoin(creatorCoin, zora, uint128(IERC20(zora).balanceOf(trader) / 2), trader);
321
291
  }
292
+
293
+ function test_canFixBrokenContentCoinAndSwap() public {
294
+ vm.createSelectFork("base", 31835069);
295
+
296
+ address trader = 0xf69fEc6d858c77e969509843852178bd24CAd2B6;
297
+
298
+ address contentCoin = 0x4E93A01c90f812284F71291a8d1415a904957156;
299
+
300
+ address creatorCoin = ICoin(contentCoin).currency();
301
+
302
+ uint256 amountIn = IERC20(creatorCoin).balanceOf(trader);
303
+
304
+ require(amountIn > 0, "no balance");
305
+
306
+ // this swap should revert because the content coin is broken
307
+ _swapSomeCurrencyForCoinAndExpectRevert(ICoin(contentCoin), creatorCoin, uint128(amountIn), trader);
308
+
309
+ bytes memory creationCode = HooksDeployment.makeHookCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
310
+
311
+ (IHooks newHook, ) = HooksDeployment.deployHookWithExistingOrNewSalt(address(this), creationCode, bytes32(0));
312
+
313
+ // etch new hook into the content coin, it shouldn't revert anymore when swapping
314
+ vm.etch(address(ICoin(contentCoin).hooks()), address(newHook).code);
315
+
316
+ _swapSomeCurrencyForCoin(ICoin(contentCoin), creatorCoin, uint128(amountIn), trader);
317
+ }
322
318
  }
@@ -0,0 +1,266 @@
1
+ // SPDX-License-Identifier: UNLICENSED
2
+ pragma solidity ^0.8.28;
3
+
4
+ import "forge-std/Test.sol";
5
+
6
+ import {IZoraHookRegistry} from "../src/interfaces/IZoraHookRegistry.sol";
7
+ import {ZoraHookRegistry} from "../src/hook-registry/ZoraHookRegistry.sol";
8
+
9
+ contract MockHook {
10
+ function contractVersion() public pure returns (string memory) {
11
+ return "0.0.0";
12
+ }
13
+ }
14
+
15
+ contract ZoraHookRegistryTest is Test {
16
+ uint256 internal forkId;
17
+ address internal owner;
18
+
19
+ ZoraHookRegistry internal zoraHookRegistry;
20
+ MockHook internal mockHook;
21
+
22
+ function setUp() public {
23
+ forkId = vm.createSelectFork("base", 34509280);
24
+ owner = makeAddr("owner");
25
+
26
+ address[] memory initialOwners = new address[](1);
27
+ initialOwners[0] = owner;
28
+
29
+ zoraHookRegistry = new ZoraHookRegistry();
30
+ zoraHookRegistry.initialize(initialOwners);
31
+
32
+ mockHook = new MockHook();
33
+ }
34
+
35
+ function test_register_hooks() public {
36
+ address[] memory hooks = new address[](1);
37
+ string[] memory tags = new string[](1);
38
+
39
+ hooks[0] = address(mockHook);
40
+ tags[0] = "ZoraHook";
41
+
42
+ vm.prank(owner);
43
+ zoraHookRegistry.registerHooks(hooks, tags);
44
+
45
+ assertEq(zoraHookRegistry.isRegisteredHook(hooks[0]), true);
46
+
47
+ address[] memory addrs = zoraHookRegistry.getHookAddresses();
48
+ assertEq(addrs.length, 1);
49
+ assertEq(addrs[0], hooks[0]);
50
+
51
+ assertEq(zoraHookRegistry.getHookTag(hooks[0]), tags[0]);
52
+
53
+ IZoraHookRegistry.ZoraHook[] memory zoraHooks = zoraHookRegistry.getHooks();
54
+ assertEq(zoraHooks.length, 1);
55
+ assertEq(zoraHooks[0].hook, hooks[0]);
56
+ assertEq(zoraHooks[0].tag, "ZoraHook");
57
+ assertEq(zoraHooks[0].version, "0.0.0");
58
+ }
59
+
60
+ function test_revert_register_hooks_only_owner() public {
61
+ address[] memory hooks = new address[](1);
62
+ string[] memory tags = new string[](1);
63
+
64
+ hooks[0] = address(mockHook);
65
+ tags[0] = "ZoraHook";
66
+
67
+ vm.expectRevert(abi.encodeWithSignature("OnlyOwner()"));
68
+ vm.prank(makeAddr("notOwner"));
69
+ zoraHookRegistry.registerHooks(hooks, tags);
70
+ }
71
+
72
+ function test_revert_register_hooks_array_length_mismatch() public {
73
+ address[] memory hooks = new address[](2);
74
+ string[] memory tags = new string[](1);
75
+
76
+ hooks[0] = address(mockHook);
77
+ hooks[1] = makeAddr("anotherHook");
78
+ tags[0] = "Tag0";
79
+
80
+ vm.prank(owner);
81
+ vm.expectRevert(abi.encodeWithSignature("ArrayLengthMismatch()"));
82
+ zoraHookRegistry.registerHooks(hooks, tags);
83
+ }
84
+
85
+ function test_register_duplicate_is_idempotent() public {
86
+ address[] memory hooks = new address[](1);
87
+ string[] memory tags = new string[](1);
88
+
89
+ hooks[0] = address(mockHook);
90
+ tags[0] = "ZoraHook";
91
+
92
+ vm.startPrank(owner);
93
+ zoraHookRegistry.registerHooks(hooks, tags);
94
+ zoraHookRegistry.registerHooks(hooks, tags);
95
+ vm.stopPrank();
96
+
97
+ assertEq(zoraHookRegistry.getHookAddresses().length, 1);
98
+ assertEq(zoraHookRegistry.isRegisteredHook(hooks[0]), true);
99
+ }
100
+
101
+ function test_remove_hooks() public {
102
+ address[] memory hooks = new address[](1);
103
+ string[] memory tags = new string[](1);
104
+
105
+ hooks[0] = address(mockHook);
106
+ tags[0] = "ZoraHook";
107
+
108
+ vm.prank(owner);
109
+ zoraHookRegistry.registerHooks(hooks, tags);
110
+
111
+ vm.prank(owner);
112
+ zoraHookRegistry.removeHooks(hooks);
113
+
114
+ assertEq(zoraHookRegistry.isRegisteredHook(hooks[0]), false);
115
+ assertEq(zoraHookRegistry.getHookAddresses().length, 0);
116
+ assertEq(zoraHookRegistry.getHookTag(hooks[0]), "");
117
+ }
118
+
119
+ function test_revert_remove_hooks_only_owner() public {
120
+ address[] memory hooks = new address[](1);
121
+ string[] memory tags = new string[](1);
122
+
123
+ hooks[0] = address(mockHook);
124
+ tags[0] = "ZoraHook";
125
+
126
+ vm.prank(owner);
127
+ zoraHookRegistry.registerHooks(hooks, tags);
128
+
129
+ vm.expectRevert(abi.encodeWithSignature("OnlyOwner()"));
130
+ vm.prank(makeAddr("notOwner"));
131
+ zoraHookRegistry.removeHooks(hooks);
132
+ }
133
+
134
+ function test_remove_unregistered_noop() public {
135
+ address[] memory hooks = new address[](1);
136
+ hooks[0] = makeAddr("unregistered");
137
+
138
+ uint256 beforeLen = zoraHookRegistry.getHookAddresses().length;
139
+
140
+ vm.prank(owner);
141
+ zoraHookRegistry.removeHooks(hooks);
142
+
143
+ assertEq(zoraHookRegistry.getHookAddresses().length, beforeLen);
144
+ assertEq(zoraHookRegistry.isRegisteredHook(hooks[0]), false);
145
+ }
146
+
147
+ function test_emit_register_hooks_event() public {
148
+ address[] memory hooks = new address[](1);
149
+ string[] memory tags = new string[](1);
150
+
151
+ hooks[0] = address(mockHook);
152
+ tags[0] = "ZoraHook";
153
+
154
+ vm.expectEmit(true, true, true, false, address(zoraHookRegistry));
155
+ emit IZoraHookRegistry.ZoraHookRegistered(hooks[0], tags[0], "0.0.0");
156
+
157
+ vm.prank(owner);
158
+ zoraHookRegistry.registerHooks(hooks, tags);
159
+ }
160
+
161
+ function test_emit_remove_hooks_event() public {
162
+ address[] memory hooks = new address[](1);
163
+ string[] memory tags = new string[](1);
164
+
165
+ hooks[0] = address(mockHook);
166
+ tags[0] = "ZoraHook";
167
+
168
+ vm.prank(owner);
169
+ zoraHookRegistry.registerHooks(hooks, tags);
170
+
171
+ vm.expectEmit(true, true, true, false, address(zoraHookRegistry));
172
+ emit IZoraHookRegistry.ZoraHookRemoved(hooks[0], tags[0], "0.0.0");
173
+
174
+ vm.prank(owner);
175
+ zoraHookRegistry.removeHooks(hooks);
176
+ }
177
+
178
+ function test_hook_version() public {
179
+ address[] memory hooks = new address[](1);
180
+ string[] memory tags = new string[](1);
181
+
182
+ hooks[0] = 0x81542dC43Aff247eff4a0eceFC286A2973aE1040;
183
+ tags[0] = "CONTENT";
184
+
185
+ vm.prank(owner);
186
+ zoraHookRegistry.registerHooks(hooks, tags);
187
+
188
+ assertEq(zoraHookRegistry.getHookVersion(hooks[0]), "1.1.1");
189
+ }
190
+
191
+ function test_hook_version_not_found() public {
192
+ address[] memory hooks = new address[](1);
193
+ string[] memory tags = new string[](1);
194
+
195
+ hooks[0] = 0xA1eBdD5cA6470Bbd67114331387f2dDa7bfad040;
196
+ tags[0] = "CONTENT";
197
+
198
+ vm.prank(owner);
199
+ zoraHookRegistry.registerHooks(hooks, tags);
200
+
201
+ assertEq(zoraHookRegistry.getHookVersion(hooks[0]), "");
202
+ }
203
+
204
+ function test_is_registered_hook_false_when_never_registered() public view {
205
+ assertEq(zoraHookRegistry.isRegisteredHook(address(this)), false);
206
+ }
207
+
208
+ function test_get_hook_addresses_multiple_and_remove_middle() public {
209
+ address a = address(mockHook);
210
+ address b = address(new MockHook());
211
+ address c = address(new MockHook());
212
+
213
+ address[] memory hooks = new address[](3);
214
+ string[] memory tags = new string[](3);
215
+ hooks[0] = a;
216
+ tags[0] = "A";
217
+ hooks[1] = b;
218
+ tags[1] = "B";
219
+ hooks[2] = c;
220
+ tags[2] = "C";
221
+
222
+ vm.prank(owner);
223
+ zoraHookRegistry.registerHooks(hooks, tags);
224
+
225
+ address[] memory removeB = new address[](1);
226
+ removeB[0] = b;
227
+
228
+ vm.prank(owner);
229
+ zoraHookRegistry.removeHooks(removeB);
230
+
231
+ address[] memory addrs = zoraHookRegistry.getHookAddresses();
232
+ assertEq(addrs.length, 2);
233
+
234
+ bool hasA;
235
+ bool hasC;
236
+ for (uint256 i = 0; i < addrs.length; i++) {
237
+ if (addrs[i] == a) hasA = true;
238
+ if (addrs[i] == c) hasC = true;
239
+ assertTrue(addrs[i] != b);
240
+ }
241
+ assertTrue(hasA);
242
+ assertTrue(hasC);
243
+
244
+ assertEq(zoraHookRegistry.getHookTag(a), "A");
245
+ assertEq(zoraHookRegistry.getHookTag(b), "");
246
+ assertEq(zoraHookRegistry.getHookTag(c), "C");
247
+
248
+ IZoraHookRegistry.ZoraHook[] memory full = zoraHookRegistry.getHooks();
249
+ assertEq(full.length, 2);
250
+
251
+ bool okA;
252
+ bool okC;
253
+ for (uint256 i = 0; i < full.length; i++) {
254
+ if (full[i].hook == a) {
255
+ assertEq(full[i].tag, "A");
256
+ assertEq(full[i].version, "0.0.0");
257
+ okA = true;
258
+ } else if (full[i].hook == c) {
259
+ assertEq(full[i].tag, "C");
260
+ assertEq(full[i].version, "0.0.0");
261
+ okC = true;
262
+ }
263
+ }
264
+ assertTrue(okA && okC);
265
+ }
266
+ }
@@ -27,7 +27,7 @@ import {ProtocolRewards} from "../utils/ProtocolRewards.sol";
27
27
  import {MarketConstants} from "../../src/libs/MarketConstants.sol";
28
28
  import {CoinConfigurationVersions} from "../../src/libs/CoinConfigurationVersions.sol";
29
29
  import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
30
- import {ContentCoinHook} from "../../src/hooks/ContentCoinHook.sol";
30
+ import {ZoraV4CoinHook} from "../../src/hooks/ZoraV4CoinHook.sol";
31
31
  import {HooksDeployment} from "../../src/libs/HooksDeployment.sol";
32
32
  import {CoinConstants} from "../../src/libs/CoinConstants.sol";
33
33
  import {ProxyShim} from "./ProxyShim.sol";
@@ -41,15 +41,19 @@ import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
41
41
  import {Actions} from "@uniswap/v4-periphery/src/libraries/Actions.sol";
42
42
  import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
43
43
  import {CreatorCoin} from "../../src/CreatorCoin.sol";
44
- import {CreatorCoinHook} from "../../src/hooks/CreatorCoinHook.sol";
45
44
  import {ContractAddresses} from "./ContractAddresses.sol";
46
45
  import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
47
46
  import {HookUpgradeGate} from "../../src/hooks/HookUpgradeGate.sol";
47
+ import {ZoraHookRegistry} from "../../src/hook-registry/ZoraHookRegistry.sol";
48
48
 
49
49
  contract BaseTest is Test, ContractAddresses {
50
50
  using stdStorage for StdStorage;
51
51
 
52
52
  int24 internal constant USDC_TICK_LOWER = 57200;
53
+ int24 internal constant DEFAULT_DISCOVERY_TICK_LOWER = CoinConstants.DEFAULT_DISCOVERY_TICK_LOWER;
54
+ int24 internal constant DEFAULT_DISCOVERY_TICK_UPPER = CoinConstants.DEFAULT_DISCOVERY_TICK_UPPER;
55
+ uint16 internal constant DEFAULT_NUM_DISCOVERY_POSITIONS = CoinConstants.DEFAULT_NUM_DISCOVERY_POSITIONS;
56
+ uint256 internal constant DEFAULT_DISCOVERY_SUPPLY_SHARE = CoinConstants.DEFAULT_DISCOVERY_SUPPLY_SHARE;
53
57
 
54
58
  struct Users {
55
59
  address factoryOwner;
@@ -85,13 +89,9 @@ contract BaseTest is Test, ContractAddresses {
85
89
  CreatorCoin internal creatorCoinImpl;
86
90
  ZoraFactoryImpl internal factoryImpl;
87
91
  IZoraFactory internal factory;
88
- ContentCoinHook internal contentCoinHook;
89
- CreatorCoinHook internal creatorCoinHook;
92
+ ZoraV4CoinHook internal hook;
90
93
  HookUpgradeGate internal hookUpgradeGate;
91
- int24 internal constant DEFAULT_DISCOVERY_TICK_LOWER = CoinConstants.DEFAULT_DISCOVERY_TICK_LOWER;
92
- int24 internal constant DEFAULT_DISCOVERY_TICK_UPPER = CoinConstants.DEFAULT_DISCOVERY_TICK_UPPER;
93
- uint16 internal constant DEFAULT_NUM_DISCOVERY_POSITIONS = CoinConstants.DEFAULT_NUM_DISCOVERY_POSITIONS;
94
- uint256 internal constant DEFAULT_DISCOVERY_SUPPLY_SHARE = CoinConstants.DEFAULT_DISCOVERY_SUPPLY_SHARE;
94
+ ZoraHookRegistry internal zoraHookRegistry;
95
95
 
96
96
  function _defaultPoolConfig(address currency) internal pure returns (bytes memory) {
97
97
  return CoinConfigurationVersions.defaultDopplerMultiCurveUniV4(currency);
@@ -203,28 +203,14 @@ contract BaseTest is Test, ContractAddresses {
203
203
  vm.stopPrank();
204
204
  }
205
205
 
206
- function _deployFeeEstimatorHook(uint256 initialSupplyForPositions, address hooks) internal {
207
- deployCodeTo("FeeEstimatorHook.sol", abi.encode(V4_POOL_MANAGER, address(factory), hookUpgradeGate, initialSupplyForPositions), hooks);
206
+ function _deployFeeEstimatorHook(address hooks) internal {
207
+ deployCodeTo("FeeEstimatorHook.sol", abi.encode(V4_POOL_MANAGER, address(factory), hookUpgradeGate), hooks);
208
208
  }
209
209
 
210
- function getSalts(address[] memory trustedMessageSenders) public returns (bytes32 contentCoinSalt, bytes32 creatorCoinSalt) {
210
+ function getSalt(address[] memory trustedMessageSenders) public returns (bytes32 hookSalt) {
211
211
  address deployer = address(this);
212
212
 
213
- (, contentCoinSalt) = HooksDeployment.mineForContentCoinSalt(
214
- deployer,
215
- V4_POOL_MANAGER,
216
- address(factory),
217
- trustedMessageSenders,
218
- address(hookUpgradeGate)
219
- );
220
-
221
- (, creatorCoinSalt) = HooksDeployment.mineForCreatorCoinSalt(
222
- deployer,
223
- V4_POOL_MANAGER,
224
- address(factory),
225
- trustedMessageSenders,
226
- address(hookUpgradeGate)
227
- );
213
+ (, hookSalt) = HooksDeployment.mineForCoinSalt(deployer, V4_POOL_MANAGER, address(factory), trustedMessageSenders, address(hookUpgradeGate));
228
214
  }
229
215
 
230
216
  function _deployHooks() internal {
@@ -232,24 +218,14 @@ contract BaseTest is Test, ContractAddresses {
232
218
  trustedMessageSenders[0] = UNIVERSAL_ROUTER;
233
219
  trustedMessageSenders[1] = V4_POSITION_MANAGER;
234
220
 
235
- (bytes32 contentCoinSalt, bytes32 creatorCoinSalt) = getSalts(trustedMessageSenders);
221
+ bytes32 hookSalt = getSalt(trustedMessageSenders);
236
222
 
237
- contentCoinHook = ContentCoinHook(
238
- payable(
239
- address(
240
- HooksDeployment.deployHookWithSalt(
241
- HooksDeployment.contentCoinCreationCode(V4_POOL_MANAGER, address(factory), trustedMessageSenders, address(hookUpgradeGate)),
242
- contentCoinSalt
243
- )
244
- )
245
- )
246
- );
247
- creatorCoinHook = CreatorCoinHook(
223
+ hook = ZoraV4CoinHook(
248
224
  payable(
249
225
  address(
250
226
  HooksDeployment.deployHookWithSalt(
251
- HooksDeployment.creatorCoinHookCreationCode(V4_POOL_MANAGER, address(factory), trustedMessageSenders, address(hookUpgradeGate)),
252
- creatorCoinSalt
227
+ HooksDeployment.makeHookCreationCode(V4_POOL_MANAGER, address(factory), trustedMessageSenders, address(hookUpgradeGate)),
228
+ hookSalt
253
229
  )
254
230
  )
255
231
  )
@@ -291,13 +267,20 @@ contract BaseTest is Test, ContractAddresses {
291
267
 
292
268
  hookUpgradeGate = new HookUpgradeGate(users.factoryOwner);
293
269
 
270
+ zoraHookRegistry = new ZoraHookRegistry();
271
+
272
+ address[] memory initialOwners = new address[](2);
273
+ initialOwners[0] = users.factoryOwner;
274
+ initialOwners[1] = address(factory);
275
+ zoraHookRegistry.initialize(initialOwners);
276
+
294
277
  _deployHooks();
295
278
 
296
279
  coinV4Impl = new ContentCoin(users.feeRecipient, address(protocolRewards), IPoolManager(V4_POOL_MANAGER), DOPPLER_AIRLOCK);
297
280
 
298
281
  creatorCoinImpl = new CreatorCoin(users.feeRecipient, address(protocolRewards), IPoolManager(V4_POOL_MANAGER), DOPPLER_AIRLOCK);
299
282
 
300
- factoryImpl = new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(contentCoinHook), address(creatorCoinHook));
283
+ factoryImpl = new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(hook), address(zoraHookRegistry));
301
284
  UUPSUpgradeable(address(factory)).upgradeToAndCall(address(factoryImpl), "");
302
285
  factory = IZoraFactory(address(factory));
303
286
 
@@ -317,7 +300,7 @@ contract BaseTest is Test, ContractAddresses {
317
300
  vm.label(address(V4_QUOTER), "V4_QUOTER");
318
301
  vm.label(address(V4_PERMIT2), "V4_PERMIT2");
319
302
  vm.label(address(UNIVERSAL_ROUTER), "UNIVERSAL_ROUTER");
320
- vm.label(address(creatorCoinHook), "CREATOR_COIN_HOOK");
303
+ vm.label(address(hook), "HOOK");
321
304
  }
322
305
 
323
306
  struct TradeRewards {
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity ^0.8.13;
3
3
 
4
- import {ContentCoinHook} from "../../src/hooks/ContentCoinHook.sol";
4
+ import {ZoraV4CoinHook} from "../../src/hooks/ZoraV4CoinHook.sol";
5
5
  import {IPoolManager, PoolKey} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
6
6
  import {IDeployedCoinVersionLookup} from "../../src/interfaces/IDeployedCoinVersionLookup.sol";
7
7
  import {IHasRewardsRecipients} from "../../src/interfaces/IHasRewardsRecipients.sol";
@@ -15,11 +15,10 @@ import {ICoin, IHasSwapPath} from "../../src/interfaces/ICoin.sol";
15
15
  import {UniV4SwapToCurrency} from "../../src/libs/UniV4SwapToCurrency.sol";
16
16
  import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
17
17
  import {CoinRewardsV4} from "../../src/libs/CoinRewardsV4.sol";
18
- import {BaseZoraV4CoinHook} from "../../src/hooks/BaseZoraV4CoinHook.sol";
19
18
  import {IHooksUpgradeGate} from "../../src/interfaces/IHooksUpgradeGate.sol";
20
19
 
21
20
  /// @dev Test util - meant to be able to etched where a normal zora hook is, to gather the fees from swaps but not distribute them
22
- contract FeeEstimatorHook is BaseZoraV4CoinHook {
21
+ contract FeeEstimatorHook is ZoraV4CoinHook {
23
22
  struct FeeEstimatorState {
24
23
  uint128 fees0;
25
24
  uint128 fees1;
@@ -34,9 +33,8 @@ contract FeeEstimatorHook is BaseZoraV4CoinHook {
34
33
  constructor(
35
34
  IPoolManager _poolManager,
36
35
  IDeployedCoinVersionLookup _coinVersionLookup,
37
- IHooksUpgradeGate upgradeGate,
38
- uint256 initialSupplyForPositions
39
- ) BaseZoraV4CoinHook(_poolManager, _coinVersionLookup, new address[](0), upgradeGate, initialSupplyForPositions) {}
36
+ IHooksUpgradeGate upgradeGate
37
+ ) ZoraV4CoinHook(_poolManager, _coinVersionLookup, new address[](0), upgradeGate) {}
40
38
 
41
39
  FeeEstimatorState public feeState;
42
40