@zoralabs/coins 0.7.1 → 0.9.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.
- package/.env +1 -0
- package/.turbo/turbo-build.log +114 -109
- package/.turbo/turbo-update-contract-version.log +22 -0
- package/CHANGELOG.md +28 -0
- package/abis/BadImpl.json +15 -0
- package/abis/BalanceDeltaLibrary.json +15 -0
- package/abis/BaseCoin.json +1442 -0
- package/abis/BaseCoinDeployHook.json +78 -0
- package/abis/BaseHook.json +897 -0
- package/abis/BaseTest.json +13 -91
- package/abis/BeforeSwapDeltaLibrary.json +15 -0
- package/abis/BuySupplyWithSwapRouterHook.json +126 -0
- package/abis/Coin.json +48 -92
- package/abis/CoinConstants.json +65 -0
- package/abis/CoinTest.json +13 -91
- package/abis/CoinV4.json +1664 -0
- package/abis/CurrencyLibrary.json +25 -0
- package/abis/DeployHooks.json +9 -0
- package/abis/DopplerUniswapV3Test.json +13 -91
- package/abis/FactoryTest.json +13 -91
- package/abis/FakeHookNoInterface.json +21 -0
- package/abis/HookDeployer.json +68 -0
- package/abis/Hooks.json +28 -0
- package/abis/HooksTest.json +651 -0
- package/abis/IAllowanceTransfer.json +486 -0
- package/abis/ICoin.json +25 -1
- package/abis/ICoinDeployHook.json +31 -0
- package/abis/IContractMetadata.json +28 -0
- package/abis/IEIP712.json +15 -0
- package/abis/IEIP712_v4.json +15 -0
- package/abis/IERC20Minimal.json +172 -0
- package/abis/IERC6909Claims.json +288 -0
- package/abis/IERC721Permit_v4.json +88 -0
- package/abis/IExtsload.json +64 -0
- package/abis/IExttload.json +40 -0
- package/abis/IHasAfterCoinDeploy.json +31 -0
- package/abis/IHasContractName.json +15 -0
- package/abis/IHookDeployer.json +42 -0
- package/abis/IHooks.json +789 -0
- package/abis/IImmutableState.json +15 -0
- package/abis/IMulticall_v4.json +21 -0
- package/abis/INotifier.json +187 -0
- package/abis/IPermit2.json +865 -0
- package/abis/IPermit2Forwarder.json +138 -0
- package/abis/IPoolInitializer_v4.json +53 -0
- package/abis/IPoolManager.json +1286 -0
- package/abis/IPositionManager.json +712 -0
- package/abis/IProtocolFees.json +174 -0
- package/abis/ISignatureTransfer.json +394 -0
- package/abis/ISubscriber.json +89 -0
- package/abis/ISwapRouter.json +82 -0
- package/abis/IUnorderedNonce.json +44 -0
- package/abis/IV4Router.json +47 -0
- package/abis/IZoraFactory.json +144 -0
- package/abis/IZoraV4CoinHook.json +83 -0
- package/abis/ImmutableState.json +36 -0
- package/abis/LPFeeLibrary.json +65 -0
- package/abis/MultiOwnableTest.json +13 -91
- package/abis/Simulate.json +0 -91
- package/abis/UniV3BuySell.json +12 -0
- package/abis/UniV3Errors.json +32 -0
- package/abis/UpgradeFactoryImpl.json +9 -0
- package/abis/UpgradesTest.json +604 -0
- package/abis/ZoraFactoryImpl.json +111 -0
- package/abis/ZoraV4CoinHook.json +989 -0
- package/addresses/8453.json +2 -1
- package/addresses/84532.json +4 -3
- package/dist/index.cjs +125 -62
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +120 -56
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +212 -464
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/package/wagmiGenerated.ts +122 -66
- package/package.json +4 -4
- package/script/CoinsDeployerBase.sol +32 -0
- package/script/DeployHooks.s.sol +22 -0
- package/script/Simulate.s.sol +3 -2
- package/script/UpgradeCoinImpl.sol +2 -2
- package/script/UpgradeFactoryImpl.s.sol +23 -0
- package/src/Coin.sol +35 -342
- package/src/ZoraFactoryImpl.sol +73 -45
- package/src/hooks/BaseCoinDeployHook.sol +62 -0
- package/src/hooks/BuySupplyWithSwapRouterHook.sol +78 -0
- package/src/interfaces/ICoin.sol +5 -1
- package/src/interfaces/ICoinDeployHook.sol +8 -0
- package/src/interfaces/ISwapRouter.sol +1 -35
- package/src/interfaces/IZoraFactory.sol +52 -0
- package/src/{utils → libs}/CoinConstants.sol +6 -6
- package/src/libs/CoinLegacy.sol +4 -4
- package/src/libs/CoinLegacyMarket.sol +182 -0
- package/src/libs/CoinSetupV3.sol +111 -0
- package/src/libs/UniV3BuySell.sol +449 -0
- package/src/libs/UniV3Errors.sol +11 -0
- package/src/version/ContractVersionBase.sol +1 -1
- package/test/Coin.t.sol +20 -17
- package/test/CoinDopplerUniV3.t.sol +7 -17
- package/test/Factory.t.sol +4 -3
- package/test/Hooks.t.sol +274 -0
- package/test/Upgrades.t.sol +67 -0
- package/test/utils/BaseTest.sol +18 -3
- package/wagmi.config.ts +6 -9
- package/src/libs/CoinSetup.sol +0 -37
- /package/abis/{CoinSetup.json → CoinSetupV3.json} +0 -0
|
@@ -0,0 +1,449 @@
|
|
|
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 {ISwapRouter} from "../interfaces/ISwapRouter.sol";
|
|
7
|
+
import {IWETH} from "../interfaces/IWETH.sol";
|
|
8
|
+
import {MarketConstants} from "./MarketConstants.sol";
|
|
9
|
+
import {CoinConstants} from "./CoinConstants.sol";
|
|
10
|
+
import {ICoin} from "../interfaces/ICoin.sol";
|
|
11
|
+
import {IProtocolRewards} from "../interfaces/IProtocolRewards.sol";
|
|
12
|
+
import {LpPosition} from "../types/LpPosition.sol";
|
|
13
|
+
import {PoolConfiguration} from "../interfaces/ICoin.sol";
|
|
14
|
+
import {IUniswapV3Pool} from "../interfaces/IUniswapV3Pool.sol";
|
|
15
|
+
import {IAirlock} from "../interfaces/IAirlock.sol";
|
|
16
|
+
import {UniV3Config, CoinV3Config} from "./CoinSetupV3.sol";
|
|
17
|
+
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
|
|
18
|
+
import {CoinLegacyMarket} from "./CoinLegacyMarket.sol";
|
|
19
|
+
import {CoinDopplerUniV3} from "./CoinDopplerUniV3.sol";
|
|
20
|
+
import {CoinConfigurationVersions} from "./CoinConfigurationVersions.sol";
|
|
21
|
+
|
|
22
|
+
struct CoinConfig {
|
|
23
|
+
address protocolRewardRecipient;
|
|
24
|
+
address platformReferrer;
|
|
25
|
+
address currency;
|
|
26
|
+
address payoutRecipient;
|
|
27
|
+
address protocolRewards;
|
|
28
|
+
address poolAddress;
|
|
29
|
+
PoolConfiguration poolConfiguration;
|
|
30
|
+
UniV3Config uniswapV3Config;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
library UniV3BuySell {
|
|
34
|
+
using SafeERC20 for IERC20;
|
|
35
|
+
|
|
36
|
+
error AddressZero();
|
|
37
|
+
error InvalidPoolVersion();
|
|
38
|
+
|
|
39
|
+
function _handleBuy(
|
|
40
|
+
address recipient,
|
|
41
|
+
uint256 orderSize,
|
|
42
|
+
uint256 minAmountOut,
|
|
43
|
+
uint160 sqrtPriceLimitX96,
|
|
44
|
+
address tradeReferrer,
|
|
45
|
+
address coin,
|
|
46
|
+
CoinConfig memory coinConfig
|
|
47
|
+
) internal returns (uint256 amountOut, uint256 tradeReward, uint256 trueOrderSize) {
|
|
48
|
+
if (recipient == address(0)) {
|
|
49
|
+
revert AddressZero();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Calculate the trade reward
|
|
53
|
+
tradeReward = _calculateReward(orderSize, CoinConstants.TOTAL_FEE_BPS);
|
|
54
|
+
|
|
55
|
+
// Calculate the remaining size
|
|
56
|
+
trueOrderSize = orderSize - tradeReward;
|
|
57
|
+
|
|
58
|
+
// Handle incoming currency
|
|
59
|
+
_handleIncomingCurrency(orderSize, trueOrderSize, coinConfig.currency, coinConfig.uniswapV3Config.weth, coinConfig.uniswapV3Config.swapRouter);
|
|
60
|
+
|
|
61
|
+
// Set up the swap parameters
|
|
62
|
+
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
|
|
63
|
+
tokenIn: coinConfig.currency,
|
|
64
|
+
tokenOut: coin,
|
|
65
|
+
fee: MarketConstants.LP_FEE,
|
|
66
|
+
recipient: recipient,
|
|
67
|
+
amountIn: trueOrderSize,
|
|
68
|
+
amountOutMinimum: minAmountOut,
|
|
69
|
+
sqrtPriceLimitX96: sqrtPriceLimitX96
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Execute the swap
|
|
73
|
+
amountOut = ISwapRouter(coinConfig.uniswapV3Config.swapRouter).exactInputSingle(params);
|
|
74
|
+
|
|
75
|
+
_handleTradeRewards(tradeReward, tradeReferrer, coinConfig);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// @notice Executes a buy order
|
|
79
|
+
/// @param recipient The recipient address of the coins
|
|
80
|
+
/// @param orderSize The amount of coins to buy
|
|
81
|
+
/// @param tradeReferrer The address of the trade referrer
|
|
82
|
+
/// @param sqrtPriceLimitX96 The price limit for Uniswap V3 pool swap
|
|
83
|
+
function buy(
|
|
84
|
+
address recipient,
|
|
85
|
+
uint256 orderSize,
|
|
86
|
+
uint256 minAmountOut,
|
|
87
|
+
uint160 sqrtPriceLimitX96,
|
|
88
|
+
address tradeReferrer,
|
|
89
|
+
address coin,
|
|
90
|
+
CoinConfig memory coinConfig
|
|
91
|
+
) internal returns (uint256, uint256) {
|
|
92
|
+
(uint256 amountOut, uint256 tradeReward, uint256 trueOrderSize) = _handleBuy(
|
|
93
|
+
recipient,
|
|
94
|
+
orderSize,
|
|
95
|
+
minAmountOut,
|
|
96
|
+
sqrtPriceLimitX96,
|
|
97
|
+
tradeReferrer,
|
|
98
|
+
coin,
|
|
99
|
+
coinConfig
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
handleMarketRewards(coin, coinConfig);
|
|
103
|
+
|
|
104
|
+
emit ICoin.CoinBuy(msg.sender, recipient, tradeReferrer, amountOut, coinConfig.currency, tradeReward, trueOrderSize);
|
|
105
|
+
|
|
106
|
+
return (orderSize, amountOut);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function _handleSell(
|
|
110
|
+
address recipient,
|
|
111
|
+
uint256 beforeCoinBalance,
|
|
112
|
+
uint256 orderSize,
|
|
113
|
+
uint256 minAmountOut,
|
|
114
|
+
uint160 sqrtPriceLimitX96,
|
|
115
|
+
address tradeReferrer,
|
|
116
|
+
CoinConfig memory coinConfig
|
|
117
|
+
) internal returns (uint256 payoutSize, uint256 tradeReward, uint256 trueOrderSize) {
|
|
118
|
+
// Ensure the recipient is not the zero address
|
|
119
|
+
if (recipient == address(0)) {
|
|
120
|
+
revert AddressZero();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Set the swap parameters
|
|
124
|
+
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
|
|
125
|
+
tokenIn: address(this),
|
|
126
|
+
tokenOut: coinConfig.currency,
|
|
127
|
+
fee: MarketConstants.LP_FEE,
|
|
128
|
+
recipient: address(this),
|
|
129
|
+
amountIn: orderSize,
|
|
130
|
+
amountOutMinimum: minAmountOut,
|
|
131
|
+
sqrtPriceLimitX96: sqrtPriceLimitX96
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Execute the swap
|
|
135
|
+
uint256 amountOut = ISwapRouter(coinConfig.uniswapV3Config.swapRouter).exactInputSingle(params);
|
|
136
|
+
|
|
137
|
+
// Record the coin balance of this contract after the swap
|
|
138
|
+
uint256 afterCoinBalance = IERC20(address(this)).balanceOf(address(this));
|
|
139
|
+
|
|
140
|
+
trueOrderSize = orderSize;
|
|
141
|
+
|
|
142
|
+
// If the swap was partially executed:
|
|
143
|
+
if (afterCoinBalance > beforeCoinBalance) {
|
|
144
|
+
// Calculate the refund
|
|
145
|
+
uint256 coinRefund = afterCoinBalance - beforeCoinBalance;
|
|
146
|
+
|
|
147
|
+
// Update the order size
|
|
148
|
+
trueOrderSize -= coinRefund;
|
|
149
|
+
|
|
150
|
+
// Transfer the refund back to the seller
|
|
151
|
+
IERC20(address(this)).safeTransfer(recipient, coinRefund);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// If currency is WETH, convert to ETH
|
|
155
|
+
if (coinConfig.currency == coinConfig.uniswapV3Config.weth) {
|
|
156
|
+
IWETH(coinConfig.uniswapV3Config.weth).withdraw(amountOut);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Calculate the trade reward
|
|
160
|
+
tradeReward = _calculateReward(amountOut, CoinConstants.TOTAL_FEE_BPS);
|
|
161
|
+
|
|
162
|
+
// Calculate the payout after the fee
|
|
163
|
+
payoutSize = amountOut - tradeReward;
|
|
164
|
+
|
|
165
|
+
_handlePayout(payoutSize, recipient, coinConfig.currency, coinConfig.uniswapV3Config.weth);
|
|
166
|
+
|
|
167
|
+
_handleTradeRewards(tradeReward, tradeReferrer, coinConfig);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/// @notice Executes a sell order
|
|
171
|
+
/// @param recipient The recipient of the currency
|
|
172
|
+
/// @param _orderSize The amount of coins to sell
|
|
173
|
+
/// @param minAmountOut The minimum amount of currency to receive
|
|
174
|
+
/// @param sqrtPriceLimitX96 The price limit for the swap
|
|
175
|
+
/// @param tradeReferrer The address of the trade referrer
|
|
176
|
+
function sell(
|
|
177
|
+
address recipient,
|
|
178
|
+
uint256 beforeCoinBalance,
|
|
179
|
+
uint256 _orderSize,
|
|
180
|
+
uint256 minAmountOut,
|
|
181
|
+
uint160 sqrtPriceLimitX96,
|
|
182
|
+
address tradeReferrer,
|
|
183
|
+
CoinConfig memory coinConfig
|
|
184
|
+
) internal returns (uint256 trueOrderSize, uint256 payoutSize) {
|
|
185
|
+
uint256 tradeReward;
|
|
186
|
+
(payoutSize, tradeReward, trueOrderSize) = _handleSell(
|
|
187
|
+
recipient,
|
|
188
|
+
beforeCoinBalance,
|
|
189
|
+
_orderSize,
|
|
190
|
+
minAmountOut,
|
|
191
|
+
sqrtPriceLimitX96,
|
|
192
|
+
tradeReferrer,
|
|
193
|
+
coinConfig
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
handleMarketRewards(address(this), coinConfig);
|
|
197
|
+
|
|
198
|
+
emit ICoin.CoinSell(msg.sender, recipient, tradeReferrer, trueOrderSize, coinConfig.currency, tradeReward, payoutSize);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/// @dev Handles incoming currency transfers for buy orders; if WETH is the currency the caller has the option to send native-ETH
|
|
202
|
+
/// @param orderSize The total size of the order in the currency
|
|
203
|
+
/// @param trueOrderSize The actual amount being used for the swap after fees
|
|
204
|
+
function _handleIncomingCurrency(uint256 orderSize, uint256 trueOrderSize, address currency, address weth, address swapRouter) internal {
|
|
205
|
+
if (currency == weth && msg.value > 0) {
|
|
206
|
+
if (msg.value != orderSize) {
|
|
207
|
+
revert ICoin.EthAmountMismatch();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (msg.value < CoinConstants.MIN_ORDER_SIZE) {
|
|
211
|
+
revert ICoin.EthAmountTooSmall();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
IWETH(weth).deposit{value: trueOrderSize}();
|
|
215
|
+
IWETH(weth).approve(swapRouter, trueOrderSize);
|
|
216
|
+
} else {
|
|
217
|
+
// Ensure ETH is not sent with a non-ETH pair
|
|
218
|
+
if (msg.value != 0) {
|
|
219
|
+
revert ICoin.EthTransferInvalid();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
uint256 beforeBalance = IERC20(currency).balanceOf(address(this));
|
|
223
|
+
IERC20(currency).safeTransferFrom(msg.sender, address(this), orderSize);
|
|
224
|
+
uint256 afterBalance = IERC20(currency).balanceOf(address(this));
|
|
225
|
+
|
|
226
|
+
if ((afterBalance - beforeBalance) != orderSize) {
|
|
227
|
+
revert ICoin.ERC20TransferAmountMismatch();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
IERC20(currency).approve(swapRouter, trueOrderSize);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/// @dev Handles sending ETH and ERC20 payouts and refunds to recipients
|
|
235
|
+
/// @param orderPayout The amount of currency to pay out
|
|
236
|
+
/// @param recipient The address to receive the payout
|
|
237
|
+
function _handlePayout(uint256 orderPayout, address recipient, address currency, address weth) internal {
|
|
238
|
+
if (currency == weth) {
|
|
239
|
+
Address.sendValue(payable(recipient), orderPayout);
|
|
240
|
+
} else {
|
|
241
|
+
IERC20(currency).safeTransfer(recipient, orderPayout);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/// @dev Handles calculating and depositing fees to an escrow protocol rewards contract
|
|
246
|
+
function _handleTradeRewards(uint256 totalValue, address _tradeReferrer, CoinConfig memory coinConfig) internal {
|
|
247
|
+
address protocolRewardRecipient = coinConfig.protocolRewardRecipient;
|
|
248
|
+
address platformReferrer = coinConfig.platformReferrer;
|
|
249
|
+
address currency = coinConfig.currency;
|
|
250
|
+
address weth = coinConfig.uniswapV3Config.weth;
|
|
251
|
+
address payoutRecipient = coinConfig.payoutRecipient;
|
|
252
|
+
IProtocolRewards protocolRewards = IProtocolRewards(coinConfig.protocolRewards);
|
|
253
|
+
|
|
254
|
+
if (_tradeReferrer == address(0)) {
|
|
255
|
+
_tradeReferrer = protocolRewardRecipient;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
uint256 tokenCreatorFee = _calculateReward(totalValue, CoinConstants.TOKEN_CREATOR_FEE_BPS);
|
|
259
|
+
uint256 platformReferrerFee = _calculateReward(totalValue, CoinConstants.PLATFORM_REFERRER_FEE_BPS);
|
|
260
|
+
uint256 tradeReferrerFee = _calculateReward(totalValue, CoinConstants.TRADE_REFERRER_FEE_BPS);
|
|
261
|
+
uint256 protocolFee = totalValue - tokenCreatorFee - platformReferrerFee - tradeReferrerFee;
|
|
262
|
+
|
|
263
|
+
if (currency == weth) {
|
|
264
|
+
address[] memory recipients = new address[](4);
|
|
265
|
+
uint256[] memory amounts = new uint256[](4);
|
|
266
|
+
bytes4[] memory reasons = new bytes4[](4);
|
|
267
|
+
|
|
268
|
+
recipients[0] = payoutRecipient;
|
|
269
|
+
amounts[0] = tokenCreatorFee;
|
|
270
|
+
reasons[0] = bytes4(keccak256("COIN_CREATOR_REWARD"));
|
|
271
|
+
|
|
272
|
+
recipients[1] = platformReferrer;
|
|
273
|
+
amounts[1] = platformReferrerFee;
|
|
274
|
+
reasons[1] = bytes4(keccak256("COIN_PLATFORM_REFERRER_REWARD"));
|
|
275
|
+
|
|
276
|
+
recipients[2] = _tradeReferrer;
|
|
277
|
+
amounts[2] = tradeReferrerFee;
|
|
278
|
+
reasons[2] = bytes4(keccak256("COIN_TRADE_REFERRER_REWARD"));
|
|
279
|
+
|
|
280
|
+
recipients[3] = protocolRewardRecipient;
|
|
281
|
+
amounts[3] = protocolFee;
|
|
282
|
+
reasons[3] = bytes4(keccak256("COIN_PROTOCOL_REWARD"));
|
|
283
|
+
|
|
284
|
+
IProtocolRewards(protocolRewards).depositBatch{value: totalValue}(recipients, amounts, reasons, "");
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (currency != weth) {
|
|
288
|
+
IERC20(currency).safeTransfer(payoutRecipient, tokenCreatorFee);
|
|
289
|
+
IERC20(currency).safeTransfer(platformReferrer, platformReferrerFee);
|
|
290
|
+
IERC20(currency).safeTransfer(_tradeReferrer, tradeReferrerFee);
|
|
291
|
+
IERC20(currency).safeTransfer(protocolRewardRecipient, protocolFee);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
emit ICoin.CoinTradeRewards(
|
|
295
|
+
payoutRecipient,
|
|
296
|
+
platformReferrer,
|
|
297
|
+
_tradeReferrer,
|
|
298
|
+
protocolRewardRecipient,
|
|
299
|
+
tokenCreatorFee,
|
|
300
|
+
platformReferrerFee,
|
|
301
|
+
tradeReferrerFee,
|
|
302
|
+
protocolFee,
|
|
303
|
+
currency
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function _distributeMarketRewards(
|
|
308
|
+
LpPosition[] memory positions,
|
|
309
|
+
address poolAddress,
|
|
310
|
+
address currency,
|
|
311
|
+
address coin,
|
|
312
|
+
CoinConfig memory coinConfig
|
|
313
|
+
) internal returns (ICoin.MarketRewards memory) {
|
|
314
|
+
uint256 totalAmountToken0;
|
|
315
|
+
uint256 totalAmountToken1;
|
|
316
|
+
uint256 amount0;
|
|
317
|
+
uint256 amount1;
|
|
318
|
+
|
|
319
|
+
for (uint256 i; i < positions.length; i++) {
|
|
320
|
+
// Must burn to update the collect mapping on the pool
|
|
321
|
+
IUniswapV3Pool(poolAddress).burn(positions[i].tickLower, positions[i].tickUpper, 0);
|
|
322
|
+
|
|
323
|
+
(amount0, amount1) = IUniswapV3Pool(poolAddress).collect(
|
|
324
|
+
address(this),
|
|
325
|
+
positions[i].tickLower,
|
|
326
|
+
positions[i].tickUpper,
|
|
327
|
+
type(uint128).max,
|
|
328
|
+
type(uint128).max
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
totalAmountToken0 += amount0;
|
|
332
|
+
totalAmountToken1 += amount1;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
address token0 = currency < address(this) ? currency : address(this);
|
|
336
|
+
address token1 = currency < address(this) ? address(this) : currency;
|
|
337
|
+
|
|
338
|
+
ICoin.MarketRewards memory rewards;
|
|
339
|
+
|
|
340
|
+
rewards = _transferMarketRewards(token0, totalAmountToken0, rewards, coin, coinConfig);
|
|
341
|
+
rewards = _transferMarketRewards(token1, totalAmountToken1, rewards, coin, coinConfig);
|
|
342
|
+
|
|
343
|
+
emit ICoin.CoinMarketRewards(coinConfig.payoutRecipient, coinConfig.platformReferrer, coinConfig.protocolRewardRecipient, coinConfig.currency, rewards);
|
|
344
|
+
|
|
345
|
+
return rewards;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/// @dev Collects and distributes accrued fees from all LP positions
|
|
349
|
+
function handleMarketRewards(address coin, CoinConfig memory coinConfig) internal returns (ICoin.MarketRewards memory) {
|
|
350
|
+
address poolAddress = coinConfig.poolAddress;
|
|
351
|
+
address currency = coinConfig.currency;
|
|
352
|
+
|
|
353
|
+
bool isCoinToken0 = coin < currency;
|
|
354
|
+
LpPosition[] memory positions = calculatePositions(isCoinToken0, coinConfig.poolConfiguration);
|
|
355
|
+
|
|
356
|
+
return _distributeMarketRewards(positions, poolAddress, currency, coin, coinConfig);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function _transferMarketRewards(
|
|
360
|
+
address token,
|
|
361
|
+
uint256 totalAmount,
|
|
362
|
+
ICoin.MarketRewards memory rewards,
|
|
363
|
+
address coin,
|
|
364
|
+
CoinConfig memory coinConfig
|
|
365
|
+
) internal returns (ICoin.MarketRewards memory) {
|
|
366
|
+
address payoutRecipient = coinConfig.payoutRecipient;
|
|
367
|
+
address platformReferrer = coinConfig.platformReferrer;
|
|
368
|
+
address protocolRewardRecipient = coinConfig.protocolRewardRecipient;
|
|
369
|
+
address currency = coinConfig.currency;
|
|
370
|
+
address weth = coinConfig.uniswapV3Config.weth;
|
|
371
|
+
address airlock = coinConfig.uniswapV3Config.airlock;
|
|
372
|
+
address protocolRewards = coinConfig.protocolRewards;
|
|
373
|
+
|
|
374
|
+
if (totalAmount > 0) {
|
|
375
|
+
address dopplerRecipient = IAirlock(airlock).owner();
|
|
376
|
+
uint256 dopplerPayout = _calculateReward(totalAmount, CoinConstants.DOPPLER_MARKET_REWARD_BPS);
|
|
377
|
+
uint256 creatorPayout = _calculateReward(totalAmount, CoinConstants.CREATOR_MARKET_REWARD_BPS);
|
|
378
|
+
uint256 platformReferrerPayout = _calculateReward(totalAmount, CoinConstants.PLATFORM_REFERRER_MARKET_REWARD_BPS);
|
|
379
|
+
uint256 protocolPayout = totalAmount - creatorPayout - platformReferrerPayout - dopplerPayout;
|
|
380
|
+
|
|
381
|
+
if (token == weth) {
|
|
382
|
+
IWETH(weth).withdraw(totalAmount);
|
|
383
|
+
|
|
384
|
+
rewards.totalAmountCurrency = totalAmount;
|
|
385
|
+
rewards.creatorPayoutAmountCurrency = creatorPayout;
|
|
386
|
+
rewards.platformReferrerAmountCurrency = platformReferrerPayout;
|
|
387
|
+
rewards.protocolAmountCurrency = protocolPayout;
|
|
388
|
+
|
|
389
|
+
address[] memory recipients = new address[](4);
|
|
390
|
+
recipients[0] = payoutRecipient;
|
|
391
|
+
recipients[1] = platformReferrer;
|
|
392
|
+
recipients[2] = protocolRewardRecipient;
|
|
393
|
+
recipients[3] = dopplerRecipient;
|
|
394
|
+
|
|
395
|
+
uint256[] memory amounts = new uint256[](4);
|
|
396
|
+
amounts[0] = rewards.creatorPayoutAmountCurrency;
|
|
397
|
+
amounts[1] = rewards.platformReferrerAmountCurrency;
|
|
398
|
+
amounts[2] = rewards.protocolAmountCurrency;
|
|
399
|
+
amounts[3] = dopplerPayout;
|
|
400
|
+
|
|
401
|
+
bytes4[] memory reasons = new bytes4[](4);
|
|
402
|
+
reasons[0] = bytes4(keccak256("COIN_CREATOR_MARKET_REWARD"));
|
|
403
|
+
reasons[1] = bytes4(keccak256("COIN_PLATFORM_REFERRER_MARKET_REWARD"));
|
|
404
|
+
reasons[2] = bytes4(keccak256("COIN_PROTOCOL_MARKET_REWARD"));
|
|
405
|
+
reasons[3] = bytes4(keccak256("COIN_DOPPLER_MARKET_REWARD"));
|
|
406
|
+
|
|
407
|
+
IProtocolRewards(protocolRewards).depositBatch{value: totalAmount}(recipients, amounts, reasons, "");
|
|
408
|
+
IProtocolRewards(protocolRewards).withdrawFor(dopplerRecipient, dopplerPayout);
|
|
409
|
+
} else if (token == coin) {
|
|
410
|
+
rewards.totalAmountCoin = totalAmount;
|
|
411
|
+
rewards.creatorPayoutAmountCoin = creatorPayout;
|
|
412
|
+
rewards.platformReferrerAmountCoin = platformReferrerPayout;
|
|
413
|
+
rewards.protocolAmountCoin = protocolPayout;
|
|
414
|
+
|
|
415
|
+
IERC20(coin).safeTransfer(payoutRecipient, rewards.creatorPayoutAmountCoin);
|
|
416
|
+
IERC20(coin).safeTransfer(platformReferrer, rewards.platformReferrerAmountCoin);
|
|
417
|
+
IERC20(coin).safeTransfer(protocolRewardRecipient, rewards.protocolAmountCoin);
|
|
418
|
+
IERC20(coin).safeTransfer(dopplerRecipient, dopplerPayout);
|
|
419
|
+
} else {
|
|
420
|
+
rewards.totalAmountCurrency = totalAmount;
|
|
421
|
+
rewards.creatorPayoutAmountCurrency = creatorPayout;
|
|
422
|
+
rewards.platformReferrerAmountCurrency = platformReferrerPayout;
|
|
423
|
+
rewards.protocolAmountCurrency = protocolPayout;
|
|
424
|
+
|
|
425
|
+
IERC20(currency).safeTransfer(payoutRecipient, creatorPayout);
|
|
426
|
+
IERC20(currency).safeTransfer(platformReferrer, platformReferrerPayout);
|
|
427
|
+
IERC20(currency).safeTransfer(protocolRewardRecipient, protocolPayout);
|
|
428
|
+
IERC20(currency).safeTransfer(dopplerRecipient, dopplerPayout);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return rewards;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/// @dev Utility for computing amounts in basis points.
|
|
436
|
+
function _calculateReward(uint256 amount, uint256 bps) internal pure returns (uint256) {
|
|
437
|
+
return (amount * bps) / 10_000;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function calculatePositions(bool isCoinToken0, PoolConfiguration memory poolConfiguration) internal pure returns (LpPosition[] memory positions) {
|
|
441
|
+
if (poolConfiguration.version == CoinConfigurationVersions.LEGACY_POOL_VERSION) {
|
|
442
|
+
positions = CoinLegacyMarket.calculatePositions(isCoinToken0, poolConfiguration);
|
|
443
|
+
} else if (poolConfiguration.version == CoinConfigurationVersions.DOPPLER_UNI_V3_POOL_VERSION) {
|
|
444
|
+
positions = CoinDopplerUniV3.calculatePositions(isCoinToken0, poolConfiguration);
|
|
445
|
+
} else {
|
|
446
|
+
revert InvalidPoolVersion();
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.23;
|
|
3
|
+
|
|
4
|
+
library UniV3Errors {
|
|
5
|
+
error InvalidPoolAddress();
|
|
6
|
+
error InvalidCurrency();
|
|
7
|
+
error InvalidWeth();
|
|
8
|
+
error InvalidTickLower();
|
|
9
|
+
error InvalidTickUpper();
|
|
10
|
+
error InvalidUniswapV3Factory();
|
|
11
|
+
}
|
|
@@ -9,6 +9,6 @@ import {IVersionedContract} from "@zoralabs/shared-contracts/interfaces/IVersion
|
|
|
9
9
|
contract ContractVersionBase is IVersionedContract {
|
|
10
10
|
/// @notice The version of the contract
|
|
11
11
|
function contractVersion() external pure override returns (string memory) {
|
|
12
|
-
return "0.
|
|
12
|
+
return "0.9.0";
|
|
13
13
|
}
|
|
14
14
|
}
|
package/test/Coin.t.sol
CHANGED
|
@@ -4,6 +4,7 @@ pragma solidity ^0.8.13;
|
|
|
4
4
|
import "./utils/BaseTest.sol";
|
|
5
5
|
import {ISwapRouter} from "../src/interfaces/ISwapRouter.sol";
|
|
6
6
|
import {CoinConfigurationVersions} from "../src/libs/CoinConfigurationVersions.sol";
|
|
7
|
+
import {CoinConstants} from "../src/libs/CoinConstants.sol";
|
|
7
8
|
|
|
8
9
|
contract CoinTest is BaseTest {
|
|
9
10
|
function setUp() public override {
|
|
@@ -13,19 +14,19 @@ contract CoinTest is BaseTest {
|
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
function test_contract_version() public view {
|
|
16
|
-
assertEq(coin.contractVersion(), "0.
|
|
17
|
+
assertEq(coin.contractVersion(), "0.8.0");
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
function test_supply_constants() public view {
|
|
20
|
-
assertEq(MAX_TOTAL_SUPPLY, POOL_LAUNCH_SUPPLY + CREATOR_LAUNCH_REWARD);
|
|
21
|
+
assertEq(CoinConstants.MAX_TOTAL_SUPPLY, CoinConstants.POOL_LAUNCH_SUPPLY + CoinConstants.CREATOR_LAUNCH_REWARD);
|
|
21
22
|
|
|
22
|
-
assertEq(MAX_TOTAL_SUPPLY, 1_000_000_000e18);
|
|
23
|
-
assertEq(POOL_LAUNCH_SUPPLY, 990_000_000e18);
|
|
24
|
-
assertEq(CREATOR_LAUNCH_REWARD, 10_000_000e18);
|
|
23
|
+
assertEq(CoinConstants.MAX_TOTAL_SUPPLY, 1_000_000_000e18);
|
|
24
|
+
assertEq(CoinConstants.POOL_LAUNCH_SUPPLY, 990_000_000e18);
|
|
25
|
+
assertEq(CoinConstants.CREATOR_LAUNCH_REWARD, 10_000_000e18);
|
|
25
26
|
|
|
26
|
-
assertEq(coin.totalSupply(), MAX_TOTAL_SUPPLY);
|
|
27
|
-
assertEq(coin.balanceOf(coin.payoutRecipient()), CREATOR_LAUNCH_REWARD);
|
|
28
|
-
assertApproxEqAbs(coin.balanceOf(address(pool)), POOL_LAUNCH_SUPPLY, 1e18);
|
|
27
|
+
assertEq(coin.totalSupply(), CoinConstants.MAX_TOTAL_SUPPLY);
|
|
28
|
+
assertEq(coin.balanceOf(coin.payoutRecipient()), CoinConstants.CREATOR_LAUNCH_REWARD);
|
|
29
|
+
assertApproxEqAbs(coin.balanceOf(address(pool)), CoinConstants.POOL_LAUNCH_SUPPLY, 1e18);
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
function test_constructor_validation() public {
|
|
@@ -162,7 +163,7 @@ contract CoinTest is BaseTest {
|
|
|
162
163
|
}
|
|
163
164
|
|
|
164
165
|
function test_buy_with_eth_fuzz(uint256 ethOrderSize) public {
|
|
165
|
-
vm.assume(ethOrderSize >= MIN_ORDER_SIZE);
|
|
166
|
+
vm.assume(ethOrderSize >= CoinConstants.MIN_ORDER_SIZE);
|
|
166
167
|
vm.assume(ethOrderSize < 10 ether);
|
|
167
168
|
|
|
168
169
|
uint256 platformReferrerBalanceBeforeSale = users.platformReferrer.balance;
|
|
@@ -183,11 +184,11 @@ contract CoinTest is BaseTest {
|
|
|
183
184
|
|
|
184
185
|
function test_buy_with_eth_too_small() public {
|
|
185
186
|
vm.expectRevert(abi.encodeWithSelector(ICoin.EthAmountTooSmall.selector));
|
|
186
|
-
coin.buy{value: MIN_ORDER_SIZE - 1}(users.coinRecipient, MIN_ORDER_SIZE - 1, 0, 0, users.tradeReferrer);
|
|
187
|
+
coin.buy{value: CoinConstants.MIN_ORDER_SIZE - 1}(users.coinRecipient, CoinConstants.MIN_ORDER_SIZE - 1, 0, 0, users.tradeReferrer);
|
|
187
188
|
}
|
|
188
189
|
|
|
189
190
|
function test_buy_with_minimum_eth() public {
|
|
190
|
-
uint256 minEth = MIN_ORDER_SIZE;
|
|
191
|
+
uint256 minEth = CoinConstants.MIN_ORDER_SIZE;
|
|
191
192
|
vm.deal(users.buyer, minEth);
|
|
192
193
|
vm.prank(users.buyer);
|
|
193
194
|
coin.buy{value: minEth}(users.coinRecipient, minEth, 0, 0, users.tradeReferrer);
|
|
@@ -236,7 +237,7 @@ contract CoinTest is BaseTest {
|
|
|
236
237
|
}
|
|
237
238
|
|
|
238
239
|
function test_buy_validate_return_amounts(uint256 orderSize) public {
|
|
239
|
-
vm.assume(orderSize >= MIN_ORDER_SIZE);
|
|
240
|
+
vm.assume(orderSize >= CoinConstants.MIN_ORDER_SIZE);
|
|
240
241
|
vm.assume(orderSize < 10 ether);
|
|
241
242
|
|
|
242
243
|
vm.deal(users.buyer, orderSize);
|
|
@@ -341,7 +342,7 @@ contract CoinTest is BaseTest {
|
|
|
341
342
|
|
|
342
343
|
function test_sell_for_eth_fuzz(uint256 ethOrderSize) public {
|
|
343
344
|
vm.assume(ethOrderSize < 10 ether);
|
|
344
|
-
vm.assume(ethOrderSize >= MIN_ORDER_SIZE);
|
|
345
|
+
vm.assume(ethOrderSize >= CoinConstants.MIN_ORDER_SIZE);
|
|
345
346
|
|
|
346
347
|
vm.deal(users.buyer, ethOrderSize);
|
|
347
348
|
vm.prank(users.buyer);
|
|
@@ -411,14 +412,14 @@ contract CoinTest is BaseTest {
|
|
|
411
412
|
coin.buy{value: 0.001 ether}(users.creator, 0.001 ether, 0, 0, users.tradeReferrer);
|
|
412
413
|
|
|
413
414
|
uint256 beforeBalance = coin.balanceOf(users.creator);
|
|
414
|
-
assertEq(beforeBalance, 11077349369032224007213331); // 11,077,349 coins
|
|
415
|
+
assertEq(beforeBalance, 11077349369032224007213331, "before balance"); // 11,077,349 coins
|
|
415
416
|
|
|
416
417
|
vm.prank(users.creator);
|
|
417
418
|
(uint256 amountSold, ) = coin.sell(users.creator, beforeBalance, 0, 0, users.tradeReferrer);
|
|
418
|
-
assertEq(amountSold, 1088231685891135360821548); // 1,088,232 coins (max that could be sold)
|
|
419
|
+
assertEq(amountSold, 1088231685891135360821548, "amountSold"); // 1,088,232 coins (max that could be sold)
|
|
419
420
|
|
|
420
421
|
uint256 afterBalance = coin.balanceOf(users.creator);
|
|
421
|
-
assertEq(afterBalance, 9994558841570544323195890); // 9,994,559 coins
|
|
422
|
+
assertEq(afterBalance, 9994558841570544323195890, "after balance"); // 9,994,559 coins
|
|
422
423
|
|
|
423
424
|
uint256 expectedMarketReward = 5441158429455676804107; // 5,441 coins
|
|
424
425
|
|
|
@@ -512,7 +513,9 @@ contract CoinTest is BaseTest {
|
|
|
512
513
|
function test_eth_transfer_fail() public {
|
|
513
514
|
vm.deal(users.buyer, 1 ether);
|
|
514
515
|
vm.prank(users.buyer);
|
|
515
|
-
coin.buy{value: 1 ether}(users.coinRecipient, 1 ether, 0, 0, users.tradeReferrer);
|
|
516
|
+
(, uint256 amountOut) = coin.buy{value: 1 ether}(users.coinRecipient, 1 ether, 0, 0, users.tradeReferrer);
|
|
517
|
+
|
|
518
|
+
assertEq(coin.balanceOf(users.coinRecipient), amountOut);
|
|
516
519
|
|
|
517
520
|
// Recipient reverts on ETH receive
|
|
518
521
|
address payable badRecipient = payable(makeAddr("badRecipient"));
|
|
@@ -5,6 +5,7 @@ import {CoinConfigurationVersions} from "../src/libs/CoinConfigurationVersions.s
|
|
|
5
5
|
import {MarketConstants} from "../src/libs/MarketConstants.sol";
|
|
6
6
|
import {BaseTest} from "./utils/BaseTest.sol";
|
|
7
7
|
import {Coin} from "../src/Coin.sol";
|
|
8
|
+
import {CoinConstants} from "../src/libs/CoinConstants.sol";
|
|
8
9
|
import {IUniswapV3Pool} from "../src/interfaces/IUniswapV3Pool.sol";
|
|
9
10
|
import {LpPosition} from "../src/types/LpPosition.sol";
|
|
10
11
|
import {IDopplerErrors} from "../src/interfaces/IDopplerErrors.sol";
|
|
@@ -17,17 +18,6 @@ contract DopplerUniswapV3Test is BaseTest {
|
|
|
17
18
|
uint16 internal constant DEFAULT_NUM_DISCOVERY_POSITIONS = 10; // will be 11 total with tail position
|
|
18
19
|
uint256 internal constant DEFAULT_DISCOVERY_SUPPLY_SHARE = 0.495e18; // half of the 990m total pool supply
|
|
19
20
|
|
|
20
|
-
function _generatePoolConfig(
|
|
21
|
-
uint8 version_,
|
|
22
|
-
address currency_,
|
|
23
|
-
int24 tickLower_,
|
|
24
|
-
int24 tickUpper_,
|
|
25
|
-
uint16 numDiscoveryPositions_,
|
|
26
|
-
uint256 maxDiscoverySupplyShare_
|
|
27
|
-
) internal pure returns (bytes memory) {
|
|
28
|
-
return abi.encode(version_, currency_, tickLower_, tickUpper_, numDiscoveryPositions_, maxDiscoverySupplyShare_);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
21
|
function _deployCoin(bytes memory poolConfig_) internal {
|
|
32
22
|
vm.prank(users.creator);
|
|
33
23
|
(address coinAddress, ) = factory.deploy(
|
|
@@ -87,7 +77,7 @@ contract DopplerUniswapV3Test is BaseTest {
|
|
|
87
77
|
assertTrue(isInitialized);
|
|
88
78
|
assertFalse(isExited);
|
|
89
79
|
assertEq(maxShareToBeSold, 0);
|
|
90
|
-
assertEq(totalTokensOnBondingCurve, POOL_LAUNCH_SUPPLY);
|
|
80
|
+
assertEq(totalTokensOnBondingCurve, CoinConstants.POOL_LAUNCH_SUPPLY);
|
|
91
81
|
|
|
92
82
|
bool isCoinToken0 = address(coin) < address(weth);
|
|
93
83
|
|
|
@@ -116,7 +106,7 @@ contract DopplerUniswapV3Test is BaseTest {
|
|
|
116
106
|
}
|
|
117
107
|
|
|
118
108
|
function test_deploy_legacy_eth_config_with_prebuy(uint256 initialOrderSize) public {
|
|
119
|
-
vm.assume(initialOrderSize > MIN_ORDER_SIZE);
|
|
109
|
+
vm.assume(initialOrderSize > CoinConstants.MIN_ORDER_SIZE);
|
|
120
110
|
vm.assume(initialOrderSize < 10 ether);
|
|
121
111
|
|
|
122
112
|
vm.deal(users.creator, initialOrderSize);
|
|
@@ -176,7 +166,7 @@ contract DopplerUniswapV3Test is BaseTest {
|
|
|
176
166
|
vm.label(address(pool), "POOL");
|
|
177
167
|
|
|
178
168
|
assertEq(coin.currency(), address(usdc), "currency");
|
|
179
|
-
assertEq(coin.balanceOf(users.creator), CREATOR_LAUNCH_REWARD + coinsPurchased);
|
|
169
|
+
assertEq(coin.balanceOf(users.creator), CoinConstants.CREATOR_LAUNCH_REWARD + coinsPurchased);
|
|
180
170
|
}
|
|
181
171
|
|
|
182
172
|
function test_deploy_doppler_eth() public {
|
|
@@ -209,11 +199,11 @@ contract DopplerUniswapV3Test is BaseTest {
|
|
|
209
199
|
assertTrue(isInitialized, "poolState.isInitialized");
|
|
210
200
|
assertFalse(isExited, "poolState.isExited");
|
|
211
201
|
assertEq(maxShareToBeSold, DEFAULT_DISCOVERY_SUPPLY_SHARE, "poolState.maxShareToBeSold");
|
|
212
|
-
assertEq(totalTokensOnBondingCurve, POOL_LAUNCH_SUPPLY, "poolState.totalTokensOnBondingCurve");
|
|
202
|
+
assertEq(totalTokensOnBondingCurve, CoinConstants.POOL_LAUNCH_SUPPLY, "poolState.totalTokensOnBondingCurve");
|
|
213
203
|
}
|
|
214
204
|
|
|
215
205
|
function test_deploy_doppler_eth_with_prebuy(uint256 initialOrderSize) public {
|
|
216
|
-
vm.assume(initialOrderSize > MIN_ORDER_SIZE);
|
|
206
|
+
vm.assume(initialOrderSize > CoinConstants.MIN_ORDER_SIZE);
|
|
217
207
|
vm.assume(initialOrderSize < 1 ether);
|
|
218
208
|
|
|
219
209
|
vm.deal(users.creator, initialOrderSize);
|
|
@@ -244,7 +234,7 @@ contract DopplerUniswapV3Test is BaseTest {
|
|
|
244
234
|
|
|
245
235
|
assertEq(coin.currency(), address(weth), "currency");
|
|
246
236
|
assertGt(coinsPurchased, 0, "coinsPurchased > 0");
|
|
247
|
-
assertEq(coin.balanceOf(users.creator), CREATOR_LAUNCH_REWARD + coinsPurchased, "balanceOf creator");
|
|
237
|
+
assertEq(coin.balanceOf(users.creator), CoinConstants.CREATOR_LAUNCH_REWARD + coinsPurchased, "balanceOf creator");
|
|
248
238
|
assertGt(weth.balanceOf(address(pool)), 0, "Pool WETH balance");
|
|
249
239
|
}
|
|
250
240
|
|
package/test/Factory.t.sol
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
pragma solidity ^0.8.13;
|
|
3
3
|
|
|
4
4
|
import "./utils/BaseTest.sol";
|
|
5
|
+
import {CoinConstants} from "../src/libs/CoinConstants.sol";
|
|
5
6
|
|
|
6
7
|
contract FactoryTest is BaseTest {
|
|
7
8
|
function setUp() public override {
|
|
@@ -58,7 +59,7 @@ contract FactoryTest is BaseTest {
|
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
function test_deploy_with_eth(uint256 initialOrderSize) public {
|
|
61
|
-
vm.assume(initialOrderSize > MIN_ORDER_SIZE);
|
|
62
|
+
vm.assume(initialOrderSize > CoinConstants.MIN_ORDER_SIZE);
|
|
62
63
|
vm.assume(initialOrderSize < 10 ether);
|
|
63
64
|
|
|
64
65
|
address[] memory owners = new address[](1);
|
|
@@ -97,7 +98,7 @@ contract FactoryTest is BaseTest {
|
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
function test_deploy_with_weth(uint256 initialOrderSize) public {
|
|
100
|
-
vm.assume(initialOrderSize > MIN_ORDER_SIZE);
|
|
101
|
+
vm.assume(initialOrderSize > CoinConstants.MIN_ORDER_SIZE);
|
|
101
102
|
vm.assume(initialOrderSize < 10 ether);
|
|
102
103
|
|
|
103
104
|
address[] memory owners = new address[](1);
|
|
@@ -203,7 +204,7 @@ contract FactoryTest is BaseTest {
|
|
|
203
204
|
vm.label(address(pool), "POOL");
|
|
204
205
|
|
|
205
206
|
assertEq(coin.currency(), USDC_ADDRESS, "currency");
|
|
206
|
-
assertEq(coin.balanceOf(users.creator), CREATOR_LAUNCH_REWARD + coinsPurchased);
|
|
207
|
+
assertEq(coin.balanceOf(users.creator), CoinConstants.CREATOR_LAUNCH_REWARD + coinsPurchased);
|
|
207
208
|
}
|
|
208
209
|
|
|
209
210
|
function test_deploy_with_usdc_revert_payout_recipient_zero() public {
|