@zoralabs/coins 1.1.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +107 -110
- package/CHANGELOG.md +50 -0
- package/README.md +48 -1
- package/abis/BaseCoin.json +442 -0
- package/abis/BaseZoraV4CoinHook.json +6 -2
- package/abis/CoinTest.json +3 -246
- package/abis/CoinUniV4Test.json +20 -0
- package/abis/ContentCoinHook.json +6 -2
- package/abis/CreatorCoinHook.json +6 -2
- package/abis/FactoryTest.json +8 -133
- package/abis/FeeEstimatorHook.json +6 -2
- package/abis/HooksTest.json +0 -26
- package/abis/ICoin.json +378 -0
- package/abis/ICoinV3.json +378 -0
- package/abis/IZoraFactory.json +0 -18
- package/abis/IZoraV4CoinHook.json +2 -2
- package/abis/LiquidityMigrationTest.json +101 -0
- package/abis/MockBadFactory.json +15 -0
- package/abis/Ownable2StepUpgradeable.json +138 -0
- package/abis/ZoraFactoryImpl.json +38 -65
- package/addresses/8453.json +5 -5
- package/dist/index.cjs +272 -268
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +270 -266
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +397 -470
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/package/wagmiGenerated.ts +275 -271
- package/package.json +3 -3
- package/script/DeployPostDeploymentHooks.s.sol +2 -2
- package/script/TestBackingCoinSwap.s.sol +9 -9
- package/script/TestV4Swap.s.sol +9 -9
- package/script/UpgradeFactoryImpl.s.sol +0 -1
- package/src/BaseCoin.sol +109 -6
- package/src/ContentCoin.sol +45 -0
- package/src/CreatorCoin.sol +7 -5
- package/src/ZoraFactoryImpl.sol +12 -95
- package/src/deployment/CoinsDeployerBase.sol +13 -30
- package/src/hooks/BaseZoraV4CoinHook.sol +8 -6
- package/src/hooks/deployment/BuySupplyWithSwapRouterHook.sol +4 -5
- package/src/interfaces/ICoin.sol +67 -1
- package/src/interfaces/ICreatorCoin.sol +2 -2
- package/src/interfaces/IZoraFactory.sol +0 -5
- package/src/interfaces/IZoraV4CoinHook.sol +1 -1
- package/src/libs/CoinConfigurationVersions.sol +1 -39
- package/src/libs/CoinRewardsV4.sol +2 -2
- package/src/libs/CoinSetup.sol +1 -4
- package/src/libs/UniV4SwapHelper.sol +1 -1
- package/src/libs/UniV4SwapToCurrency.sol +2 -2
- package/src/libs/V4Liquidity.sol +1 -1
- package/src/version/ContractVersionBase.sol +1 -1
- package/test/Coin.t.sol +112 -535
- package/test/CoinUniV4.t.sol +66 -10
- package/test/DeploymentHooks.t.sol +5 -102
- package/test/Factory.t.sol +49 -291
- package/test/LiquidityMigration.t.sol +160 -2
- package/test/MultiOwnable.t.sol +36 -36
- package/test/Upgrades.t.sol +23 -42
- package/test/utils/BaseTest.sol +39 -84
- package/test/utils/FeeEstimatorHook.sol +3 -3
- package/wagmi.config.ts +2 -2
- package/abis/Coin.json +0 -1912
- package/abis/DopplerUniswapV3Test.json +0 -800
- package/abis/ICoinV4.json +0 -1048
- package/abis/Simulate.json +0 -29
- package/abis/UniV3BuySell.json +0 -12
- package/abis/UniV3Errors.json +0 -32
- package/script/Simulate.s.sol +0 -59
- package/src/Coin.sol +0 -236
- package/src/CoinV4.sol +0 -151
- package/src/interfaces/ICoinV4.sol +0 -74
- package/src/libs/CoinDopplerUniV3.sol +0 -50
- package/src/libs/CoinRewards.sol +0 -201
- package/src/libs/CoinSetupV3.sol +0 -50
- package/src/libs/UniV3BuySell.sol +0 -231
- package/src/libs/UniV3Errors.sol +0 -11
- package/test/CoinDopplerUniV3.t.sol +0 -310
- /package/abis/{CoinV4.json → ContentCoin.json} +0 -0
package/test/Coin.t.sol
CHANGED
|
@@ -10,6 +10,7 @@ import {IHasRewardsRecipients} from "../src/interfaces/IHasRewardsRecipients.sol
|
|
|
10
10
|
import {PoolConfiguration} from "../src/interfaces/ICoin.sol";
|
|
11
11
|
import {IERC165, IERC7572, ICoin, ICoinComments, IERC20} from "../src/BaseCoin.sol";
|
|
12
12
|
import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
|
|
13
|
+
import {BaseCoin} from "../src/BaseCoin.sol";
|
|
13
14
|
|
|
14
15
|
contract CoinTest is BaseTest {
|
|
15
16
|
using stdJson for string;
|
|
@@ -19,20 +20,20 @@ contract CoinTest is BaseTest {
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
function test_contract_ierc165_support() public {
|
|
22
|
-
|
|
23
|
-
assertEq(
|
|
24
|
-
assertEq(
|
|
25
|
-
assertEq(
|
|
26
|
-
assertEq(
|
|
27
|
-
assertEq(
|
|
28
|
-
assertEq(
|
|
29
|
-
assertEq(
|
|
23
|
+
_deployV4Coin();
|
|
24
|
+
assertEq(coinV4.supportsInterface(type(IZoraFactory).interfaceId), false);
|
|
25
|
+
assertEq(coinV4.supportsInterface(bytes4(0x00000000)), false);
|
|
26
|
+
assertEq(coinV4.supportsInterface(type(IERC165).interfaceId), true);
|
|
27
|
+
assertEq(coinV4.supportsInterface(type(IERC7572).interfaceId), true);
|
|
28
|
+
assertEq(coinV4.supportsInterface(type(ICoin).interfaceId), true);
|
|
29
|
+
assertEq(coinV4.supportsInterface(type(ICoinComments).interfaceId), true);
|
|
30
|
+
assertEq(coinV4.supportsInterface(type(IERC7572).interfaceId), true);
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
function test_contract_version() public {
|
|
33
|
-
|
|
34
|
+
_deployV4Coin();
|
|
34
35
|
string memory package = vm.readFile("./package.json");
|
|
35
|
-
assertEq(package.readString(".version"),
|
|
36
|
+
assertEq(package.readString(".version"), coinV4.contractVersion());
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
function test_supply_constants() public {
|
|
@@ -42,36 +43,10 @@ contract CoinTest is BaseTest {
|
|
|
42
43
|
assertEq(CoinConstants.POOL_LAUNCH_SUPPLY, 990_000_000e18);
|
|
43
44
|
assertEq(CoinConstants.CREATOR_LAUNCH_REWARD, 10_000_000e18);
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
assertEq(
|
|
47
|
-
assertEq(
|
|
48
|
-
assertApproxEqAbs(
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function test_constructor_validation() public {
|
|
52
|
-
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
53
|
-
new Coin(address(0), address(protocolRewards), WETH_ADDRESS, NONFUNGIBLE_POSITION_MANAGER, SWAP_ROUTER, DOPPLER_AIRLOCK);
|
|
54
|
-
|
|
55
|
-
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
56
|
-
new Coin(users.feeRecipient, address(0), WETH_ADDRESS, NONFUNGIBLE_POSITION_MANAGER, SWAP_ROUTER, DOPPLER_AIRLOCK);
|
|
57
|
-
|
|
58
|
-
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
59
|
-
new Coin(users.feeRecipient, address(protocolRewards), address(0), NONFUNGIBLE_POSITION_MANAGER, SWAP_ROUTER, DOPPLER_AIRLOCK);
|
|
60
|
-
|
|
61
|
-
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
62
|
-
new Coin(users.feeRecipient, address(protocolRewards), WETH_ADDRESS, address(0), SWAP_ROUTER, DOPPLER_AIRLOCK);
|
|
63
|
-
|
|
64
|
-
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
65
|
-
new Coin(users.feeRecipient, address(protocolRewards), WETH_ADDRESS, NONFUNGIBLE_POSITION_MANAGER, address(0), DOPPLER_AIRLOCK);
|
|
66
|
-
|
|
67
|
-
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
68
|
-
new Coin(users.feeRecipient, address(protocolRewards), WETH_ADDRESS, NONFUNGIBLE_POSITION_MANAGER, SWAP_ROUTER, address(0));
|
|
69
|
-
|
|
70
|
-
Coin newToken = new Coin(users.feeRecipient, address(protocolRewards), WETH_ADDRESS, NONFUNGIBLE_POSITION_MANAGER, SWAP_ROUTER, DOPPLER_AIRLOCK);
|
|
71
|
-
assertEq(address(newToken.protocolRewardRecipient()), users.feeRecipient);
|
|
72
|
-
assertEq(address(newToken.protocolRewards()), address(protocolRewards));
|
|
73
|
-
assertEq(address(newToken.WETH()), WETH_ADDRESS);
|
|
74
|
-
assertEq(address(newToken.swapRouter()), SWAP_ROUTER);
|
|
46
|
+
_deployV4Coin();
|
|
47
|
+
assertEq(coinV4.totalSupply(), CoinConstants.MAX_TOTAL_SUPPLY);
|
|
48
|
+
assertEq(coinV4.balanceOf(coinV4.payoutRecipient()), CoinConstants.CREATOR_LAUNCH_REWARD);
|
|
49
|
+
assertApproxEqAbs(coinV4.balanceOf(address(coinV4.poolManager())), CoinConstants.POOL_LAUNCH_SUPPLY, 1e18);
|
|
75
50
|
}
|
|
76
51
|
|
|
77
52
|
function test_initialize_validation() public {
|
|
@@ -82,16 +57,16 @@ contract CoinTest is BaseTest {
|
|
|
82
57
|
|
|
83
58
|
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
84
59
|
(address coinAddress, ) = factory.deploy(address(0), owners, "https://init.com", "Init Token", "INIT", poolConfig_, users.platformReferrer, 0);
|
|
85
|
-
|
|
60
|
+
coinV4 = ContentCoin(payable(coinAddress));
|
|
86
61
|
|
|
87
62
|
(coinAddress, ) = factory.deploy(users.creator, owners, "https://init.com", "Init Token", "INIT", poolConfig_, users.platformReferrer, 0);
|
|
88
|
-
|
|
63
|
+
coinV4 = ContentCoin(payable(coinAddress));
|
|
89
64
|
|
|
90
|
-
assertEq(
|
|
91
|
-
assertEq(
|
|
92
|
-
assertEq(
|
|
93
|
-
assertEq(
|
|
94
|
-
assertEq(
|
|
65
|
+
assertEq(coinV4.payoutRecipient(), users.creator, "creator");
|
|
66
|
+
assertEq(coinV4.platformReferrer(), users.platformReferrer, "platformReferrer");
|
|
67
|
+
assertEq(coinV4.tokenURI(), "https://init.com");
|
|
68
|
+
assertEq(coinV4.name(), "Init Token");
|
|
69
|
+
assertEq(coinV4.symbol(), "INIT");
|
|
95
70
|
}
|
|
96
71
|
|
|
97
72
|
function test_invalid_pool_config_version() public {
|
|
@@ -117,568 +92,170 @@ contract CoinTest is BaseTest {
|
|
|
117
92
|
0
|
|
118
93
|
);
|
|
119
94
|
|
|
120
|
-
|
|
95
|
+
ContentCoin coin = ContentCoin(payable(coinAddress));
|
|
121
96
|
|
|
122
97
|
PoolConfiguration memory poolConfig = coin.getPoolConfiguration();
|
|
123
98
|
|
|
124
|
-
assertEq(poolConfig.version, CoinConfigurationVersions.
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function test_uniswap_v3_mint_callback_wrong_sender() public {
|
|
128
|
-
_deployCoin();
|
|
129
|
-
address random = makeAddr("random");
|
|
130
|
-
vm.prank(random);
|
|
131
|
-
vm.expectRevert(abi.encodeWithSelector(ICoin.OnlyPool.selector, random, address(pool)));
|
|
132
|
-
coin.uniswapV3MintCallback(1 ether, 1 ether, "");
|
|
99
|
+
assertEq(poolConfig.version, CoinConfigurationVersions.DOPPLER_MULTICURVE_UNI_V4_POOL_VERSION);
|
|
133
100
|
}
|
|
134
101
|
|
|
135
102
|
function test_erc165_interface_support() public {
|
|
136
|
-
|
|
137
|
-
assertEq(
|
|
138
|
-
assertEq(
|
|
139
|
-
assertEq(
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function test_buy_with_eth() public {
|
|
143
|
-
_deployCoin();
|
|
144
|
-
vm.deal(users.buyer, 1 ether);
|
|
145
|
-
vm.prank(users.buyer);
|
|
146
|
-
coin.buy{value: 1 ether}(users.coinRecipient, 1 ether, 0, 0, users.tradeReferrer);
|
|
147
|
-
|
|
148
|
-
assertGt(coin.balanceOf(users.coinRecipient), 0);
|
|
149
|
-
assertEq(users.seller.balance, 0);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function test_buy_with_eth_fuzz(uint256 ethOrderSize) public {
|
|
153
|
-
vm.assume(ethOrderSize >= CoinConstants.MIN_ORDER_SIZE);
|
|
154
|
-
vm.assume(ethOrderSize < 10 ether);
|
|
155
|
-
_deployCoin();
|
|
156
|
-
|
|
157
|
-
uint256 platformReferrerBalanceBeforeSale = users.platformReferrer.balance;
|
|
158
|
-
uint256 orderReferrerBalanceBeforeSale = users.tradeReferrer.balance;
|
|
159
|
-
uint256 tokenCreatorBalanceBeforeSale = users.creator.balance;
|
|
160
|
-
uint256 feeRecipientBalanceBeforeSale = users.feeRecipient.balance;
|
|
161
|
-
|
|
162
|
-
vm.deal(users.buyer, ethOrderSize);
|
|
163
|
-
vm.prank(users.buyer);
|
|
164
|
-
coin.buy{value: ethOrderSize}(users.coinRecipient, ethOrderSize, 0, 0, users.tradeReferrer);
|
|
165
|
-
|
|
166
|
-
assertGt(coin.balanceOf(users.coinRecipient), 0, "coinRecipient coin balance");
|
|
167
|
-
assertGt(protocolRewards.balanceOf(users.feeRecipient), feeRecipientBalanceBeforeSale, "feeRecipient eth balance");
|
|
168
|
-
assertGt(protocolRewards.balanceOf(users.platformReferrer), platformReferrerBalanceBeforeSale, "platformReferrer eth balance");
|
|
169
|
-
assertGt(protocolRewards.balanceOf(users.tradeReferrer), orderReferrerBalanceBeforeSale, "tradeReferrer eth balance");
|
|
170
|
-
assertGt(protocolRewards.balanceOf(users.creator), tokenCreatorBalanceBeforeSale, "creator eth balance");
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function test_buy_with_eth_too_small() public {
|
|
174
|
-
_deployCoin();
|
|
175
|
-
vm.expectRevert(abi.encodeWithSelector(ICoin.EthAmountTooSmall.selector));
|
|
176
|
-
coin.buy{value: CoinConstants.MIN_ORDER_SIZE - 1}(users.coinRecipient, CoinConstants.MIN_ORDER_SIZE - 1, 0, 0, users.tradeReferrer);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function test_buy_with_minimum_eth() public {
|
|
180
|
-
_deployCoin();
|
|
181
|
-
uint256 minEth = CoinConstants.MIN_ORDER_SIZE;
|
|
182
|
-
vm.deal(users.buyer, minEth);
|
|
183
|
-
vm.prank(users.buyer);
|
|
184
|
-
coin.buy{value: minEth}(users.coinRecipient, minEth, 0, 0, users.tradeReferrer);
|
|
185
|
-
|
|
186
|
-
assertGt(coin.balanceOf(users.coinRecipient), 0, "coinRecipient coin balance");
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function test_revert_buy_zero_address_recipient_legacy() public {
|
|
190
|
-
_deployCoin();
|
|
191
|
-
vm.deal(users.buyer, 1 ether);
|
|
192
|
-
|
|
193
|
-
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
194
|
-
vm.prank(users.buyer);
|
|
195
|
-
coin.buy{value: 1 ether}(address(0), 1 ether, 0, 0, users.tradeReferrer);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function test_revert_buy_zero_address_recipient() public {
|
|
199
|
-
_deployCoin();
|
|
200
|
-
vm.deal(users.buyer, 1 ether);
|
|
201
|
-
|
|
202
|
-
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
203
|
-
vm.prank(users.buyer);
|
|
204
|
-
coin.buy(address(0), 1 ether, 0, 0, users.tradeReferrer);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function test_buy_with_usdc() public {
|
|
208
|
-
_deployCoinUSDCPair();
|
|
209
|
-
|
|
210
|
-
deal(address(usdc), users.buyer, 100e6);
|
|
211
|
-
|
|
212
|
-
vm.prank(users.buyer);
|
|
213
|
-
usdc.approve(address(coin), 10e6);
|
|
214
|
-
|
|
215
|
-
vm.prank(users.buyer);
|
|
216
|
-
coin.buy(users.coinRecipient, 10e6, 0, 0, users.tradeReferrer);
|
|
217
|
-
|
|
218
|
-
assertGt(coin.balanceOf(users.coinRecipient), 0, "coinRecipient coin balance");
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function test_buy_with_usdc_revert_no_approval() public {
|
|
222
|
-
_deployCoinUSDCPair();
|
|
223
|
-
|
|
224
|
-
deal(address(usdc), users.buyer, 100e6);
|
|
225
|
-
|
|
226
|
-
vm.prank(users.buyer);
|
|
227
|
-
vm.expectRevert("ERC20: transfer amount exceeds allowance");
|
|
228
|
-
coin.buy(users.coinRecipient, 100e6, 0, 0, users.tradeReferrer);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function test_buy_validate_return_amounts(uint256 orderSize) public {
|
|
232
|
-
vm.assume(orderSize >= CoinConstants.MIN_ORDER_SIZE);
|
|
233
|
-
vm.assume(orderSize < 10 ether);
|
|
234
|
-
_deployCoin();
|
|
235
|
-
|
|
236
|
-
vm.deal(users.buyer, orderSize);
|
|
237
|
-
vm.prank(users.buyer);
|
|
238
|
-
(uint256 amountIn, uint256 amountOut) = coin.buy{value: orderSize}(users.coinRecipient, orderSize, 0, 0, users.tradeReferrer);
|
|
239
|
-
|
|
240
|
-
assertEq(amountIn, orderSize, "amountIn");
|
|
241
|
-
assertGe(coin.balanceOf(users.coinRecipient), amountOut, "coinRecipient coin balance");
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
function test_sell_for_eth_direct_and_claim_secondary() public {
|
|
245
|
-
_deployCoin();
|
|
246
|
-
vm.deal(users.buyer, 1 ether);
|
|
247
|
-
|
|
248
|
-
vm.prank(users.buyer);
|
|
249
|
-
weth.deposit{value: 100_000}();
|
|
250
|
-
|
|
251
|
-
vm.prank(users.buyer);
|
|
252
|
-
weth.approve(address(swapRouter), 100_000);
|
|
253
|
-
|
|
254
|
-
assertEq(coin.balanceOf(users.buyer), 0, "buyer coin balance initial");
|
|
255
|
-
|
|
256
|
-
// Set up the swap parameters
|
|
257
|
-
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
|
|
258
|
-
tokenIn: WETH_ADDRESS,
|
|
259
|
-
tokenOut: address(coin),
|
|
260
|
-
fee: MarketConstants.LP_FEE,
|
|
261
|
-
recipient: address(users.buyer),
|
|
262
|
-
amountIn: 100_000,
|
|
263
|
-
amountOutMinimum: 0,
|
|
264
|
-
sqrtPriceLimitX96: 0
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
// Execute the swap
|
|
268
|
-
vm.prank(users.buyer);
|
|
269
|
-
uint256 amountOut = ISwapRouter(swapRouter).exactInputSingle(params);
|
|
270
|
-
|
|
271
|
-
assertGt(coin.balanceOf(users.buyer), 0, "buyer coin balance");
|
|
272
|
-
assertGt(amountOut, 0, "amountOut");
|
|
273
|
-
assertGt(users.buyer.balance, 0, "seller eth balance");
|
|
274
|
-
|
|
275
|
-
// now we have unclaimed secondary rewards to claim
|
|
276
|
-
vm.prank(users.buyer);
|
|
277
|
-
|
|
278
|
-
// don't push ETH
|
|
279
|
-
coin.claimSecondaryRewards(false);
|
|
280
|
-
assertGt(protocolRewards.balanceOf(users.creator), 0);
|
|
281
|
-
assertGt(protocolRewards.balanceOf(users.platformReferrer), 0);
|
|
282
|
-
assertGt(protocolRewards.balanceOf(users.feeRecipient), 0);
|
|
283
|
-
assertGt(dopplerFeeRecipient().balance, 0);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
function test_sell_for_eth_direct_and_claim_secondary_push_eth() public {
|
|
287
|
-
_deployCoin();
|
|
288
|
-
vm.deal(users.buyer, 1 ether);
|
|
289
|
-
|
|
290
|
-
vm.prank(users.buyer);
|
|
291
|
-
weth.deposit{value: 100_000}();
|
|
292
|
-
|
|
293
|
-
vm.prank(users.buyer);
|
|
294
|
-
weth.approve(address(swapRouter), 100_000);
|
|
295
|
-
|
|
296
|
-
// Set up the swap parameters
|
|
297
|
-
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
|
|
298
|
-
tokenIn: WETH_ADDRESS,
|
|
299
|
-
tokenOut: address(coin),
|
|
300
|
-
fee: MarketConstants.LP_FEE,
|
|
301
|
-
recipient: address(users.buyer),
|
|
302
|
-
amountIn: 100_000,
|
|
303
|
-
amountOutMinimum: 0,
|
|
304
|
-
sqrtPriceLimitX96: 0
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
// Execute the swap
|
|
308
|
-
vm.prank(users.buyer);
|
|
309
|
-
uint256 amountOut = ISwapRouter(swapRouter).exactInputSingle(params);
|
|
310
|
-
|
|
311
|
-
assertGt(coin.balanceOf(users.buyer), 0, "buyer coin balance");
|
|
312
|
-
assertGt(amountOut, 0, "amountOut");
|
|
313
|
-
assertGt(users.buyer.balance, 0, "seller eth balance");
|
|
314
|
-
|
|
315
|
-
// Now we have unclaimed secondary rewards to claim
|
|
316
|
-
vm.prank(users.buyer);
|
|
317
|
-
|
|
318
|
-
uint256 initialBalance = users.creator.balance;
|
|
319
|
-
|
|
320
|
-
// Push ETH
|
|
321
|
-
coin.claimSecondaryRewards(true);
|
|
322
|
-
assertGt(users.creator.balance, initialBalance);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
function test_sell_for_eth() public {
|
|
326
|
-
_deployCoin();
|
|
327
|
-
vm.deal(users.buyer, 1 ether);
|
|
328
|
-
vm.prank(users.buyer);
|
|
329
|
-
coin.buy{value: 1 ether}(users.seller, 1 ether, 0, 0, users.tradeReferrer);
|
|
330
|
-
|
|
331
|
-
uint256 tokensToSell = coin.balanceOf(users.seller);
|
|
332
|
-
vm.prank(users.seller);
|
|
333
|
-
coin.sell(users.seller, tokensToSell, 0, 0, users.tradeReferrer);
|
|
334
|
-
|
|
335
|
-
assertEq(coin.balanceOf(users.seller), 0, "seller coin balance");
|
|
336
|
-
assertGt(users.seller.balance, 0, "seller eth balance");
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
function test_sell_for_eth_fuzz(uint256 ethOrderSize) public {
|
|
340
|
-
vm.assume(ethOrderSize < 10 ether);
|
|
341
|
-
vm.assume(ethOrderSize >= CoinConstants.MIN_ORDER_SIZE);
|
|
342
|
-
_deployCoin();
|
|
343
|
-
vm.deal(users.buyer, ethOrderSize);
|
|
344
|
-
vm.prank(users.buyer);
|
|
345
|
-
coin.buy{value: ethOrderSize}(users.seller, ethOrderSize, 0, 0, users.tradeReferrer);
|
|
346
|
-
|
|
347
|
-
uint256 platformReferrerBalanceBeforeSale = users.platformReferrer.balance;
|
|
348
|
-
uint256 orderReferrerBalanceBeforeSale = users.tradeReferrer.balance;
|
|
349
|
-
uint256 tokenCreatorBalanceBeforeSale = users.creator.balance;
|
|
350
|
-
uint256 feeRecipientBalanceBeforeSale = users.feeRecipient.balance;
|
|
351
|
-
|
|
352
|
-
uint256 tokensToSell = coin.balanceOf(users.seller);
|
|
353
|
-
vm.prank(users.seller);
|
|
354
|
-
coin.sell(users.coinRecipient, tokensToSell, 0, 0, users.tradeReferrer);
|
|
355
|
-
|
|
356
|
-
assertEq(coin.balanceOf(users.seller), 0, "seller coin balance");
|
|
357
|
-
assertEq(coin.balanceOf(users.coinRecipient), 0, "coinRecipient coin balance");
|
|
358
|
-
|
|
359
|
-
assertEq(users.seller.balance, 0, "seller eth balance");
|
|
360
|
-
assertGt(protocolRewards.balanceOf(users.feeRecipient), feeRecipientBalanceBeforeSale, "feeRecipient eth balance");
|
|
361
|
-
assertGt(protocolRewards.balanceOf(users.platformReferrer), platformReferrerBalanceBeforeSale, "platformReferrer eth balance");
|
|
362
|
-
assertGt(protocolRewards.balanceOf(users.tradeReferrer), orderReferrerBalanceBeforeSale, "tradeReferrer eth balance");
|
|
363
|
-
assertGt(protocolRewards.balanceOf(users.creator), tokenCreatorBalanceBeforeSale, "creator eth balance");
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
function test_sell_for_usdc() public {
|
|
367
|
-
_deployCoinUSDCPair();
|
|
368
|
-
|
|
369
|
-
deal(address(usdc), users.buyer, 10e6);
|
|
370
|
-
|
|
371
|
-
vm.prank(users.buyer);
|
|
372
|
-
usdc.approve(address(coin), 10e6);
|
|
373
|
-
|
|
374
|
-
vm.prank(users.buyer);
|
|
375
|
-
coin.buy(users.coinRecipient, 10e6, 0, 0, users.tradeReferrer);
|
|
376
|
-
|
|
377
|
-
uint256 coinBalance = coin.balanceOf(users.coinRecipient);
|
|
378
|
-
|
|
379
|
-
vm.prank(users.coinRecipient);
|
|
380
|
-
coin.sell(users.seller, coinBalance, 0, 0, users.tradeReferrer);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
function test_revert_sell_zero_address_recipient() public {
|
|
384
|
-
_deployCoin();
|
|
385
|
-
vm.deal(users.buyer, 1 ether);
|
|
386
|
-
vm.prank(users.buyer);
|
|
387
|
-
coin.buy{value: 1 ether}(users.seller, 1 ether, 0, 0, users.tradeReferrer);
|
|
388
|
-
|
|
389
|
-
uint256 tokensToSell = coin.balanceOf(users.seller);
|
|
390
|
-
vm.prank(users.seller);
|
|
391
|
-
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
392
|
-
coin.sell(address(0), tokensToSell, 0, 0, users.tradeReferrer);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
function test_revert_sell_insufficient_liquidity() public {
|
|
396
|
-
_deployCoin();
|
|
397
|
-
vm.deal(users.buyer, 1 ether);
|
|
398
|
-
vm.prank(users.buyer);
|
|
399
|
-
coin.buy{value: 1 ether}(users.seller, 1 ether, 0, 0, users.tradeReferrer);
|
|
400
|
-
|
|
401
|
-
uint256 balance = coin.balanceOf(users.seller);
|
|
402
|
-
vm.prank(users.seller);
|
|
403
|
-
vm.expectRevert(abi.encodeWithSignature("ERC20InsufficientBalance(address,uint256,uint256)", users.seller, balance, balance + 1));
|
|
404
|
-
coin.sell(users.coinRecipient, balance + 1, 0, 0, users.tradeReferrer);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
function test_sell_partial_execution() public {
|
|
408
|
-
_deployCoin();
|
|
409
|
-
vm.deal(users.creator, 1 ether);
|
|
410
|
-
vm.prank(users.creator);
|
|
411
|
-
coin.buy{value: 0.001 ether}(users.creator, 0.001 ether, 0, 0, users.tradeReferrer);
|
|
412
|
-
|
|
413
|
-
uint256 beforeBalance = coin.balanceOf(users.creator);
|
|
414
|
-
assertGt(beforeBalance, 0, "before balance");
|
|
415
|
-
|
|
416
|
-
vm.prank(users.creator);
|
|
417
|
-
(uint256 amountSold, ) = coin.sell(users.creator, beforeBalance, 0, 0, users.tradeReferrer);
|
|
418
|
-
assertGt(amountSold, 0, "amountSold");
|
|
419
|
-
|
|
420
|
-
// these seemed to change with different configuration of the pool. uncomment when we can figure
|
|
421
|
-
// out the values
|
|
422
|
-
// uint256 afterBalance = coin.balanceOf(users.creator);
|
|
423
|
-
// assertEq(afterBalance, 9994558841570544323195890, "after balance"); // 9,994,559 coins
|
|
424
|
-
|
|
425
|
-
// uint256 expectedMarketReward = 5441158429455676804107; // 5,441 coins
|
|
426
|
-
|
|
427
|
-
// // 9,994,559 = 11,077,349 order size - 1,088,232 true order size + 5,441 creator market reward
|
|
428
|
-
// assertEq(afterBalance, ((beforeBalance - amountSold) + expectedMarketReward), "amountSold");
|
|
103
|
+
_deployV4Coin();
|
|
104
|
+
assertEq(coinV4.supportsInterface(type(IERC165).interfaceId), true);
|
|
105
|
+
assertEq(coinV4.supportsInterface(type(IHasRewardsRecipients).interfaceId), true);
|
|
106
|
+
assertEq(coinV4.supportsInterface(type(IERC7572).interfaceId), true);
|
|
429
107
|
}
|
|
430
108
|
|
|
431
109
|
function test_burn() public {
|
|
432
|
-
|
|
110
|
+
_deployV4Coin();
|
|
433
111
|
vm.deal(users.buyer, 1 ether);
|
|
434
112
|
vm.prank(users.buyer);
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
uint256 beforeBalance = coin.balanceOf(users.coinRecipient);
|
|
438
|
-
uint256 beforeTotalSupply = coin.totalSupply();
|
|
113
|
+
_swapSomeCurrencyForCoin(coinV4, address(weth), 1 ether, users.coinRecipient);
|
|
439
114
|
|
|
440
|
-
|
|
441
|
-
|
|
115
|
+
uint256 beforeBalance = coinV4.balanceOf(users.coinRecipient);
|
|
116
|
+
uint256 beforeTotalSupply = coinV4.totalSupply();
|
|
442
117
|
|
|
443
|
-
uint256
|
|
444
|
-
uint256 afterTotalSupply = coin.totalSupply();
|
|
445
|
-
|
|
446
|
-
assertEq(beforeBalance - afterBalance, 1e18, "coinRecipient coin balance");
|
|
447
|
-
assertEq(beforeTotalSupply - afterTotalSupply, 1e18, "coin total supply");
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
function test_receive_from_weth() public {
|
|
451
|
-
_deployCoin();
|
|
452
|
-
uint256 orderSize = 1 ether;
|
|
453
|
-
vm.deal(users.buyer, orderSize);
|
|
454
|
-
vm.prank(users.buyer);
|
|
455
|
-
coin.buy{value: orderSize}(users.coinRecipient, orderSize, 0, 0, users.tradeReferrer);
|
|
456
|
-
|
|
457
|
-
vm.deal(WETH_ADDRESS, 1 ether);
|
|
458
|
-
vm.prank(WETH_ADDRESS);
|
|
459
|
-
(bool success, ) = address(coin).call{value: 1 ether}("");
|
|
460
|
-
assertTrue(success);
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
function test_revert_receive_from_weth_wrong_sender() public {
|
|
464
|
-
_deployCoin();
|
|
465
|
-
address random = makeAddr("random");
|
|
466
|
-
vm.prank(random);
|
|
467
|
-
vm.expectRevert(abi.encodeWithSelector(ICoin.OnlyWeth.selector, random));
|
|
468
|
-
(bool success, ) = address(coin).call{value: 1 ether}("");
|
|
469
|
-
assertFalse(success);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
function test_default_platform_referrer() public {
|
|
473
|
-
address[] memory owners = new address[](1);
|
|
474
|
-
owners[0] = users.creator;
|
|
475
|
-
|
|
476
|
-
bytes memory poolConfig_ = _generatePoolConfig(
|
|
477
|
-
CoinConfigurationVersions.DOPPLER_UNI_V3_POOL_VERSION,
|
|
478
|
-
address(weth),
|
|
479
|
-
DEFAULT_DISCOVERY_TICK_LOWER,
|
|
480
|
-
DEFAULT_DISCOVERY_TICK_UPPER,
|
|
481
|
-
DEFAULT_NUM_DISCOVERY_POSITIONS,
|
|
482
|
-
DEFAULT_DISCOVERY_SUPPLY_SHARE
|
|
483
|
-
);
|
|
484
|
-
|
|
485
|
-
(address newCoinAddr, ) = factory.deploy(users.creator, owners, "https://test.com", "Test Token", "TEST", poolConfig_, users.platformReferrer, 0);
|
|
486
|
-
Coin newCoin = Coin(payable(newCoinAddr));
|
|
487
|
-
|
|
488
|
-
vm.deal(users.buyer, 1 ether);
|
|
489
|
-
vm.prank(users.buyer);
|
|
490
|
-
newCoin.buy{value: 1 ether}(users.coinRecipient, 1 ether, 0, 0, users.tradeReferrer);
|
|
491
|
-
|
|
492
|
-
uint256 fee = _calculateExpectedFee(1 ether);
|
|
493
|
-
TradeRewards memory expectedFees = _calculateTradeRewards(fee);
|
|
494
|
-
|
|
495
|
-
assertGt(protocolRewards.balanceOf(users.feeRecipient), expectedFees.platformReferrer, "feeRecipient eth balance");
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
function test_default_order_referrer() public {
|
|
499
|
-
_deployCoin();
|
|
500
|
-
vm.deal(users.buyer, 1 ether);
|
|
501
|
-
vm.prank(users.buyer);
|
|
502
|
-
coin.buy{value: 1 ether}(users.coinRecipient, 1 ether, 0, 0, address(0));
|
|
503
|
-
|
|
504
|
-
uint256 fee = _calculateExpectedFee(1 ether);
|
|
505
|
-
TradeRewards memory expectedFees = _calculateTradeRewards(fee);
|
|
506
|
-
|
|
507
|
-
assertGt(protocolRewards.balanceOf(users.feeRecipient), expectedFees.tradeReferrer, "feeRecipient eth balance");
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
function test_market_slippage() public {
|
|
511
|
-
_deployCoin();
|
|
512
|
-
vm.deal(users.buyer, 1 ether);
|
|
513
|
-
vm.prank(users.buyer);
|
|
514
|
-
coin.buy{value: 1 ether}(users.coinRecipient, 1 ether, 0, 0, users.tradeReferrer);
|
|
515
|
-
|
|
516
|
-
vm.deal(users.buyer, 1 ether);
|
|
517
|
-
vm.prank(users.buyer);
|
|
518
|
-
vm.expectRevert("Too little received"); // Uniswap V3 revert
|
|
519
|
-
coin.buy{value: 1 ether}(users.coinRecipient, 1 ether, type(uint256).max, 0, users.tradeReferrer);
|
|
520
|
-
|
|
521
|
-
vm.prank(users.coinRecipient);
|
|
522
|
-
vm.expectRevert("Too little received"); // Uniswap V3 revert
|
|
523
|
-
coin.sell(users.coinRecipient, 1e18, type(uint256).max, 0, users.tradeReferrer);
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
function test_eth_transfer_fail() public {
|
|
527
|
-
_deployCoin();
|
|
528
|
-
vm.deal(users.buyer, 1 ether);
|
|
529
|
-
vm.prank(users.buyer);
|
|
530
|
-
(, uint256 amountOut) = coin.buy{value: 1 ether}(users.coinRecipient, 1 ether, 0, 0, users.tradeReferrer);
|
|
531
|
-
|
|
532
|
-
assertEq(coin.balanceOf(users.coinRecipient), amountOut);
|
|
533
|
-
|
|
534
|
-
// Recipient reverts on ETH receive
|
|
535
|
-
address payable badRecipient = payable(makeAddr("badRecipient"));
|
|
536
|
-
vm.etch(badRecipient, hex"fe");
|
|
118
|
+
uint256 burnAmount = beforeBalance / 2;
|
|
537
119
|
|
|
538
120
|
vm.prank(users.coinRecipient);
|
|
539
|
-
|
|
540
|
-
coin.sell(badRecipient, 1e18, 0, 0, users.tradeReferrer);
|
|
541
|
-
}
|
|
121
|
+
coinV4.burn(burnAmount);
|
|
542
122
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
vm.deal(users.buyer, 1 ether);
|
|
546
|
-
vm.prank(users.buyer);
|
|
547
|
-
vm.expectRevert(abi.encodeWithSelector(ICoin.OnlyWeth.selector));
|
|
548
|
-
(bool ignoredSuccess, ) = address(coin).call{value: 1 ether}("");
|
|
549
|
-
(ignoredSuccess);
|
|
550
|
-
|
|
551
|
-
assertEq(address(coin).balance, 0, "coin balance");
|
|
552
|
-
}
|
|
123
|
+
uint256 afterBalance = coinV4.balanceOf(users.coinRecipient);
|
|
124
|
+
uint256 afterTotalSupply = coinV4.totalSupply();
|
|
553
125
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
uint256 initialPlatformReferrerBalance = protocolRewards.balanceOf(users.platformReferrer);
|
|
557
|
-
uint256 initialTokenCreatorBalance = protocolRewards.balanceOf(users.creator);
|
|
558
|
-
uint256 initialOrderReferrerBalance = protocolRewards.balanceOf(users.tradeReferrer);
|
|
559
|
-
uint256 initialFeeRecipientBalance = protocolRewards.balanceOf(users.feeRecipient);
|
|
560
|
-
uint256 initialDopplerRecipientBalance = airlock.owner().balance;
|
|
561
|
-
|
|
562
|
-
uint256 buyAmount = 1 ether;
|
|
563
|
-
vm.deal(users.buyer, buyAmount);
|
|
564
|
-
vm.prank(users.buyer);
|
|
565
|
-
coin.buy{value: buyAmount}(users.coinRecipient, buyAmount, 0, 0, users.tradeReferrer);
|
|
566
|
-
|
|
567
|
-
uint256 orderFee = _calculateExpectedFee(buyAmount); // 1 ETH * 1% --> 0.01 ETH
|
|
568
|
-
TradeRewards memory orderFees = _calculateTradeRewards(orderFee);
|
|
569
|
-
|
|
570
|
-
uint256 expectedLpFee = 9900000000000000; // 0.99 ETH * 1% --> ~0.00989 ETH
|
|
571
|
-
MarketRewards memory marketRewards = _calculateMarketRewards(expectedLpFee);
|
|
572
|
-
|
|
573
|
-
assertEq(
|
|
574
|
-
marketRewards.creator + marketRewards.platformReferrer + marketRewards.protocol + marketRewards.doppler,
|
|
575
|
-
expectedLpFee,
|
|
576
|
-
"Secondary rewards incorrect"
|
|
577
|
-
);
|
|
578
|
-
assertApproxEqAbs(
|
|
579
|
-
protocolRewards.balanceOf(users.creator),
|
|
580
|
-
initialTokenCreatorBalance + orderFees.creator + marketRewards.creator,
|
|
581
|
-
0.0000000000000001 ether,
|
|
582
|
-
"Token creator rewards incorrect"
|
|
583
|
-
);
|
|
584
|
-
assertApproxEqAbs(
|
|
585
|
-
protocolRewards.balanceOf(users.platformReferrer),
|
|
586
|
-
initialPlatformReferrerBalance + orderFees.platformReferrer + marketRewards.platformReferrer,
|
|
587
|
-
0.0000000000000001 ether,
|
|
588
|
-
"Platform referrer rewards incorrect"
|
|
589
|
-
);
|
|
590
|
-
assertApproxEqAbs(
|
|
591
|
-
airlock.owner().balance,
|
|
592
|
-
initialDopplerRecipientBalance + marketRewards.doppler,
|
|
593
|
-
0.0000000000000001 ether,
|
|
594
|
-
"Doppler rewards incorrect"
|
|
595
|
-
);
|
|
596
|
-
assertApproxEqAbs(
|
|
597
|
-
protocolRewards.balanceOf(users.feeRecipient),
|
|
598
|
-
initialFeeRecipientBalance + orderFees.protocol + marketRewards.protocol,
|
|
599
|
-
0.0000000000000001 ether,
|
|
600
|
-
"Protocol rewards incorrect"
|
|
601
|
-
);
|
|
602
|
-
assertEq(protocolRewards.balanceOf(users.tradeReferrer), initialOrderReferrerBalance + orderFees.tradeReferrer, "Order referrer rewards incorrect");
|
|
126
|
+
assertEq(beforeBalance - afterBalance, burnAmount, "coinRecipient coin balance");
|
|
127
|
+
assertEq(beforeTotalSupply - afterTotalSupply, burnAmount, "coin total supply");
|
|
603
128
|
}
|
|
604
129
|
|
|
605
130
|
function test_contract_uri() public {
|
|
606
|
-
|
|
607
|
-
assertEq(
|
|
131
|
+
_deployV4Coin();
|
|
132
|
+
assertEq(coinV4.contractURI(), "https://test.com");
|
|
608
133
|
}
|
|
609
134
|
|
|
610
135
|
function test_set_contract_uri() public {
|
|
611
|
-
|
|
136
|
+
_deployV4Coin();
|
|
612
137
|
string memory newURI = "https://new.com";
|
|
613
138
|
|
|
614
139
|
vm.prank(users.creator);
|
|
615
|
-
|
|
616
|
-
assertEq(
|
|
140
|
+
coinV4.setContractURI(newURI);
|
|
141
|
+
assertEq(coinV4.contractURI(), newURI);
|
|
617
142
|
}
|
|
618
143
|
|
|
619
144
|
function test_set_contract_uri_reverts_if_not_owner() public {
|
|
620
|
-
|
|
145
|
+
_deployV4Coin();
|
|
621
146
|
string memory newURI = "https://new.com";
|
|
622
147
|
|
|
623
148
|
vm.expectRevert(abi.encodeWithSelector(MultiOwnable.OnlyOwner.selector));
|
|
624
|
-
|
|
149
|
+
coinV4.setContractURI(newURI);
|
|
625
150
|
}
|
|
626
151
|
|
|
627
152
|
function test_set_payout_recipient() public {
|
|
628
|
-
|
|
153
|
+
_deployV4Coin();
|
|
629
154
|
address newPayoutRecipient = makeAddr("NewPayoutRecipient");
|
|
630
155
|
|
|
631
156
|
vm.prank(users.creator);
|
|
632
|
-
|
|
633
|
-
assertEq(
|
|
157
|
+
coinV4.setPayoutRecipient(newPayoutRecipient);
|
|
158
|
+
assertEq(coinV4.payoutRecipient(), newPayoutRecipient);
|
|
634
159
|
}
|
|
635
160
|
|
|
636
161
|
function test_revert_set_payout_recipient_address_zero() public {
|
|
637
|
-
|
|
162
|
+
_deployV4Coin();
|
|
638
163
|
address newPayoutRecipient = address(0);
|
|
639
164
|
|
|
640
165
|
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
641
166
|
vm.prank(users.creator);
|
|
642
|
-
|
|
167
|
+
coinV4.setPayoutRecipient(newPayoutRecipient);
|
|
643
168
|
}
|
|
644
169
|
|
|
645
170
|
function test_revert_set_payout_recipient_only_owner() public {
|
|
646
|
-
|
|
171
|
+
_deployV4Coin();
|
|
647
172
|
address newPayoutRecipient = makeAddr("NewPayoutRecipient");
|
|
648
173
|
|
|
649
174
|
vm.expectRevert(abi.encodeWithSelector(MultiOwnable.OnlyOwner.selector));
|
|
650
|
-
|
|
175
|
+
coinV4.setPayoutRecipient(newPayoutRecipient);
|
|
651
176
|
}
|
|
652
177
|
|
|
653
178
|
function test_update_metadata() public {
|
|
654
|
-
|
|
179
|
+
_deployV4Coin();
|
|
655
180
|
string memory newName = "NewName";
|
|
656
181
|
string memory newSymbol = "NEW";
|
|
657
182
|
|
|
658
183
|
vm.prank(users.creator);
|
|
659
184
|
vm.expectEmit(true, true, true, true);
|
|
660
185
|
emit ICoin.NameAndSymbolUpdated(users.creator, newName, newSymbol);
|
|
661
|
-
|
|
662
|
-
assertEq(
|
|
663
|
-
assertEq(
|
|
186
|
+
coinV4.setNameAndSymbol(newName, newSymbol);
|
|
187
|
+
assertEq(coinV4.name(), newName);
|
|
188
|
+
assertEq(coinV4.symbol(), newSymbol);
|
|
664
189
|
}
|
|
665
190
|
|
|
666
191
|
function test_update_metadata_reverts_if_not_owner() public {
|
|
667
|
-
|
|
192
|
+
_deployV4Coin();
|
|
668
193
|
string memory newName = "NewName";
|
|
669
194
|
string memory newSymbol = "NEW";
|
|
670
195
|
|
|
671
196
|
vm.expectRevert(abi.encodeWithSelector(MultiOwnable.OnlyOwner.selector));
|
|
672
|
-
|
|
197
|
+
coinV4.setNameAndSymbol(newName, newSymbol);
|
|
673
198
|
}
|
|
674
199
|
|
|
675
200
|
function test_update_metadata_reverts_if_name_is_blank() public {
|
|
676
|
-
|
|
201
|
+
_deployV4Coin();
|
|
677
202
|
string memory newName = "";
|
|
678
203
|
string memory newSymbol = "NEW";
|
|
679
204
|
|
|
680
205
|
vm.prank(users.creator);
|
|
681
206
|
vm.expectRevert(abi.encodeWithSelector(ICoin.NameIsRequired.selector));
|
|
682
|
-
|
|
207
|
+
coinV4.setNameAndSymbol(newName, newSymbol);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function test_deploy_coin_with_invalid_parameters() public {
|
|
211
|
+
address[] memory owners = new address[](1);
|
|
212
|
+
owners[0] = users.creator;
|
|
213
|
+
|
|
214
|
+
bytes memory poolConfig = CoinConfigurationVersions.defaultDopplerMultiCurveUniV4(address(weth));
|
|
215
|
+
|
|
216
|
+
// Test with empty name - should revert
|
|
217
|
+
vm.expectRevert(abi.encodeWithSelector(ICoin.NameIsRequired.selector));
|
|
218
|
+
factory.deploy(
|
|
219
|
+
users.creator,
|
|
220
|
+
owners,
|
|
221
|
+
"https://test.com",
|
|
222
|
+
"", // empty name
|
|
223
|
+
"TEST",
|
|
224
|
+
poolConfig,
|
|
225
|
+
users.platformReferrer,
|
|
226
|
+
address(0),
|
|
227
|
+
bytes(""),
|
|
228
|
+
bytes32(0)
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
// Test with zero address payout recipient - should revert
|
|
232
|
+
vm.expectRevert();
|
|
233
|
+
factory.deploy(
|
|
234
|
+
address(0), // zero address payout recipient
|
|
235
|
+
owners,
|
|
236
|
+
"https://test.com",
|
|
237
|
+
"TestCoin",
|
|
238
|
+
"TEST",
|
|
239
|
+
poolConfig,
|
|
240
|
+
users.platformReferrer,
|
|
241
|
+
address(0),
|
|
242
|
+
bytes(""),
|
|
243
|
+
bytes32(0)
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function test_access_control_unauthorized_actions() public {
|
|
248
|
+
_deployV4Coin();
|
|
249
|
+
|
|
250
|
+
address unauthorizedUser = makeAddr("unauthorized");
|
|
251
|
+
|
|
252
|
+
// Test unauthorized access to owner-only functions
|
|
253
|
+
vm.prank(unauthorizedUser);
|
|
254
|
+
vm.expectRevert(abi.encodeWithSelector(MultiOwnable.OnlyOwner.selector));
|
|
255
|
+
coinV4.setPayoutRecipient(makeAddr("newRecipient"));
|
|
256
|
+
|
|
257
|
+
vm.prank(unauthorizedUser);
|
|
258
|
+
vm.expectRevert(abi.encodeWithSelector(MultiOwnable.OnlyOwner.selector));
|
|
259
|
+
coinV4.setContractURI("https://new-uri.com");
|
|
683
260
|
}
|
|
684
261
|
}
|