@zoralabs/coins 2.2.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/.turbo/turbo-build$colon$js.log +99 -99
  2. package/CHANGELOG.md +44 -5
  3. package/README.md +4 -0
  4. package/abis/BaseCoin.json +0 -5
  5. package/abis/ContentCoin.json +0 -5
  6. package/abis/CreatorCoin.json +0 -5
  7. package/abis/FeeEstimatorHook.json +94 -1
  8. package/abis/IUpgradeableDestinationV4HookWithUpdateableFee.json +95 -0
  9. package/abis/IZoraFactory.json +69 -0
  10. package/abis/ZoraFactoryImpl.json +69 -0
  11. package/abis/ZoraV4CoinHook.json +94 -1
  12. package/addresses/8453.json +6 -6
  13. package/audits/report-cantinacode-zora-0827.pdf +3498 -4
  14. package/dist/index.cjs +21 -3
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.js +21 -3
  17. package/dist/index.js.map +1 -1
  18. package/dist/wagmiGenerated.d.ts +54 -12
  19. package/dist/wagmiGenerated.d.ts.map +1 -1
  20. package/foundry.toml +3 -3
  21. package/package/wagmiGenerated.ts +21 -3
  22. package/package.json +1 -1
  23. package/script/TestBackingCoinSwap.s.sol +0 -2
  24. package/script/TestV4Swap.s.sol +0 -2
  25. package/src/BaseCoin.sol +4 -12
  26. package/src/ContentCoin.sol +3 -4
  27. package/src/CreatorCoin.sol +8 -10
  28. package/src/ZoraFactoryImpl.sol +115 -83
  29. package/src/hook-registry/ZoraHookRegistry.sol +4 -0
  30. package/src/hooks/ZoraV4CoinHook.sol +66 -9
  31. package/src/interfaces/IUpgradeableV4Hook.sol +18 -0
  32. package/src/interfaces/IZoraFactory.sol +21 -2
  33. package/src/libs/CoinConstants.sol +51 -8
  34. package/src/libs/CoinDopplerMultiCurve.sol +11 -11
  35. package/src/libs/CoinRewardsV4.sol +26 -33
  36. package/src/libs/CoinSetup.sol +2 -9
  37. package/src/libs/DopplerMath.sol +2 -2
  38. package/src/libs/V4Liquidity.sol +79 -15
  39. package/src/version/ContractVersionBase.sol +1 -1
  40. package/test/Coin.t.sol +5 -5
  41. package/test/CoinRewardsV4.t.sol +33 -0
  42. package/test/CoinUniV4.t.sol +2 -3
  43. package/test/ContentCoinRewards.t.sol +43 -0
  44. package/test/CreatorCoin.t.sol +53 -29
  45. package/test/DeploymentHooks.t.sol +54 -2
  46. package/test/LiquidityMigration.t.sol +145 -7
  47. package/test/V4Liquidity.t.sol +178 -0
  48. package/test/utils/BaseTest.sol +0 -1
  49. package/test/utils/RewardTestHelpers.sol +4 -4
  50. package/abis/CoinConstants.json +0 -54
  51. package/abis/CoinRewardsV4.json +0 -67
  52. package/src/libs/CreatorCoinConstants.sol +0 -15
  53. package/src/libs/MarketConstants.sol +0 -23
  54. /package/abis/{VmContractHelper227.json → VmContractHelper226.json} +0 -0
@@ -17,7 +17,13 @@ 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
19
  import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
20
+ import {MultiOwnable} from "../src/utils/MultiOwnable.sol";
20
21
  import {IHooksUpgradeGate} from "../src/interfaces/IHooksUpgradeGate.sol";
22
+ import {BaseCoin} from "../src/BaseCoin.sol";
23
+ import {CoinConstants} from "../src/libs/CoinConstants.sol";
24
+ import {SwapParams} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
25
+ import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
26
+ import {BalanceDeltaLibrary} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
21
27
 
22
28
  contract LiquidityMigrationReceiver is IUpgradeableDestinationV4Hook, IERC165 {
23
29
  function initializeFromMigration(
@@ -45,6 +51,8 @@ contract InvalidLiquidityMigrationReceiver is IERC165 {
45
51
  contract LiquidityMigrationTest is BaseTest {
46
52
  MockERC20 internal mockERC20A;
47
53
 
54
+ address constant coinVersionLookup = 0x777777751622c0d3258f214F9DF38E35BF45baF3;
55
+
48
56
  function setUp() public override {
49
57
  super.setUpWithBlockNumber(30267794);
50
58
 
@@ -125,31 +133,59 @@ contract LiquidityMigrationTest is BaseTest {
125
133
  assertEq(newPoolKey.tickSpacing, poolKey.tickSpacing, "poolkey tickSpacing");
126
134
  }
127
135
 
128
- function test_migrateLiquidity_enablesSwapsOnOldPoolKey() public {
136
+ function test_migrateLiquidity_revertsSwapsOnOldPoolKey() public {
129
137
  address currency = address(mockERC20A);
130
138
  mockERC20A.mint(address(poolManager), 1_000_000_000 ether);
131
139
  _deployV4Coin(currency);
132
140
 
133
141
  address trader = makeAddr("trader");
134
-
135
142
  mockERC20A.mint(trader, 10 ether);
136
143
 
137
- // do some swaps
144
+ // do some swaps before migration
138
145
  _swapSomeCurrencyForCoin(coinV4, currency, 1 ether, trader);
139
146
  _swapSomeCoinForCurrency(coinV4, currency, uint128(coinV4.balanceOf(trader)), trader);
140
147
 
141
- address newHook = address(new LiquidityMigrationReceiver());
142
-
143
148
  PoolKey memory poolKey = coinV4.getPoolKey();
149
+ bytes32 poolKeyHash = CoinCommon.hashPoolKey(poolKey);
150
+
151
+ // Verify the mapping exists before migration
152
+ IZoraV4CoinHook.PoolCoin memory poolCoinBefore = hook.getPoolCoin(poolKey);
153
+ assertEq(poolCoinBefore.coin, address(coinV4), "pool coin should exist before migration");
154
+
155
+ IZoraV4CoinHook.PoolCoin memory poolCoinByHashBefore = hook.getPoolCoinByHash(poolKeyHash);
156
+ assertEq(poolCoinByHashBefore.coin, address(coinV4), "pool coin by hash should exist before migration");
144
157
 
158
+ address newHook = address(new LiquidityMigrationReceiver());
145
159
  registerUpgradePath(address(poolKey.hooks), address(newHook));
146
160
 
147
161
  // migrate the liquidity
148
162
  vm.prank(users.creator);
149
163
  coinV4.migrateLiquidity(address(newHook), "");
150
164
 
151
- // now swap using the existing pool key, it should succeed
152
- _swapSomeCurrencyForCoin(poolKey, coinV4, currency, uint128(mockERC20A.balanceOf(trader)), trader);
165
+ // Verify that the old pool key mapping has been deleted
166
+ IZoraV4CoinHook.PoolCoin memory poolCoinAfter = hook.getPoolCoin(poolKey);
167
+ assertEq(poolCoinAfter.coin, address(0), "old pool key should have no associated coin after migration");
168
+ assertEq(poolCoinAfter.positions.length, 0, "old pool coin positions should be empty after migration");
169
+
170
+ IZoraV4CoinHook.PoolCoin memory poolCoinByHashAfter = hook.getPoolCoinByHash(poolKeyHash);
171
+ assertEq(poolCoinByHashAfter.coin, address(0), "old pool coin by hash should have no associated coin after migration");
172
+ assertEq(poolCoinByHashAfter.positions.length, 0, "old pool coin by hash positions should be empty after migration");
173
+
174
+ // Verify that hook operations revert with NoCoinForHook on the old poolkey
175
+ vm.expectRevert(abi.encodeWithSelector(IZoraV4CoinHook.NoCoinForHook.selector, poolKey));
176
+
177
+ SwapParams memory mockSwapParams = SwapParams({zeroForOne: true, amountSpecified: 1 ether, sqrtPriceLimitX96: 0});
178
+
179
+ BalanceDelta mockDelta = BalanceDeltaLibrary.ZERO_DELTA;
180
+
181
+ // Call afterSwap directly - this should revert with NoCoinForHook
182
+ vm.prank(address(poolManager));
183
+ IHooks(address(hook)).afterSwap(trader, poolKey, mockSwapParams, mockDelta, "");
184
+
185
+ // Verify the new pool key still works
186
+ PoolKey memory newPoolKey = coinV4.getPoolKey();
187
+ assertEq(address(newPoolKey.hooks), address(newHook), "coin should have updated to new hook");
188
+ assertTrue(address(poolKey.hooks) != address(newPoolKey.hooks), "old and new pool keys should be different");
153
189
  }
154
190
 
155
191
  function test_migrateLiquidity_emitsLiquidityMigrated() public {
@@ -383,4 +419,106 @@ contract LiquidityMigrationTest is BaseTest {
383
419
  // Should match isRegisteredUpgradePath
384
420
  assertEq(hookUpgradeGate.isAllowedHookUpgrade(baseImpl, upgradeImpl), hookUpgradeGate.isRegisteredUpgradePath(baseImpl, upgradeImpl));
385
421
  }
422
+
423
+ function test_migrateLiquidity_failsWithEmptyPositionBug() public {
424
+ // Reproduce the bug discovered in hook version 1.1.2 where migration
425
+ // tries to modify liquidity positions that have zero liquidity
426
+ vm.createSelectFork("base", 35671635);
427
+
428
+ address contentCoin = 0x81f5F30217dA777a5d6441606AFa57E093833d7C;
429
+ address oldHook = 0x9ea932730A7787000042e34390B8E435dD839040; // v1.1.2 hook
430
+ address newHook = 0xff74Be9D3596eA7a33BB4983DD7906fB34135040; // current hook
431
+ address upgradeGate = 0xD88f6BdD765313CaFA5888C177c325E2C3AbF2D2; // deployed upgrade gate
432
+
433
+ BaseCoin coin = BaseCoin(contentCoin);
434
+
435
+ uint24 oldFee = coin.getPoolKey().fee;
436
+
437
+ // Register upgrade path
438
+ address[] memory baseImpls = new address[](1);
439
+ baseImpls[0] = oldHook;
440
+
441
+ vm.prank(Ownable(upgradeGate).owner());
442
+ IHooksUpgradeGate(upgradeGate).registerUpgradePath(baseImpls, newHook);
443
+
444
+ // Get coin owner
445
+ address coinOwner = MultiOwnable(contentCoin).owners()[0];
446
+
447
+ // First, demonstrate the bug exists - this should fail
448
+ vm.prank(coinOwner);
449
+ vm.expectRevert();
450
+ coin.migrateLiquidity(newHook, "");
451
+
452
+ // Now fix the bug by etching fixed hook code onto the old hook address
453
+ bytes memory creationCode = HooksDeployment.makeHookCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
454
+
455
+ (IHooks fixedHook, ) = HooksDeployment.deployHookWithExistingOrNewSalt(address(this), creationCode, bytes32(0));
456
+
457
+ // Etch the fixed hook code onto the old hook address
458
+ vm.etch(oldHook, address(fixedHook).code);
459
+
460
+ // Now migration should work
461
+ vm.prank(coinOwner);
462
+ coin.migrateLiquidity(newHook, "");
463
+ }
464
+
465
+ function test_migrateLiquidity_canUseNewFee() public {
466
+ // Reproduce the bug discovered in hook version 1.1.2 where migration
467
+ // tries to modify liquidity positions that have zero liquidity
468
+ vm.createSelectFork("base", 35754730);
469
+
470
+ // jacob creator coin
471
+ BaseCoin coin = BaseCoin(0x9B13358E3a023507E7046c18f508A958cDA75f54);
472
+
473
+ address upgradeGate = 0xD88f6BdD765313CaFA5888C177c325E2C3AbF2D2; // live upgrade gate
474
+
475
+ uint24 oldFee = coin.getPoolKey().fee;
476
+
477
+ assertEq(oldFee, 30000);
478
+
479
+ // Now fix the bug by etching fixed hook code onto the old hook address
480
+ bytes memory creationCode = HooksDeployment.makeHookCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
481
+
482
+ (IHooks newHook, ) = HooksDeployment.deployHookWithExistingOrNewSalt(address(this), creationCode, bytes32(0));
483
+
484
+ // Register upgrade path
485
+ address[] memory baseImpls = new address[](1);
486
+ baseImpls[0] = address(coin.hooks());
487
+
488
+ vm.prank(Ownable(upgradeGate).owner());
489
+ IHooksUpgradeGate(upgradeGate).registerUpgradePath(baseImpls, address(newHook));
490
+
491
+ // Get coin owner
492
+ address coinOwner = MultiOwnable(address(coin)).owners()[0];
493
+
494
+ vm.prank(coinOwner);
495
+ coin.migrateLiquidity(address(newHook), "");
496
+
497
+ // fee should still be the same as before, because we didnt have the logic to update the fee in the old coin's hook.
498
+ assertEq(coin.getPoolKey().fee, oldFee);
499
+
500
+ address currencyAddress = address(coin.currency());
501
+
502
+ // now test swapping the migrated liquidity
503
+ address trader = makeAddr("trader");
504
+ deal(currencyAddress, trader, 10 ether);
505
+ _swapSomeCurrencyForCoin(coin, coin.currency(), 1 ether, trader);
506
+
507
+ // now migrate liquidity again, but this time to the same new hook as before
508
+ // since the bug has been fixed in the new hook, we should now be able to get the new fee
509
+ // register the upgrade path for the new hook to itself
510
+ baseImpls[0] = address(newHook);
511
+ vm.prank(Ownable(upgradeGate).owner());
512
+ IHooksUpgradeGate(upgradeGate).registerUpgradePath(baseImpls, address(newHook));
513
+
514
+ // migrate liquidity again to the same new hook as before
515
+ vm.prank(coinOwner);
516
+ coin.migrateLiquidity(address(newHook), "");
517
+
518
+ // the new fee should be the correct current fee
519
+ assertEq(coin.getPoolKey().fee, CoinConstants.LP_FEE_V4);
520
+
521
+ // now test swapping the migrated liquidity - it should work
522
+ _swapSomeCurrencyForCoin(coin, coin.currency(), 1 ether, trader);
523
+ }
386
524
  }
@@ -0,0 +1,178 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.13;
3
+
4
+ import "./utils/BaseTest.sol";
5
+ import {CoinConfigurationVersions} from "../src/libs/CoinConfigurationVersions.sol";
6
+ import {CoinDopplerMultiCurve} from "../src/libs/CoinDopplerMultiCurve.sol";
7
+ import {V4Liquidity} from "../src/libs/V4Liquidity.sol";
8
+ import {LpPosition} from "../src/types/LpPosition.sol";
9
+ import {PoolConfiguration} from "../src/interfaces/ICoin.sol";
10
+ import {CoinConstants} from "../src/libs/CoinConstants.sol";
11
+ import {MockERC20} from "./mocks/MockERC20.sol";
12
+ import {ContentCoin} from "../src/ContentCoin.sol";
13
+ import {ZoraV4CoinHook} from "../src/hooks/ZoraV4CoinHook.sol";
14
+ import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
15
+
16
+ contract V4LiquidityTest is BaseTest {
17
+ MockERC20 internal mockERC20A;
18
+
19
+ function setUp() public override {
20
+ super.setUp();
21
+ mockERC20A = new MockERC20("MockERC20A", "MCKA");
22
+ }
23
+
24
+ function _poolConfigWithDuplicatePositions(address currency) private pure returns (bytes memory poolConfig) {
25
+ // Create configuration that will produce duplicate positions
26
+ int24[] memory tickLower_ = new int24[](2);
27
+ tickLower_[0] = -54000;
28
+ tickLower_[1] = -54000; // Same as first curve
29
+
30
+ int24[] memory tickUpper_ = new int24[](2);
31
+ tickUpper_[0] = 7000;
32
+ tickUpper_[1] = 7000; // Same as first curve
33
+
34
+ uint16[] memory numDiscoveryPositions_ = new uint16[](2);
35
+ numDiscoveryPositions_[0] = 5;
36
+ numDiscoveryPositions_[1] = 5;
37
+
38
+ uint256[] memory maxDiscoverySupplyShare_ = new uint256[](2);
39
+ maxDiscoverySupplyShare_[0] = 100000000000000000; // 0.1e18
40
+ maxDiscoverySupplyShare_[1] = 100000000000000000; // 0.1e18
41
+
42
+ poolConfig = CoinConfigurationVersions.encodeDopplerMultiCurveUniV4(currency, tickLower_, tickUpper_, numDiscoveryPositions_, maxDiscoverySupplyShare_);
43
+ }
44
+
45
+ function _countDuplicatePositions(LpPosition[] memory positions) private pure returns (uint256 duplicateCount) {
46
+ for (uint256 i = 0; i < positions.length; i++) {
47
+ for (uint256 j = i + 1; j < positions.length; j++) {
48
+ if (positions[i].tickLower == positions[j].tickLower && positions[i].tickUpper == positions[j].tickUpper) {
49
+ duplicateCount++;
50
+ break; // Only count each unique duplicate once
51
+ }
52
+ }
53
+ }
54
+ }
55
+
56
+ function test_calculatePositionsWithDuplicateConfigCreatesDuplicates() public view {
57
+ address currency = address(mockERC20A);
58
+ bytes memory poolConfig = _poolConfigWithDuplicatePositions(currency);
59
+
60
+ (, PoolConfiguration memory poolConfiguration) = CoinDopplerMultiCurve.setupPool(true, poolConfig);
61
+
62
+ LpPosition[] memory positions = CoinDopplerMultiCurve.calculatePositions(
63
+ true, // isCoinToken0
64
+ poolConfiguration,
65
+ CoinConstants.CONTENT_COIN_MARKET_SUPPLY
66
+ );
67
+
68
+ uint256 duplicateCount = _countDuplicatePositions(positions);
69
+ assertGt(duplicateCount, 0, "Should have duplicate positions");
70
+ }
71
+
72
+ function test_dedupePositionsMergesDuplicates() public view {
73
+ address currency = address(mockERC20A);
74
+ bytes memory poolConfig = _poolConfigWithDuplicatePositions(currency);
75
+
76
+ (, PoolConfiguration memory poolConfiguration) = CoinDopplerMultiCurve.setupPool(true, poolConfig);
77
+
78
+ LpPosition[] memory originalPositions = CoinDopplerMultiCurve.calculatePositions(
79
+ true, // isCoinToken0
80
+ poolConfiguration,
81
+ CoinConstants.CONTENT_COIN_MARKET_SUPPLY
82
+ );
83
+
84
+ uint256 originalDuplicateCount = _countDuplicatePositions(originalPositions);
85
+ assertGt(originalDuplicateCount, 0, "Should have duplicate positions to test deduplication");
86
+
87
+ // Deduplicate the positions
88
+ LpPosition[] memory dedupedPositions = V4Liquidity.dedupePositions(originalPositions);
89
+
90
+ // Verify no duplicates exist in deduped array
91
+ uint256 dedupedDuplicateCount = _countDuplicatePositions(dedupedPositions);
92
+ assertEq(dedupedDuplicateCount, 0, "Should have no duplicates after deduplication");
93
+
94
+ // Verify that array is smaller after deduplication
95
+ assertLt(dedupedPositions.length, originalPositions.length, "Deduped array should be smaller");
96
+
97
+ // Calculate total liquidity before and after deduplication
98
+ uint256 totalOriginalLiquidity = 0;
99
+ uint256 totalDedupedLiquidity = 0;
100
+
101
+ for (uint256 i = 0; i < originalPositions.length; i++) {
102
+ totalOriginalLiquidity += originalPositions[i].liquidity;
103
+ }
104
+
105
+ for (uint256 i = 0; i < dedupedPositions.length; i++) {
106
+ totalDedupedLiquidity += dedupedPositions[i].liquidity;
107
+ }
108
+
109
+ assertEq(totalOriginalLiquidity, totalDedupedLiquidity, "Total liquidity should be preserved");
110
+ }
111
+
112
+ function test_memoryStructModification() public pure {
113
+ // this test shows that we can modify a struct in memory and it will be reflected in the array
114
+ LpPosition[] memory positions = new LpPosition[](2);
115
+ positions[0] = LpPosition({tickLower: -100, tickUpper: 100, liquidity: 1000});
116
+ positions[1] = LpPosition({tickLower: -200, tickUpper: 200, liquidity: 2000});
117
+
118
+ LpPosition memory pos = positions[0];
119
+ pos.liquidity += 500;
120
+ pos = positions[1];
121
+ pos.liquidity = 3000;
122
+
123
+ // The array element should be modified
124
+ assertEq(positions[0].liquidity, 1500, "Array element should change when modifying copy");
125
+ assertEq(positions[1].liquidity, 3000, "Array element should change when modifying copy");
126
+ }
127
+
128
+ function test_mstoreArrayLength() public pure {
129
+ LpPosition[] memory positions = new LpPosition[](5);
130
+ positions[0] = LpPosition({tickLower: -100, tickUpper: 100, liquidity: 1000});
131
+ positions[1] = LpPosition({tickLower: -200, tickUpper: 200, liquidity: 2000});
132
+ positions[2] = LpPosition({tickLower: -300, tickUpper: 300, liquidity: 3000});
133
+ positions[3] = LpPosition({tickLower: -400, tickUpper: 400, liquidity: 4000});
134
+ positions[4] = LpPosition({tickLower: -500, tickUpper: 500, liquidity: 5000});
135
+
136
+ assertEq(positions.length, 5, "Initial length should be 5");
137
+
138
+ assembly {
139
+ mstore(positions, 2)
140
+ }
141
+
142
+ assertEq(positions.length, 2, "Length should be 2 after mstore");
143
+ assertEq(positions[0].liquidity, 1000, "First element should be preserved");
144
+ assertEq(positions[1].liquidity, 2000, "Second element should be preserved");
145
+ }
146
+
147
+ function test_deployedCoinWithDuplicateConfigHasNoDuplicatePositions() public {
148
+ address currency = address(mockERC20A);
149
+
150
+ address[] memory owners = new address[](1);
151
+ owners[0] = users.creator;
152
+
153
+ bytes memory poolConfig = _poolConfigWithDuplicatePositions(currency);
154
+
155
+ (address coinAddress, ) = factory.deploy(
156
+ users.creator,
157
+ owners,
158
+ "https://test.com",
159
+ DEFAULT_NAME,
160
+ DEFAULT_SYMBOL,
161
+ poolConfig,
162
+ address(0),
163
+ address(0),
164
+ bytes(""),
165
+ bytes32(0)
166
+ );
167
+
168
+ ContentCoin coinV4 = ContentCoin(payable(coinAddress));
169
+
170
+ // get hooks
171
+ PoolKey memory poolKey = coinV4.getPoolKey();
172
+ LpPosition[] memory positions = ZoraV4CoinHook(payable(address(coinV4.hooks()))).getPoolCoin(poolKey).positions;
173
+
174
+ // Verify no duplicate positions exist in the deployed coin (deduplication worked during deployment)
175
+ uint256 duplicateCount = _countDuplicatePositions(positions);
176
+ assertEq(duplicateCount, 0, "Should have no duplicates after deployment");
177
+ }
178
+ }
@@ -24,7 +24,6 @@ import {IUniswapV3Factory} from "../../src/interfaces/IUniswapV3Factory.sol";
24
24
  import {IUniswapV3Pool} from "../../src/interfaces/IUniswapV3Pool.sol";
25
25
  import {IProtocolRewards} from "../../src/interfaces/IProtocolRewards.sol";
26
26
  import {ProtocolRewards} from "../utils/ProtocolRewards.sol";
27
- import {MarketConstants} from "../../src/libs/MarketConstants.sol";
28
27
  import {CoinConfigurationVersions} from "../../src/libs/CoinConfigurationVersions.sol";
29
28
  import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
30
29
  import {ZoraV4CoinHook} from "../../src/hooks/ZoraV4CoinHook.sol";
@@ -29,10 +29,10 @@ library RewardTestHelpers {
29
29
  bool hasPlatformReferrer,
30
30
  bool hasTradeReferrer
31
31
  ) internal pure returns (RewardBalances memory rewards) {
32
- rewards.creator = calculateReward(marketRewards, CoinRewardsV4.CREATOR_REWARD_BPS);
33
- rewards.platformReferrer = hasPlatformReferrer ? calculateReward(marketRewards, CoinRewardsV4.CREATE_REFERRAL_REWARD_BPS) : 0;
34
- rewards.tradeReferrer = hasTradeReferrer ? calculateReward(marketRewards, CoinRewardsV4.TRADE_REFERRAL_REWARD_BPS) : 0;
35
- rewards.doppler = calculateReward(marketRewards, CoinRewardsV4.DOPPLER_REWARD_BPS);
32
+ rewards.creator = calculateReward(marketRewards, CoinConstants.CREATOR_REWARD_BPS);
33
+ rewards.platformReferrer = hasPlatformReferrer ? calculateReward(marketRewards, CoinConstants.CREATE_REFERRAL_REWARD_BPS) : 0;
34
+ rewards.tradeReferrer = hasTradeReferrer ? calculateReward(marketRewards, CoinConstants.TRADE_REFERRAL_REWARD_BPS) : 0;
35
+ rewards.doppler = calculateReward(marketRewards, CoinConstants.DOPPLER_REWARD_BPS);
36
36
  rewards.protocol = marketRewards - rewards.creator - rewards.platformReferrer - rewards.tradeReferrer - rewards.doppler;
37
37
  }
38
38
 
@@ -1,54 +0,0 @@
1
- [
2
- {
3
- "type": "function",
4
- "name": "CREATOR_LAUNCH_REWARD",
5
- "inputs": [],
6
- "outputs": [
7
- {
8
- "name": "",
9
- "type": "uint256",
10
- "internalType": "uint256"
11
- }
12
- ],
13
- "stateMutability": "view"
14
- },
15
- {
16
- "type": "function",
17
- "name": "MAX_TOTAL_SUPPLY",
18
- "inputs": [],
19
- "outputs": [
20
- {
21
- "name": "",
22
- "type": "uint256",
23
- "internalType": "uint256"
24
- }
25
- ],
26
- "stateMutability": "view"
27
- },
28
- {
29
- "type": "function",
30
- "name": "MIN_ORDER_SIZE",
31
- "inputs": [],
32
- "outputs": [
33
- {
34
- "name": "",
35
- "type": "uint256",
36
- "internalType": "uint256"
37
- }
38
- ],
39
- "stateMutability": "view"
40
- },
41
- {
42
- "type": "function",
43
- "name": "POOL_LAUNCH_SUPPLY",
44
- "inputs": [],
45
- "outputs": [
46
- {
47
- "name": "",
48
- "type": "uint256",
49
- "internalType": "uint256"
50
- }
51
- ],
52
- "stateMutability": "view"
53
- }
54
- ]
@@ -1,67 +0,0 @@
1
- [
2
- {
3
- "type": "function",
4
- "name": "CREATE_REFERRAL_REWARD_BPS",
5
- "inputs": [],
6
- "outputs": [
7
- {
8
- "name": "",
9
- "type": "uint256",
10
- "internalType": "uint256"
11
- }
12
- ],
13
- "stateMutability": "view"
14
- },
15
- {
16
- "type": "function",
17
- "name": "CREATOR_REWARD_BPS",
18
- "inputs": [],
19
- "outputs": [
20
- {
21
- "name": "",
22
- "type": "uint256",
23
- "internalType": "uint256"
24
- }
25
- ],
26
- "stateMutability": "view"
27
- },
28
- {
29
- "type": "function",
30
- "name": "DOPPLER_REWARD_BPS",
31
- "inputs": [],
32
- "outputs": [
33
- {
34
- "name": "",
35
- "type": "uint256",
36
- "internalType": "uint256"
37
- }
38
- ],
39
- "stateMutability": "view"
40
- },
41
- {
42
- "type": "function",
43
- "name": "LP_REWARD_BPS",
44
- "inputs": [],
45
- "outputs": [
46
- {
47
- "name": "",
48
- "type": "uint256",
49
- "internalType": "uint256"
50
- }
51
- ],
52
- "stateMutability": "view"
53
- },
54
- {
55
- "type": "function",
56
- "name": "TRADE_REFERRAL_REWARD_BPS",
57
- "inputs": [],
58
- "outputs": [
59
- {
60
- "name": "",
61
- "type": "uint256",
62
- "internalType": "uint256"
63
- }
64
- ],
65
- "stateMutability": "view"
66
- }
67
- ]
@@ -1,15 +0,0 @@
1
- // SPDX-License-Identifier: ZORA-DELAYED-OSL-v1
2
- // This software is licensed under the Zora Delayed Open Source License.
3
- // Under this license, you may use, copy, modify, and distribute this software for
4
- // non-commercial purposes only. Commercial use and competitive products are prohibited
5
- // until the "Open Date" (3 years from first public distribution or earlier at Zora's discretion),
6
- // at which point this software automatically becomes available under the MIT License.
7
- // Full license terms available at: https://docs.zora.co/coins/license
8
- pragma solidity ^0.8.23;
9
-
10
- library CreatorCoinConstants {
11
- uint256 internal constant TOTAL_SUPPLY = 1_000_000_000e18; // 1b coins
12
- uint256 internal constant CREATOR_VESTING_SUPPLY = 500_000_000e18; // 500m coins
13
- uint256 internal constant CREATOR_VESTING_DURATION = 5 * 365 days; // 5 years
14
- address internal constant CURRENCY = 0x1111111111166b7FE7bd91427724B487980aFc69;
15
- }
@@ -1,23 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.23;
3
-
4
- library MarketConstants {
5
- /// @dev Constant used to increase precision during calculations
6
- uint256 internal constant WAD = 1e18;
7
-
8
- /// @notice The number of coins allocated to the liquidity pool for content coins
9
- /// @dev 990 million coins
10
- uint256 internal constant CONTENT_COIN_MARKET_SUPPLY = 990_000_000 * WAD;
11
-
12
- /// @notice The number of coins allocated to the liquidity pool for creator coins
13
- /// @dev 500 million coins
14
- uint256 internal constant CREATOR_COIN_MARKET_SUPPLY = 500_000_000 * WAD;
15
-
16
- /// @notice The LP fee
17
- /// @dev 10000 basis points = 1%
18
- uint24 internal constant LP_FEE_V4 = 10_000;
19
-
20
- /// @notice The spacing for 1% pools
21
- /// @dev 200 ticks
22
- int24 internal constant TICK_SPACING = 200;
23
- }