@zoralabs/coins 2.0.0 → 2.1.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 (69) hide show
  1. package/.turbo/turbo-build.log +106 -110
  2. package/CHANGELOG.md +28 -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/package/wagmiGenerated.ts +240 -269
  21. package/package.json +3 -3
  22. package/script/DeployPostDeploymentHooks.s.sol +2 -2
  23. package/script/TestBackingCoinSwap.s.sol +8 -8
  24. package/script/TestV4Swap.s.sol +8 -8
  25. package/script/UpgradeFactoryImpl.s.sol +0 -1
  26. package/src/BaseCoin.sol +109 -6
  27. package/src/ContentCoin.sol +4 -4
  28. package/src/CreatorCoin.sol +5 -5
  29. package/src/ZoraFactoryImpl.sol +10 -93
  30. package/src/deployment/CoinsDeployerBase.sol +10 -27
  31. package/src/hooks/BaseZoraV4CoinHook.sol +5 -5
  32. package/src/hooks/deployment/BuySupplyWithSwapRouterHook.sol +4 -5
  33. package/src/interfaces/ICoin.sol +67 -1
  34. package/src/interfaces/ICreatorCoin.sol +2 -2
  35. package/src/interfaces/IZoraFactory.sol +0 -5
  36. package/src/libs/CoinConfigurationVersions.sol +1 -39
  37. package/src/libs/CoinRewardsV4.sol +2 -2
  38. package/src/libs/CoinSetup.sol +1 -4
  39. package/src/libs/UniV4SwapHelper.sol +1 -1
  40. package/src/libs/UniV4SwapToCurrency.sol +2 -2
  41. package/src/libs/V4Liquidity.sol +1 -1
  42. package/src/version/ContractVersionBase.sol +1 -1
  43. package/test/Coin.t.sol +112 -535
  44. package/test/CoinUniV4.t.sol +5 -5
  45. package/test/DeploymentHooks.t.sol +5 -102
  46. package/test/Factory.t.sol +23 -306
  47. package/test/LiquidityMigration.t.sol +160 -2
  48. package/test/MultiOwnable.t.sol +36 -36
  49. package/test/Upgrades.t.sol +16 -35
  50. package/test/utils/BaseTest.sol +16 -69
  51. package/test/utils/FeeEstimatorHook.sol +3 -3
  52. package/wagmi.config.ts +1 -1
  53. package/abis/BaseCoinV4.json +0 -1840
  54. package/abis/Coin.json +0 -1912
  55. package/abis/DopplerUniswapV3Test.json +0 -800
  56. package/abis/ICoinV4.json +0 -1048
  57. package/abis/Simulate.json +0 -29
  58. package/abis/UniV3BuySell.json +0 -12
  59. package/abis/UniV3Errors.json +0 -32
  60. package/script/Simulate.s.sol +0 -59
  61. package/src/BaseCoinV4.sol +0 -143
  62. package/src/Coin.sol +0 -236
  63. package/src/interfaces/ICoinV4.sol +0 -74
  64. package/src/libs/CoinDopplerUniV3.sol +0 -50
  65. package/src/libs/CoinRewards.sol +0 -201
  66. package/src/libs/CoinSetupV3.sol +0 -50
  67. package/src/libs/UniV3BuySell.sol +0 -231
  68. package/src/libs/UniV3Errors.sol +0 -11
  69. package/test/CoinDopplerUniV3.t.sol +0 -310
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zoralabs/coins",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -35,9 +35,9 @@
35
35
  "tsx": "^3.13.0",
36
36
  "typescript": "^5.2.2",
37
37
  "viem": "^2.21.18",
38
- "@zoralabs/shared-contracts": "^0.0.5",
38
+ "@zoralabs/tsconfig": "^0.0.1",
39
39
  "@zoralabs/shared-scripts": "^0.0.0",
40
- "@zoralabs/tsconfig": "^0.0.1"
40
+ "@zoralabs/shared-contracts": "^0.0.5"
41
41
  },
42
42
  "scripts": {
43
43
  "build": "pnpm run wagmi:generate && pnpm run copy-abis && pnpm run prettier:write && tsup",
@@ -10,9 +10,9 @@ contract DeployHooks is CoinsDeployerBase {
10
10
 
11
11
  vm.startBroadcast();
12
12
 
13
- address buySupplyWithSwapRouterHook = address(deployBuySupplyWithSwapRouterHook(deployment));
13
+ // address buySupplyWithSwapRouterHook = address(deployBuySupplyWithSwapRouterHook(deployment));
14
14
 
15
- deployment.buySupplyWithSwapRouterHook = buySupplyWithSwapRouterHook;
15
+ // deployment.buySupplyWithSwapRouterHook = buySupplyWithSwapRouterHook;
16
16
 
17
17
  vm.stopBroadcast();
18
18
 
@@ -16,7 +16,7 @@ import {MockERC20} from "../test/mocks/MockERC20.sol";
16
16
  import {MarketConstants} from "../src/libs/MarketConstants.sol";
17
17
  import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
18
18
  import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
19
- import {ICoinV4} from "../src/interfaces/ICoinV4.sol";
19
+ import {ICoin} from "../src/interfaces/ICoin.sol";
20
20
 
21
21
  import {console} from "forge-std/console.sol";
22
22
 
@@ -34,7 +34,7 @@ contract TestV4Swap is CoinsDeployerBase {
34
34
  string memory uri,
35
35
  address createReferral,
36
36
  bytes32 salt
37
- ) internal returns (ICoinV4 coin) {
37
+ ) internal returns (ICoin coin) {
38
38
  CoinsDeployment memory deployment = readDeployment();
39
39
  address[] memory owners = new address[](1);
40
40
  owners[0] = creator;
@@ -54,10 +54,10 @@ contract TestV4Swap is CoinsDeployerBase {
54
54
  salt
55
55
  );
56
56
 
57
- coin = ICoinV4(coinAddress);
57
+ coin = ICoin(coinAddress);
58
58
  }
59
59
 
60
- function _swap(address currencyIn, uint128 amountIn, ICoinV4 coin, address trader, address tradeReferral) internal returns (uint256 amountOut) {
60
+ function _swap(address currencyIn, uint128 amountIn, ICoin coin, address trader, address tradeReferral) internal returns (uint256 amountOut) {
61
61
  uint128 minAmountOut = 0;
62
62
 
63
63
  PoolKey memory poolKey = coin.getPoolKey();
@@ -106,8 +106,8 @@ contract TestV4Swap is CoinsDeployerBase {
106
106
  address createReferral = 0xC077e4cC02fa01A5b7fAca1acE9BBe9f5ac5Af9F;
107
107
  address tradeReferral = 0xC077e4cC02fa01A5b7fAca1acE9BBe9f5ac5Af9F;
108
108
 
109
- ICoinV4 backingCoin = _deployCoin(zora, trader, "Backing Coin", "BACK", "https://testc.com", createReferral, bytes32("creator"));
110
- ICoinV4 contentCoin = _deployCoin(
109
+ ICoin backingCoin = _deployCoin(zora, trader, "Backing Coin", "BACK", "https://testc.com", createReferral, bytes32("creator"));
110
+ ICoin contentCoin = _deployCoin(
111
111
  address(backingCoin),
112
112
  trader,
113
113
  "Content Coin",
@@ -116,8 +116,8 @@ contract TestV4Swap is CoinsDeployerBase {
116
116
  createReferral,
117
117
  bytes32("content coin")
118
118
  );
119
- // ICoinV4 backingCoin = ICoinV4(0xeA734b5997F35cD469921cCa7BB9A03C104f2f64);
120
- // ICoinV4 contentCoin = ICoinV4(0x72218BFEEc7D556BD3Dd8eFf2a317CEd49533769);
119
+ // ICoin backingCoin = ICoin(0xeA734b5997F35cD469921cCa7BB9A03C104f2f64);
120
+ // ICoin contentCoin = ICoin(0x72218BFEEc7D556BD3Dd8eFf2a317CEd49533769);
121
121
 
122
122
  console.log("backingCoin", address(backingCoin));
123
123
  console.log("contentCoin", address(contentCoin));
@@ -16,7 +16,7 @@ import {MockERC20} from "../test/mocks/MockERC20.sol";
16
16
  import {MarketConstants} from "../src/libs/MarketConstants.sol";
17
17
  import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
18
18
  import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
19
- import {ICoinV4} from "../src/interfaces/ICoinV4.sol";
19
+ import {ICoin} from "../src/interfaces/ICoin.sol";
20
20
 
21
21
  import {console} from "forge-std/console.sol";
22
22
 
@@ -31,7 +31,7 @@ contract TestV4Swap is CoinsDeployerBase {
31
31
  currency.mint(getUniswapV4PoolManager(), 1000000 ether);
32
32
  }
33
33
 
34
- function _deployMockCoin(address currency, address creator, address createReferral, bytes32 salt) internal returns (ICoinV4 coin) {
34
+ function _deployMockCoin(address currency, address creator, address createReferral, bytes32 salt) internal returns (ICoin coin) {
35
35
  CoinsDeployment memory deployment = readDeployment();
36
36
  address[] memory owners = new address[](1);
37
37
  owners[0] = creator;
@@ -51,10 +51,10 @@ contract TestV4Swap is CoinsDeployerBase {
51
51
  salt
52
52
  );
53
53
 
54
- coin = ICoinV4(coinAddress);
54
+ coin = ICoin(coinAddress);
55
55
  }
56
56
 
57
- function _swap(address currencyIn, uint128 amountIn, ICoinV4 coin, address trader, address tradeReferral) internal returns (uint256 amountOut) {
57
+ function _swap(address currencyIn, uint128 amountIn, ICoin coin, address trader, address tradeReferral) internal returns (uint256 amountOut) {
58
58
  uint128 minAmountOut = 0;
59
59
 
60
60
  PoolKey memory poolKey = coin.getPoolKey();
@@ -101,12 +101,12 @@ contract TestV4Swap is CoinsDeployerBase {
101
101
 
102
102
  // MockERC20 currency = _deployMockCurrency();
103
103
 
104
- // ICoinV4 backingCoin = _deployMockCoin(address(currency), trader, createReferral, bytes32("backing coin"));
105
- // ICoinV4 contentCoin = _deployMockCoin(address(backingCoin), trader, createReferral, bytes32("content coin"));
104
+ // ICoin backingCoin = _deployMockCoin(address(currency), trader, createReferral, bytes32("backing coin"));
105
+ // ICoin contentCoin = _deployMockCoin(address(backingCoin), trader, createReferral, bytes32("content coin"));
106
106
 
107
107
  MockERC20 currency = MockERC20(0x1b183Bd0E2c03Fc830F4d813bA37E82F9F97cA21);
108
- ICoinV4 backingCoin = ICoinV4(0x7D74416C4c295A592Fc6F9232911C945354b253C);
109
- ICoinV4 contentCoin = ICoinV4(0xf6d6660bcdA588F7f99e2961f279f500fB501730);
108
+ ICoin backingCoin = ICoin(0x7D74416C4c295A592Fc6F9232911C945354b253C);
109
+ ICoin contentCoin = ICoin(0xf6d6660bcdA588F7f99e2961f279f500fB501730);
110
110
 
111
111
  console.log("currency", address(currency));
112
112
  console.log("backingCoin", address(backingCoin));
@@ -11,7 +11,6 @@ contract UpgradeFactoryImpl is CoinsDeployerBase {
11
11
  vm.startBroadcast();
12
12
 
13
13
  ZoraFactoryImpl zoraFactoryImpl = deployZoraFactoryImpl(
14
- deployment.coinV3Impl,
15
14
  deployment.coinV4Impl,
16
15
  deployment.creatorCoinImpl,
17
16
  deployment.zoraV4CoinHook,
package/src/BaseCoin.sol CHANGED
@@ -19,6 +19,15 @@ import {IAirlock} from "./interfaces/IAirlock.sol";
19
19
  import {IProtocolRewards} from "./interfaces/IProtocolRewards.sol";
20
20
  import {IWETH} from "./interfaces/IWETH.sol";
21
21
 
22
+ import {IPoolManager, PoolKey, Currency, IHooks} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
23
+ import {IHasPoolKey, IHasSwapPath} from "./interfaces/ICoin.sol";
24
+ import {PoolConfiguration} from "./types/PoolConfiguration.sol";
25
+ import {UniV4SwapToCurrency} from "./libs/UniV4SwapToCurrency.sol";
26
+ import {PathKey} from "@uniswap/v4-periphery/src/libraries/PathKey.sol";
27
+ import {IDeployedCoinVersionLookup} from "./interfaces/IDeployedCoinVersionLookup.sol";
28
+ import {IUpgradeableV4Hook} from "./interfaces/IUpgradeableV4Hook.sol";
29
+ import {CoinCommon} from "./libs/CoinCommon.sol";
30
+
22
31
  import {Address} from "@openzeppelin/contracts/utils/Address.sol";
23
32
  import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol";
24
33
  import {ERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
@@ -33,8 +42,6 @@ import {CoinConstants} from "./libs/CoinConstants.sol";
33
42
  import {MarketConstants} from "./libs/MarketConstants.sol";
34
43
  import {LpPosition} from "./types/LpPosition.sol";
35
44
  import {PoolState} from "./types/PoolState.sol";
36
- import {CoinSetupV3, UniV3Config, CoinV3Config} from "./libs/CoinSetupV3.sol";
37
- import {UniV3BuySell, CoinConfig} from "./libs/UniV3BuySell.sol";
38
45
 
39
46
  /*
40
47
  $$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\
@@ -56,6 +63,15 @@ abstract contract BaseCoin is ICoin, ContractVersionBase, ERC20PermitUpgradeable
56
63
  /// @notice The address of the Airlock contract, ownership is used for a protocol fee split.
57
64
  address public immutable airlock;
58
65
 
66
+ /// @notice The Uniswap v4 pool manager singleton contract reference.
67
+ IPoolManager public immutable poolManager;
68
+
69
+ /// @notice The pool key for the coin. Type from Uniswap V4 core.
70
+ PoolKey internal poolKey;
71
+
72
+ /// @notice The configuration for the pool.
73
+ PoolConfiguration internal poolConfiguration;
74
+
59
75
  /// @notice The metadata URI
60
76
  string public tokenURI;
61
77
  /// @notice The address of the coin creator
@@ -76,24 +92,53 @@ abstract contract BaseCoin is ICoin, ContractVersionBase, ERC20PermitUpgradeable
76
92
  * @param _protocolRewards The address of the protocol rewards contract
77
93
  * @param _airlock The address of the Airlock contract
78
94
  */
79
- constructor(address _protocolRewardRecipient, address _protocolRewards, address _airlock) initializer {
95
+ constructor(address _protocolRewardRecipient, address _protocolRewards, IPoolManager poolManager_, address _airlock) initializer {
80
96
  if (_protocolRewardRecipient == address(0)) {
81
97
  revert AddressZero();
82
98
  }
83
99
  if (_protocolRewards == address(0)) {
84
100
  revert AddressZero();
85
101
  }
86
-
102
+ if (address(poolManager_) == address(0)) {
103
+ revert AddressZero();
104
+ }
87
105
  if (_airlock == address(0)) {
88
106
  revert AddressZero();
89
107
  }
90
108
 
91
109
  protocolRewardRecipient = _protocolRewardRecipient;
92
110
  protocolRewards = _protocolRewards;
111
+ poolManager = poolManager_;
93
112
  airlock = _airlock;
94
113
  }
95
114
 
96
- /// @notice Initializes a new coin
115
+ /// @inheritdoc ICoin
116
+ function initialize(
117
+ address payoutRecipient_,
118
+ address[] memory owners_,
119
+ string memory tokenURI_,
120
+ string memory name_,
121
+ string memory symbol_,
122
+ address platformReferrer_,
123
+ address currency_,
124
+ PoolKey memory poolKey_,
125
+ uint160 sqrtPriceX96,
126
+ PoolConfiguration memory poolConfiguration_
127
+ ) public virtual initializer {
128
+ currency = currency_;
129
+ // we need to set this before initialization, because
130
+ // distributing currency relies on the poolkey being set since the hooks
131
+ // are retrieved from there
132
+ poolKey = poolKey_;
133
+ poolConfiguration = poolConfiguration_;
134
+
135
+ _initialize(payoutRecipient_, owners_, tokenURI_, name_, symbol_, platformReferrer_);
136
+
137
+ // initialize the pool - the hook will mint its positions in the afterInitialize callback
138
+ poolManager.initialize(poolKey, sqrtPriceX96);
139
+ }
140
+
141
+ /// @notice Initializes a new coin (internal version)
97
142
  /// @param payoutRecipient_ The address of the coin creator
98
143
  /// @param tokenURI_ The metadata URI
99
144
  /// @param name_ The coin name
@@ -210,7 +255,9 @@ abstract contract BaseCoin is ICoin, ContractVersionBase, ERC20PermitUpgradeable
210
255
  interfaceId == type(ICoin).interfaceId ||
211
256
  interfaceId == type(ICoinComments).interfaceId ||
212
257
  interfaceId == type(IERC7572).interfaceId ||
213
- interfaceId == type(IHasRewardsRecipients).interfaceId;
258
+ interfaceId == type(IHasRewardsRecipients).interfaceId ||
259
+ interfaceId == type(IHasPoolKey).interfaceId ||
260
+ type(IHasSwapPath).interfaceId == interfaceId;
214
261
  }
215
262
 
216
263
  /// @dev Overrides ERC20's _update function to emit a superset `CoinTransfer` event
@@ -245,4 +292,60 @@ abstract contract BaseCoin is ICoin, ContractVersionBase, ERC20PermitUpgradeable
245
292
  function dopplerFeeRecipient() public view returns (address) {
246
293
  return IAirlock(airlock).owner();
247
294
  }
295
+
296
+ /// @inheritdoc IHasPoolKey
297
+ function getPoolKey() public view returns (PoolKey memory) {
298
+ return poolKey;
299
+ }
300
+
301
+ /// @inheritdoc ICoin
302
+ function getPoolConfiguration() public view returns (PoolConfiguration memory) {
303
+ return poolConfiguration;
304
+ }
305
+
306
+ /// @inheritdoc ICoin
307
+ function hooks() external view returns (IHooks) {
308
+ return poolKey.hooks;
309
+ }
310
+
311
+ /// @notice Migrate liquidity from current hook to a new hook implementation
312
+ /// @param newHook Address of the new hook implementation
313
+ /// @param additionalData Additional data to pass to the new hook during initialization
314
+ function migrateLiquidity(address newHook, bytes calldata additionalData) external onlyOwner returns (PoolKey memory newPoolKey) {
315
+ newPoolKey = IUpgradeableV4Hook(address(poolKey.hooks)).migrateLiquidity(newHook, poolKey, additionalData);
316
+
317
+ emit LiquidityMigrated(poolKey, CoinCommon.hashPoolKey(poolKey), newPoolKey, CoinCommon.hashPoolKey(newPoolKey));
318
+
319
+ poolKey = newPoolKey;
320
+ }
321
+
322
+ /// @inheritdoc IHasSwapPath
323
+ function getPayoutSwapPath(IDeployedCoinVersionLookup coinVersionLookup) external view returns (IHasSwapPath.PayoutSwapPath memory payoutSwapPath) {
324
+ // if to swap in is this currency,
325
+ // if backing currency is a coin, then recursively get the path from the coin
326
+ payoutSwapPath.currencyIn = Currency.wrap(address(this));
327
+
328
+ // swap to backing currency
329
+ PathKey memory thisPathKey = PathKey({
330
+ intermediateCurrency: Currency.wrap(currency),
331
+ fee: poolKey.fee,
332
+ tickSpacing: poolKey.tickSpacing,
333
+ hooks: poolKey.hooks,
334
+ hookData: ""
335
+ });
336
+
337
+ // get backing currency swap path - if the backing currency is a v4 coin and has a swap path.
338
+ PathKey[] memory subPath = UniV4SwapToCurrency.getSubSwapPath(currency, coinVersionLookup);
339
+
340
+ if (subPath.length > 0) {
341
+ payoutSwapPath.path = new PathKey[](1 + subPath.length);
342
+ payoutSwapPath.path[0] = thisPathKey;
343
+ for (uint256 i = 0; i < subPath.length; i++) {
344
+ payoutSwapPath.path[i + 1] = subPath[i];
345
+ }
346
+ } else {
347
+ payoutSwapPath.path = new PathKey[](1);
348
+ payoutSwapPath.path[0] = thisPathKey;
349
+ }
350
+ }
248
351
  }
@@ -8,15 +8,15 @@
8
8
  pragma solidity ^0.8.23;
9
9
 
10
10
  import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
11
- import {BaseCoinV4} from "./BaseCoinV4.sol";
11
+ import {BaseCoin} from "./BaseCoin.sol";
12
12
  import {CoinConstants} from "./libs/CoinConstants.sol";
13
13
 
14
14
  /**
15
15
  * @title ContentCoin
16
16
  * @notice Content coin implementation that uses creator coins as backing currency
17
- * @dev Inherits from BaseCoinV4 and implements content-specific distribution logic
17
+ * @dev Inherits from BaseCoin and implements content-specific distribution logic
18
18
  */
19
- contract ContentCoin is BaseCoinV4 {
19
+ contract ContentCoin is BaseCoin {
20
20
  /// @notice The constructor for the static ContentCoin contract deployment shared across all content coins.
21
21
  /// @dev All arguments are required and cannot be set to the 0 address.
22
22
  /// @param protocolRewardRecipient_ The address of the protocol reward recipient
@@ -28,7 +28,7 @@ contract ContentCoin is BaseCoinV4 {
28
28
  address protocolRewards_,
29
29
  IPoolManager poolManager_,
30
30
  address airlock_
31
- ) BaseCoinV4(protocolRewardRecipient_, protocolRewards_, poolManager_, airlock_) {}
31
+ ) BaseCoin(protocolRewardRecipient_, protocolRewards_, poolManager_, airlock_) {}
32
32
 
33
33
  /// @dev The initial mint and distribution of the coin supply.
34
34
  /// Implements content coin specific distribution: 990M to liquidity pool, 10M to creator.
@@ -9,11 +9,11 @@ pragma solidity ^0.8.28;
9
9
 
10
10
  import {ICreatorCoin} from "./interfaces/ICreatorCoin.sol";
11
11
  import {CreatorCoinConstants} from "./libs/CreatorCoinConstants.sol";
12
- import {IHooks, PoolConfiguration, PoolKey, ICoinV4} from "./interfaces/ICoinV4.sol";
12
+ import {IHooks, PoolConfiguration, PoolKey, ICoin} from "./interfaces/ICoin.sol";
13
13
  import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
14
- import {BaseCoinV4} from "./BaseCoinV4.sol";
14
+ import {BaseCoin} from "./BaseCoin.sol";
15
15
 
16
- contract CreatorCoin is ICreatorCoin, BaseCoinV4 {
16
+ contract CreatorCoin is ICreatorCoin, BaseCoin {
17
17
  uint256 public vestingStartTime;
18
18
  uint256 public vestingEndTime;
19
19
  uint256 public totalClaimed;
@@ -23,7 +23,7 @@ contract CreatorCoin is ICreatorCoin, BaseCoinV4 {
23
23
  address _protocolRewards,
24
24
  IPoolManager _poolManager,
25
25
  address _airlock
26
- ) BaseCoinV4(_protocolRewardRecipient, _protocolRewards, _poolManager, _airlock) initializer {}
26
+ ) BaseCoin(_protocolRewardRecipient, _protocolRewards, _poolManager, _airlock) initializer {}
27
27
 
28
28
  function initialize(
29
29
  address payoutRecipient_,
@@ -36,7 +36,7 @@ contract CreatorCoin is ICreatorCoin, BaseCoinV4 {
36
36
  PoolKey memory poolKey_,
37
37
  uint160 sqrtPriceX96,
38
38
  PoolConfiguration memory poolConfiguration_
39
- ) public override(BaseCoinV4, ICoinV4) {
39
+ ) public override(BaseCoin, ICoin) {
40
40
  require(currency_ == CreatorCoinConstants.CURRENCY, InvalidCurrency());
41
41
 
42
42
  super.initialize(payoutRecipient_, owners_, tokenURI_, name_, symbol_, platformReferrer_, currency_, poolKey_, sqrtPriceX96, poolConfiguration_);
@@ -20,18 +20,13 @@ import {IWETH} from "./interfaces/IWETH.sol";
20
20
  import {IZoraFactory} from "./interfaces/IZoraFactory.sol";
21
21
  import {IHasAfterCoinDeploy} from "./hooks/deployment/BaseCoinDeployHook.sol";
22
22
  import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
23
- import {Coin} from "./Coin.sol";
24
- import {ContentCoin} from "./ContentCoin.sol";
25
23
  import {ICoin, PoolKeyStruct} from "./interfaces/ICoin.sol";
26
- import {ICoinV3} from "./interfaces/ICoinV3.sol";
27
- import {ICoinV4} from "./interfaces/ICoinV4.sol";
24
+ import {ICoin} from "./interfaces/ICoin.sol";
28
25
  import {IHasContractName} from "@zoralabs/shared-contracts/interfaces/IContractMetadata.sol";
29
26
  import {ContractVersionBase} from "./version/ContractVersionBase.sol";
30
27
  import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
31
28
  import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
32
29
  import {CoinCommon} from "./libs/CoinCommon.sol";
33
- import {UniV3Config} from "./libs/CoinSetupV3.sol";
34
- import {CoinSetupV3} from "./libs/CoinSetupV3.sol";
35
30
  import {PoolConfiguration} from "./types/PoolConfiguration.sol";
36
31
  import {LpPosition} from "./types/LpPosition.sol";
37
32
  import {IVersionedContract} from "@zoralabs/shared-contracts/interfaces/IVersionedContract.sol";
@@ -53,16 +48,14 @@ contract ZoraFactoryImpl is
53
48
  using SafeERC20 for IERC20;
54
49
 
55
50
  /// @notice The coin contract implementation address
56
- address public immutable coinImpl;
57
51
  address public immutable coinV4Impl;
58
52
  address public immutable creatorCoinImpl;
59
53
  address public immutable contentCoinHook;
60
54
  address public immutable creatorCoinHook;
61
55
 
62
- constructor(address _coinImpl, address _coinV4Impl, address _creatorCoinImpl, address _contentCoinHook, address _creatorCoinHook) {
56
+ constructor(address _coinV4Impl, address _creatorCoinImpl, address _contentCoinHook, address _creatorCoinHook) {
63
57
  _disableInitializers();
64
58
 
65
- coinImpl = _coinImpl;
66
59
  coinV4Impl = _coinV4Impl;
67
60
  creatorCoinImpl = _creatorCoinImpl;
68
61
  contentCoinHook = _contentCoinHook;
@@ -180,13 +173,13 @@ contract ZoraFactoryImpl is
180
173
  string memory symbol,
181
174
  bytes memory poolConfig,
182
175
  address platformReferrer,
183
- uint256 orderSize
176
+ uint256 /*orderSize*/
184
177
  ) public payable nonReentrant returns (address, uint256) {
185
178
  bytes32 salt = _randomSalt(payoutRecipient, uri, bytes32(0));
186
179
 
187
180
  ICoin coin = _createAndInitializeCoin(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer, salt);
188
181
 
189
- uint256 coinsPurchased = _handleFirstOrder(coin, orderSize);
182
+ uint256 coinsPurchased = 0;
190
183
 
191
184
  return (address(coin), coinsPurchased);
192
185
  }
@@ -225,15 +218,11 @@ contract ZoraFactoryImpl is
225
218
 
226
219
  ICoin coin = _createAndInitializeCoin(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer, salt);
227
220
 
228
- uint256 coinsPurchased = _handleFirstOrder(coin, orderSize);
229
-
230
- return (address(coin), coinsPurchased);
221
+ return (address(coin), 0);
231
222
  }
232
223
 
233
224
  function getCoinImpl(uint8 version) internal view returns (address) {
234
- if (CoinConfigurationVersions.isV3(version)) {
235
- return coinImpl;
236
- } else if (CoinConfigurationVersions.isV4(version)) {
225
+ if (CoinConfigurationVersions.isV4(version)) {
237
226
  return coinV4Impl;
238
227
  }
239
228
 
@@ -244,44 +233,8 @@ contract ZoraFactoryImpl is
244
233
  return payable(Clones.cloneDeterministic(getCoinImpl(version), salt));
245
234
  }
246
235
 
247
- function _setupV3Coin(
248
- ICoinV3 coin,
249
- address currency,
250
- bool isCoinToken0,
251
- uint160 sqrtPriceX96,
252
- PoolConfiguration memory poolConfiguration,
253
- address payoutRecipient,
254
- address[] memory owners,
255
- string memory uri,
256
- string memory name,
257
- string memory symbol,
258
- address platformReferrer
259
- ) internal {
260
- address v3Factory = coin.v3Factory();
261
-
262
- address poolAddress = CoinSetupV3.createV3Pool(address(coin), currency, isCoinToken0, sqrtPriceX96, v3Factory);
263
-
264
- LpPosition[] memory positions = CoinDopplerMultiCurve.calculatePositions(isCoinToken0, poolConfiguration, MarketConstants.POOL_LAUNCH_SUPPLY);
265
-
266
- // Initialize coin with pre-configured pool
267
- coin.initialize(payoutRecipient, owners, uri, name, symbol, platformReferrer, currency, poolAddress, poolConfiguration, positions);
268
-
269
- emit CoinCreated(
270
- msg.sender,
271
- payoutRecipient,
272
- platformReferrer,
273
- currency,
274
- uri,
275
- name,
276
- symbol,
277
- address(coin),
278
- poolAddress,
279
- IVersionedContract(address(coin)).contractVersion()
280
- );
281
- }
282
-
283
236
  function _setupV4Coin(
284
- ICoinV4 coin,
237
+ ICoin coin,
285
238
  address currency,
286
239
  bool isCoinToken0,
287
240
  uint160 sqrtPriceX96,
@@ -335,9 +288,10 @@ contract ZoraFactoryImpl is
335
288
  );
336
289
 
337
290
  if (CoinConfigurationVersions.isV3(version)) {
338
- _setupV3Coin(ICoinV3(coin), currency, isCoinToken0, sqrtPriceX96, poolConfiguration, payoutRecipient, owners, uri, name, symbol, platformReferrer);
291
+ // V3 is no longer supported
292
+ revert ICoin.InvalidPoolVersion();
339
293
  } else if (CoinConfigurationVersions.isV4(version)) {
340
- _setupV4Coin(ICoinV4(coin), currency, isCoinToken0, sqrtPriceX96, poolConfiguration, payoutRecipient, owners, uri, name, symbol, platformReferrer);
294
+ _setupV4Coin(ICoin(coin), currency, isCoinToken0, sqrtPriceX96, poolConfiguration, payoutRecipient, owners, uri, name, symbol, platformReferrer);
341
295
  } else {
342
296
  revert ICoin.InvalidPoolVersion();
343
297
  }
@@ -375,43 +329,6 @@ contract ZoraFactoryImpl is
375
329
  );
376
330
  }
377
331
 
378
- /// @dev Handles the first buy of a newly created coin
379
- /// @param coin The newly created coin contract
380
- /// @param orderSize The size of the first buy order; must match msg.value for ETH/WETH pairs
381
- function _handleFirstOrder(ICoin coin, uint256 orderSize) internal returns (uint256 coinsPurchased) {
382
- if (msg.value > 0 || orderSize > 0) {
383
- address currency = coin.currency();
384
- address payoutRecipient = coin.payoutRecipient();
385
-
386
- if (currency != Coin(payable(address(coin))).WETH()) {
387
- if (msg.value != 0) {
388
- revert EthTransferInvalid();
389
- }
390
-
391
- _handleIncomingCurrency(currency, orderSize);
392
-
393
- IERC20(currency).approve(address(coin), orderSize);
394
-
395
- (, coinsPurchased) = Coin(payable(address(coin))).buy(payoutRecipient, orderSize, 0, 0, address(0));
396
- } else {
397
- (, coinsPurchased) = Coin(payable(address(coin))).buy{value: msg.value}(payoutRecipient, orderSize, 0, 0, address(0));
398
- }
399
- }
400
- }
401
-
402
- /// @dev Safely transfers ERC20 tokens from the caller to this contract to be sent to the newly created coin
403
- /// @param currency The ERC20 token address to transfer
404
- /// @param orderSize The amount of tokens to transfer for the order
405
- function _handleIncomingCurrency(address currency, uint256 orderSize) internal {
406
- uint256 beforeBalance = IERC20(currency).balanceOf(address(this));
407
- IERC20(currency).safeTransferFrom(msg.sender, address(this), orderSize);
408
- uint256 afterBalance = IERC20(currency).balanceOf(address(this));
409
-
410
- if ((afterBalance - beforeBalance) != orderSize) {
411
- revert ERC20TransferAmountMismatch();
412
- }
413
- }
414
-
415
332
  /// @notice Initializes the factory proxy contract
416
333
  /// @param initialOwner Address of the contract owner
417
334
  /// @dev Can only be called once due to initializer modifier
@@ -6,9 +6,8 @@ import "forge-std/Script.sol";
6
6
  import {ProxyDeployerScript, DeterministicContractConfig, DeterministicDeployerAndCaller} from "@zoralabs/shared-contracts/deployment/ProxyDeployerScript.sol";
7
7
  import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
8
8
  import {ZoraFactoryImpl} from "../ZoraFactoryImpl.sol";
9
- import {Coin} from "../Coin.sol";
10
9
  import {IVersionedContract} from "@zoralabs/shared-contracts/interfaces/IVersionedContract.sol";
11
- import {BuySupplyWithSwapRouterHook} from "../hooks/deployment/BuySupplyWithSwapRouterHook.sol";
10
+ // import {BuySupplyWithSwapRouterHook} from "../hooks/deployment/BuySupplyWithSwapRouterHook.sol";
12
11
  import {IZoraFactory} from "../interfaces/IZoraFactory.sol";
13
12
  import {ContentCoin} from "../ContentCoin.sol";
14
13
  import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
@@ -102,18 +101,6 @@ contract CoinsDeployerBase is ProxyDeployerScript {
102
101
  deployment.hookUpgradeGate = readAddressOrDefaultToZero(json, "HOOK_UPGRADE_GATE");
103
102
  }
104
103
 
105
- function deployCoinV3Impl() internal returns (Coin) {
106
- return
107
- new Coin({
108
- protocolRewardRecipient_: getZoraRecipient(),
109
- protocolRewards_: PROTOCOL_REWARDS,
110
- weth_: getWeth(),
111
- v3Factory_: getUniswapV3Factory(),
112
- swapRouter_: getUniswapSwapRouter(),
113
- airlock_: getDopplerAirlock()
114
- });
115
- }
116
-
117
104
  function deployCoinV4Impl(address zoraV4CoinHook) internal returns (ContentCoin) {
118
105
  return
119
106
  new ContentCoin({
@@ -135,7 +122,6 @@ contract CoinsDeployerBase is ProxyDeployerScript {
135
122
  }
136
123
 
137
124
  function deployZoraFactoryImpl(
138
- address _coinV3Impl,
139
125
  address _coinV4Impl,
140
126
  address _creatorCoinImpl,
141
127
  address _contentCoinHook,
@@ -143,7 +129,6 @@ contract CoinsDeployerBase is ProxyDeployerScript {
143
129
  ) internal returns (ZoraFactoryImpl) {
144
130
  return
145
131
  new ZoraFactoryImpl({
146
- _coinImpl: _coinV3Impl,
147
132
  _coinV4Impl: _coinV4Impl,
148
133
  _creatorCoinImpl: _creatorCoinImpl,
149
134
  _contentCoinHook: _contentCoinHook,
@@ -151,14 +136,14 @@ contract CoinsDeployerBase is ProxyDeployerScript {
151
136
  });
152
137
  }
153
138
 
154
- function deployBuySupplyWithSwapRouterHook(CoinsDeployment memory deployment) internal returns (BuySupplyWithSwapRouterHook) {
155
- return
156
- new BuySupplyWithSwapRouterHook({
157
- _factory: IZoraFactory(deployment.zoraFactory),
158
- _swapRouter: getUniswapSwapRouter(),
159
- _poolManager: getUniswapV4PoolManager()
160
- });
161
- }
139
+ // function deployBuySupplyWithSwapRouterHook(CoinsDeployment memory deployment) internal returns (BuySupplyWithSwapRouterHook) {
140
+ // return
141
+ // new BuySupplyWithSwapRouterHook({
142
+ // _factory: IZoraFactory(deployment.zoraFactory),
143
+ // _swapRouter: getUniswapSwapRouter(),
144
+ // _poolManager: getUniswapV4PoolManager()
145
+ // });
146
+ // }
162
147
 
163
148
  function deployUpgradeGate(CoinsDeployment memory deployment) internal returns (CoinsDeployment memory) {
164
149
  deployment.hookUpgradeGate = address(new HookUpgradeGate(getProxyAdmin()));
@@ -205,7 +190,6 @@ contract CoinsDeployerBase is ProxyDeployerScript {
205
190
  return
206
191
  address(
207
192
  deployZoraFactoryImpl({
208
- _coinV3Impl: deployment.coinV3Impl,
209
193
  _coinV4Impl: deployment.coinV4Impl,
210
194
  _creatorCoinImpl: deployment.creatorCoinImpl,
211
195
  _contentCoinHook: deployment.zoraV4CoinHook,
@@ -216,7 +200,6 @@ contract CoinsDeployerBase is ProxyDeployerScript {
216
200
 
217
201
  function deployImpls(CoinsDeployment memory deployment) internal returns (CoinsDeployment memory) {
218
202
  // Deploy implementation contracts
219
- deployment.coinV3Impl = address(deployCoinV3Impl());
220
203
 
221
204
  // Deploy hook first, then use its address for coin v4 impl
222
205
  console.log("deploying content coin hook");
@@ -233,7 +216,7 @@ contract CoinsDeployerBase is ProxyDeployerScript {
233
216
  deployment.creatorCoinImpl = address(deployCreatorCoinImpl(deployment.creatorCoinHook));
234
217
  deployment.zoraFactoryImpl = deployFactoryImpl(deployment);
235
218
  deployment.coinVersion = IVersionedContract(deployment.coinV4Impl).contractVersion();
236
- deployment.buySupplyWithSwapRouterHook = address(deployBuySupplyWithSwapRouterHook(deployment));
219
+ // deployment.buySupplyWithSwapRouterHook = address(deployBuySupplyWithSwapRouterHook(deployment));
237
220
 
238
221
  return deployment;
239
222
  }