@zoralabs/coins 0.7.1 → 1.0.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 (167) hide show
  1. package/.turbo/turbo-build.log +106 -84
  2. package/CHANGELOG.md +68 -0
  3. package/abis/BadImpl.json +15 -0
  4. package/abis/BalanceDeltaLibrary.json +15 -0
  5. package/abis/BaseCoin.json +1350 -0
  6. package/abis/BaseCoinDeployHook.json +78 -0
  7. package/abis/BaseHook.json +897 -0
  8. package/abis/BaseTest.json +60 -91
  9. package/abis/BeforeSwapDeltaLibrary.json +15 -0
  10. package/abis/BuySupplyWithSwapRouterHook.json +126 -0
  11. package/abis/Coin.json +214 -150
  12. package/abis/CoinConstants.json +65 -0
  13. package/abis/CoinDopplerMultiCurve.json +38 -0
  14. package/abis/CoinRewardsV4.json +54 -0
  15. package/abis/CoinTest.json +66 -111
  16. package/abis/CoinUniV4Test.json +1053 -0
  17. package/abis/CoinV4.json +1687 -0
  18. package/abis/CurrencyLibrary.json +25 -0
  19. package/abis/DeployHooks.json +9 -0
  20. package/abis/DeployScript.json +47 -0
  21. package/abis/DeployedCoinVersionLookup.json +21 -0
  22. package/abis/DeployedCoinVersionLookupTest.json +716 -0
  23. package/abis/DifferentNamespaceVersionLookup.json +39 -0
  24. package/abis/DopplerUniswapV3Test.json +62 -184
  25. package/abis/ERC20.json +310 -0
  26. package/abis/FactoryTest.json +98 -98
  27. package/abis/FakeHookNoInterface.json +21 -0
  28. package/abis/FeeEstimatorHook.json +1528 -0
  29. package/abis/Hooks.json +28 -0
  30. package/abis/HooksDeployment.json +23 -0
  31. package/abis/HooksTest.json +698 -0
  32. package/abis/IAllowanceTransfer.json +486 -0
  33. package/abis/ICoin.json +62 -69
  34. package/abis/ICoinDeployHook.json +31 -0
  35. package/abis/ICoinV3.json +879 -0
  36. package/abis/ICoinV4.json +915 -0
  37. package/abis/IContractMetadata.json +28 -0
  38. package/abis/IDeployedCoinVersionLookup.json +21 -0
  39. package/abis/IEIP712.json +15 -0
  40. package/abis/IEIP712_v4.json +15 -0
  41. package/abis/IERC20Minimal.json +172 -0
  42. package/abis/IERC6909Claims.json +288 -0
  43. package/abis/IERC721.json +36 -36
  44. package/abis/IERC721Permit_v4.json +88 -0
  45. package/abis/IExtsload.json +64 -0
  46. package/abis/IExttload.json +40 -0
  47. package/abis/IHasAfterCoinDeploy.json +31 -0
  48. package/abis/IHasContractName.json +15 -0
  49. package/abis/IHasPoolKey.json +42 -0
  50. package/abis/IHasRewardsRecipients.json +54 -0
  51. package/abis/IHasSwapPath.json +60 -0
  52. package/abis/IHooks.json +789 -0
  53. package/abis/IImmutableState.json +15 -0
  54. package/abis/IMsgSender.json +15 -0
  55. package/abis/IMulticall_v4.json +21 -0
  56. package/abis/INotifier.json +187 -0
  57. package/abis/IPermit2.json +865 -0
  58. package/abis/IPermit2Forwarder.json +138 -0
  59. package/abis/IPoolConfigEncoding.json +46 -0
  60. package/abis/IPoolInitializer_v4.json +53 -0
  61. package/abis/IPoolManager.json +1286 -0
  62. package/abis/IPositionManager.json +712 -0
  63. package/abis/IProtocolFees.json +174 -0
  64. package/abis/ISignatureTransfer.json +394 -0
  65. package/abis/ISubscriber.json +89 -0
  66. package/abis/ISwapPathRouter.json +92 -0
  67. package/abis/ISwapRouter.json +82 -0
  68. package/abis/IUniversalRouter.json +61 -0
  69. package/abis/IUnlockCallback.json +21 -0
  70. package/abis/IUnorderedNonce.json +44 -0
  71. package/abis/IV4Quoter.json +310 -0
  72. package/abis/IV4Router.json +47 -0
  73. package/abis/IZoraFactory.json +328 -4
  74. package/abis/IZoraV4CoinHook.json +427 -0
  75. package/abis/ImmutableState.json +36 -0
  76. package/abis/LPFeeLibrary.json +65 -0
  77. package/abis/MockERC20.json +21 -0
  78. package/abis/MultiOwnableTest.json +60 -91
  79. package/abis/{CoinConfigurationVersions.json → Position.json} +1 -1
  80. package/abis/PrintUpgradeCommand.json +9 -0
  81. package/abis/ProxyShim.json +24 -0
  82. package/abis/Simulate.json +0 -91
  83. package/abis/StateLibrary.json +80 -0
  84. package/abis/TestDeployedCoinVersionLookupImplementation.json +39 -0
  85. package/abis/TestV4Swap.json +9 -0
  86. package/abis/{CoinSetup.json → UniV3BuySell.json} +5 -0
  87. package/abis/UniV3Errors.json +32 -0
  88. package/abis/UpgradeCoinImpl.json +47 -0
  89. package/abis/UpgradeFactoryImpl.json +9 -0
  90. package/abis/UpgradesTest.json +671 -0
  91. package/abis/Vm.json +1482 -111
  92. package/abis/VmSafe.json +856 -32
  93. package/abis/ZoraFactoryImpl.json +450 -1
  94. package/abis/ZoraV4CoinHook.json +1439 -0
  95. package/addresses/8453.json +8 -3
  96. package/addresses/84532.json +8 -3
  97. package/dist/index.cjs +1998 -184
  98. package/dist/index.cjs.map +1 -1
  99. package/dist/index.js +1989 -178
  100. package/dist/index.js.map +1 -1
  101. package/dist/wagmiGenerated.d.ts +2852 -688
  102. package/dist/wagmiGenerated.d.ts.map +1 -1
  103. package/package/wagmiGenerated.ts +1992 -173
  104. package/package.json +7 -2
  105. package/remappings.txt +6 -1
  106. package/script/CoinsDeployerBase.sol +105 -10
  107. package/script/DeployDevFactory.s.sol +21 -0
  108. package/script/DeployHooks.s.sol +22 -0
  109. package/script/PrintUpgradeCommand.s.sol +13 -0
  110. package/script/Simulate.s.sol +4 -12
  111. package/script/TestBackingCoinSwap.s.sol +146 -0
  112. package/script/TestV4Swap.s.sol +136 -0
  113. package/script/UpgradeCoinImpl.sol +2 -2
  114. package/script/UpgradeFactoryImpl.s.sol +23 -0
  115. package/src/BaseCoin.sol +176 -0
  116. package/src/Coin.sol +93 -515
  117. package/src/CoinV4.sol +121 -0
  118. package/src/ZoraFactoryImpl.sol +257 -57
  119. package/src/hooks/ZoraV4CoinHook.sol +195 -0
  120. package/src/hooks/deployment/BaseCoinDeployHook.sol +62 -0
  121. package/src/hooks/deployment/BuySupplyWithSwapRouterHook.sol +80 -0
  122. package/src/interfaces/ICoin.sol +35 -39
  123. package/src/interfaces/ICoinDeployHook.sol +8 -0
  124. package/src/interfaces/ICoinV3.sol +71 -0
  125. package/src/interfaces/ICoinV4.sol +69 -0
  126. package/src/interfaces/IDeployedCoinVersionLookup.sol +11 -0
  127. package/src/interfaces/IMsgSender.sol +9 -0
  128. package/src/interfaces/IPoolConfigEncoding.sol +14 -0
  129. package/src/interfaces/ISwapPathRouter.sol +14 -0
  130. package/src/interfaces/ISwapRouter.sol +1 -35
  131. package/src/interfaces/IZoraFactory.sol +97 -7
  132. package/src/interfaces/IZoraV4CoinHook.sol +116 -0
  133. package/src/libs/CoinCommon.sol +15 -0
  134. package/src/libs/CoinConfigurationVersions.sol +116 -1
  135. package/src/{utils → libs}/CoinConstants.sol +11 -6
  136. package/src/libs/CoinDopplerMultiCurve.sol +134 -0
  137. package/src/libs/CoinDopplerUniV3.sol +19 -171
  138. package/src/libs/CoinRewards.sol +195 -0
  139. package/src/libs/CoinRewardsV4.sol +180 -0
  140. package/src/libs/CoinSetup.sol +40 -20
  141. package/src/libs/CoinSetupV3.sol +50 -0
  142. package/src/libs/DopplerMath.sol +156 -0
  143. package/src/libs/HooksDeployment.sol +84 -0
  144. package/src/libs/MarketConstants.sol +4 -0
  145. package/src/libs/PoolStateReader.sol +22 -0
  146. package/src/libs/UniV3BuySell.sol +231 -0
  147. package/src/libs/UniV3Errors.sol +11 -0
  148. package/src/libs/UniV4SwapHelper.sol +65 -0
  149. package/src/libs/UniV4SwapToCurrency.sol +109 -0
  150. package/src/libs/V4Liquidity.sol +129 -0
  151. package/src/types/PoolConfiguration.sol +15 -0
  152. package/src/utils/DeployedCoinVersionLookup.sol +52 -0
  153. package/src/version/ContractVersionBase.sol +1 -1
  154. package/test/Coin.t.sol +94 -101
  155. package/test/CoinDopplerUniV3.t.sol +35 -184
  156. package/test/CoinUniV4.t.sol +752 -0
  157. package/test/DeploymentHooks.t.sol +270 -0
  158. package/test/Factory.t.sol +84 -50
  159. package/test/MultiOwnable.t.sol +6 -3
  160. package/test/Upgrades.t.sol +68 -0
  161. package/test/mocks/MockERC20.sol +12 -0
  162. package/test/utils/BaseTest.sol +124 -59
  163. package/test/utils/DeployedCoinVersionLookup.t.sol +127 -0
  164. package/test/utils/FeeEstimatorHook.sol +84 -0
  165. package/test/utils/ProxyShim.sol +17 -0
  166. package/wagmi.config.ts +10 -9
  167. package/src/libs/CoinLegacy.sol +0 -48
@@ -8,11 +8,12 @@ import {Address} from "@openzeppelin/contracts/utils/Address.sol";
8
8
  import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
9
9
  import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
10
10
  import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
11
-
11
+ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
12
+ import {IZoraFactory} from "../../src/interfaces/IZoraFactory.sol";
12
13
  import {ZoraFactoryImpl} from "../../src/ZoraFactoryImpl.sol";
13
14
  import {ZoraFactory} from "../../src/proxy/ZoraFactory.sol";
14
15
  import {Coin} from "../../src/Coin.sol";
15
- import {CoinConstants} from "../../src/utils/CoinConstants.sol";
16
+ import {CoinV4} from "../../src/CoinV4.sol";
16
17
  import {MultiOwnable} from "../../src/utils/MultiOwnable.sol";
17
18
  import {ICoin} from "../../src/interfaces/ICoin.sol";
18
19
  import {IERC7572} from "../../src/interfaces/IERC7572.sol";
@@ -25,7 +26,14 @@ import {IUniswapV3Pool} from "../../src/interfaces/IUniswapV3Pool.sol";
25
26
  import {IProtocolRewards} from "../../src/interfaces/IProtocolRewards.sol";
26
27
  import {ProtocolRewards} from "../utils/ProtocolRewards.sol";
27
28
  import {MarketConstants} from "../../src/libs/MarketConstants.sol";
28
- contract BaseTest is Test, CoinConstants {
29
+ import {CoinConfigurationVersions} from "../../src/libs/CoinConfigurationVersions.sol";
30
+ import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
31
+ import {ZoraV4CoinHook} from "../../src/hooks/ZoraV4CoinHook.sol";
32
+ import {HooksDeployment} from "../../src/libs/HooksDeployment.sol";
33
+ import {CoinConstants} from "../../src/libs/CoinConstants.sol";
34
+ import {ProxyShim} from "./ProxyShim.sol";
35
+
36
+ contract BaseTest is Test {
29
37
  using stdStorage for StdStorage;
30
38
 
31
39
  address internal constant PROTOCOL_REWARDS = 0x7777777F279eba3d3Ad8F4E708545291A6fDBA8B;
@@ -35,6 +43,11 @@ contract BaseTest is Test, CoinConstants {
35
43
  address internal constant SWAP_ROUTER = 0x2626664c2603336E57B271c5C0b26F421741e481;
36
44
  address internal constant DOPPLER_AIRLOCK = 0x660eAaEdEBc968f8f3694354FA8EC0b4c5Ba8D12;
37
45
  address internal constant USDC_ADDRESS = 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913;
46
+ address internal constant V4_POOL_MANAGER = 0x498581fF718922c3f8e6A244956aF099B2652b2b;
47
+ address internal constant V4_POSITION_MANAGER = 0x7C5f5A4bBd8fD63184577525326123B519429bDc;
48
+ address internal constant V4_PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
49
+ address internal constant V4_QUOTER = 0x0d5e0F971ED27FBfF6c2837bf31316121532048D;
50
+ address internal constant UNIVERSAL_ROUTER = 0x6fF5693b99212Da76ad316178A184AB56D299b43;
38
51
  int24 internal constant USDC_TICK_LOWER = 57200;
39
52
 
40
53
  struct Users {
@@ -54,18 +67,86 @@ contract BaseTest is Test, CoinConstants {
54
67
  ProtocolRewards internal protocolRewards;
55
68
  IUniswapV3Factory internal v3Factory;
56
69
  INonfungiblePositionManager internal nonfungiblePositionManager;
70
+
57
71
  ISwapRouter internal swapRouter;
58
72
  IAirlock internal airlock;
59
73
  Users internal users;
60
74
 
61
- Coin internal coinImpl;
75
+ Coin internal coinV3Impl;
76
+ CoinV4 internal coinV4Impl;
62
77
  ZoraFactoryImpl internal factoryImpl;
63
- ZoraFactoryImpl internal factory;
78
+ IZoraFactory internal factory;
79
+ ZoraV4CoinHook internal zoraV4CoinHook;
64
80
  Coin internal coin;
81
+
65
82
  IUniswapV3Pool internal pool;
83
+ int24 internal constant DEFAULT_DISCOVERY_TICK_LOWER = CoinConstants.DEFAULT_DISCOVERY_TICK_LOWER;
84
+ int24 internal constant DEFAULT_DISCOVERY_TICK_UPPER = CoinConstants.DEFAULT_DISCOVERY_TICK_UPPER;
85
+ uint16 internal constant DEFAULT_NUM_DISCOVERY_POSITIONS = CoinConstants.DEFAULT_NUM_DISCOVERY_POSITIONS;
86
+ uint256 internal constant DEFAULT_DISCOVERY_SUPPLY_SHARE = CoinConstants.DEFAULT_DISCOVERY_SUPPLY_SHARE;
87
+
88
+ function _deployCoin() internal {
89
+ bytes memory poolConfig_ = _generatePoolConfig(
90
+ CoinConfigurationVersions.DOPPLER_UNI_V3_POOL_VERSION,
91
+ address(weth),
92
+ DEFAULT_DISCOVERY_TICK_LOWER,
93
+ DEFAULT_DISCOVERY_TICK_UPPER,
94
+ DEFAULT_NUM_DISCOVERY_POSITIONS,
95
+ DEFAULT_DISCOVERY_SUPPLY_SHARE
96
+ );
97
+ vm.prank(users.creator);
98
+ (address coinAddress, ) = factory.deploy(
99
+ users.creator,
100
+ _getDefaultOwners(),
101
+ "https://test.com",
102
+ "Testcoin",
103
+ "TEST",
104
+ poolConfig_,
105
+ users.platformReferrer,
106
+ 0
107
+ );
108
+
109
+ coin = Coin(payable(coinAddress));
110
+ pool = IUniswapV3Pool(coin.poolAddress());
111
+
112
+ vm.label(address(coin), "COIN");
113
+ vm.label(address(pool), "POOL");
114
+ }
115
+
116
+ function _deployCoinUSDCPair() internal {
117
+ bytes memory poolConfig_ = _generatePoolConfig(
118
+ CoinConfigurationVersions.DOPPLER_UNI_V3_POOL_VERSION,
119
+ USDC_ADDRESS,
120
+ DEFAULT_DISCOVERY_TICK_LOWER,
121
+ DEFAULT_DISCOVERY_TICK_UPPER,
122
+ DEFAULT_NUM_DISCOVERY_POSITIONS,
123
+ DEFAULT_DISCOVERY_SUPPLY_SHARE
124
+ );
125
+ vm.prank(users.creator);
126
+ (address coinAddress, ) = factory.deploy(
127
+ users.creator,
128
+ _getDefaultOwners(),
129
+ "https://test.com",
130
+ "Testcoin",
131
+ "TEST",
132
+ poolConfig_,
133
+ users.platformReferrer,
134
+ 0
135
+ );
136
+
137
+ coin = Coin(payable(coinAddress));
138
+ pool = IUniswapV3Pool(coin.poolAddress());
139
+
140
+ vm.label(address(coin), "COIN");
141
+ vm.label(address(pool), "POOL");
142
+ }
66
143
 
67
144
  function setUp() public virtual {
68
- forkId = vm.createSelectFork("base", 28415528);
145
+ setUpWithBlockNumber(28415528);
146
+ }
147
+
148
+ function setUpWithBlockNumber(uint256 forkBlockNumber) public {
149
+ forkId = vm.createSelectFork("base", forkBlockNumber);
69
150
 
70
151
  weth = IWETH(WETH_ADDRESS);
71
152
  usdc = IERC20Metadata(USDC_ADDRESS);
@@ -74,7 +155,6 @@ contract BaseTest is Test, CoinConstants {
74
155
  swapRouter = ISwapRouter(SWAP_ROUTER);
75
156
  airlock = IAirlock(DOPPLER_AIRLOCK);
76
157
  protocolRewards = new ProtocolRewards();
77
-
78
158
  users = Users({
79
159
  factoryOwner: makeAddr("factoryOwner"),
80
160
  feeRecipient: makeAddr("feeRecipient"),
@@ -86,11 +166,21 @@ contract BaseTest is Test, CoinConstants {
86
166
  tradeReferrer: makeAddr("tradeReferrer")
87
167
  });
88
168
 
89
- coinImpl = new Coin(users.feeRecipient, address(protocolRewards), WETH_ADDRESS, V3_FACTORY, SWAP_ROUTER, DOPPLER_AIRLOCK);
90
- factoryImpl = new ZoraFactoryImpl(address(coinImpl));
91
- factory = ZoraFactoryImpl(address(new ZoraFactory(address(factoryImpl))));
169
+ address[] memory trustedMessageSenders = new address[](2);
170
+ trustedMessageSenders[0] = UNIVERSAL_ROUTER;
171
+ trustedMessageSenders[1] = V4_POSITION_MANAGER;
172
+
173
+ ProxyShim mockUpgradeableImpl = new ProxyShim();
174
+ factory = IZoraFactory(address(new ZoraFactory(address(mockUpgradeableImpl))));
175
+ zoraV4CoinHook = ZoraV4CoinHook(address(HooksDeployment.deployZoraV4CoinHookFromContract(V4_POOL_MANAGER, address(factory), trustedMessageSenders)));
176
+ coinV3Impl = new Coin(users.feeRecipient, address(protocolRewards), WETH_ADDRESS, V3_FACTORY, SWAP_ROUTER, DOPPLER_AIRLOCK);
177
+ coinV4Impl = new CoinV4(users.feeRecipient, address(protocolRewards), IPoolManager(V4_POOL_MANAGER), DOPPLER_AIRLOCK, zoraV4CoinHook);
178
+ factoryImpl = new ZoraFactoryImpl(address(coinV3Impl), address(coinV4Impl));
179
+ UUPSUpgradeable(address(factory)).upgradeToAndCall(address(factoryImpl), "");
180
+ factory = IZoraFactory(address(factory));
181
+ // factory = ZoraFactoryImpl(address(new ZoraFactory(address(factoryImpl))));
92
182
 
93
- ZoraFactoryImpl(factory).initialize(users.factoryOwner);
183
+ ZoraFactoryImpl(address(factory)).initialize(users.factoryOwner);
94
184
 
95
185
  vm.label(address(factory), "ZORA_FACTORY");
96
186
  vm.label(address(protocolRewards), "PROTOCOL_REWARDS");
@@ -116,54 +206,6 @@ contract BaseTest is Test, CoinConstants {
116
206
  uint256 protocol;
117
207
  }
118
208
 
119
- function _deployCoin() internal {
120
- address[] memory owners = new address[](1);
121
- owners[0] = users.creator;
122
-
123
- vm.prank(users.creator);
124
- (address coinAddress, ) = factory.deploy(
125
- users.creator,
126
- owners,
127
- "https://test.com",
128
- "Testcoin",
129
- "TEST",
130
- users.platformReferrer,
131
- address(weth),
132
- MarketConstants.LP_TICK_LOWER_WETH,
133
- 0
134
- );
135
-
136
- coin = Coin(payable(coinAddress));
137
- pool = IUniswapV3Pool(coin.poolAddress());
138
-
139
- vm.label(address(coin), "COIN");
140
- vm.label(address(pool), "POOL");
141
- }
142
-
143
- function _deployCoinUSDCPair() internal {
144
- address[] memory owners = new address[](1);
145
- owners[0] = users.creator;
146
-
147
- vm.prank(users.creator);
148
- (address coinAddress, ) = factory.deploy(
149
- users.creator,
150
- owners,
151
- "https://testusdccoin.com",
152
- "Testusdccoin",
153
- "TESTUSDCCOIN",
154
- users.platformReferrer,
155
- USDC_ADDRESS,
156
- USDC_TICK_LOWER,
157
- 0
158
- );
159
-
160
- coin = Coin(payable(coinAddress));
161
- pool = IUniswapV3Pool(coin.poolAddress());
162
-
163
- vm.label(address(coin), "COIN");
164
- vm.label(address(pool), "POOL");
165
- }
166
-
167
209
  function _calculateTradeRewards(uint256 ethAmount) internal pure returns (TradeRewards memory) {
168
210
  return
169
211
  TradeRewards({
@@ -202,4 +244,27 @@ contract BaseTest is Test, CoinConstants {
202
244
  function dopplerFeeRecipient() internal view returns (address) {
203
245
  return airlock.owner();
204
246
  }
247
+
248
+ function _generatePoolConfig(address currency_) internal pure returns (bytes memory) {
249
+ return
250
+ _generatePoolConfig(
251
+ CoinConfigurationVersions.DOPPLER_UNI_V3_POOL_VERSION,
252
+ currency_,
253
+ DEFAULT_DISCOVERY_TICK_LOWER,
254
+ DEFAULT_DISCOVERY_TICK_UPPER,
255
+ DEFAULT_NUM_DISCOVERY_POSITIONS,
256
+ DEFAULT_DISCOVERY_SUPPLY_SHARE
257
+ );
258
+ }
259
+
260
+ function _generatePoolConfig(
261
+ uint8 version_,
262
+ address currency_,
263
+ int24 tickLower_,
264
+ int24 tickUpper_,
265
+ uint16 numDiscoveryPositions_,
266
+ uint256 maxDiscoverySupplyShare_
267
+ ) internal pure returns (bytes memory) {
268
+ return abi.encode(version_, currency_, tickLower_, tickUpper_, numDiscoveryPositions_, maxDiscoverySupplyShare_);
269
+ }
205
270
  }
@@ -0,0 +1,127 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ import {BaseTest} from "../utils/BaseTest.sol";
5
+ import {DeployedCoinVersionLookup} from "../../src/utils/DeployedCoinVersionLookup.sol";
6
+
7
+ contract TestDeployedCoinVersionLookupImplementation is DeployedCoinVersionLookup {
8
+ function setVersionForTesting(address coin, uint8 version) external {
9
+ _setVersionForDeployedCoin(coin, version);
10
+ }
11
+ }
12
+
13
+ /**
14
+ * @title Mock implementation with different namespace
15
+ * @dev Used to verify that different namespaces don't collide
16
+ */
17
+ contract DifferentNamespaceVersionLookup {
18
+ /// @custom:storage-location erc7201:different.namespace
19
+ struct DeployedCoinVersionStorage {
20
+ mapping(address => uint8) deployedCoinWithVersion;
21
+ }
22
+
23
+ // keccak256(abi.encode(uint256(keccak256("different.namespace")) - 1)) & ~bytes32(uint256(0xff))
24
+ bytes32 private constant DEPLOYED_COIN_VERSION_STORAGE_LOCATION = 0xf0ec9c7ea8b861b539967dd0659fb8887a9724eca55e932839a2a8e01f50c400;
25
+
26
+ function _getDeployedCoinVersionStorage() private pure returns (DeployedCoinVersionStorage storage $) {
27
+ assembly {
28
+ $.slot := DEPLOYED_COIN_VERSION_STORAGE_LOCATION
29
+ }
30
+ }
31
+
32
+ function getVersionForDeployedCoin(address coin) public view returns (uint8) {
33
+ return _getDeployedCoinVersionStorage().deployedCoinWithVersion[coin];
34
+ }
35
+
36
+ function setVersionForTesting(address coin, uint8 version) external {
37
+ _getDeployedCoinVersionStorage().deployedCoinWithVersion[coin] = version;
38
+ }
39
+ }
40
+
41
+ contract DeployedCoinVersionLookupTest is BaseTest {
42
+ TestDeployedCoinVersionLookupImplementation public versionLookup;
43
+ DifferentNamespaceVersionLookup public differentNamespaceLookup;
44
+ address public testCoin1;
45
+ address public testCoin2;
46
+ address public testContractAddress;
47
+
48
+ function setUp() public override {
49
+ super.setUp();
50
+ versionLookup = new TestDeployedCoinVersionLookupImplementation();
51
+ differentNamespaceLookup = new DifferentNamespaceVersionLookup();
52
+ testCoin1 = makeAddr("testCoin1");
53
+ testCoin2 = makeAddr("testCoin2");
54
+ testContractAddress = makeAddr("testContractAddress");
55
+ }
56
+
57
+ function test_getAndSetVersionForDeployedCoin() public {
58
+ // Default version should be 0
59
+ assertEq(versionLookup.getVersionForDeployedCoin(testCoin1), 0);
60
+
61
+ // Set version and verify
62
+ versionLookup.setVersionForTesting(testCoin1, 1);
63
+ assertEq(versionLookup.getVersionForDeployedCoin(testCoin1), 1);
64
+
65
+ // Set version for a different coin
66
+ versionLookup.setVersionForTesting(testCoin2, 2);
67
+ assertEq(versionLookup.getVersionForDeployedCoin(testCoin2), 2);
68
+
69
+ // First coin's version should remain unchanged
70
+ assertEq(versionLookup.getVersionForDeployedCoin(testCoin1), 1);
71
+
72
+ // Update version and verify
73
+ versionLookup.setVersionForTesting(testCoin1, 3);
74
+ assertEq(versionLookup.getVersionForDeployedCoin(testCoin1), 3);
75
+ }
76
+
77
+ function test_differentNamespaceIndependence() public {
78
+ // First deploy the original implementation at a fixed address
79
+ TestDeployedCoinVersionLookupImplementation originalImpl = new TestDeployedCoinVersionLookupImplementation();
80
+ bytes memory originalBytecode = address(originalImpl).code;
81
+
82
+ // Deploy a different implementation
83
+ DifferentNamespaceVersionLookup differentImpl = new DifferentNamespaceVersionLookup();
84
+ bytes memory differentBytecode = address(differentImpl).code;
85
+
86
+ // Etch the original implementation to the test address
87
+ vm.etch(testContractAddress, originalBytecode);
88
+
89
+ // Test setting values with the first implementation
90
+ TestDeployedCoinVersionLookupImplementation(testContractAddress).setVersionForTesting(testCoin1, 42);
91
+ assertEq(TestDeployedCoinVersionLookupImplementation(testContractAddress).getVersionForDeployedCoin(testCoin1), 42);
92
+
93
+ // Save the bytecode location for the first implementation
94
+ bytes32 firstSlot = vm.load(
95
+ testContractAddress,
96
+ bytes32(uint256(keccak256(abi.encode(testCoin1, 0x9a79df0b86f39d0543c14aee714123562f798115071e932933bcc3e29cc86f00))))
97
+ );
98
+ assertEq(uint256(firstSlot), 42);
99
+
100
+ // Now replace the code with the different namespace implementation
101
+ vm.etch(testContractAddress, differentBytecode);
102
+
103
+ // Set a value with the different implementation
104
+ DifferentNamespaceVersionLookup(testContractAddress).setVersionForTesting(testCoin1, 99);
105
+
106
+ // This should use a different storage slot, so it shouldn't affect the original value
107
+ assertEq(DifferentNamespaceVersionLookup(testContractAddress).getVersionForDeployedCoin(testCoin1), 99);
108
+
109
+ // Verify the original storage slot still has the original value
110
+ bytes32 secondSlot = vm.load(
111
+ testContractAddress,
112
+ bytes32(uint256(keccak256(abi.encode(testCoin1, 0xf0ec9c7ea8b861b539967dd0659fb8887a9724eca55e932839a2a8e01f50c400))))
113
+ );
114
+ assertEq(uint256(secondSlot), 99);
115
+
116
+ // Switch back to the original implementation to verify its storage is unchanged
117
+ vm.etch(testContractAddress, originalBytecode);
118
+ assertEq(TestDeployedCoinVersionLookupImplementation(testContractAddress).getVersionForDeployedCoin(testCoin1), 42);
119
+
120
+ // Change the value in the original implementation
121
+ TestDeployedCoinVersionLookupImplementation(testContractAddress).setVersionForTesting(testCoin1, 123);
122
+
123
+ // Switch back to the different namespace implementation to verify its storage is unchanged
124
+ vm.etch(testContractAddress, differentBytecode);
125
+ assertEq(DifferentNamespaceVersionLookup(testContractAddress).getVersionForDeployedCoin(testCoin1), 99);
126
+ }
127
+ }
@@ -0,0 +1,84 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.13;
3
+
4
+ import {ZoraV4CoinHook} from "../../src/hooks/ZoraV4CoinHook.sol";
5
+ import {IPoolManager, PoolKey} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
6
+ import {IDeployedCoinVersionLookup} from "../../src/interfaces/IDeployedCoinVersionLookup.sol";
7
+ import {IHasRewardsRecipients} from "../../src/interfaces/ICoin.sol";
8
+ import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
9
+ import {SwapParams} from "@uniswap/v4-core/src/types/PoolOperation.sol";
10
+ import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
11
+ import {CoinCommon} from "../../src/libs/CoinCommon.sol";
12
+ import {V4Liquidity} from "../../src/libs/V4Liquidity.sol";
13
+ import {BaseHook} from "@uniswap/v4-periphery/src/utils/BaseHook.sol";
14
+ import {ICoinV4, IHasSwapPath} from "../../src/interfaces/ICoinV4.sol";
15
+ import {UniV4SwapToCurrency} from "../../src/libs/UniV4SwapToCurrency.sol";
16
+ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
17
+ import {CoinRewardsV4} from "../../src/libs/CoinRewardsV4.sol";
18
+
19
+ /// @dev Test util - meant to be able to etched where a normal zora hook is, to gather the fees from swaps but not distribute them
20
+ contract FeeEstimatorHook is ZoraV4CoinHook {
21
+ struct FeeEstimatorState {
22
+ uint128 fees0;
23
+ uint128 fees1;
24
+ Currency afterSwapCurrency;
25
+ uint128 afterSwapCurrencyAmount;
26
+ BalanceDelta lastDelta;
27
+ SwapParams lastSwapParams;
28
+ uint256 currencyBalanceChange;
29
+ uint256 coinBalanceChange;
30
+ }
31
+
32
+ constructor(IPoolManager _poolManager, IDeployedCoinVersionLookup _coinVersionLookup) ZoraV4CoinHook(_poolManager, _coinVersionLookup, new address[](0)) {}
33
+
34
+ FeeEstimatorState public feeState;
35
+
36
+ function getFeeState() public view returns (FeeEstimatorState memory) {
37
+ return feeState;
38
+ }
39
+
40
+ function _afterSwap(
41
+ address,
42
+ PoolKey calldata key,
43
+ SwapParams calldata params,
44
+ BalanceDelta _delta,
45
+ bytes calldata
46
+ ) internal override returns (bytes4, int128) {
47
+ bytes32 poolKeyHash = CoinCommon.hashPoolKey(key);
48
+
49
+ // get the coin address and positions for the pool key; they must have been set in the afterInitialize callback
50
+ address coin = poolCoins[poolKeyHash].coin;
51
+ require(coin != address(0), NoCoinForHook(key));
52
+
53
+ {
54
+ uint256 coinBalanceBefore = IERC20(coin).balanceOf(address(this));
55
+ uint256 currencyBalanceBefore = IERC20(ICoinV4(coin).currency()).balanceOf(address(this));
56
+
57
+ IHasSwapPath.PayoutSwapPath memory payoutSwapPath = IHasSwapPath(coin).getPayoutSwapPath(coinVersionLookup);
58
+
59
+ int128 fee0;
60
+ int128 fee1;
61
+
62
+ (fee0, fee1, feeState.afterSwapCurrency, feeState.afterSwapCurrencyAmount) = CoinRewardsV4.collectFeesAndConvertToPayout(
63
+ poolManager,
64
+ key,
65
+ poolCoins[poolKeyHash].positions,
66
+ payoutSwapPath
67
+ );
68
+
69
+ feeState.fees0 += uint128(fee0);
70
+ feeState.fees1 += uint128(fee1);
71
+
72
+ uint256 coinBalanceAfter = IERC20(coin).balanceOf(address(this));
73
+ uint256 currencyBalanceAfter = IERC20(ICoinV4(coin).currency()).balanceOf(address(this));
74
+
75
+ feeState.coinBalanceChange = coinBalanceAfter - coinBalanceBefore;
76
+ feeState.currencyBalanceChange = currencyBalanceAfter - currencyBalanceBefore;
77
+ }
78
+
79
+ feeState.lastDelta = _delta;
80
+ feeState.lastSwapParams = params;
81
+
82
+ return (BaseHook.afterSwap.selector, 0);
83
+ }
84
+ }
@@ -0,0 +1,17 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.18;
3
+
4
+ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
5
+
6
+ /// Used to deploy the factory before we know the impl address
7
+ contract ProxyShim is UUPSUpgradeable {
8
+ address immutable canUpgrade;
9
+
10
+ constructor() {
11
+ canUpgrade = msg.sender;
12
+ }
13
+
14
+ function _authorizeUpgrade(address) internal view override {
15
+ require(msg.sender == canUpgrade, "not authorized");
16
+ }
17
+ }
package/wagmi.config.ts CHANGED
@@ -5,18 +5,19 @@ export default defineConfig({
5
5
  out: "package/wagmiGenerated.ts",
6
6
  plugins: [
7
7
  foundry({
8
- deployments: {
9
- ZoraFactoryImpl: {
10
- 84532: "0x777777751622c0d3258f214F9DF38E35BF45baF3",
11
- 8453: "0x777777751622c0d3258f214F9DF38E35BF45baF3",
12
- },
13
- },
14
8
  forge: {
15
9
  build: false,
16
10
  },
17
- include: ["Coin", "ZoraFactoryImpl", "IUniswapV3Pool"].map(
18
- (contractName) => `${contractName}.json`,
19
- ),
11
+ include: [
12
+ "Coin",
13
+ "CoinV4",
14
+ "ZoraFactoryImpl",
15
+ "IUniswapV3Pool",
16
+ "BuySupplyWithSwapRouterHook",
17
+ "IPoolConfigEncoding",
18
+ "IUniversalRouter",
19
+ "IPermit2",
20
+ ].map((contractName) => `${contractName}.json`),
20
21
  }),
21
22
  ],
22
23
  });
@@ -1,48 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.23;
3
-
4
- import {PoolConfiguration, ICoin} from "../interfaces/ICoin.sol";
5
- import {TickMath} from "../utils/uniswap/TickMath.sol";
6
- import {MarketConstants} from "./MarketConstants.sol";
7
- import {LiquidityAmounts} from "../utils/uniswap/LiquidityAmounts.sol";
8
- import {LpPosition} from "../types/LpPosition.sol";
9
- import {CoinConfigurationVersions} from "./CoinConfigurationVersions.sol";
10
-
11
- library CoinLegacy {
12
- function setupPool(
13
- bool isCoinToken0,
14
- bytes memory poolConfig_,
15
- address weth
16
- ) internal pure returns (uint160 sqrtPriceX96, PoolConfiguration memory poolConfiguration) {
17
- (, address currency, int24 tickLower_) = abi.decode(poolConfig_, (uint8, address, int24));
18
-
19
- // If WETH is the pool's currency, validate the lower tick
20
- if ((currency == weth || currency == address(0)) && tickLower_ > MarketConstants.LP_TICK_LOWER_WETH) {
21
- revert ICoin.InvalidWethLowerTick();
22
- }
23
-
24
- int24 savedTickLower = isCoinToken0 ? tickLower_ : -MarketConstants.LP_TICK_UPPER;
25
- int24 savedTickUpper = isCoinToken0 ? MarketConstants.LP_TICK_UPPER : -tickLower_;
26
-
27
- sqrtPriceX96 = TickMath.getSqrtPriceAtTick(isCoinToken0 ? savedTickLower : savedTickUpper);
28
-
29
- poolConfiguration = PoolConfiguration({
30
- version: CoinConfigurationVersions.LEGACY_POOL_VERSION,
31
- tickLower: savedTickLower,
32
- tickUpper: savedTickUpper,
33
- numPositions: 1,
34
- maxDiscoverySupplyShare: 0
35
- });
36
- }
37
-
38
- function calculatePositions(bool isCoinToken0, PoolConfiguration memory poolConfiguration) internal pure returns (LpPosition[] memory positions) {
39
- positions = new LpPosition[](1);
40
-
41
- uint160 sqrtPriceX96 = TickMath.getSqrtPriceAtTick(isCoinToken0 ? poolConfiguration.tickLower : poolConfiguration.tickUpper);
42
- uint160 farSqrtPriceX96 = TickMath.getSqrtPriceAtTick(isCoinToken0 ? poolConfiguration.tickUpper : poolConfiguration.tickLower);
43
- uint128 liquidity = isCoinToken0
44
- ? LiquidityAmounts.getLiquidityForAmount0(sqrtPriceX96, farSqrtPriceX96, MarketConstants.POOL_LAUNCH_SUPPLY)
45
- : LiquidityAmounts.getLiquidityForAmount1(sqrtPriceX96, farSqrtPriceX96, MarketConstants.POOL_LAUNCH_SUPPLY);
46
- positions[0] = LpPosition({tickLower: poolConfiguration.tickLower, tickUpper: poolConfiguration.tickUpper, liquidity: liquidity});
47
- }
48
- }