@zoralabs/coins 2.2.1 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build$colon$js.log +125 -106
- package/CHANGELOG.md +50 -5
- package/README.md +5 -0
- package/abis/AddressConstants.json +7 -0
- package/abis/BaseCoin.json +0 -5
- package/abis/BaseTest.json +62 -0
- package/abis/BuySupplyWithV4SwapHook.json +429 -0
- package/abis/ContentCoin.json +0 -5
- package/abis/CreatorCoin.json +0 -5
- package/abis/FeeEstimatorHook.json +94 -1
- package/abis/IUniswapV4Router04.json +484 -0
- package/abis/IUpgradeableDestinationV4HookWithUpdateableFee.json +95 -0
- package/abis/IZoraFactory.json +69 -0
- package/abis/MockAirlock.json +39 -0
- package/abis/SimpleERC20.json +326 -0
- package/abis/ZoraFactoryImpl.json +69 -0
- package/abis/ZoraV4CoinHook.json +94 -1
- package/addresses/8453.json +8 -10
- package/audits/report-cantinacode-zora-0827.pdf +3498 -4
- package/audits/report-cantinacode-zora-1021.pdf +0 -0
- package/dist/index.cjs +161 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +160 -21
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +259 -40
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/foundry.toml +3 -3
- package/package/wagmiGenerated.ts +160 -21
- package/package.json +1 -1
- package/script/DeployPostDeploymentHooks.s.sol +1 -3
- package/script/TestBackingCoinSwap.s.sol +0 -2
- package/script/TestV4Swap.s.sol +0 -2
- package/src/BaseCoin.sol +4 -12
- package/src/ContentCoin.sol +3 -4
- package/src/CreatorCoin.sol +8 -10
- package/src/ZoraFactoryImpl.sol +115 -83
- package/src/deployment/CoinsDeployerBase.sol +9 -8
- package/src/hook-registry/ZoraHookRegistry.sol +4 -0
- package/src/hooks/ZoraV4CoinHook.sol +66 -9
- package/src/hooks/deployment/BuySupplyWithV4SwapHook.sol +310 -0
- package/src/interfaces/IUpgradeableV4Hook.sol +18 -0
- package/src/interfaces/IZoraFactory.sol +21 -2
- package/src/libs/CoinConstants.sol +51 -8
- package/src/libs/CoinDopplerMultiCurve.sol +11 -11
- package/src/libs/CoinRewardsV4.sol +26 -33
- package/src/libs/CoinSetup.sol +2 -9
- package/src/libs/DopplerMath.sol +2 -2
- package/src/libs/V4Liquidity.sol +79 -15
- package/src/utils/AutoSwapper.sol +1 -1
- package/src/version/ContractVersionBase.sol +1 -1
- package/test/BuySupplyWithV4SwapHook.t.sol +509 -0
- package/test/Coin.t.sol +26 -14
- package/test/CoinRewardsV4.t.sol +33 -0
- package/test/CoinUniV4.t.sol +3 -5
- package/test/ContentCoinRewards.t.sol +44 -3
- package/test/CreatorCoin.t.sol +54 -33
- package/test/CreatorCoinRewards.t.sol +1 -3
- package/test/DeploymentHooks.t.sol +54 -2
- package/test/Factory.t.sol +3 -3
- package/test/LiquidityMigration.t.sol +145 -7
- package/test/MultiOwnable.t.sol +4 -4
- package/test/Upgrades.t.sol +26 -17
- package/test/V4Liquidity.t.sol +178 -0
- package/test/ZoraHookRegistry.t.sol +19 -9
- package/test/mocks/MockAirlock.sol +22 -0
- package/test/mocks/SimpleERC20.sol +8 -0
- package/test/utils/BaseTest.sol +155 -3
- package/test/utils/RewardTestHelpers.sol +4 -4
- package/test/utils/hookmate/README.md +50 -0
- package/test/utils/hookmate/artifacts/DeployHelper.sol +20 -0
- package/test/utils/hookmate/artifacts/Permit2.sol +16 -0
- package/test/utils/hookmate/artifacts/UniversalRouter.sol +29 -0
- package/test/utils/hookmate/artifacts/V4PoolManager.sol +17 -0
- package/test/utils/hookmate/artifacts/V4PositionManager.sol +23 -0
- package/test/utils/hookmate/artifacts/V4Quoter.sol +17 -0
- package/test/utils/hookmate/artifacts/V4Router.sol +18 -0
- package/test/utils/hookmate/constants/AddressConstants.sol +193 -0
- package/test/utils/hookmate/interfaces/router/IUniswapV4Router04.sol +173 -0
- package/test/utils/hookmate/interfaces/router/PathKey.sol +34 -0
- package/test/utils/hookmate/test/utils/SwapFeeEventAsserter.sol +24 -0
- package/wagmi.config.ts +1 -1
- package/abis/CoinConstants.json +0 -54
- package/abis/CoinRewardsV4.json +0 -67
- package/src/libs/CreatorCoinConstants.sol +0 -15
- package/src/libs/MarketConstants.sol +0 -23
- package/src/utils/uniswap/BytesLib.sol +0 -35
- package/src/utils/uniswap/Path.sol +0 -31
- /package/abis/{VmContractHelper227.json → VmContractHelper239.json} +0 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.23;
|
|
3
|
+
|
|
4
|
+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
5
|
+
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
6
|
+
import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol";
|
|
7
|
+
import {IPoolManager, SwapParams} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
|
8
|
+
import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
|
|
9
|
+
import {BalanceDelta, BalanceDeltaLibrary} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
|
|
10
|
+
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
|
11
|
+
import {BaseCoinDeployHook} from "./BaseCoinDeployHook.sol";
|
|
12
|
+
import {IUniswapV3SwapCallback} from "../../interfaces/IUniswapV3SwapCallback.sol";
|
|
13
|
+
import {ICoin} from "../../interfaces/ICoin.sol";
|
|
14
|
+
import {ISwapRouter} from "../../interfaces/ISwapRouter.sol";
|
|
15
|
+
import {IZoraFactory} from "../../interfaces/IZoraFactory.sol";
|
|
16
|
+
import {ICoinV3} from "../../interfaces/ICoinV3.sol";
|
|
17
|
+
import {CoinConfigurationVersions} from "../../libs/CoinConfigurationVersions.sol";
|
|
18
|
+
import {TransientStateLibrary} from "@uniswap/v4-core/src/libraries/TransientStateLibrary.sol";
|
|
19
|
+
import {Path} from "@zoralabs/shared-contracts/libs/UniswapV3/Path.sol";
|
|
20
|
+
|
|
21
|
+
/// @title BuySupplyWithV4SwapHook
|
|
22
|
+
/// @notice Hook for purchasing initial coin supply with flexible swap routing
|
|
23
|
+
/// @dev Capabilities:
|
|
24
|
+
/// - ETH → V3 swap → V4 swap → coin (e.g., ETH → ZORA → Creator Coin → Content Coin)
|
|
25
|
+
/// - ETH → V3 swap → coin (e.g., ETH → ZORA for ZORA-backed coin)
|
|
26
|
+
/// - ETH → V4 swap → coin (direct ETH-paired coins)
|
|
27
|
+
/// - ERC20 → V4 swap → coin (e.g., Creator Coins → Content Coin)
|
|
28
|
+
/// - Slippage protection with minAmountOut validation
|
|
29
|
+
///
|
|
30
|
+
/// Limitations:
|
|
31
|
+
/// - V3 swaps only support ETH as input currency
|
|
32
|
+
/// - ERC20 input currencies require pre-approval
|
|
33
|
+
/// - V3 and V4 routes must connect properly (V3 output = V4 input)
|
|
34
|
+
contract BuySupplyWithV4SwapHook is BaseCoinDeployHook {
|
|
35
|
+
using BalanceDeltaLibrary for BalanceDelta;
|
|
36
|
+
using SafeERC20 for IERC20;
|
|
37
|
+
using CurrencyLibrary for Currency;
|
|
38
|
+
using Path for bytes;
|
|
39
|
+
|
|
40
|
+
// ============ STATE VARIABLES ============
|
|
41
|
+
|
|
42
|
+
ISwapRouter public immutable swapRouter;
|
|
43
|
+
IPoolManager public immutable poolManager;
|
|
44
|
+
|
|
45
|
+
// ============ STRUCTS ============
|
|
46
|
+
|
|
47
|
+
struct InitialSupplyParams {
|
|
48
|
+
address buyRecipient; // Who gets the coins
|
|
49
|
+
bytes v3Route; // V3 route from ETH to backing currency
|
|
50
|
+
PoolKey[] v4Route; // V4 route from backing currency to coin
|
|
51
|
+
address inputCurrency; // Currency to use for the V3 swap
|
|
52
|
+
uint256 inputAmount; // Amount of input currency to use for the V3 swap
|
|
53
|
+
uint256 minAmountOut; // Minimum amount of coins to receive from final swap
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
event BuyInitialSupply(
|
|
57
|
+
address indexed coin,
|
|
58
|
+
address indexed recipient,
|
|
59
|
+
uint256 indexed coinsPurchased,
|
|
60
|
+
bytes v3Route,
|
|
61
|
+
PoolKey[] v4Route,
|
|
62
|
+
address inputCurrency,
|
|
63
|
+
uint256 inputAmount,
|
|
64
|
+
uint256 v4SwapInput
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
// ============ ERRORS ============
|
|
68
|
+
|
|
69
|
+
error OnlyPoolManager();
|
|
70
|
+
error InsufficientInputCurrency(uint256 inputAmount, uint256 availableAmount);
|
|
71
|
+
error V3RouteCannotStartWithInputCurrency();
|
|
72
|
+
error V3RouteDoesNotConnectToV4RouteStart();
|
|
73
|
+
error InsufficientOutputAmount();
|
|
74
|
+
|
|
75
|
+
// ============ CONSTRUCTOR ============
|
|
76
|
+
|
|
77
|
+
constructor(IZoraFactory _factory, address _swapRouter, address _poolManager) BaseCoinDeployHook(_factory) {
|
|
78
|
+
swapRouter = ISwapRouter(_swapRouter);
|
|
79
|
+
poolManager = IPoolManager(_poolManager);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ============ MAIN HOOK FUNCTION ============
|
|
83
|
+
|
|
84
|
+
/// @notice Hook that buys supply for a coin using V3->V4 two-step swap routing
|
|
85
|
+
/// @dev Returns abi encoded (uint256 amountCurrency, uint256 coinsPurchased)
|
|
86
|
+
function _afterCoinDeploy(address, ICoin coin, bytes calldata hookData) internal override returns (bytes memory) {
|
|
87
|
+
// STEP 1: Decode parameters
|
|
88
|
+
InitialSupplyParams memory params = abi.decode(hookData, (InitialSupplyParams));
|
|
89
|
+
|
|
90
|
+
PoolKey[] memory v4Route = _buildV4RouteToCoin(coin, params.v4Route);
|
|
91
|
+
|
|
92
|
+
// STEP 2: Validate routes
|
|
93
|
+
_validateRoutes(params, v4Route);
|
|
94
|
+
|
|
95
|
+
_validateAndTransferInputCurrency(params);
|
|
96
|
+
|
|
97
|
+
// STEP 3: Execute V3 swap (inputCurrency -> backing currency)
|
|
98
|
+
(uint256 currencyAmount, address currencyReceived) = _executeV3Swap(params);
|
|
99
|
+
|
|
100
|
+
// STEP 4: Execute V4 swaps if needed, then buy coin
|
|
101
|
+
uint256 coinAmount = _executeV4Swap(v4Route, currencyAmount, currencyReceived, params.buyRecipient);
|
|
102
|
+
|
|
103
|
+
// Validate minimum amount of coins received from final swap
|
|
104
|
+
require(coinAmount >= params.minAmountOut, InsufficientOutputAmount());
|
|
105
|
+
|
|
106
|
+
emit BuyInitialSupply({
|
|
107
|
+
recipient: params.buyRecipient,
|
|
108
|
+
coin: address(coin),
|
|
109
|
+
v3Route: params.v3Route,
|
|
110
|
+
v4Route: v4Route,
|
|
111
|
+
inputCurrency: params.inputCurrency,
|
|
112
|
+
inputAmount: params.inputAmount,
|
|
113
|
+
v4SwapInput: currencyAmount,
|
|
114
|
+
coinsPurchased: coinAmount
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// STEP 5: Return results
|
|
118
|
+
return abi.encode(currencyAmount, coinAmount);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ============ VALIDATION ============
|
|
122
|
+
|
|
123
|
+
function _validateRoutes(InitialSupplyParams memory params, PoolKey[] memory v4Route) internal pure {
|
|
124
|
+
// Determine what currency should be the input to the V4 route
|
|
125
|
+
address v4InputCurrency;
|
|
126
|
+
if (params.v3Route.length == 0) {
|
|
127
|
+
// No V3 swap - input currency should directly match V4 route start
|
|
128
|
+
v4InputCurrency = params.inputCurrency;
|
|
129
|
+
} else {
|
|
130
|
+
// V3 swap exists - V3 output should match V4 route start
|
|
131
|
+
v4InputCurrency = _getV3RouteOutputCurrency(params.v3Route);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
PoolKey memory firstPool = v4Route[0];
|
|
135
|
+
|
|
136
|
+
require(
|
|
137
|
+
v4InputCurrency == Currency.unwrap(firstPool.currency0) || v4InputCurrency == Currency.unwrap(firstPool.currency1),
|
|
138
|
+
V3RouteDoesNotConnectToV4RouteStart()
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function _validateAndTransferInputCurrency(InitialSupplyParams memory params) internal {
|
|
143
|
+
if (params.inputCurrency == address(0)) {
|
|
144
|
+
uint256 providedAmount = msg.value;
|
|
145
|
+
|
|
146
|
+
require(providedAmount == params.inputAmount, InsufficientInputCurrency(params.inputAmount, providedAmount));
|
|
147
|
+
} else {
|
|
148
|
+
uint256 providedAmount = IERC20(params.inputCurrency).allowance(params.buyRecipient, address(this));
|
|
149
|
+
|
|
150
|
+
// must be enough allowance to transfer
|
|
151
|
+
require(providedAmount >= params.inputAmount, InsufficientInputCurrency(params.inputAmount, providedAmount));
|
|
152
|
+
|
|
153
|
+
// transfer from the buy recipient to this contract
|
|
154
|
+
IERC20(params.inputCurrency).safeTransferFrom(params.buyRecipient, address(this), params.inputAmount);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function _buildV4RouteToCoin(ICoin coin, PoolKey[] memory v4Route) internal view returns (PoolKey[] memory fullRoute) {
|
|
159
|
+
fullRoute = new PoolKey[](v4Route.length + 1);
|
|
160
|
+
|
|
161
|
+
for (uint256 i = 0; i < v4Route.length; i++) {
|
|
162
|
+
fullRoute[i] = v4Route[i];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
fullRoute[v4Route.length] = coin.getPoolKey();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ============ V3 SWAP LOGIC ============
|
|
169
|
+
|
|
170
|
+
function _executeV3Swap(InitialSupplyParams memory params) internal returns (uint256 amountCurrency, address currencyReceived) {
|
|
171
|
+
if (params.v3Route.length == 0) {
|
|
172
|
+
// No V3 swap needed - return inputAmount directly
|
|
173
|
+
return (params.inputAmount, params.inputCurrency);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// for v3 swap section, we dont support currently having an input currency other than eth
|
|
177
|
+
if (params.inputCurrency != address(0)) {
|
|
178
|
+
revert V3RouteCannotStartWithInputCurrency();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Build swap router call for exactInput
|
|
182
|
+
ISwapRouter.ExactInputParams memory swapParams = ISwapRouter.ExactInputParams({
|
|
183
|
+
path: params.v3Route,
|
|
184
|
+
recipient: address(this),
|
|
185
|
+
amountIn: params.inputAmount,
|
|
186
|
+
amountOutMinimum: 0 // For testing - in production should have slippage protection
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
amountCurrency = swapRouter.exactInput{value: params.inputAmount}(swapParams);
|
|
190
|
+
|
|
191
|
+
currencyReceived = _getV3RouteOutputCurrency(params.v3Route);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function _executeV4Swap(PoolKey[] memory v4Route, uint256 amountIn, address currencyIn, address buyRecipient) internal returns (uint256 amountCoin) {
|
|
195
|
+
Currency startingCurrency = Currency.wrap(currencyIn);
|
|
196
|
+
bytes memory data = abi.encode(v4Route, amountIn, startingCurrency, buyRecipient);
|
|
197
|
+
bytes memory result = poolManager.unlock(data);
|
|
198
|
+
amountCoin = abi.decode(result, (uint256));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/// @notice Callback for V4 swaps through route or coin purchase
|
|
202
|
+
function unlockCallback(bytes calldata data) external returns (bytes memory) {
|
|
203
|
+
require(msg.sender == address(poolManager), OnlyPoolManager());
|
|
204
|
+
|
|
205
|
+
(PoolKey[] memory v4Route, uint256 amountIn, Currency startingCurrency, address buyRecipient) = abi.decode(
|
|
206
|
+
data,
|
|
207
|
+
(PoolKey[], uint256, Currency, address)
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
Currency lastReceivedCurrency = startingCurrency;
|
|
211
|
+
uint128 lastReceivedAmount = uint128(amountIn);
|
|
212
|
+
// Execute swaps through the route
|
|
213
|
+
|
|
214
|
+
uint128 outputAmount = 0;
|
|
215
|
+
for (uint256 i = 0; i < v4Route.length; i++) {
|
|
216
|
+
PoolKey memory poolKey = v4Route[i];
|
|
217
|
+
|
|
218
|
+
// Determine swap direction based on current currency
|
|
219
|
+
bool zeroForOne = lastReceivedCurrency == poolKey.currency0;
|
|
220
|
+
|
|
221
|
+
BalanceDelta delta = poolManager.swap(
|
|
222
|
+
poolKey,
|
|
223
|
+
SwapParams(zeroForOne, -(int128(lastReceivedAmount)), zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1),
|
|
224
|
+
""
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
// Extract output amount from delta
|
|
228
|
+
outputAmount = zeroForOne ? uint128(delta.amount1()) : uint128(delta.amount0());
|
|
229
|
+
|
|
230
|
+
// Update currentAmount for next iteration
|
|
231
|
+
lastReceivedAmount = uint128(outputAmount);
|
|
232
|
+
|
|
233
|
+
// Update current currency for next swap
|
|
234
|
+
lastReceivedCurrency = zeroForOne ? poolKey.currency1 : poolKey.currency0;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Settle all currency deltas and get final amount
|
|
238
|
+
_settleDeltas(startingCurrency, lastReceivedCurrency, buyRecipient, amountIn, outputAmount);
|
|
239
|
+
|
|
240
|
+
return abi.encode(lastReceivedAmount);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/// @notice Helper to decode V4 route data (external for try/catch)
|
|
244
|
+
function decodeV4RouteData(bytes calldata data) external pure returns (PoolKey[] memory v4Route, uint256 startAmount) {
|
|
245
|
+
return abi.decode(data, (PoolKey[], uint256));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function encodeBuySupplyWithV4SwapHookData(InitialSupplyParams memory params) external pure returns (bytes memory) {
|
|
249
|
+
return abi.encode(params);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function _settleDeltas(Currency inputCurrency, Currency outputCurrency, address to, uint256 inputAmount, uint128 outputAmount) private {
|
|
253
|
+
// pay the input amount
|
|
254
|
+
if (inputCurrency.isAddressZero()) {
|
|
255
|
+
// For ETH, settle with msg.value
|
|
256
|
+
poolManager.settle{value: inputAmount}();
|
|
257
|
+
} else {
|
|
258
|
+
// For ERC20, sync and transfer
|
|
259
|
+
poolManager.sync(inputCurrency);
|
|
260
|
+
inputCurrency.transfer(address(poolManager), inputAmount);
|
|
261
|
+
poolManager.settle();
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// transfer the output amount to the recipient
|
|
265
|
+
poolManager.take(outputCurrency, to, outputAmount);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// ============ UTILITIES ============
|
|
269
|
+
|
|
270
|
+
function _getCoinBackingCurrency(ICoin coin) internal view returns (Currency) {
|
|
271
|
+
PoolKey memory poolKey = coin.getPoolKey();
|
|
272
|
+
|
|
273
|
+
if (Currency.unwrap(poolKey.currency0) == address(coin)) {
|
|
274
|
+
return poolKey.currency1;
|
|
275
|
+
}
|
|
276
|
+
return poolKey.currency0;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function _getV3RouteOutputCurrency(bytes memory path) internal pure returns (address tokenOut) {
|
|
280
|
+
if (path.length == 0) {
|
|
281
|
+
// if no path, then output currency is eth
|
|
282
|
+
return address(0);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// For a path with multiple pools, we need to traverse to the end
|
|
286
|
+
// Path format: tokenA + fee + tokenB + fee + tokenC...
|
|
287
|
+
// We want the final token (tokenC in this example)
|
|
288
|
+
|
|
289
|
+
// Follow Uniswap's pattern: traverse the path to find the final token
|
|
290
|
+
bytes memory currentPath = path;
|
|
291
|
+
|
|
292
|
+
// Keep skipping tokens until we reach the final pool
|
|
293
|
+
while (currentPath.hasMultiplePools()) {
|
|
294
|
+
currentPath = currentPath.skipToken();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// The final segment contains the last pool, decode to get the output token
|
|
298
|
+
(, tokenOut, ) = currentPath.decodeFirstPool();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function _getV3RouteInputCurrency(bytes memory path) internal pure returns (address tokenIn) {
|
|
302
|
+
if (path.length == 0) {
|
|
303
|
+
// if no path, then input currency is eth
|
|
304
|
+
return address(0);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Use Path library to get the input token (first token in the path)
|
|
308
|
+
(tokenIn, , ) = path.decodeFirstPool();
|
|
309
|
+
}
|
|
310
|
+
}
|
|
@@ -50,3 +50,21 @@ interface IUpgradeableDestinationV4Hook {
|
|
|
50
50
|
bytes calldata additionalData
|
|
51
51
|
) external;
|
|
52
52
|
}
|
|
53
|
+
|
|
54
|
+
interface IUpgradeableDestinationV4HookWithUpdateableFee {
|
|
55
|
+
/// @notice Initialize after migration from old hook
|
|
56
|
+
/// @param poolKey The pool key being migrated
|
|
57
|
+
/// @param coin The coin address
|
|
58
|
+
/// @param sqrtPriceX96 The current sqrt price
|
|
59
|
+
/// @param migratedLiquidity The migrated liquidity
|
|
60
|
+
/// @param additionalData Additional data for initialization
|
|
61
|
+
/// @return fee The new fee for the migrated liquidity
|
|
62
|
+
/// @return tickSpacing The new tick spacing for the migrated liquidity
|
|
63
|
+
function initializeFromMigrationWithUpdateableFee(
|
|
64
|
+
PoolKey calldata poolKey,
|
|
65
|
+
address coin,
|
|
66
|
+
uint160 sqrtPriceX96,
|
|
67
|
+
BurnedPosition[] calldata migratedLiquidity,
|
|
68
|
+
bytes calldata additionalData
|
|
69
|
+
) external returns (uint24 fee, int24 tickSpacing);
|
|
70
|
+
}
|
|
@@ -97,7 +97,20 @@ interface IZoraFactory is IDeployedCoinVersionLookup {
|
|
|
97
97
|
/// @notice Thrwon when an invalid config version is provided
|
|
98
98
|
error InvalidConfig();
|
|
99
99
|
|
|
100
|
-
/// @
|
|
100
|
+
/// @dev Deprecated: use `deployCreatorCoin` instead that has a salt and post-deploy hook specified
|
|
101
|
+
function deployCreatorCoin(
|
|
102
|
+
address payoutRecipient,
|
|
103
|
+
address[] memory owners,
|
|
104
|
+
string memory uri,
|
|
105
|
+
string memory name,
|
|
106
|
+
string memory symbol,
|
|
107
|
+
bytes memory poolConfig,
|
|
108
|
+
address platformReferrer,
|
|
109
|
+
bytes32 coinSalt
|
|
110
|
+
) external returns (address);
|
|
111
|
+
|
|
112
|
+
/// @notice Creates a new creator coin contract with an optional hook that runs after the coin is deployed.
|
|
113
|
+
/// Enables buying initial supply by supporting ETH transfers to the post-deploy hook.
|
|
101
114
|
/// @param payoutRecipient The recipient of creator reward payouts; this can be updated by an owner
|
|
102
115
|
/// @param owners The list of addresses that will be able to manage the coin's payout address and metadata uri
|
|
103
116
|
/// @param uri The coin metadata uri
|
|
@@ -105,7 +118,11 @@ interface IZoraFactory is IDeployedCoinVersionLookup {
|
|
|
105
118
|
/// @param symbol The symbol of the coin
|
|
106
119
|
/// @param poolConfig The config parameters for the coin's pool
|
|
107
120
|
/// @param platformReferrer The address of the platform referrer
|
|
121
|
+
/// @param postDeployHook The address of the hook to run after the coin is deployed
|
|
122
|
+
/// @param postDeployHookData The data to pass to the hook
|
|
108
123
|
/// @param coinSalt The salt used to deploy the coin
|
|
124
|
+
/// @return coin The address of the deployed creator coin
|
|
125
|
+
/// @return postDeployHookDataOut The data returned by the hook
|
|
109
126
|
function deployCreatorCoin(
|
|
110
127
|
address payoutRecipient,
|
|
111
128
|
address[] memory owners,
|
|
@@ -114,8 +131,10 @@ interface IZoraFactory is IDeployedCoinVersionLookup {
|
|
|
114
131
|
string memory symbol,
|
|
115
132
|
bytes memory poolConfig,
|
|
116
133
|
address platformReferrer,
|
|
134
|
+
address postDeployHook,
|
|
135
|
+
bytes calldata postDeployHookData,
|
|
117
136
|
bytes32 coinSalt
|
|
118
|
-
) external returns (address);
|
|
137
|
+
) external payable returns (address coin, bytes memory postDeployHookDataOut);
|
|
119
138
|
|
|
120
139
|
/// @notice Creates a new coin contract with an optional hook that runs after the coin is deployed.
|
|
121
140
|
/// Requires a salt to be specified, which enabled the coin to be deployed deterministically, and at
|
|
@@ -8,21 +8,64 @@
|
|
|
8
8
|
pragma solidity ^0.8.23;
|
|
9
9
|
|
|
10
10
|
library CoinConstants {
|
|
11
|
+
/// @dev Constant used to increase precision during calculations
|
|
12
|
+
uint256 internal constant WAD = 1e18;
|
|
13
|
+
|
|
11
14
|
/// @notice The maximum total supply
|
|
12
15
|
/// @dev Set to 1 billion coins with 18 decimals
|
|
13
|
-
uint256
|
|
16
|
+
uint256 internal constant MAX_TOTAL_SUPPLY = 1_000_000_000e18;
|
|
17
|
+
|
|
18
|
+
/// @notice The total supply for creator coins (same as MAX_TOTAL_SUPPLY)
|
|
19
|
+
/// @dev 1 billion coins
|
|
20
|
+
uint256 internal constant TOTAL_SUPPLY = 1_000_000_000e18;
|
|
14
21
|
|
|
15
|
-
/// @notice The number of coins allocated to the liquidity pool
|
|
22
|
+
/// @notice The number of coins allocated to the liquidity pool for content coins
|
|
16
23
|
/// @dev 990 million coins
|
|
17
|
-
uint256
|
|
24
|
+
uint256 internal constant CONTENT_COIN_MARKET_SUPPLY = 990_000_000e18;
|
|
25
|
+
|
|
26
|
+
/// @notice The number of coins allocated to the liquidity pool for creator coins
|
|
27
|
+
/// @dev 500 million coins
|
|
28
|
+
uint256 internal constant CREATOR_COIN_MARKET_SUPPLY = 500_000_000e18;
|
|
18
29
|
|
|
19
|
-
/// @notice The number of coins rewarded to the creator
|
|
30
|
+
/// @notice The number of coins rewarded to the creator for content coins on launch
|
|
20
31
|
/// @dev 10 million coins
|
|
21
|
-
uint256
|
|
32
|
+
uint256 internal constant CONTENT_COIN_INITIAL_CREATOR_SUPPLY = TOTAL_SUPPLY - CONTENT_COIN_MARKET_SUPPLY;
|
|
33
|
+
|
|
34
|
+
/// @notice Creator coin vesting supply for creator
|
|
35
|
+
/// @dev 500 million coins
|
|
36
|
+
uint256 internal constant CREATOR_COIN_CREATOR_VESTING_SUPPLY = TOTAL_SUPPLY - CREATOR_COIN_MARKET_SUPPLY;
|
|
37
|
+
|
|
38
|
+
/// @notice Creator coin vesting duration
|
|
39
|
+
/// @dev 5 years with leap years accounted for
|
|
40
|
+
uint256 internal constant CREATOR_VESTING_DURATION = (5 * 365.25 days);
|
|
41
|
+
|
|
42
|
+
/// @notice The backing currency for creator coins
|
|
43
|
+
/// @dev ETH backing currency address
|
|
44
|
+
address internal constant CREATOR_COIN_CURRENCY = 0x1111111111166b7FE7bd91427724B487980aFc69;
|
|
45
|
+
|
|
46
|
+
/// @notice The LP fee
|
|
47
|
+
/// @dev 10000 basis points = 1%
|
|
48
|
+
uint24 internal constant LP_FEE_V4 = 10_000;
|
|
49
|
+
|
|
50
|
+
/// @notice The spacing for 1% pools
|
|
51
|
+
/// @dev 200 ticks
|
|
52
|
+
int24 internal constant TICK_SPACING = 200;
|
|
53
|
+
|
|
54
|
+
// Creator gets 62.5% of market rewards (0.50% of total 1% fee)
|
|
55
|
+
// Market rewards = 80% of total fee (0.80% of 1%)
|
|
56
|
+
uint256 internal constant CREATOR_REWARD_BPS = 6250;
|
|
57
|
+
|
|
58
|
+
// Platform referrer gets 25% of market rewards (0.20% of total 1% fee)
|
|
59
|
+
uint256 internal constant CREATE_REFERRAL_REWARD_BPS = 2500;
|
|
60
|
+
|
|
61
|
+
// Trade referrer gets 5% of market rewards (0.04% of total 1% fee)
|
|
62
|
+
uint256 internal constant TRADE_REFERRAL_REWARD_BPS = 500;
|
|
63
|
+
|
|
64
|
+
// Doppler gets 1.25% of market rewards (0.01% of total 1% fee)
|
|
65
|
+
uint256 internal constant DOPPLER_REWARD_BPS = 125;
|
|
22
66
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
uint256 public constant MIN_ORDER_SIZE = 0.0000001 ether;
|
|
67
|
+
// LPs get 20% of total fee (0.20% of 1%)
|
|
68
|
+
uint256 internal constant LP_REWARD_BPS = 2000;
|
|
26
69
|
|
|
27
70
|
int24 internal constant DEFAULT_DISCOVERY_TICK_LOWER = -777000;
|
|
28
71
|
int24 internal constant DEFAULT_DISCOVERY_TICK_UPPER = 222000;
|
|
@@ -10,7 +10,7 @@ pragma solidity ^0.8.23;
|
|
|
10
10
|
import {PoolConfiguration} from "../interfaces/ICoin.sol";
|
|
11
11
|
import {CoinConfigurationVersions} from "./CoinConfigurationVersions.sol";
|
|
12
12
|
import {LpPosition} from "../types/LpPosition.sol";
|
|
13
|
-
import {
|
|
13
|
+
import {CoinConstants} from "./CoinConstants.sol";
|
|
14
14
|
import {FullMath} from "../utils/uniswap/FullMath.sol";
|
|
15
15
|
import {TickMath} from "../utils/uniswap/TickMath.sol";
|
|
16
16
|
import {IDopplerErrors} from "../interfaces/IDopplerErrors.sol";
|
|
@@ -56,8 +56,8 @@ library CoinDopplerMultiCurve {
|
|
|
56
56
|
uint256 totalDiscoverySupplyShare;
|
|
57
57
|
uint256 totalDiscoveryPositions;
|
|
58
58
|
|
|
59
|
-
int24 boundryTickLower = DopplerMath.alignTickToTickSpacing(isCoinToken0, TickMath.MAX_TICK,
|
|
60
|
-
int24 boundryTickUpper = DopplerMath.alignTickToTickSpacing(isCoinToken0, TickMath.MIN_TICK,
|
|
59
|
+
int24 boundryTickLower = DopplerMath.alignTickToTickSpacing(isCoinToken0, TickMath.MAX_TICK, CoinConstants.TICK_SPACING);
|
|
60
|
+
int24 boundryTickUpper = DopplerMath.alignTickToTickSpacing(isCoinToken0, TickMath.MIN_TICK, CoinConstants.TICK_SPACING);
|
|
61
61
|
|
|
62
62
|
// For each curve:
|
|
63
63
|
for (uint256 i; i < numCurves; i++) {
|
|
@@ -69,8 +69,8 @@ library CoinDopplerMultiCurve {
|
|
|
69
69
|
totalDiscoveryPositions += numDiscoveryPositions_[i];
|
|
70
70
|
totalDiscoverySupplyShare += maxDiscoverySupplyShare_[i];
|
|
71
71
|
|
|
72
|
-
int24 currentTickLower = DopplerMath.alignTickToTickSpacing(isCoinToken0, tickLower_[i],
|
|
73
|
-
int24 currentTickUpper = DopplerMath.alignTickToTickSpacing(isCoinToken0, tickUpper_[i],
|
|
72
|
+
int24 currentTickLower = DopplerMath.alignTickToTickSpacing(isCoinToken0, tickLower_[i], CoinConstants.TICK_SPACING);
|
|
73
|
+
int24 currentTickUpper = DopplerMath.alignTickToTickSpacing(isCoinToken0, tickUpper_[i], CoinConstants.TICK_SPACING);
|
|
74
74
|
|
|
75
75
|
require(currentTickLower < currentTickUpper, ConfigTickLowerMustBeLessThanTickUpper());
|
|
76
76
|
|
|
@@ -84,15 +84,15 @@ library CoinDopplerMultiCurve {
|
|
|
84
84
|
|
|
85
85
|
require(boundryTickLower < boundryTickUpper, InvalidTickRangeMisordered(boundryTickLower, boundryTickUpper));
|
|
86
86
|
require(totalDiscoveryPositions > 1 && totalDiscoveryPositions <= 200, IDopplerErrors.NumDiscoveryPositionsOutOfRange());
|
|
87
|
-
require(totalDiscoverySupplyShare <
|
|
87
|
+
require(totalDiscoverySupplyShare < CoinConstants.WAD, IDopplerErrors.MaxShareToBeSoldExceeded(totalDiscoverySupplyShare, CoinConstants.WAD));
|
|
88
88
|
|
|
89
89
|
sqrtPriceX96 = TickMath.getSqrtPriceAtTick(isCoinToken0 ? boundryTickLower : boundryTickUpper);
|
|
90
90
|
|
|
91
91
|
poolConfiguration = PoolConfiguration({
|
|
92
92
|
version: CoinConfigurationVersions.DOPPLER_MULTICURVE_UNI_V4_POOL_VERSION,
|
|
93
93
|
numPositions: uint16(totalDiscoveryPositions + 1), // Add one for the final tail position
|
|
94
|
-
fee:
|
|
95
|
-
tickSpacing:
|
|
94
|
+
fee: CoinConstants.LP_FEE_V4,
|
|
95
|
+
tickSpacing: CoinConstants.TICK_SPACING,
|
|
96
96
|
numDiscoveryPositions: numDiscoveryPositions_,
|
|
97
97
|
tickLower: tickLower_,
|
|
98
98
|
tickUpper: tickUpper_,
|
|
@@ -113,12 +113,12 @@ library CoinDopplerMultiCurve {
|
|
|
113
113
|
uint256 numCurves = poolConfiguration.tickLower.length;
|
|
114
114
|
|
|
115
115
|
for (uint256 i; i < numCurves; i++) {
|
|
116
|
-
uint256 curveSupply = FullMath.mulDiv(totalSupply, poolConfiguration.maxDiscoverySupplyShare[i],
|
|
116
|
+
uint256 curveSupply = FullMath.mulDiv(totalSupply, poolConfiguration.maxDiscoverySupplyShare[i], CoinConstants.WAD);
|
|
117
117
|
|
|
118
118
|
(positions, curveSupply) = DopplerMath.calculateLogNormalDistribution(
|
|
119
119
|
poolConfiguration.tickLower[i],
|
|
120
120
|
poolConfiguration.tickUpper[i],
|
|
121
|
-
|
|
121
|
+
CoinConstants.TICK_SPACING,
|
|
122
122
|
isCoinToken0,
|
|
123
123
|
curveSupply,
|
|
124
124
|
poolConfiguration.numDiscoveryPositions[i],
|
|
@@ -138,7 +138,7 @@ library CoinDopplerMultiCurve {
|
|
|
138
138
|
poolConfiguration.tickUpper[numCurves - 1],
|
|
139
139
|
isCoinToken0,
|
|
140
140
|
tailSupply,
|
|
141
|
-
|
|
141
|
+
CoinConstants.TICK_SPACING
|
|
142
142
|
);
|
|
143
143
|
}
|
|
144
144
|
}
|
|
@@ -33,26 +33,11 @@ import {ICreatorCoinHook} from "../interfaces/ICreatorCoinHook.sol";
|
|
|
33
33
|
import {IHasCoinType} from "../interfaces/ICoin.sol";
|
|
34
34
|
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
|
|
35
35
|
import {ICreatorCoin} from "../interfaces/ICreatorCoin.sol";
|
|
36
|
+
import {CoinConstants} from "./CoinConstants.sol";
|
|
36
37
|
|
|
37
38
|
library CoinRewardsV4 {
|
|
38
39
|
using SafeERC20 for IERC20;
|
|
39
40
|
|
|
40
|
-
// Creator gets 62.5% of market rewards (0.50% of total 1% fee)
|
|
41
|
-
// Market rewards = 80% of total fee (0.80% of 1%)
|
|
42
|
-
uint256 public constant CREATOR_REWARD_BPS = 6250;
|
|
43
|
-
|
|
44
|
-
// Platform referrer gets 25% of market rewards (0.20% of total 1% fee)
|
|
45
|
-
uint256 public constant CREATE_REFERRAL_REWARD_BPS = 2500;
|
|
46
|
-
|
|
47
|
-
// Trade referrer gets 5% of market rewards (0.04% of total 1% fee)
|
|
48
|
-
uint256 public constant TRADE_REFERRAL_REWARD_BPS = 500;
|
|
49
|
-
|
|
50
|
-
// Doppler gets 1.25% of market rewards (0.01% of total 1% fee)
|
|
51
|
-
uint256 public constant DOPPLER_REWARD_BPS = 125;
|
|
52
|
-
|
|
53
|
-
// LPs get 20% of total fee (0.20% of 1%)
|
|
54
|
-
uint256 public constant LP_REWARD_BPS = 2000;
|
|
55
|
-
|
|
56
41
|
function getTradeReferral(bytes calldata hookData) internal pure returns (address) {
|
|
57
42
|
return hookData.length >= 20 ? abi.decode(hookData, (address)) : address(0);
|
|
58
43
|
}
|
|
@@ -83,13 +68,16 @@ library CoinRewardsV4 {
|
|
|
83
68
|
|
|
84
69
|
/// @dev Computes the LP reward and remaining amount for market rewards from the total amount
|
|
85
70
|
function computeLpReward(uint128 totalBackingAmount) internal pure returns (uint128 lpRewardAmount) {
|
|
86
|
-
lpRewardAmount = uint128(calculateReward(uint256(totalBackingAmount), LP_REWARD_BPS));
|
|
71
|
+
lpRewardAmount = uint128(calculateReward(uint256(totalBackingAmount), CoinConstants.LP_REWARD_BPS));
|
|
87
72
|
}
|
|
88
73
|
|
|
89
74
|
function convertDeltaToPositiveUint128(int256 delta) internal pure returns (uint128) {
|
|
90
75
|
if (delta < 0) {
|
|
91
76
|
revert SafeCast.SafeCastOverflow();
|
|
92
77
|
}
|
|
78
|
+
if (delta > int256(uint256(type(uint128).max))) {
|
|
79
|
+
revert SafeCast.SafeCastOverflow();
|
|
80
|
+
}
|
|
93
81
|
return uint128(uint256(delta));
|
|
94
82
|
}
|
|
95
83
|
|
|
@@ -181,6 +169,7 @@ library CoinRewardsV4 {
|
|
|
181
169
|
/// @param fees The total amount of fees collected to be distributed
|
|
182
170
|
/// @param coin The coin contract instance that implements IHasRewardsRecipients to get recipient addresses
|
|
183
171
|
/// @param tradeReferrer The address of the trade referrer who should receive trade referral rewards (can be zero address)
|
|
172
|
+
/// @param coinType The type of coin (Creator or Content) which affects reward distribution percentages
|
|
184
173
|
function distributeMarketRewards(
|
|
185
174
|
Currency currency,
|
|
186
175
|
uint128 fees,
|
|
@@ -258,26 +247,30 @@ library CoinRewardsV4 {
|
|
|
258
247
|
) internal returns (MarketRewards memory rewards) {
|
|
259
248
|
rewards = _computeMarketRewards(fee, tradeReferral != address(0), platformReferrer != address(0));
|
|
260
249
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
_transferCurrency(currency, rewards.creatorAmount, payoutRecipient);
|
|
268
|
-
_transferCurrency(currency, rewards.dopplerAmount, doppler);
|
|
269
|
-
_transferCurrency(currency, rewards.protocolAmount, protocolRewardRecipient);
|
|
250
|
+
// Notes on ETH transfer fallback behavior:
|
|
251
|
+
// - If the platform referrer is immutable; if it is set to an address that cannot receive ETH, it can brick swaps on the coin, as they would revert.
|
|
252
|
+
// - Both the creator recipient and trade referral are changeable, the former via updating the payout recipient on the coin, and the latter via updating the trade referrer argument when doing a swap;
|
|
253
|
+
// therefore we do not need to worry about permanently bricking swaps, and don't need a backup recipient.
|
|
254
|
+
_transferCurrency(currency, rewards.platformReferrerAmount, platformReferrer, protocolRewardRecipient);
|
|
255
|
+
_transferCurrency(currency, rewards.tradeReferrerAmount, tradeReferral, address(0));
|
|
256
|
+
_transferCurrency(currency, rewards.creatorAmount, payoutRecipient, address(0));
|
|
257
|
+
_transferCurrency(currency, rewards.dopplerAmount, doppler, protocolRewardRecipient);
|
|
258
|
+
_transferCurrency(currency, rewards.protocolAmount, protocolRewardRecipient, address(0));
|
|
270
259
|
}
|
|
271
260
|
|
|
272
|
-
function _transferCurrency(Currency currency, uint256 amount, address to) internal {
|
|
273
|
-
if (amount == 0) {
|
|
261
|
+
function _transferCurrency(Currency currency, uint256 amount, address to, address backupRecipient) internal {
|
|
262
|
+
if (amount == 0 || to == address(0)) {
|
|
274
263
|
return;
|
|
275
264
|
}
|
|
276
265
|
|
|
277
266
|
if (currency.isAddressZero()) {
|
|
278
267
|
(bool success, ) = payable(to).call{value: amount}("");
|
|
279
268
|
if (!success) {
|
|
280
|
-
|
|
269
|
+
if (backupRecipient == address(0)) {
|
|
270
|
+
revert ICoin.EthTransferFailed();
|
|
271
|
+
} else {
|
|
272
|
+
_transferCurrency(currency, amount, backupRecipient, address(0));
|
|
273
|
+
}
|
|
281
274
|
}
|
|
282
275
|
} else {
|
|
283
276
|
IERC20(Currency.unwrap(currency)).safeTransfer(to, amount);
|
|
@@ -290,10 +283,10 @@ library CoinRewardsV4 {
|
|
|
290
283
|
}
|
|
291
284
|
|
|
292
285
|
uint256 totalAmount = uint256(fee);
|
|
293
|
-
rewards.platformReferrerAmount = hasCreateReferral ? calculateReward(totalAmount, CREATE_REFERRAL_REWARD_BPS) : 0;
|
|
294
|
-
rewards.tradeReferrerAmount = hasTradeReferral ? calculateReward(totalAmount, TRADE_REFERRAL_REWARD_BPS) : 0;
|
|
295
|
-
rewards.creatorAmount = calculateReward(totalAmount, CREATOR_REWARD_BPS);
|
|
296
|
-
rewards.dopplerAmount = calculateReward(totalAmount, DOPPLER_REWARD_BPS);
|
|
286
|
+
rewards.platformReferrerAmount = hasCreateReferral ? calculateReward(totalAmount, CoinConstants.CREATE_REFERRAL_REWARD_BPS) : 0;
|
|
287
|
+
rewards.tradeReferrerAmount = hasTradeReferral ? calculateReward(totalAmount, CoinConstants.TRADE_REFERRAL_REWARD_BPS) : 0;
|
|
288
|
+
rewards.creatorAmount = calculateReward(totalAmount, CoinConstants.CREATOR_REWARD_BPS);
|
|
289
|
+
rewards.dopplerAmount = calculateReward(totalAmount, CoinConstants.DOPPLER_REWARD_BPS);
|
|
297
290
|
rewards.protocolAmount = totalAmount - rewards.platformReferrerAmount - rewards.tradeReferrerAmount - rewards.creatorAmount - rewards.dopplerAmount;
|
|
298
291
|
}
|
|
299
292
|
|
package/src/libs/CoinSetup.sol
CHANGED
|
@@ -11,12 +11,11 @@ import {PoolConfigurationV4} from "../interfaces/ICoin.sol";
|
|
|
11
11
|
import {CoinConfigurationVersions} from "./CoinConfigurationVersions.sol";
|
|
12
12
|
import {ICoin} from "../interfaces/ICoin.sol";
|
|
13
13
|
import {CoinCommon} from "./CoinCommon.sol";
|
|
14
|
-
import {
|
|
14
|
+
import {CoinConstants} from "./CoinConstants.sol";
|
|
15
15
|
import {TickMath} from "../utils/uniswap/TickMath.sol";
|
|
16
16
|
import {IPoolManager, PoolKey, Currency, IHooks} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
|
17
17
|
import {Actions} from "@uniswap/v4-periphery/src/libraries/Actions.sol";
|
|
18
18
|
import {IPositionManager} from "@uniswap/v4-periphery/src/interfaces/IPositionManager.sol";
|
|
19
|
-
import {MarketConstants} from "./MarketConstants.sol";
|
|
20
19
|
import {LpPosition} from "../types/LpPosition.sol";
|
|
21
20
|
import {CoinDopplerMultiCurve, PoolConfiguration} from "./CoinDopplerMultiCurve.sol";
|
|
22
21
|
|
|
@@ -37,13 +36,7 @@ library CoinSetup {
|
|
|
37
36
|
Currency currency0 = isCoinToken0 ? Currency.wrap(coin) : Currency.wrap(currency);
|
|
38
37
|
Currency currency1 = isCoinToken0 ? Currency.wrap(currency) : Currency.wrap(coin);
|
|
39
38
|
|
|
40
|
-
poolKey = PoolKey({
|
|
41
|
-
currency0: currency0,
|
|
42
|
-
currency1: currency1,
|
|
43
|
-
fee: MarketConstants.LP_FEE_V4,
|
|
44
|
-
tickSpacing: MarketConstants.TICK_SPACING,
|
|
45
|
-
hooks: hooks
|
|
46
|
-
});
|
|
39
|
+
poolKey = PoolKey({currency0: currency0, currency1: currency1, fee: CoinConstants.LP_FEE_V4, tickSpacing: CoinConstants.TICK_SPACING, hooks: hooks});
|
|
47
40
|
}
|
|
48
41
|
|
|
49
42
|
function setupPoolWithVersion(
|