@zoralabs/coins 0.9.0 → 1.0.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 (131) hide show
  1. package/.turbo/turbo-build.log +179 -114
  2. package/CHANGELOG.md +46 -0
  3. package/abis/BaseCoin.json +26 -118
  4. package/abis/BaseTest.json +47 -0
  5. package/abis/BuySupplyWithSwapRouterHook.json +40 -0
  6. package/abis/Coin.json +171 -63
  7. package/abis/CoinDopplerMultiCurve.json +38 -0
  8. package/abis/CoinRewardsV4.json +54 -0
  9. package/abis/CoinTest.json +53 -20
  10. package/abis/CoinUniV4Test.json +1091 -0
  11. package/abis/CoinV4.json +234 -211
  12. package/abis/DeployScript.json +47 -0
  13. package/abis/DeployedCoinVersionLookup.json +21 -0
  14. package/abis/DeployedCoinVersionLookupTest.json +716 -0
  15. package/abis/DifferentNamespaceVersionLookup.json +39 -0
  16. package/abis/DopplerUniswapV3Test.json +49 -93
  17. package/abis/ERC20.json +310 -0
  18. package/abis/FactoryTest.json +85 -7
  19. package/abis/FeeEstimatorHook.json +1515 -0
  20. package/abis/HooksDeployment.json +23 -0
  21. package/abis/HooksTest.json +60 -0
  22. package/abis/ICoin.json +40 -71
  23. package/abis/ICoinV3.json +879 -0
  24. package/abis/ICoinV4.json +915 -0
  25. package/abis/IDeployedCoinVersionLookup.json +21 -0
  26. package/abis/IERC721.json +36 -36
  27. package/abis/IHasPoolKey.json +42 -0
  28. package/abis/IHasRewardsRecipients.json +54 -0
  29. package/abis/IHasSwapPath.json +60 -0
  30. package/abis/IMsgSender.json +15 -0
  31. package/abis/IPoolConfigEncoding.json +46 -0
  32. package/abis/ISwapPathRouter.json +92 -0
  33. package/abis/IUniversalRouter.json +61 -0
  34. package/abis/IUnlockCallback.json +21 -0
  35. package/abis/IV4Quoter.json +310 -0
  36. package/abis/IZoraFactory.json +210 -11
  37. package/abis/IZoraV4CoinHook.json +348 -4
  38. package/abis/MockERC20.json +21 -0
  39. package/abis/MultiOwnableTest.json +47 -0
  40. package/abis/{CoinConfigurationVersions.json → Position.json} +1 -1
  41. package/abis/PrintUpgradeCommand.json +9 -0
  42. package/abis/ProxyShim.json +24 -0
  43. package/abis/StateLibrary.json +80 -0
  44. package/abis/TestDeployedCoinVersionLookupImplementation.json +39 -0
  45. package/abis/TestV4Swap.json +9 -0
  46. package/abis/UpgradeCoinImpl.json +47 -0
  47. package/abis/UpgradesTest.json +81 -0
  48. package/abis/Vm.json +1482 -111
  49. package/abis/VmSafe.json +856 -32
  50. package/abis/ZoraFactoryImpl.json +339 -1
  51. package/abis/ZoraV4CoinHook.json +442 -5
  52. package/addresses/8453.json +7 -4
  53. package/addresses/84532.json +8 -5
  54. package/addresses/dev/8453.json +10 -0
  55. package/dist/index.cjs +1932 -167
  56. package/dist/index.cjs.map +1 -1
  57. package/dist/index.js +1928 -167
  58. package/dist/index.js.map +1 -1
  59. package/dist/wagmiGenerated.d.ts +2606 -160
  60. package/dist/wagmiGenerated.d.ts.map +1 -1
  61. package/foundry.toml +1 -0
  62. package/package/wagmiGenerated.ts +1941 -164
  63. package/package.json +8 -3
  64. package/remappings.txt +6 -1
  65. package/script/Deploy.s.sol +1 -1
  66. package/script/DeployDevFactory.s.sol +21 -0
  67. package/script/DeployHooks.s.sol +1 -1
  68. package/script/PrintUpgradeCommand.s.sol +13 -0
  69. package/script/Simulate.s.sol +1 -10
  70. package/script/TestBackingCoinSwap.s.sol +147 -0
  71. package/script/TestV4Swap.s.sol +136 -0
  72. package/script/UpgradeCoinImpl.sol +2 -2
  73. package/script/UpgradeFactoryImpl.s.sol +2 -2
  74. package/src/BaseCoin.sol +190 -0
  75. package/src/Coin.sol +87 -202
  76. package/src/CoinV4.sol +121 -0
  77. package/src/ZoraFactoryImpl.sol +208 -36
  78. package/{script → src/deployment}/CoinsDeployerBase.sol +111 -17
  79. package/src/hooks/ZoraV4CoinHook.sol +212 -0
  80. package/src/hooks/{BaseCoinDeployHook.sol → deployment/BaseCoinDeployHook.sol} +3 -3
  81. package/src/hooks/deployment/BuySupplyWithSwapRouterHook.sol +140 -0
  82. package/src/interfaces/ICoin.sol +31 -39
  83. package/src/interfaces/ICoinV3.sol +71 -0
  84. package/src/interfaces/ICoinV4.sol +69 -0
  85. package/src/interfaces/IDeployedCoinVersionLookup.sol +11 -0
  86. package/src/interfaces/IMsgSender.sol +9 -0
  87. package/src/interfaces/IPoolConfigEncoding.sol +14 -0
  88. package/src/interfaces/ISwapPathRouter.sol +14 -0
  89. package/src/interfaces/IZoraFactory.sol +67 -28
  90. package/src/interfaces/IZoraV4CoinHook.sol +116 -0
  91. package/src/libs/CoinCommon.sol +15 -0
  92. package/src/libs/CoinConfigurationVersions.sol +116 -1
  93. package/src/libs/CoinConstants.sol +5 -0
  94. package/src/libs/CoinDopplerMultiCurve.sol +134 -0
  95. package/src/libs/CoinDopplerUniV3.sol +19 -171
  96. package/src/libs/CoinRewards.sol +195 -0
  97. package/src/libs/CoinRewardsV4.sol +179 -0
  98. package/src/libs/CoinSetup.sol +57 -0
  99. package/src/libs/CoinSetupV3.sol +6 -67
  100. package/src/libs/DopplerMath.sol +156 -0
  101. package/src/libs/HooksDeployment.sol +128 -0
  102. package/src/libs/MarketConstants.sol +4 -0
  103. package/src/libs/PoolStateReader.sol +22 -0
  104. package/src/libs/UniV3BuySell.sol +74 -292
  105. package/src/libs/UniV4SwapHelper.sol +65 -0
  106. package/src/libs/UniV4SwapToCurrency.sol +109 -0
  107. package/src/libs/V4Liquidity.sol +122 -0
  108. package/src/types/PoolConfiguration.sol +15 -0
  109. package/src/utils/DeployedCoinVersionLookup.sol +52 -0
  110. package/src/version/ContractVersionBase.sol +1 -1
  111. package/test/Coin.t.sol +78 -88
  112. package/test/CoinDopplerUniV3.t.sol +32 -171
  113. package/test/CoinUniV4.t.sol +777 -0
  114. package/test/{Hooks.t.sol → DeploymentHooks.t.sol} +53 -16
  115. package/test/Factory.t.sol +80 -47
  116. package/test/MultiOwnable.t.sol +6 -3
  117. package/test/Upgrades.t.sol +97 -5
  118. package/test/mocks/MockERC20.sol +12 -0
  119. package/test/utils/BaseTest.sol +162 -57
  120. package/test/utils/DeployedCoinVersionLookup.t.sol +127 -0
  121. package/test/utils/FeeEstimatorHook.sol +84 -0
  122. package/test/utils/ProxyShim.sol +17 -0
  123. package/wagmi.config.ts +4 -0
  124. package/.env +0 -1
  125. package/.turbo/turbo-update-contract-version.log +0 -22
  126. package/abis/CoinSetupV3.json +0 -7
  127. package/abis/HookDeployer.json +0 -68
  128. package/abis/IHookDeployer.json +0 -42
  129. package/src/hooks/BuySupplyWithSwapRouterHook.sol +0 -78
  130. package/src/libs/CoinLegacy.sol +0 -48
  131. package/src/libs/CoinLegacyMarket.sol +0 -182
@@ -2,14 +2,14 @@
2
2
  pragma solidity ^0.8.13;
3
3
 
4
4
  import {BaseTest} from "./utils/BaseTest.sol";
5
- import {BuySupplyWithSwapRouterHook} from "../src/hooks/BuySupplyWithSwapRouterHook.sol";
5
+ import {BuySupplyWithSwapRouterHook} from "../src/hooks/deployment/BuySupplyWithSwapRouterHook.sol";
6
6
  import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
7
7
  import {IUniswapV3Pool} from "../src/interfaces/IUniswapV3Pool.sol";
8
8
  import {Coin} from "../src/Coin.sol";
9
9
  import {CoinConfigurationVersions} from "../src/libs/CoinConfigurationVersions.sol";
10
10
  import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
11
11
  import {ICoin} from "../src/interfaces/ICoin.sol";
12
- import {IHasAfterCoinDeploy} from "../src/hooks/BaseCoinDeployHook.sol";
12
+ import {IHasAfterCoinDeploy} from "../src/hooks/deployment/BaseCoinDeployHook.sol";
13
13
  import {IZoraFactory} from "../src/interfaces/IZoraFactory.sol";
14
14
  import {ISwapRouter} from "../src/interfaces/ISwapRouter.sol";
15
15
  import {CoinConstants} from "../src/libs/CoinConstants.sol";
@@ -22,11 +22,8 @@ contract FakeHookNoInterface {
22
22
  }
23
23
 
24
24
  contract HooksTest is BaseTest {
25
- int24 internal constant DEFAULT_DISCOVERY_TICK_LOWER = -777000;
26
- int24 internal constant DEFAULT_DISCOVERY_TICK_UPPER = 222000;
27
- uint16 internal constant DEFAULT_NUM_DISCOVERY_POSITIONS = 10; // will be 11 total with tail position
28
- uint256 internal constant DEFAULT_DISCOVERY_SUPPLY_SHARE = 0.495e18; // half of the 990m total pool supply
29
25
  address constant zora = 0x1111111111166b7FE7bd91427724B487980aFc69;
26
+ BuySupplyWithSwapRouterHook hook;
30
27
 
31
28
  function _generateDefaultPoolConfig(address currency) internal pure returns (bytes memory) {
32
29
  return
@@ -42,9 +39,11 @@ contract HooksTest is BaseTest {
42
39
 
43
40
  function setUp() public override {
44
41
  super.setUpWithBlockNumber(29585474);
42
+
43
+ hook = new BuySupplyWithSwapRouterHook(factory, address(swapRouter), address(V4_POOL_MANAGER));
45
44
  }
46
45
 
47
- function _deployWithHook(address hook, bytes memory hookData, address currency) internal returns (address, bytes memory) {
46
+ function _deployWithHook(address _hook, bytes memory hookData, address currency) internal returns (address, bytes memory) {
48
47
  bytes memory poolConfig = _generateDefaultPoolConfig(currency);
49
48
  return
50
49
  factory.deployWithHook(
@@ -55,7 +54,7 @@ contract HooksTest is BaseTest {
55
54
  "TEST",
56
55
  poolConfig,
57
56
  users.platformReferrer,
58
- hook,
57
+ _hook,
59
58
  hookData
60
59
  );
61
60
  }
@@ -78,8 +77,6 @@ contract HooksTest is BaseTest {
78
77
 
79
78
  vm.deal(users.creator, initialOrderSize);
80
79
 
81
- BuySupplyWithSwapRouterHook hook = new BuySupplyWithSwapRouterHook(factory, address(swapRouter));
82
-
83
80
  bytes memory hookData = _encodeExactInputSingle(
84
81
  users.creator,
85
82
  ISwapRouter.ExactInputSingleParams({
@@ -118,7 +115,7 @@ contract HooksTest is BaseTest {
118
115
  assertGt(IERC20(zora).balanceOf(address(pool)), 0, "Pool ZORA balance");
119
116
  }
120
117
 
121
- function test_buySupplyWithEthUsingV3Hook_withExactInputMultiHop(uint256 initialOrderSize) public {
118
+ function test_buySupplyWithEthUsingV4Hook_withExactInputMultiHop(uint256 initialOrderSize) public {
122
119
  vm.assume(initialOrderSize > CoinConstants.MIN_ORDER_SIZE);
123
120
  vm.assume(initialOrderSize < 1 ether);
124
121
 
@@ -126,7 +123,51 @@ contract HooksTest is BaseTest {
126
123
 
127
124
  // lets try weth to usdc to zora
128
125
 
129
- BuySupplyWithSwapRouterHook hook = new BuySupplyWithSwapRouterHook(factory, address(swapRouter));
126
+ uint24 poolFee = 3000;
127
+
128
+ bytes memory hookData = _encodeExactInput(
129
+ users.creator,
130
+ ISwapRouter.ExactInputParams({
131
+ path: abi.encodePacked(address(weth), poolFee, USDC_ADDRESS, poolFee, zora),
132
+ recipient: address(hook),
133
+ amountIn: initialOrderSize,
134
+ amountOutMinimum: 0
135
+ })
136
+ );
137
+
138
+ bytes memory poolConfig = CoinConfigurationVersions.defaultDopplerMultiCurveUniV4(zora);
139
+
140
+ vm.prank(users.creator);
141
+ (address coinAddress, bytes memory hookDataOut) = factory.deployWithHook{value: initialOrderSize}(
142
+ users.creator,
143
+ _getDefaultOwners(),
144
+ "https://test.com",
145
+ "Testcoin",
146
+ "TEST",
147
+ poolConfig,
148
+ users.platformReferrer,
149
+ address(hook),
150
+ hookData
151
+ );
152
+
153
+ coin = Coin(payable(coinAddress));
154
+
155
+ (uint256 amountCurrency, uint256 coinsPurchased) = abi.decode(hookDataOut, (uint256, uint256));
156
+
157
+ assertEq(coin.currency(), zora, "currency");
158
+ assertGt(amountCurrency, 0, "amountCurrency > 0");
159
+ assertGt(coinsPurchased, 0, "coinsPurchased > 0");
160
+ assertEq(coin.balanceOf(users.creator), CoinConstants.CREATOR_LAUNCH_REWARD + coinsPurchased, "balanceOf creator");
161
+ // assertGt(IERC20(zora).balanceOf(address(pool)), 0, "Pool ZORA balance");
162
+ }
163
+
164
+ function test_buySupplyWithEthUsingV3Hook_withExactInputMultiHop(uint256 initialOrderSize) public {
165
+ vm.assume(initialOrderSize > CoinConstants.MIN_ORDER_SIZE);
166
+ vm.assume(initialOrderSize < 1 ether);
167
+
168
+ vm.deal(users.creator, initialOrderSize);
169
+
170
+ // lets try weth to usdc to zora
130
171
 
131
172
  uint24 poolFee = 3000;
132
173
 
@@ -168,8 +209,6 @@ contract HooksTest is BaseTest {
168
209
  function test_buySupplyWithEthUsingV3Hook_revertsWhenBadCall() public {
169
210
  vm.deal(users.creator, 0.0001 ether);
170
211
 
171
- BuySupplyWithSwapRouterHook hook = new BuySupplyWithSwapRouterHook(factory, address(swapRouter));
172
-
173
212
  uint24 poolFee = 3000;
174
213
 
175
214
  // exact output single is not supported
@@ -205,8 +244,6 @@ contract HooksTest is BaseTest {
205
244
  uint256 initialOrderSize = 0.0001 ether;
206
245
  vm.deal(users.creator, initialOrderSize);
207
246
 
208
- BuySupplyWithSwapRouterHook hook = new BuySupplyWithSwapRouterHook(factory, address(swapRouter));
209
-
210
247
  bytes memory hookData = _encodeExactInputSingle(
211
248
  users.creator,
212
249
  ISwapRouter.ExactInputSingleParams({
@@ -10,8 +10,9 @@ contract FactoryTest is BaseTest {
10
10
  }
11
11
 
12
12
  function test_constructor() public view {
13
- assertEq(factory.coinImpl(), address(coinImpl));
14
- assertEq(factory.owner(), users.factoryOwner);
13
+ assertEq(ZoraFactoryImpl(address(factory)).coinImpl(), address(coinV3Impl));
14
+ assertEq(ZoraFactoryImpl(address(factory)).owner(), users.factoryOwner);
15
+ assertEq(ZoraFactoryImpl(address(factory)).coinV4Impl(), address(coinV4Impl));
15
16
  }
16
17
 
17
18
  function test_deploy_no_eth() public {
@@ -24,9 +25,8 @@ contract FactoryTest is BaseTest {
24
25
  "https://test2.com",
25
26
  "Test2 Token",
26
27
  "TEST2",
28
+ _generatePoolConfig(address(weth)),
27
29
  users.platformReferrer,
28
- address(weth),
29
- MarketConstants.LP_TICK_LOWER_WETH,
30
30
  0
31
31
  );
32
32
  coin = Coin(payable(coinAddress));
@@ -73,9 +73,8 @@ contract FactoryTest is BaseTest {
73
73
  "https://test2.com",
74
74
  "Test2 Token",
75
75
  "TEST2",
76
+ _generatePoolConfig(address(weth)),
76
77
  users.platformReferrer,
77
- address(weth),
78
- MarketConstants.LP_TICK_LOWER_WETH,
79
78
  initialOrderSize
80
79
  );
81
80
  coin = Coin(payable(coinAddress));
@@ -119,9 +118,8 @@ contract FactoryTest is BaseTest {
119
118
  "https://test2.com",
120
119
  "Test2 Token",
121
120
  "TEST2",
121
+ _generatePoolConfig(address(weth)),
122
122
  users.platformReferrer,
123
- address(weth),
124
- MarketConstants.LP_TICK_LOWER_WETH,
125
123
  initialOrderSize
126
124
  );
127
125
  }
@@ -139,9 +137,8 @@ contract FactoryTest is BaseTest {
139
137
  "https://test2.com",
140
138
  "Test2 Token",
141
139
  "TEST2",
140
+ _generatePoolConfig(address(weth)),
142
141
  users.platformReferrer,
143
- address(weth),
144
- MarketConstants.LP_TICK_LOWER_WETH,
145
142
  orderSize
146
143
  );
147
144
  coin = Coin(payable(coinAddress));
@@ -160,9 +157,8 @@ contract FactoryTest is BaseTest {
160
157
  "https://testcoinusdcpair.com",
161
158
  "Testcoinusdcpair",
162
159
  "TESTCOINUSDCPAIR",
160
+ _generatePoolConfig(USDC_ADDRESS),
163
161
  users.platformReferrer,
164
- USDC_ADDRESS,
165
- USDC_TICK_LOWER,
166
162
  0
167
163
  );
168
164
  coin = Coin(payable(coinAddress));
@@ -193,9 +189,8 @@ contract FactoryTest is BaseTest {
193
189
  "https://testcoinusdcpair.com",
194
190
  "Testcoinusdcpair",
195
191
  "TESTCOINUSDCPAIR",
192
+ _generatePoolConfig(USDC_ADDRESS),
196
193
  users.platformReferrer,
197
- USDC_ADDRESS,
198
- USDC_TICK_LOWER,
199
194
  orderSize
200
195
  );
201
196
  coin = Coin(payable(coinAddress));
@@ -218,9 +213,8 @@ contract FactoryTest is BaseTest {
218
213
  "https://testcoinusdcpair.com",
219
214
  "Testcoinusdcpair",
220
215
  "TESTCOINUSDCPAIR",
216
+ _generatePoolConfig(USDC_ADDRESS),
221
217
  users.platformReferrer,
222
- USDC_ADDRESS,
223
- USDC_TICK_LOWER,
224
218
  0
225
219
  );
226
220
  }
@@ -235,9 +229,8 @@ contract FactoryTest is BaseTest {
235
229
  "https://testcoinusdcpair.com",
236
230
  "Testcoinusdcpair",
237
231
  "TESTCOINUSDCPAIR",
232
+ _generatePoolConfig(USDC_ADDRESS),
238
233
  users.platformReferrer,
239
- USDC_ADDRESS,
240
- USDC_TICK_LOWER,
241
234
  0
242
235
  );
243
236
  }
@@ -252,9 +245,8 @@ contract FactoryTest is BaseTest {
252
245
  "https://testcoinusdcpair.com",
253
246
  "Testcoinusdcpair",
254
247
  "TESTCOINUSDCPAIR",
248
+ _generatePoolConfig(USDC_ADDRESS),
255
249
  address(0),
256
- USDC_ADDRESS,
257
- USDC_TICK_LOWER,
258
250
  0
259
251
  );
260
252
 
@@ -263,24 +255,6 @@ contract FactoryTest is BaseTest {
263
255
  assertEq(coin.platformReferrer(), coin.protocolRewardRecipient(), "platformReferrer");
264
256
  }
265
257
 
266
- function test_revert_deploy_with_invalid_currency_tick() public {
267
- address[] memory owners = new address[](1);
268
- owners[0] = users.creator;
269
-
270
- vm.expectRevert(abi.encodeWithSelector(ICoin.InvalidWethLowerTick.selector));
271
- factory.deploy(
272
- users.creator,
273
- owners,
274
- "https://testcoin.com",
275
- "Testcoin",
276
- "TESTCOIN",
277
- users.platformReferrer,
278
- address(0),
279
- MarketConstants.LP_TICK_LOWER_WETH + 1,
280
- 0
281
- );
282
- }
283
-
284
258
  function test_deploy_with_usdc_revert_invalid_eth_transfer() public {
285
259
  address[] memory owners = new address[](1);
286
260
  owners[0] = users.creator;
@@ -298,9 +272,8 @@ contract FactoryTest is BaseTest {
298
272
  "https://testcoinusdcpair.com",
299
273
  "Testcoinusdcpair",
300
274
  "TESTCOINUSDCPAIR",
275
+ _generatePoolConfig(USDC_ADDRESS),
301
276
  users.platformReferrer,
302
- USDC_ADDRESS,
303
- USDC_TICK_LOWER,
304
277
  0
305
278
  );
306
279
  }
@@ -315,9 +288,8 @@ contract FactoryTest is BaseTest {
315
288
  "https://test.com",
316
289
  "Test Token",
317
290
  "TEST",
291
+ _generatePoolConfig(address(weth)),
318
292
  users.platformReferrer,
319
- address(weth),
320
- MarketConstants.LP_TICK_LOWER_WETH,
321
293
  0
322
294
  );
323
295
  coin = Coin(payable(coinAddress));
@@ -326,10 +298,10 @@ contract FactoryTest is BaseTest {
326
298
  }
327
299
 
328
300
  function test_upgrade() public {
329
- ZoraFactoryImpl newImpl = new ZoraFactoryImpl(address(coinImpl));
301
+ ZoraFactoryImpl newImpl = new ZoraFactoryImpl(address(coinV3Impl), address(coinV4Impl));
330
302
 
331
303
  vm.prank(users.factoryOwner);
332
- factory.upgradeToAndCall(address(newImpl), "");
304
+ ZoraFactoryImpl(address(factory)).upgradeToAndCall(address(newImpl), "");
333
305
 
334
306
  assertEq(factory.implementation(), address(newImpl), "implementation");
335
307
  }
@@ -343,14 +315,75 @@ contract FactoryTest is BaseTest {
343
315
 
344
316
  vm.prank(users.factoryOwner);
345
317
  vm.expectRevert(abi.encodeWithSelector(ERC1967Utils.ERC1967InvalidImplementation.selector, address(newImpl)));
346
- factory.upgradeToAndCall(address(newImpl), "");
318
+ ZoraFactoryImpl(address(factory)).upgradeToAndCall(address(newImpl), "");
347
319
  }
348
320
 
349
321
  function test_revert_invalid_owner() public {
350
- ZoraFactoryImpl newImpl = new ZoraFactoryImpl(address(coinImpl));
322
+ ZoraFactoryImpl newImpl = new ZoraFactoryImpl(address(coinV3Impl), address(coinV4Impl));
351
323
 
352
324
  vm.prank(users.creator);
353
325
  vm.expectRevert(abi.encodeWithSelector(OwnableUpgradeable.OwnableUnauthorizedAccount.selector, users.creator));
354
- factory.upgradeToAndCall(address(newImpl), "");
326
+ ZoraFactoryImpl(address(factory)).upgradeToAndCall(address(newImpl), "");
327
+ }
328
+
329
+ function test_coinAddress_canBePredicted(
330
+ bool msgSenderChanged,
331
+ bool saltChanged,
332
+ bool poolConfigChanged,
333
+ bool platformReferrerChanged,
334
+ bool nameChanged,
335
+ bool symbolChanged
336
+ ) public {
337
+ address[] memory owners = new address[](1);
338
+ owners[0] = users.creator;
339
+
340
+ address payoutRecipient = users.creator;
341
+
342
+ bytes32 salt = keccak256(abi.encode(bytes("randomSalt")));
343
+
344
+ address msgSender = makeAddr("msgSender");
345
+
346
+ string memory uri = "https://test.com";
347
+ string memory name = "Testcoin";
348
+ string memory symbol = "TEST";
349
+
350
+ address platformReferrer = users.platformReferrer;
351
+
352
+ bytes memory poolConfig = CoinConfigurationVersions.defaultDopplerMultiCurveUniV4(address(weth));
353
+ bytes memory poolConfigForGettingAddress = poolConfigChanged ? CoinConfigurationVersions.defaultDopplerUniV3(address(weth)) : poolConfig;
354
+
355
+ address expectedCoinAddress = factory.coinAddress(msgSender, name, symbol, poolConfigForGettingAddress, platformReferrer, salt);
356
+
357
+ if (msgSenderChanged) {
358
+ msgSender = makeAddr("msgSender2");
359
+ }
360
+
361
+ if (saltChanged) {
362
+ salt = keccak256(abi.encode(bytes("randomSalt2")));
363
+ }
364
+
365
+ if (platformReferrerChanged) {
366
+ platformReferrer = makeAddr("platformReferrer2");
367
+ }
368
+
369
+ if (nameChanged) {
370
+ name = "Testcoin2";
371
+ }
372
+
373
+ if (symbolChanged) {
374
+ symbol = "TEST2";
375
+ }
376
+
377
+ // now deploy the coin
378
+ vm.prank(msgSender);
379
+ (address coinAddress, ) = factory.deploy(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer, address(0), bytes(""), salt);
380
+
381
+ bool addressShouldMismatch = msgSenderChanged || saltChanged || poolConfigChanged || platformReferrerChanged || nameChanged || symbolChanged;
382
+
383
+ if (addressShouldMismatch) {
384
+ assertNotEq(coinAddress, expectedCoinAddress, "coinAddress should mismatch");
385
+ } else {
386
+ assertEq(coinAddress, expectedCoinAddress, "coinAddress should match");
387
+ }
355
388
  }
356
389
  }
@@ -135,22 +135,25 @@ contract MultiOwnableTest is BaseTest {
135
135
 
136
136
  function test_revert_init_with_zero_owners() public {
137
137
  address[] memory emptyOwners = new address[](0);
138
+ bytes memory poolConfig_ = _generatePoolConfig(address(weth));
138
139
  vm.expectRevert(MultiOwnable.OneOwnerRequired.selector);
139
- factory.deploy(users.creator, emptyOwners, "https://test.com", "Test Token", "TEST", users.platformReferrer, address(0), 0, 0);
140
+ factory.deploy(users.creator, emptyOwners, "https://test.com", "Test Token", "TEST", poolConfig_, users.platformReferrer, 0);
140
141
  }
141
142
 
142
143
  function test_revert_init_with_zero_address() public {
143
144
  address[] memory owners = new address[](1);
144
145
  owners[0] = address(0);
146
+ bytes memory poolConfig_ = _generatePoolConfig(address(weth));
145
147
  vm.expectRevert(MultiOwnable.OwnerCannotBeAddressZero.selector);
146
- factory.deploy(users.creator, owners, "https://test.com", "Test Token", "TEST", users.platformReferrer, address(0), 0, 0);
148
+ factory.deploy(users.creator, owners, "https://test.com", "Test Token", "TEST", poolConfig_, users.platformReferrer, 0);
147
149
  }
148
150
 
149
151
  function test_revert_init_with_duplicate_owner() public {
150
152
  address[] memory owners = new address[](2);
151
153
  owners[0] = users.creator;
152
154
  owners[1] = users.creator;
155
+ bytes memory poolConfig_ = _generatePoolConfig(address(weth));
153
156
  vm.expectRevert(MultiOwnable.AlreadyOwner.selector);
154
- factory.deploy(users.creator, owners, "https://test.com", "Test Token", "TEST", users.platformReferrer, address(0), 0, 0);
157
+ factory.deploy(users.creator, owners, "https://test.com", "Test Token", "TEST", poolConfig_, users.platformReferrer, 0);
155
158
  }
156
159
  }
@@ -3,6 +3,18 @@ pragma solidity ^0.8.13;
3
3
  import {Test} from "forge-std/Test.sol";
4
4
  import {IZoraFactory} from "../src/interfaces/IZoraFactory.sol";
5
5
  import {ZoraFactoryImpl} from "../src/ZoraFactoryImpl.sol";
6
+ import {BaseTest} from "./utils/BaseTest.sol";
7
+ import {CoinsDeployerBase} from "../src/deployment/CoinsDeployerBase.sol";
8
+ import {CoinConfigurationVersions} from "../src/libs/CoinConfigurationVersions.sol";
9
+ import {ICoinV4} from "../src/interfaces/ICoinV4.sol";
10
+ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
11
+ import {ISwapRouter} from "../src/interfaces/ISwapRouter.sol";
12
+ import {IWETH} from "../src/interfaces/IWETH.sol";
13
+ import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
14
+ import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
15
+ import {BuySupplyWithSwapRouterHook} from "../src/hooks/deployment/BuySupplyWithSwapRouterHook.sol";
16
+
17
+ import {console} from "forge-std/console.sol";
6
18
 
7
19
  contract BadImpl {
8
20
  function contractName() public pure returns (string memory) {
@@ -10,7 +22,7 @@ contract BadImpl {
10
22
  }
11
23
  }
12
24
 
13
- contract UpgradesTest is Test {
25
+ contract UpgradesTest is BaseTest, CoinsDeployerBase {
14
26
  ZoraFactoryImpl public factoryProxy;
15
27
 
16
28
  function test_canUpgradeFromVersionWithoutContractName() public {
@@ -19,7 +31,7 @@ contract UpgradesTest is Test {
19
31
 
20
32
  factoryProxy = ZoraFactoryImpl(0x777777751622c0d3258f214F9DF38E35BF45baF3);
21
33
 
22
- ZoraFactoryImpl newImpl = new ZoraFactoryImpl(factoryProxy.implementation());
34
+ ZoraFactoryImpl newImpl = new ZoraFactoryImpl(factoryProxy.coinImpl(), address(coinV4Impl));
23
35
 
24
36
  vm.prank(factoryProxy.owner());
25
37
  factoryProxy.upgradeToAndCall(address(newImpl), "");
@@ -34,7 +46,7 @@ contract UpgradesTest is Test {
34
46
 
35
47
  factoryProxy = ZoraFactoryImpl(0x777777751622c0d3258f214F9DF38E35BF45baF3);
36
48
 
37
- ZoraFactoryImpl newImpl = new ZoraFactoryImpl(factoryProxy.implementation());
49
+ ZoraFactoryImpl newImpl = new ZoraFactoryImpl(factoryProxy.coinImpl(), address(coinV4Impl));
38
50
 
39
51
  vm.prank(factoryProxy.owner());
40
52
  factoryProxy.upgradeToAndCall(address(newImpl), "");
@@ -52,16 +64,96 @@ contract UpgradesTest is Test {
52
64
 
53
65
  factoryProxy = ZoraFactoryImpl(0x777777751622c0d3258f214F9DF38E35BF45baF3);
54
66
 
55
- ZoraFactoryImpl newImpl = new ZoraFactoryImpl(factoryProxy.implementation());
67
+ ZoraFactoryImpl newImpl = new ZoraFactoryImpl(factoryProxy.coinImpl(), address(coinV4Impl));
56
68
 
57
69
  vm.prank(factoryProxy.owner());
58
70
  factoryProxy.upgradeToAndCall(address(newImpl), "");
59
71
 
60
- ZoraFactoryImpl newImpl2 = new ZoraFactoryImpl(factoryProxy.implementation());
72
+ ZoraFactoryImpl newImpl2 = new ZoraFactoryImpl(factoryProxy.coinImpl(), factoryProxy.coinV4Impl());
61
73
 
62
74
  vm.prank(factoryProxy.owner());
63
75
  factoryProxy.upgradeToAndCall(address(newImpl2), "");
64
76
 
65
77
  assertEq(factoryProxy.implementation(), address(newImpl2));
66
78
  }
79
+
80
+ function test_canUpgradeAndSwap() public {
81
+ vm.createSelectFork("base");
82
+
83
+ factoryProxy = ZoraFactoryImpl(0x777777751622c0d3258f214F9DF38E35BF45baF3);
84
+
85
+ CoinsDeployment memory deployment = readDeployment();
86
+
87
+ vm.prank(factoryProxy.owner());
88
+ factoryProxy.upgradeToAndCall(deployment.zoraFactoryImpl, "");
89
+
90
+ // deploy a v4 coin
91
+
92
+ bytes memory poolConfig = CoinConfigurationVersions.defaultDopplerMultiCurveUniV4(ZORA);
93
+
94
+ uint128 amountIn = 1 ether;
95
+
96
+ address buySupplyWithSwapRouterHook = deployment.buySupplyWithSwapRouterHook;
97
+
98
+ // build weth to usdc swap
99
+ bytes memory call = abi.encodeWithSelector(
100
+ ISwapRouter.exactInputSingle.selector,
101
+ ISwapRouter.ExactInputSingleParams({
102
+ tokenIn: WETH_ADDRESS,
103
+ tokenOut: ZORA,
104
+ fee: 3000,
105
+ recipient: buySupplyWithSwapRouterHook,
106
+ amountIn: amountIn,
107
+ amountOutMinimum: 0,
108
+ sqrtPriceLimitX96: 0
109
+ })
110
+ );
111
+
112
+ address buyRecipient = makeAddr("buyRecipient");
113
+
114
+ address trader = 0xC077e4cC02fa01A5b7fAca1acE9BBe9f5ac5Af9F;
115
+
116
+ vm.startPrank(trader);
117
+ vm.deal(trader, amountIn);
118
+
119
+ (address coinAddress, ) = factoryProxy.deploy{value: amountIn}(
120
+ users.creator,
121
+ _getDefaultOwners(),
122
+ "https://test.com",
123
+ "Testcoin",
124
+ "TEST",
125
+ poolConfig,
126
+ users.platformReferrer,
127
+ buySupplyWithSwapRouterHook,
128
+ abi.encode(buyRecipient, call),
129
+ keccak256("test")
130
+ );
131
+
132
+ // do some swaps to test out
133
+ _swapSomeCurrencyForCoin(ICoinV4(coinAddress), ZORA, uint128(IERC20(ZORA).balanceOf(trader)), trader);
134
+
135
+ // do some swaps to test out
136
+ _swapSomeCoinForCurrency(ICoinV4(coinAddress), ZORA, uint128(IERC20(coinAddress).balanceOf(trader)), trader);
137
+ }
138
+
139
+ function test_realSwapUsingCurrentCode() external {
140
+ bytes[] memory inputs = new bytes[](5);
141
+
142
+ vm.createSelectFork("base", 31138268);
143
+
144
+ address trader = vm.parseAddress("0xa3c881f39972925d865b300bcd65e72a6222c10a");
145
+
146
+ ICoinV4 coin = ICoinV4(vm.parseAddress("0xca1de5b8e8336326d5749fde43e245285cd1daf1"));
147
+
148
+ PoolKey memory key = coin.getPoolKey();
149
+
150
+ address[] memory trustedMessageSenders = new address[](0);
151
+ deployCodeTo(
152
+ "ZoraV4CoinHook.sol:ZoraV4CoinHook",
153
+ abi.encode(V4_POOL_MANAGER, 0x3d7A3f3351855e135CF89AB412A7C2AA449f9296, trustedMessageSenders),
154
+ address(coin.hooks())
155
+ );
156
+
157
+ _swapSomeCurrencyForCoin(coin, ZORA, uint128(IERC20(ZORA).balanceOf(trader)), trader);
158
+ }
67
159
  }
@@ -0,0 +1,12 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
5
+
6
+ contract MockERC20 is ERC20 {
7
+ constructor(string memory name, string memory symbol) ERC20(name, symbol) {}
8
+
9
+ function mint(address to, uint256 amount) external {
10
+ _mint(to, amount);
11
+ }
12
+ }