@zoralabs/coins 2.0.0 → 2.1.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 (72) hide show
  1. package/.turbo/turbo-build.log +107 -114
  2. package/CHANGELOG.md +34 -0
  3. package/README.md +30 -109
  4. package/abis/BaseCoin.json +442 -0
  5. package/abis/CoinTest.json +3 -246
  6. package/abis/FactoryTest.json +5 -137
  7. package/abis/HooksTest.json +0 -26
  8. package/abis/ICoin.json +378 -0
  9. package/abis/ICoinV3.json +378 -0
  10. package/abis/IZoraFactory.json +0 -18
  11. package/abis/LiquidityMigrationTest.json +101 -0
  12. package/abis/MockBadFactory.json +15 -0
  13. package/abis/ZoraFactoryImpl.json +1 -67
  14. package/dist/index.cjs +236 -265
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.js +235 -264
  17. package/dist/index.js.map +1 -1
  18. package/dist/wagmiGenerated.d.ts +389 -493
  19. package/dist/wagmiGenerated.d.ts.map +1 -1
  20. package/foundry.toml +1 -3
  21. package/package/wagmiGenerated.ts +240 -269
  22. package/package.json +3 -3
  23. package/script/DeployPostDeploymentHooks.s.sol +2 -2
  24. package/script/TestBackingCoinSwap.s.sol +8 -8
  25. package/script/TestV4Swap.s.sol +8 -8
  26. package/script/UpgradeFactoryImpl.s.sol +0 -1
  27. package/src/BaseCoin.sol +111 -7
  28. package/src/ContentCoin.sol +4 -4
  29. package/src/CreatorCoin.sol +5 -5
  30. package/src/ZoraFactoryImpl.sol +10 -93
  31. package/src/deployment/CoinsDeployerBase.sol +10 -27
  32. package/src/hooks/BaseZoraV4CoinHook.sol +5 -5
  33. package/src/hooks/ContentCoinHook.sol +2 -2
  34. package/src/hooks/deployment/BuySupplyWithSwapRouterHook.sol +4 -5
  35. package/src/interfaces/ICoin.sol +67 -1
  36. package/src/interfaces/ICreatorCoin.sol +2 -2
  37. package/src/interfaces/IZoraFactory.sol +0 -5
  38. package/src/libs/CoinConfigurationVersions.sol +1 -39
  39. package/src/libs/CoinRewardsV4.sol +2 -2
  40. package/src/libs/CoinSetup.sol +1 -4
  41. package/src/libs/MarketConstants.sol +0 -4
  42. package/src/libs/UniV4SwapHelper.sol +1 -1
  43. package/src/libs/UniV4SwapToCurrency.sol +2 -2
  44. package/src/libs/V4Liquidity.sol +1 -1
  45. package/src/version/ContractVersionBase.sol +1 -1
  46. package/test/Coin.t.sol +112 -535
  47. package/test/CoinUniV4.t.sol +7 -7
  48. package/test/DeploymentHooks.t.sol +5 -102
  49. package/test/Factory.t.sol +23 -306
  50. package/test/LiquidityMigration.t.sol +160 -2
  51. package/test/MultiOwnable.t.sol +36 -36
  52. package/test/Upgrades.t.sol +16 -35
  53. package/test/utils/BaseTest.sol +16 -69
  54. package/test/utils/FeeEstimatorHook.sol +3 -3
  55. package/wagmi.config.ts +1 -1
  56. package/abis/BaseCoinV4.json +0 -1840
  57. package/abis/Coin.json +0 -1912
  58. package/abis/DopplerUniswapV3Test.json +0 -800
  59. package/abis/ICoinV4.json +0 -1048
  60. package/abis/Simulate.json +0 -29
  61. package/abis/UniV3BuySell.json +0 -12
  62. package/abis/UniV3Errors.json +0 -32
  63. package/script/Simulate.s.sol +0 -59
  64. package/src/BaseCoinV4.sol +0 -143
  65. package/src/Coin.sol +0 -236
  66. package/src/interfaces/ICoinV4.sol +0 -74
  67. package/src/libs/CoinDopplerUniV3.sol +0 -50
  68. package/src/libs/CoinRewards.sol +0 -201
  69. package/src/libs/CoinSetupV3.sol +0 -50
  70. package/src/libs/UniV3BuySell.sol +0 -231
  71. package/src/libs/UniV3Errors.sol +0 -11
  72. package/test/CoinDopplerUniV3.t.sol +0 -310
@@ -13,9 +13,11 @@ import {LpPosition} from "../src/types/LpPosition.sol";
13
13
  import {V4Liquidity} from "../src/libs/V4Liquidity.sol";
14
14
  import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
15
15
  import {IZoraV4CoinHook} from "../src/interfaces/IZoraV4CoinHook.sol";
16
- import {ICoinV4} from "../src/interfaces/ICoinV4.sol";
16
+ import {ICoin} from "../src/interfaces/ICoin.sol";
17
17
  import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
18
18
  import {CoinCommon} from "../src/libs/CoinCommon.sol";
19
+ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
20
+ import {IHooksUpgradeGate} from "../src/interfaces/IHooksUpgradeGate.sol";
19
21
 
20
22
  contract LiquidityMigrationReceiver is IUpgradeableDestinationV4Hook, IERC165 {
21
23
  function initializeFromMigration(
@@ -175,7 +177,7 @@ contract LiquidityMigrationTest is BaseTest {
175
177
  // migrate the liquidity
176
178
  vm.prank(users.creator);
177
179
  vm.expectEmit(true, true, true, true);
178
- emit ICoinV4.LiquidityMigrated(poolKey, fromPoolKeyHash, newPoolKey, toPoolKeyHash);
180
+ emit ICoin.LiquidityMigrated(poolKey, fromPoolKeyHash, newPoolKey, toPoolKeyHash);
179
181
  coinV4.migrateLiquidity(address(newHook), "");
180
182
  }
181
183
 
@@ -230,4 +232,160 @@ contract LiquidityMigrationTest is BaseTest {
230
232
  vm.expectRevert(abi.encodeWithSelector(IZoraV4CoinHook.OnlyCoin.selector, users.creator, address(coinV4)));
231
233
  IUpgradeableV4Hook(originalHook).migrateLiquidity(address(newHook), poolKey, "");
232
234
  }
235
+
236
+ // Hook Upgrade Gate Tests
237
+ function test_hookUpgradeGate_removeUpgradePath() public {
238
+ address baseImpl = makeAddr("baseImpl");
239
+ address upgradeImpl = makeAddr("upgradeImpl");
240
+
241
+ // First register the upgrade path
242
+ address[] memory baseImpls = new address[](1);
243
+ baseImpls[0] = baseImpl;
244
+
245
+ vm.prank(hookUpgradeGate.owner());
246
+ hookUpgradeGate.registerUpgradePath(baseImpls, upgradeImpl);
247
+
248
+ // Verify it's registered
249
+ assertTrue(hookUpgradeGate.isRegisteredUpgradePath(baseImpl, upgradeImpl));
250
+
251
+ // Remove the upgrade path
252
+ vm.prank(hookUpgradeGate.owner());
253
+ vm.expectEmit(true, true, false, false);
254
+ emit IHooksUpgradeGate.UpgradeRemoved(baseImpl, upgradeImpl);
255
+ hookUpgradeGate.removeUpgradePath(baseImpl, upgradeImpl);
256
+
257
+ // Verify it's removed
258
+ assertFalse(hookUpgradeGate.isRegisteredUpgradePath(baseImpl, upgradeImpl));
259
+ }
260
+
261
+ function test_hookUpgradeGate_removeUpgradePath_onlyOwner() public {
262
+ address baseImpl = makeAddr("baseImpl");
263
+ address upgradeImpl = makeAddr("upgradeImpl");
264
+ address nonOwner = makeAddr("nonOwner");
265
+
266
+ // Try to remove upgrade path as non-owner
267
+ vm.prank(nonOwner);
268
+ vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, nonOwner));
269
+ hookUpgradeGate.removeUpgradePath(baseImpl, upgradeImpl);
270
+ }
271
+
272
+ function test_hookUpgradeGate_registerUpgradePath_onlyOwner() public {
273
+ address baseImpl = makeAddr("baseImpl");
274
+ address upgradeImpl = makeAddr("upgradeImpl");
275
+ address nonOwner = makeAddr("nonOwner");
276
+
277
+ address[] memory baseImpls = new address[](1);
278
+ baseImpls[0] = baseImpl;
279
+
280
+ // Try to register upgrade path as non-owner
281
+ vm.prank(nonOwner);
282
+ vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, nonOwner));
283
+ hookUpgradeGate.registerUpgradePath(baseImpls, upgradeImpl);
284
+ }
285
+
286
+ function test_hookUpgradeGate_registerMultipleUpgradePaths() public {
287
+ address baseImpl1 = makeAddr("baseImpl1");
288
+ address baseImpl2 = makeAddr("baseImpl2");
289
+ address baseImpl3 = makeAddr("baseImpl3");
290
+ address upgradeImpl = makeAddr("upgradeImpl");
291
+
292
+ address[] memory baseImpls = new address[](3);
293
+ baseImpls[0] = baseImpl1;
294
+ baseImpls[1] = baseImpl2;
295
+ baseImpls[2] = baseImpl3;
296
+
297
+ // Register multiple upgrade paths at once
298
+ vm.prank(hookUpgradeGate.owner());
299
+ vm.expectEmit(true, true, false, false);
300
+ emit IHooksUpgradeGate.UpgradeRegistered(baseImpl1, upgradeImpl);
301
+ vm.expectEmit(true, true, false, false);
302
+ emit IHooksUpgradeGate.UpgradeRegistered(baseImpl2, upgradeImpl);
303
+ vm.expectEmit(true, true, false, false);
304
+ emit IHooksUpgradeGate.UpgradeRegistered(baseImpl3, upgradeImpl);
305
+ hookUpgradeGate.registerUpgradePath(baseImpls, upgradeImpl);
306
+
307
+ // Verify all paths are registered
308
+ assertTrue(hookUpgradeGate.isRegisteredUpgradePath(baseImpl1, upgradeImpl));
309
+ assertTrue(hookUpgradeGate.isRegisteredUpgradePath(baseImpl2, upgradeImpl));
310
+ assertTrue(hookUpgradeGate.isRegisteredUpgradePath(baseImpl3, upgradeImpl));
311
+ }
312
+
313
+ function test_hookUpgradeGate_registerEmptyArray() public {
314
+ address upgradeImpl = makeAddr("upgradeImpl");
315
+ address[] memory baseImpls = new address[](0);
316
+
317
+ // Register with empty array - should succeed but do nothing
318
+ vm.prank(hookUpgradeGate.owner());
319
+ hookUpgradeGate.registerUpgradePath(baseImpls, upgradeImpl);
320
+
321
+ // No events should be emitted, no state changes
322
+ }
323
+
324
+ function test_hookUpgradeGate_removeNonexistentUpgradePath() public {
325
+ address baseImpl = makeAddr("baseImpl");
326
+ address upgradeImpl = makeAddr("upgradeImpl");
327
+
328
+ // Try to remove a path that was never registered
329
+ vm.prank(hookUpgradeGate.owner());
330
+ vm.expectEmit(true, true, false, false);
331
+ emit IHooksUpgradeGate.UpgradeRemoved(baseImpl, upgradeImpl);
332
+ hookUpgradeGate.removeUpgradePath(baseImpl, upgradeImpl);
333
+
334
+ // Should still be false (was already false)
335
+ assertFalse(hookUpgradeGate.isRegisteredUpgradePath(baseImpl, upgradeImpl));
336
+ }
337
+
338
+ function test_hookUpgradeGate_registerSamePathTwice() public {
339
+ address baseImpl = makeAddr("baseImpl");
340
+ address upgradeImpl = makeAddr("upgradeImpl");
341
+
342
+ address[] memory baseImpls = new address[](1);
343
+ baseImpls[0] = baseImpl;
344
+
345
+ // Register once
346
+ vm.prank(hookUpgradeGate.owner());
347
+ hookUpgradeGate.registerUpgradePath(baseImpls, upgradeImpl);
348
+ assertTrue(hookUpgradeGate.isRegisteredUpgradePath(baseImpl, upgradeImpl));
349
+
350
+ // Register again - should succeed and overwrite (true -> true)
351
+ vm.prank(hookUpgradeGate.owner());
352
+ vm.expectEmit(true, true, false, false);
353
+ emit IHooksUpgradeGate.UpgradeRegistered(baseImpl, upgradeImpl);
354
+ hookUpgradeGate.registerUpgradePath(baseImpls, upgradeImpl);
355
+ assertTrue(hookUpgradeGate.isRegisteredUpgradePath(baseImpl, upgradeImpl));
356
+ }
357
+
358
+ function test_hookUpgradeGate_zeroAddressHandling() public {
359
+ address[] memory baseImpls = new address[](2);
360
+ baseImpls[0] = address(0);
361
+ baseImpls[1] = makeAddr("baseImpl");
362
+ address upgradeImpl = address(0);
363
+
364
+ // Should allow zero addresses (no validation in contract)
365
+ vm.prank(hookUpgradeGate.owner());
366
+ hookUpgradeGate.registerUpgradePath(baseImpls, upgradeImpl);
367
+
368
+ assertTrue(hookUpgradeGate.isRegisteredUpgradePath(address(0), address(0)));
369
+ assertTrue(hookUpgradeGate.isRegisteredUpgradePath(makeAddr("baseImpl"), address(0)));
370
+ }
371
+
372
+ function test_hookUpgradeGate_isAllowedHookUpgradeMapping() public {
373
+ address baseImpl = makeAddr("baseImpl");
374
+ address upgradeImpl = makeAddr("upgradeImpl");
375
+
376
+ // Test direct mapping access
377
+ assertFalse(hookUpgradeGate.isAllowedHookUpgrade(baseImpl, upgradeImpl));
378
+
379
+ // Register upgrade path
380
+ address[] memory baseImpls = new address[](1);
381
+ baseImpls[0] = baseImpl;
382
+ vm.prank(hookUpgradeGate.owner());
383
+ hookUpgradeGate.registerUpgradePath(baseImpls, upgradeImpl);
384
+
385
+ // Test direct mapping access
386
+ assertTrue(hookUpgradeGate.isAllowedHookUpgrade(baseImpl, upgradeImpl));
387
+
388
+ // Should match isRegisteredUpgradePath
389
+ assertEq(hookUpgradeGate.isAllowedHookUpgrade(baseImpl, upgradeImpl), hookUpgradeGate.isRegisteredUpgradePath(baseImpl, upgradeImpl));
390
+ }
233
391
  }
@@ -7,13 +7,13 @@ contract MultiOwnableTest is BaseTest {
7
7
  function setUp() public override {
8
8
  super.setUp();
9
9
 
10
- _deployCoin();
10
+ _deployV4Coin();
11
11
  }
12
12
 
13
13
  function test_initial_owners() public view {
14
- assertEq(coin.owners().length, 1);
15
- assertEq(coin.owners()[0], users.creator);
16
- assertEq(coin.isOwner(users.creator), true);
14
+ assertEq(coinV4.owners().length, 1);
15
+ assertEq(coinV4.owners()[0], users.creator);
16
+ assertEq(coinV4.isOwner(users.creator), true);
17
17
  }
18
18
 
19
19
  function test_add_owners() public {
@@ -22,21 +22,21 @@ contract MultiOwnableTest is BaseTest {
22
22
  newOwners[1] = makeAddr("NewOwner2");
23
23
 
24
24
  vm.prank(users.creator);
25
- coin.addOwners(newOwners);
25
+ coinV4.addOwners(newOwners);
26
26
 
27
- assertEq(coin.owners().length, 3);
28
- assertEq(coin.isOwner(users.creator), true);
29
- assertEq(coin.isOwner(newOwners[0]), true);
30
- assertEq(coin.isOwner(newOwners[1]), true);
27
+ assertEq(coinV4.owners().length, 3);
28
+ assertEq(coinV4.isOwner(users.creator), true);
29
+ assertEq(coinV4.isOwner(newOwners[0]), true);
30
+ assertEq(coinV4.isOwner(newOwners[1]), true);
31
31
  }
32
32
 
33
33
  function test_add_owner() public {
34
34
  vm.prank(users.creator);
35
- coin.addOwner(address(this));
35
+ coinV4.addOwner(address(this));
36
36
 
37
- assertEq(coin.owners().length, 2);
38
- assertEq(coin.isOwner(users.creator), true);
39
- assertEq(coin.isOwner(address(this)), true);
37
+ assertEq(coinV4.owners().length, 2);
38
+ assertEq(coinV4.isOwner(users.creator), true);
39
+ assertEq(coinV4.isOwner(address(this)), true);
40
40
  }
41
41
 
42
42
  function test_remove_owners() public {
@@ -45,67 +45,67 @@ contract MultiOwnableTest is BaseTest {
45
45
  newOwners[1] = makeAddr("NewOwner2");
46
46
 
47
47
  vm.prank(users.creator);
48
- coin.addOwners(newOwners);
48
+ coinV4.addOwners(newOwners);
49
49
 
50
50
  vm.prank(users.creator);
51
- coin.removeOwners(newOwners);
51
+ coinV4.removeOwners(newOwners);
52
52
 
53
- assertEq(coin.owners().length, 1);
54
- assertEq(coin.isOwner(users.creator), true);
55
- assertEq(coin.isOwner(newOwners[0]), false);
56
- assertEq(coin.isOwner(newOwners[1]), false);
53
+ assertEq(coinV4.owners().length, 1);
54
+ assertEq(coinV4.isOwner(users.creator), true);
55
+ assertEq(coinV4.isOwner(newOwners[0]), false);
56
+ assertEq(coinV4.isOwner(newOwners[1]), false);
57
57
  }
58
58
 
59
59
  function test_remove_owner() public {
60
60
  vm.prank(users.creator);
61
- coin.addOwner(address(this));
61
+ coinV4.addOwner(address(this));
62
62
 
63
63
  vm.prank(address(this));
64
- coin.removeOwner(users.creator);
64
+ coinV4.removeOwner(users.creator);
65
65
 
66
- assertEq(coin.owners().length, 1);
67
- assertEq(coin.isOwner(users.creator), false);
68
- assertEq(coin.isOwner(address(this)), true);
66
+ assertEq(coinV4.owners().length, 1);
67
+ assertEq(coinV4.isOwner(users.creator), false);
68
+ assertEq(coinV4.isOwner(address(this)), true);
69
69
  }
70
70
 
71
71
  function test_revert_only_owner_can_add() public {
72
72
  vm.expectRevert(abi.encodeWithSelector(MultiOwnable.OnlyOwner.selector));
73
- coin.addOwner(address(this));
73
+ coinV4.addOwner(address(this));
74
74
  }
75
75
 
76
76
  function test_revert_only_owner_can_remove() public {
77
77
  vm.expectRevert(abi.encodeWithSelector(MultiOwnable.OnlyOwner.selector));
78
78
 
79
79
  vm.prank(address(this));
80
- coin.removeOwner(users.creator);
80
+ coinV4.removeOwner(users.creator);
81
81
  }
82
82
 
83
83
  function test_revert_cannot_remove_not_owner() public {
84
84
  vm.expectRevert(abi.encodeWithSelector(MultiOwnable.NotOwner.selector));
85
85
  vm.prank(users.creator);
86
- coin.removeOwner(address(this));
86
+ coinV4.removeOwner(address(this));
87
87
  }
88
88
 
89
89
  function test_revert_last_owner_must_revoke() public {
90
90
  address newOwner = makeAddr("NewOwner1");
91
91
 
92
92
  vm.prank(users.creator);
93
- coin.addOwner(newOwner);
93
+ coinV4.addOwner(newOwner);
94
94
 
95
95
  vm.prank(newOwner);
96
- coin.removeOwner(users.creator);
96
+ coinV4.removeOwner(users.creator);
97
97
 
98
98
  vm.prank(newOwner);
99
99
  vm.expectRevert(abi.encodeWithSelector(MultiOwnable.UseRevokeOwnershipToRemoveSelf.selector));
100
- coin.removeOwner(newOwner);
100
+ coinV4.removeOwner(newOwner);
101
101
  }
102
102
 
103
103
  function test_revoke_ownership() public {
104
104
  vm.prank(users.creator);
105
- coin.revokeOwnership();
105
+ coinV4.revokeOwnership();
106
106
 
107
- assertEq(coin.owners().length, 0);
108
- assertEq(coin.isOwner(users.creator), false);
107
+ assertEq(coinV4.owners().length, 0);
108
+ assertEq(coinV4.isOwner(users.creator), false);
109
109
  }
110
110
 
111
111
  function test_revert_add_owners_with_zero_address() public {
@@ -116,7 +116,7 @@ contract MultiOwnableTest is BaseTest {
116
116
 
117
117
  vm.prank(users.creator);
118
118
  vm.expectRevert(MultiOwnable.OwnerCannotBeAddressZero.selector);
119
- coin.addOwners(newOwners);
119
+ coinV4.addOwners(newOwners);
120
120
  }
121
121
 
122
122
  function test_revert_add_owners_with_duplicate() public {
@@ -126,11 +126,11 @@ contract MultiOwnableTest is BaseTest {
126
126
  newOwners[1] = newOwner;
127
127
 
128
128
  vm.prank(users.creator);
129
- coin.addOwner(newOwner);
129
+ coinV4.addOwner(newOwner);
130
130
 
131
131
  vm.expectRevert(MultiOwnable.AlreadyOwner.selector);
132
132
  vm.prank(users.creator);
133
- coin.addOwners(newOwners);
133
+ coinV4.addOwners(newOwners);
134
134
  }
135
135
 
136
136
  function test_revert_init_with_zero_owners() public {
@@ -6,7 +6,7 @@ import {ZoraFactoryImpl} from "../src/ZoraFactoryImpl.sol";
6
6
  import {BaseTest} from "./utils/BaseTest.sol";
7
7
  import {CoinsDeployerBase} from "../src/deployment/CoinsDeployerBase.sol";
8
8
  import {CoinConfigurationVersions} from "../src/libs/CoinConfigurationVersions.sol";
9
- import {ICoinV4} from "../src/interfaces/ICoinV4.sol";
9
+ import {ICoin} from "../src/interfaces/ICoin.sol";
10
10
  import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
11
11
  import {ISwapRouter} from "../src/interfaces/ISwapRouter.sol";
12
12
  import {IWETH} from "../src/interfaces/IWETH.sol";
@@ -43,13 +43,7 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
43
43
 
44
44
  factoryProxy = ZoraFactoryImpl(0x777777751622c0d3258f214F9DF38E35BF45baF3);
45
45
 
46
- ZoraFactoryImpl newImpl = new ZoraFactoryImpl(
47
- factoryProxy.coinImpl(),
48
- address(coinV4Impl),
49
- address(creatorCoinImpl),
50
- address(contentCoinHook),
51
- address(creatorCoinHook)
52
- );
46
+ ZoraFactoryImpl newImpl = new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(contentCoinHook), address(creatorCoinHook));
53
47
 
54
48
  vm.prank(factoryProxy.owner());
55
49
  factoryProxy.upgradeToAndCall(address(newImpl), "");
@@ -64,13 +58,7 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
64
58
 
65
59
  factoryProxy = ZoraFactoryImpl(0x777777751622c0d3258f214F9DF38E35BF45baF3);
66
60
 
67
- ZoraFactoryImpl newImpl = new ZoraFactoryImpl(
68
- factoryProxy.coinImpl(),
69
- address(coinV4Impl),
70
- address(creatorCoinImpl),
71
- address(contentCoinHook),
72
- address(creatorCoinHook)
73
- );
61
+ ZoraFactoryImpl newImpl = new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(contentCoinHook), address(creatorCoinHook));
74
62
 
75
63
  vm.prank(factoryProxy.owner());
76
64
  factoryProxy.upgradeToAndCall(address(newImpl), "");
@@ -88,19 +76,12 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
88
76
 
89
77
  factoryProxy = ZoraFactoryImpl(0x777777751622c0d3258f214F9DF38E35BF45baF3);
90
78
 
91
- ZoraFactoryImpl newImpl = new ZoraFactoryImpl(
92
- factoryProxy.coinImpl(),
93
- address(coinV4Impl),
94
- address(creatorCoinImpl),
95
- address(contentCoinHook),
96
- address(creatorCoinHook)
97
- );
79
+ ZoraFactoryImpl newImpl = new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(contentCoinHook), address(creatorCoinHook));
98
80
 
99
81
  vm.prank(factoryProxy.owner());
100
82
  factoryProxy.upgradeToAndCall(address(newImpl), "");
101
83
 
102
84
  ZoraFactoryImpl newImpl2 = new ZoraFactoryImpl(
103
- factoryProxy.coinImpl(),
104
85
  factoryProxy.coinV4Impl(),
105
86
  factoryProxy.creatorCoinImpl(),
106
87
  address(contentCoinHook),
@@ -166,16 +147,16 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
166
147
  );
167
148
 
168
149
  // do some swaps to test out
169
- _swapSomeCurrencyForCoin(ICoinV4(coinAddress), ZORA, uint128(IERC20(ZORA).balanceOf(trader)), trader);
150
+ _swapSomeCurrencyForCoin(ICoin(coinAddress), ZORA, uint128(IERC20(ZORA).balanceOf(trader)), trader);
170
151
 
171
152
  // do some swaps to test out
172
- _swapSomeCoinForCurrency(ICoinV4(coinAddress), ZORA, uint128(IERC20(coinAddress).balanceOf(trader)), trader);
153
+ _swapSomeCoinForCurrency(ICoin(coinAddress), ZORA, uint128(IERC20(coinAddress).balanceOf(trader)), trader);
173
154
  }
174
155
 
175
156
  address coinVersionLookup = 0x777777751622c0d3258f214F9DF38E35BF45baF3;
176
157
  address upgradeGate = 0xD88f6BdD765313CaFA5888C177c325E2C3AbF2D2;
177
158
 
178
- function _swapSomeCurrencyForCoinAndExpectRevert(ICoinV4 _coin, address currency, uint128 amountIn, address trader) internal {
159
+ function _swapSomeCurrencyForCoinAndExpectRevert(ICoin _coin, address currency, uint128 amountIn, address trader) internal {
179
160
  uint128 minAmountOut = uint128(0);
180
161
 
181
162
  (bytes memory commands, bytes[] memory inputs) = UniV4SwapHelper.buildExactInputSingleSwapCommand(
@@ -205,23 +186,23 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
205
186
 
206
187
  address contentCoin = 0x4E93A01c90f812284F71291a8d1415a904957156;
207
188
 
208
- address creatorCoin = ICoinV4(contentCoin).currency();
189
+ address creatorCoin = ICoin(contentCoin).currency();
209
190
 
210
191
  uint256 amountIn = IERC20(creatorCoin).balanceOf(trader);
211
192
 
212
193
  require(amountIn > 0, "no balance");
213
194
 
214
195
  // this swap should revert because the content coin is broken
215
- _swapSomeCurrencyForCoinAndExpectRevert(ICoinV4(contentCoin), creatorCoin, uint128(amountIn), trader);
196
+ _swapSomeCurrencyForCoinAndExpectRevert(ICoin(contentCoin), creatorCoin, uint128(amountIn), trader);
216
197
 
217
198
  bytes memory creationCode = HooksDeployment.contentCoinCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
218
199
 
219
200
  (IHooks newHook, ) = HooksDeployment.deployHookWithExistingOrNewSalt(address(this), creationCode, bytes32(0));
220
201
 
221
202
  // etch new hook into the content coin, it shouldn't revert anymore when swapping
222
- vm.etch(address(ICoinV4(contentCoin).hooks()), address(newHook).code);
203
+ vm.etch(address(ICoin(contentCoin).hooks()), address(newHook).code);
223
204
 
224
- _swapSomeCurrencyForCoin(ICoinV4(contentCoin), creatorCoin, uint128(amountIn), trader);
205
+ _swapSomeCurrencyForCoin(ICoin(contentCoin), creatorCoin, uint128(amountIn), trader);
225
206
  }
226
207
 
227
208
  function test_canUpgradeBrokenContentCoinAndSwap() public {
@@ -231,7 +212,7 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
231
212
 
232
213
  address contentCoin = 0xB9799C839818bF50240CE683363D00c43a2E23b8;
233
214
 
234
- address creatorCoin = ICoinV4(contentCoin).currency();
215
+ address creatorCoin = ICoin(contentCoin).currency();
235
216
 
236
217
  uint256 amountIn = 0.000111 ether;
237
218
 
@@ -239,7 +220,7 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
239
220
 
240
221
  (IHooks newHook, ) = HooksDeployment.deployHookWithExistingOrNewSalt(address(this), creationCode, bytes32(0));
241
222
 
242
- address existingHook = address(ICoinV4(contentCoin).hooks());
223
+ address existingHook = address(ICoin(contentCoin).hooks());
243
224
 
244
225
  address[] memory baseImpls = new address[](1);
245
226
  baseImpls[0] = existingHook;
@@ -251,7 +232,7 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
251
232
  ContentCoin(contentCoin).migrateLiquidity(address(newHook), "");
252
233
 
253
234
  // do some swaps to test out
254
- _swapSomeCurrencyForCoin(ICoinV4(contentCoin), creatorCoin, uint128(amountIn), trader);
235
+ _swapSomeCurrencyForCoin(ICoin(contentCoin), creatorCoin, uint128(amountIn), trader);
255
236
  }
256
237
 
257
238
  function getPositionInfo(
@@ -272,7 +253,7 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
272
253
  }
273
254
  }
274
255
 
275
- function getLiquidityForPoolCoin(ICoinV4 coin) internal view returns (uint128[] memory liquidityForPositions) {
256
+ function getLiquidityForPoolCoin(ICoin coin) internal view returns (uint128[] memory liquidityForPositions) {
276
257
  return getLiquidityForPositions(coin.getPoolKey(), IZoraV4CoinHook(address(coin.hooks())).getPoolCoin(coin.getPoolKey()).positions);
277
258
  }
278
259
 
@@ -281,7 +262,7 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
281
262
 
282
263
  address trader = 0xf69fEc6d858c77e969509843852178bd24CAd2B6;
283
264
 
284
- ICoinV4 creatorCoin = ICoinV4(0x2F03aB8fD97F5874bc3274C296Bb954Ae92EdA34);
265
+ ICoin creatorCoin = ICoin(0x2F03aB8fD97F5874bc3274C296Bb954Ae92EdA34);
285
266
 
286
267
  address zora = creatorCoin.currency();
287
268
 
@@ -12,7 +12,6 @@ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/U
12
12
  import {IZoraFactory} from "../../src/interfaces/IZoraFactory.sol";
13
13
  import {ZoraFactoryImpl} from "../../src/ZoraFactoryImpl.sol";
14
14
  import {ZoraFactory} from "../../src/proxy/ZoraFactory.sol";
15
- import {Coin} from "../../src/Coin.sol";
16
15
  import {ContentCoin} from "../../src/ContentCoin.sol";
17
16
  import {MultiOwnable} from "../../src/utils/MultiOwnable.sol";
18
17
  import {ICoin} from "../../src/interfaces/ICoin.sol";
@@ -32,7 +31,7 @@ import {ContentCoinHook} from "../../src/hooks/ContentCoinHook.sol";
32
31
  import {HooksDeployment} from "../../src/libs/HooksDeployment.sol";
33
32
  import {CoinConstants} from "../../src/libs/CoinConstants.sol";
34
33
  import {ProxyShim} from "./ProxyShim.sol";
35
- import {ICoinV4} from "../../src/interfaces/ICoinV4.sol";
34
+ import {ICoin} from "../../src/interfaces/ICoin.sol";
36
35
  import {UniV4SwapHelper} from "../../src/libs/UniV4SwapHelper.sol";
37
36
  import {IPermit2} from "permit2/src/interfaces/IPermit2.sol";
38
37
  import {IUniversalRouter} from "@uniswap/universal-router/contracts/interfaces/IUniversalRouter.sol";
@@ -81,7 +80,7 @@ contract BaseTest is Test, ContractAddresses {
81
80
  IAirlock internal airlock;
82
81
  Users internal users;
83
82
 
84
- Coin internal coinV3Impl;
83
+ // Coin internal coinV3Impl;
85
84
  ContentCoin internal coinV4Impl;
86
85
  CreatorCoin internal creatorCoinImpl;
87
86
  ZoraFactoryImpl internal factoryImpl;
@@ -89,47 +88,16 @@ contract BaseTest is Test, ContractAddresses {
89
88
  ContentCoinHook internal contentCoinHook;
90
89
  CreatorCoinHook internal creatorCoinHook;
91
90
  HookUpgradeGate internal hookUpgradeGate;
92
- Coin internal coin;
93
-
94
- IUniswapV3Pool internal pool;
95
91
  int24 internal constant DEFAULT_DISCOVERY_TICK_LOWER = CoinConstants.DEFAULT_DISCOVERY_TICK_LOWER;
96
92
  int24 internal constant DEFAULT_DISCOVERY_TICK_UPPER = CoinConstants.DEFAULT_DISCOVERY_TICK_UPPER;
97
93
  uint16 internal constant DEFAULT_NUM_DISCOVERY_POSITIONS = CoinConstants.DEFAULT_NUM_DISCOVERY_POSITIONS;
98
94
  uint256 internal constant DEFAULT_DISCOVERY_SUPPLY_SHARE = CoinConstants.DEFAULT_DISCOVERY_SUPPLY_SHARE;
99
95
 
100
- function _deployCoin() internal {
101
- bytes memory poolConfig_ = _generatePoolConfig(
102
- CoinConfigurationVersions.DOPPLER_UNI_V3_POOL_VERSION,
103
- address(weth),
104
- DEFAULT_DISCOVERY_TICK_LOWER,
105
- DEFAULT_DISCOVERY_TICK_UPPER,
106
- DEFAULT_NUM_DISCOVERY_POSITIONS,
107
- DEFAULT_DISCOVERY_SUPPLY_SHARE
108
- );
109
- vm.prank(users.creator);
110
- (address coinAddress, ) = factory.deploy(
111
- users.creator,
112
- _getDefaultOwners(),
113
- "https://test.com",
114
- "Testcoin",
115
- "TEST",
116
- poolConfig_,
117
- users.platformReferrer,
118
- 0
119
- );
120
-
121
- coin = Coin(payable(coinAddress));
122
- pool = IUniswapV3Pool(coin.poolAddress());
123
-
124
- vm.label(address(coin), "COIN");
125
- vm.label(address(pool), "POOL");
126
- }
127
-
128
96
  function _defaultPoolConfig(address currency) internal pure returns (bytes memory) {
129
97
  return CoinConfigurationVersions.defaultDopplerMultiCurveUniV4(currency);
130
98
  }
131
99
 
132
- function _deployV4Coin(address currency) internal returns (ICoinV4) {
100
+ function _deployV4Coin(address currency) internal returns (ICoin) {
133
101
  bytes32 salt = keccak256(abi.encode(bytes("randomSalt")));
134
102
  return _deployV4Coin(currency, address(0), salt);
135
103
  }
@@ -137,7 +105,7 @@ contract BaseTest is Test, ContractAddresses {
137
105
  string constant DEFAULT_NAME = "Testcoin";
138
106
  string constant DEFAULT_SYMBOL = "TEST";
139
107
 
140
- function _deployV4Coin(address currency, address createReferral, bytes32 salt) internal returns (ICoinV4) {
108
+ function _deployV4Coin(address currency, address createReferral, bytes32 salt) internal returns (ICoin) {
141
109
  address[] memory owners = new address[](1);
142
110
  owners[0] = users.creator;
143
111
 
@@ -161,15 +129,13 @@ contract BaseTest is Test, ContractAddresses {
161
129
  return coinV4;
162
130
  }
163
131
 
132
+ function _deployV4Coin() internal returns (ICoin) {
133
+ // deploy with eth and no referral
134
+ return _deployV4Coin(address(0), address(0), bytes32(0));
135
+ }
136
+
164
137
  function _deployCoinUSDCPair() internal {
165
- bytes memory poolConfig_ = _generatePoolConfig(
166
- CoinConfigurationVersions.DOPPLER_UNI_V3_POOL_VERSION,
167
- USDC_ADDRESS,
168
- DEFAULT_DISCOVERY_TICK_LOWER,
169
- DEFAULT_DISCOVERY_TICK_UPPER,
170
- DEFAULT_NUM_DISCOVERY_POSITIONS,
171
- DEFAULT_DISCOVERY_SUPPLY_SHARE
172
- );
138
+ bytes memory poolConfig_ = _defaultPoolConfig(USDC_ADDRESS);
173
139
  vm.prank(users.creator);
174
140
  (address coinAddress, ) = factory.deploy(
175
141
  users.creator,
@@ -182,18 +148,14 @@ contract BaseTest is Test, ContractAddresses {
182
148
  0
183
149
  );
184
150
 
185
- coin = Coin(payable(coinAddress));
186
- pool = IUniswapV3Pool(coin.poolAddress());
187
-
188
- vm.label(address(coin), "COIN");
189
- vm.label(address(pool), "POOL");
151
+ vm.label(coinAddress, "COIN");
190
152
  }
191
153
 
192
- function _swapSomeCurrencyForCoin(ICoinV4 _coin, address currency, uint128 amountIn, address trader) internal {
154
+ function _swapSomeCurrencyForCoin(ICoin _coin, address currency, uint128 amountIn, address trader) internal {
193
155
  _swapSomeCurrencyForCoin(_coin.getPoolKey(), _coin, currency, amountIn, trader);
194
156
  }
195
157
 
196
- function _swapSomeCurrencyForCoin(PoolKey memory poolKey, ICoinV4 _coin, address currency, uint128 amountIn, address trader) internal {
158
+ function _swapSomeCurrencyForCoin(PoolKey memory poolKey, ICoin _coin, address currency, uint128 amountIn, address trader) internal {
197
159
  uint128 minAmountOut = uint128(0);
198
160
 
199
161
  (bytes memory commands, bytes[] memory inputs) = UniV4SwapHelper.buildExactInputSingleSwapCommand(
@@ -219,7 +181,7 @@ contract BaseTest is Test, ContractAddresses {
219
181
  vm.stopPrank();
220
182
  }
221
183
 
222
- function _swapSomeCoinForCurrency(ICoinV4 _coin, address currency, uint128 amountIn, address trader) internal {
184
+ function _swapSomeCoinForCurrency(ICoin _coin, address currency, uint128 amountIn, address trader) internal {
223
185
  uint128 minAmountOut = uint128(0);
224
186
 
225
187
  (bytes memory commands, bytes[] memory inputs) = UniV4SwapHelper.buildExactInputSingleSwapCommand(
@@ -326,7 +288,6 @@ contract BaseTest is Test, ContractAddresses {
326
288
 
327
289
  ProxyShim mockUpgradeableImpl = new ProxyShim();
328
290
  factory = IZoraFactory(address(new ZoraFactory(address(mockUpgradeableImpl))));
329
- coinV3Impl = new Coin(users.feeRecipient, address(protocolRewards), WETH_ADDRESS, V3_FACTORY, SWAP_ROUTER, DOPPLER_AIRLOCK);
330
291
 
331
292
  hookUpgradeGate = new HookUpgradeGate(users.factoryOwner);
332
293
 
@@ -336,13 +297,7 @@ contract BaseTest is Test, ContractAddresses {
336
297
 
337
298
  creatorCoinImpl = new CreatorCoin(users.feeRecipient, address(protocolRewards), IPoolManager(V4_POOL_MANAGER), DOPPLER_AIRLOCK);
338
299
 
339
- factoryImpl = new ZoraFactoryImpl(
340
- address(coinV3Impl),
341
- address(coinV4Impl),
342
- address(creatorCoinImpl),
343
- address(contentCoinHook),
344
- address(creatorCoinHook)
345
- );
300
+ factoryImpl = new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(contentCoinHook), address(creatorCoinHook));
346
301
  UUPSUpgradeable(address(factory)).upgradeToAndCall(address(factoryImpl), "");
347
302
  factory = IZoraFactory(address(factory));
348
303
 
@@ -419,15 +374,7 @@ contract BaseTest is Test, ContractAddresses {
419
374
  }
420
375
 
421
376
  function _generatePoolConfig(address currency_) internal pure returns (bytes memory) {
422
- return
423
- _generatePoolConfig(
424
- CoinConfigurationVersions.DOPPLER_UNI_V3_POOL_VERSION,
425
- currency_,
426
- DEFAULT_DISCOVERY_TICK_LOWER,
427
- DEFAULT_DISCOVERY_TICK_UPPER,
428
- DEFAULT_NUM_DISCOVERY_POSITIONS,
429
- DEFAULT_DISCOVERY_SUPPLY_SHARE
430
- );
377
+ return CoinConfigurationVersions.defaultDopplerMultiCurveUniV4(currency_);
431
378
  }
432
379
 
433
380
  function _generatePoolConfig(