@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.
- package/.turbo/turbo-build.log +107 -114
- package/CHANGELOG.md +34 -0
- package/README.md +30 -109
- package/abis/BaseCoin.json +442 -0
- package/abis/CoinTest.json +3 -246
- package/abis/FactoryTest.json +5 -137
- package/abis/HooksTest.json +0 -26
- package/abis/ICoin.json +378 -0
- package/abis/ICoinV3.json +378 -0
- package/abis/IZoraFactory.json +0 -18
- package/abis/LiquidityMigrationTest.json +101 -0
- package/abis/MockBadFactory.json +15 -0
- package/abis/ZoraFactoryImpl.json +1 -67
- package/dist/index.cjs +236 -265
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +235 -264
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +389 -493
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/foundry.toml +1 -3
- package/package/wagmiGenerated.ts +240 -269
- package/package.json +3 -3
- package/script/DeployPostDeploymentHooks.s.sol +2 -2
- package/script/TestBackingCoinSwap.s.sol +8 -8
- package/script/TestV4Swap.s.sol +8 -8
- package/script/UpgradeFactoryImpl.s.sol +0 -1
- package/src/BaseCoin.sol +111 -7
- package/src/ContentCoin.sol +4 -4
- package/src/CreatorCoin.sol +5 -5
- package/src/ZoraFactoryImpl.sol +10 -93
- package/src/deployment/CoinsDeployerBase.sol +10 -27
- package/src/hooks/BaseZoraV4CoinHook.sol +5 -5
- package/src/hooks/ContentCoinHook.sol +2 -2
- package/src/hooks/deployment/BuySupplyWithSwapRouterHook.sol +4 -5
- package/src/interfaces/ICoin.sol +67 -1
- package/src/interfaces/ICreatorCoin.sol +2 -2
- package/src/interfaces/IZoraFactory.sol +0 -5
- package/src/libs/CoinConfigurationVersions.sol +1 -39
- package/src/libs/CoinRewardsV4.sol +2 -2
- package/src/libs/CoinSetup.sol +1 -4
- package/src/libs/MarketConstants.sol +0 -4
- package/src/libs/UniV4SwapHelper.sol +1 -1
- package/src/libs/UniV4SwapToCurrency.sol +2 -2
- package/src/libs/V4Liquidity.sol +1 -1
- package/src/version/ContractVersionBase.sol +1 -1
- package/test/Coin.t.sol +112 -535
- package/test/CoinUniV4.t.sol +7 -7
- package/test/DeploymentHooks.t.sol +5 -102
- package/test/Factory.t.sol +23 -306
- package/test/LiquidityMigration.t.sol +160 -2
- package/test/MultiOwnable.t.sol +36 -36
- package/test/Upgrades.t.sol +16 -35
- package/test/utils/BaseTest.sol +16 -69
- package/test/utils/FeeEstimatorHook.sol +3 -3
- package/wagmi.config.ts +1 -1
- package/abis/BaseCoinV4.json +0 -1840
- package/abis/Coin.json +0 -1912
- package/abis/DopplerUniswapV3Test.json +0 -800
- package/abis/ICoinV4.json +0 -1048
- package/abis/Simulate.json +0 -29
- package/abis/UniV3BuySell.json +0 -12
- package/abis/UniV3Errors.json +0 -32
- package/script/Simulate.s.sol +0 -59
- package/src/BaseCoinV4.sol +0 -143
- package/src/Coin.sol +0 -236
- package/src/interfaces/ICoinV4.sol +0 -74
- package/src/libs/CoinDopplerUniV3.sol +0 -50
- package/src/libs/CoinRewards.sol +0 -201
- package/src/libs/CoinSetupV3.sol +0 -50
- package/src/libs/UniV3BuySell.sol +0 -231
- package/src/libs/UniV3Errors.sol +0 -11
- 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 {
|
|
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
|
|
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
|
}
|
package/test/MultiOwnable.t.sol
CHANGED
|
@@ -7,13 +7,13 @@ contract MultiOwnableTest is BaseTest {
|
|
|
7
7
|
function setUp() public override {
|
|
8
8
|
super.setUp();
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
_deployV4Coin();
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
function test_initial_owners() public view {
|
|
14
|
-
assertEq(
|
|
15
|
-
assertEq(
|
|
16
|
-
assertEq(
|
|
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
|
-
|
|
25
|
+
coinV4.addOwners(newOwners);
|
|
26
26
|
|
|
27
|
-
assertEq(
|
|
28
|
-
assertEq(
|
|
29
|
-
assertEq(
|
|
30
|
-
assertEq(
|
|
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
|
-
|
|
35
|
+
coinV4.addOwner(address(this));
|
|
36
36
|
|
|
37
|
-
assertEq(
|
|
38
|
-
assertEq(
|
|
39
|
-
assertEq(
|
|
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
|
-
|
|
48
|
+
coinV4.addOwners(newOwners);
|
|
49
49
|
|
|
50
50
|
vm.prank(users.creator);
|
|
51
|
-
|
|
51
|
+
coinV4.removeOwners(newOwners);
|
|
52
52
|
|
|
53
|
-
assertEq(
|
|
54
|
-
assertEq(
|
|
55
|
-
assertEq(
|
|
56
|
-
assertEq(
|
|
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
|
-
|
|
61
|
+
coinV4.addOwner(address(this));
|
|
62
62
|
|
|
63
63
|
vm.prank(address(this));
|
|
64
|
-
|
|
64
|
+
coinV4.removeOwner(users.creator);
|
|
65
65
|
|
|
66
|
-
assertEq(
|
|
67
|
-
assertEq(
|
|
68
|
-
assertEq(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
93
|
+
coinV4.addOwner(newOwner);
|
|
94
94
|
|
|
95
95
|
vm.prank(newOwner);
|
|
96
|
-
|
|
96
|
+
coinV4.removeOwner(users.creator);
|
|
97
97
|
|
|
98
98
|
vm.prank(newOwner);
|
|
99
99
|
vm.expectRevert(abi.encodeWithSelector(MultiOwnable.UseRevokeOwnershipToRemoveSelf.selector));
|
|
100
|
-
|
|
100
|
+
coinV4.removeOwner(newOwner);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
function test_revoke_ownership() public {
|
|
104
104
|
vm.prank(users.creator);
|
|
105
|
-
|
|
105
|
+
coinV4.revokeOwnership();
|
|
106
106
|
|
|
107
|
-
assertEq(
|
|
108
|
-
assertEq(
|
|
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
|
-
|
|
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
|
-
|
|
129
|
+
coinV4.addOwner(newOwner);
|
|
130
130
|
|
|
131
131
|
vm.expectRevert(MultiOwnable.AlreadyOwner.selector);
|
|
132
132
|
vm.prank(users.creator);
|
|
133
|
-
|
|
133
|
+
coinV4.addOwners(newOwners);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
function test_revert_init_with_zero_owners() public {
|
package/test/Upgrades.t.sol
CHANGED
|
@@ -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 {
|
|
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(
|
|
150
|
+
_swapSomeCurrencyForCoin(ICoin(coinAddress), ZORA, uint128(IERC20(ZORA).balanceOf(trader)), trader);
|
|
170
151
|
|
|
171
152
|
// do some swaps to test out
|
|
172
|
-
_swapSomeCoinForCurrency(
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
203
|
+
vm.etch(address(ICoin(contentCoin).hooks()), address(newHook).code);
|
|
223
204
|
|
|
224
|
-
_swapSomeCurrencyForCoin(
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
265
|
+
ICoin creatorCoin = ICoin(0x2F03aB8fD97F5874bc3274C296Bb954Ae92EdA34);
|
|
285
266
|
|
|
286
267
|
address zora = creatorCoin.currency();
|
|
287
268
|
|
package/test/utils/BaseTest.sol
CHANGED
|
@@ -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 {
|
|
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 (
|
|
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 (
|
|
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_ =
|
|
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
|
-
|
|
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(
|
|
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,
|
|
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(
|
|
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(
|