@zoralabs/coins 2.1.1 → 2.2.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 +152 -0
- package/CHANGELOG.md +60 -0
- package/abis/BaseCoin.json +26 -0
- package/abis/BaseTest.json +2 -7
- package/abis/CoinConstants.json +0 -104
- package/abis/ContentCoin.json +26 -0
- package/abis/CreatorCoin.json +30 -4
- package/abis/FeeEstimatorHook.json +0 -5
- package/abis/ICoin.json +26 -0
- package/abis/ICoinV3.json +26 -0
- package/abis/ICreatorCoin.json +39 -0
- package/abis/IERC721.json +36 -36
- package/abis/IHasCoinType.json +15 -0
- package/abis/IHasTotalSupplyForPositions.json +15 -0
- package/abis/IZoraFactory.json +52 -0
- package/abis/IZoraHookRegistry.json +188 -0
- package/abis/VmContractHelper227.json +233 -0
- package/abis/ZoraFactoryImpl.json +32 -6
- package/abis/ZoraHookRegistry.json +375 -0
- package/abis/{CreatorCoinHook.json → ZoraV4CoinHook.json} +1 -1
- package/addresses/8453.json +2 -1
- package/dist/index.cjs +72 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +72 -10
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +90 -10
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/foundry.toml +4 -1
- package/package/wagmiGenerated.ts +72 -10
- package/package.json +7 -5
- package/script/PrintRegisterUpgradePath.s.sol +0 -7
- package/script/TestBackingCoinSwap.s.sol +0 -1
- package/script/TestV4Swap.s.sol +0 -1
- package/script/UpgradeFactoryImpl.s.sol +1 -1
- package/src/BaseCoin.sol +15 -12
- package/src/ContentCoin.sol +10 -0
- package/src/CreatorCoin.sol +28 -7
- package/src/ZoraFactoryImpl.sol +62 -23
- package/src/deployment/CoinsDeployerBase.sol +24 -58
- package/src/hook-registry/ZoraHookRegistry.sol +93 -0
- package/src/hooks/{BaseZoraV4CoinHook.sol → ZoraV4CoinHook.sol} +13 -8
- package/src/interfaces/ICoin.sol +19 -1
- package/src/interfaces/ICreatorCoin.sol +4 -0
- package/src/interfaces/IZoraFactory.sol +32 -10
- package/src/interfaces/IZoraHookRegistry.sol +47 -0
- package/src/libs/CoinConstants.sol +0 -32
- package/src/libs/CoinRewardsV4.sol +53 -15
- package/src/libs/CreatorCoinConstants.sol +0 -1
- package/src/libs/HooksDeployment.sol +13 -65
- package/src/libs/MarketConstants.sol +10 -12
- package/src/libs/V4Liquidity.sol +30 -0
- package/src/version/ContractVersionBase.sol +1 -1
- package/test/CoinUniV4.t.sol +33 -30
- package/test/ContentCoinRewards.t.sol +320 -0
- package/test/CreatorCoin.t.sol +1 -1
- package/test/CreatorCoinRewards.t.sol +375 -0
- package/test/DeploymentHooks.t.sol +10 -10
- package/test/Factory.t.sol +24 -7
- package/test/HooksDeployment.t.sol +4 -4
- package/test/LiquidityMigration.t.sol +4 -9
- package/test/Upgrades.t.sol +44 -48
- package/test/ZoraHookRegistry.t.sol +266 -0
- package/test/utils/BaseTest.sol +25 -42
- package/test/utils/FeeEstimatorHook.sol +4 -6
- package/test/utils/RewardTestHelpers.sol +106 -0
- package/.turbo/turbo-build.log +0 -199
- package/abis/AutoSwapperTest.json +0 -618
- package/abis/BadImpl.json +0 -15
- package/abis/BaseZoraV4CoinHook.json +0 -1664
- package/abis/CoinTest.json +0 -819
- package/abis/CoinUniV4Test.json +0 -1128
- package/abis/ContentCoinHook.json +0 -1733
- package/abis/CreatorCoinTest.json +0 -887
- package/abis/Deploy.json +0 -9
- package/abis/DeployHooks.json +0 -9
- package/abis/DeployScript.json +0 -35
- package/abis/DeployedCoinVersionLookupTest.json +0 -740
- package/abis/DifferentNamespaceVersionLookup.json +0 -39
- package/abis/FactoryTest.json +0 -748
- package/abis/FakeHookNoInterface.json +0 -21
- package/abis/GenerateDeterministicParams.json +0 -9
- package/abis/HooksDeploymentTest.json +0 -645
- package/abis/HooksTest.json +0 -709
- package/abis/InvalidLiquidityMigrationReceiver.json +0 -21
- package/abis/LiquidityMigrationReceiver.json +0 -103
- package/abis/LiquidityMigrationTest.json +0 -889
- package/abis/MockBadFactory.json +0 -15
- package/abis/MultiOwnableTest.json +0 -766
- package/abis/PrintUpgradeCommand.json +0 -9
- package/abis/TestDeployedCoinVersionLookupImplementation.json +0 -39
- package/abis/TestV4Swap.json +0 -9
- package/abis/UpgradeFactoryImpl.json +0 -9
- package/abis/UpgradeHooks.json +0 -35
- package/abis/UpgradesTest.json +0 -723
- package/src/hooks/ContentCoinHook.sol +0 -27
- package/src/hooks/CreatorCoinHook.sol +0 -27
- package/src/libs/CreatorCoinRewards.sol +0 -34
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.13;
|
|
3
|
+
|
|
4
|
+
import "./utils/BaseTest.sol";
|
|
5
|
+
import {console} from "forge-std/console.sol";
|
|
6
|
+
|
|
7
|
+
import {CoinRewardsV4} from "../src/libs/CoinRewardsV4.sol";
|
|
8
|
+
import {IHasRewardsRecipients} from "../src/interfaces/IHasRewardsRecipients.sol";
|
|
9
|
+
import {UniV4SwapHelper} from "../src/libs/UniV4SwapHelper.sol";
|
|
10
|
+
import {FeeEstimatorHook} from "./utils/FeeEstimatorHook.sol";
|
|
11
|
+
import {RewardTestHelpers, RewardBalances} from "./utils/RewardTestHelpers.sol";
|
|
12
|
+
import {CoinConstants} from "../src/libs/CoinConstants.sol";
|
|
13
|
+
import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
|
|
14
|
+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
15
|
+
|
|
16
|
+
contract ContentCoinRewardsTest is BaseTest {
|
|
17
|
+
ContentCoin internal contentCoin;
|
|
18
|
+
CreatorCoin internal backingCreatorCoin;
|
|
19
|
+
|
|
20
|
+
address internal platformReferrer;
|
|
21
|
+
address internal tradeReferrer;
|
|
22
|
+
|
|
23
|
+
function setUp() public override {
|
|
24
|
+
super.setUpWithBlockNumber(30267794);
|
|
25
|
+
|
|
26
|
+
deal(address(zoraToken), address(poolManager), 1_000_000_000e18);
|
|
27
|
+
|
|
28
|
+
backingCreatorCoin = CreatorCoin(_deployCreatorCoin());
|
|
29
|
+
|
|
30
|
+
vm.label(address(backingCreatorCoin), "BACKING_CREATOR_COIN");
|
|
31
|
+
|
|
32
|
+
// Set up referrer addresses for all tests
|
|
33
|
+
platformReferrer = makeAddr("platformReferrer");
|
|
34
|
+
tradeReferrer = makeAddr("tradeReferrer");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Generic function to record token balances for all reward recipients
|
|
38
|
+
function _recordBalances(IERC20 token) internal view returns (RewardBalances memory balances) {
|
|
39
|
+
balances.creator = token.balanceOf(users.creator);
|
|
40
|
+
balances.platformReferrer = token.balanceOf(platformReferrer);
|
|
41
|
+
balances.tradeReferrer = token.balanceOf(tradeReferrer);
|
|
42
|
+
balances.protocol = token.balanceOf(contentCoin.protocolRewardRecipient());
|
|
43
|
+
balances.doppler = token.balanceOf(contentCoin.dopplerFeeRecipient());
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Helper function to record initial ZORA token balances for all reward recipients
|
|
47
|
+
function _recordZoraBalances() internal view returns (RewardBalances memory balances) {
|
|
48
|
+
return _recordBalances(zoraToken);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Helper function to calculate ZORA token reward deltas after trade
|
|
52
|
+
function _calculateZoraRewardDeltas(RewardBalances memory initialBalances) internal view returns (RewardBalances memory deltas) {
|
|
53
|
+
deltas.creator = zoraToken.balanceOf(users.creator) - initialBalances.creator;
|
|
54
|
+
deltas.platformReferrer = zoraToken.balanceOf(platformReferrer) - initialBalances.platformReferrer;
|
|
55
|
+
deltas.tradeReferrer = zoraToken.balanceOf(tradeReferrer) - initialBalances.tradeReferrer;
|
|
56
|
+
deltas.protocol = zoraToken.balanceOf(contentCoin.protocolRewardRecipient()) - initialBalances.protocol;
|
|
57
|
+
deltas.doppler = zoraToken.balanceOf(contentCoin.dopplerFeeRecipient()) - initialBalances.doppler;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/// @dev Estimates the fees from a swap
|
|
61
|
+
function _estimateLpFees(bytes memory commands, bytes[] memory inputs) internal returns (FeeEstimatorHook.FeeEstimatorState memory feeState) {
|
|
62
|
+
uint256 snapshot = vm.snapshot();
|
|
63
|
+
_deployFeeEstimatorHook(address(hook));
|
|
64
|
+
|
|
65
|
+
// Execute the swap
|
|
66
|
+
uint256 deadline = block.timestamp + 20;
|
|
67
|
+
router.execute(commands, inputs, deadline);
|
|
68
|
+
|
|
69
|
+
feeState = FeeEstimatorHook(payable(address(hook))).getFeeState();
|
|
70
|
+
|
|
71
|
+
vm.revertToState(snapshot);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Helper function to buy content coin
|
|
75
|
+
function _buyContentCoin(address currencyIn, uint128 amountIn, bool hasTradeReferrer) internal returns (uint256 feeCurrency) {
|
|
76
|
+
vm.warp(block.timestamp + 1 days);
|
|
77
|
+
|
|
78
|
+
vm.startPrank(users.buyer);
|
|
79
|
+
UniV4SwapHelper.approveTokenWithPermit2(permit2, address(router), currencyIn, uint128(amountIn), uint48(block.timestamp + 1 days));
|
|
80
|
+
|
|
81
|
+
// Build hook data with trade referrer if provided
|
|
82
|
+
bytes memory hookData = hasTradeReferrer ? abi.encode(tradeReferrer) : bytes("");
|
|
83
|
+
|
|
84
|
+
(bytes memory commands, bytes[] memory inputs) = UniV4SwapHelper.buildExactInputSingleSwapCommand(
|
|
85
|
+
currencyIn,
|
|
86
|
+
uint128(amountIn),
|
|
87
|
+
address(contentCoin),
|
|
88
|
+
0,
|
|
89
|
+
contentCoin.getPoolKey(),
|
|
90
|
+
hookData
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
// Estimate the total fees before executing
|
|
94
|
+
FeeEstimatorHook.FeeEstimatorState memory feeState = _estimateLpFees(commands, inputs);
|
|
95
|
+
feeCurrency = feeState.afterSwapCurrencyAmount;
|
|
96
|
+
|
|
97
|
+
router.execute(commands, inputs, block.timestamp + 1 days);
|
|
98
|
+
vm.stopPrank();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Helper function to deploy content coin backed by creator coin
|
|
102
|
+
function _deployContentCoin(bool hasPlatformReferrer) internal {
|
|
103
|
+
// Then deploy content coin backed by the creator coin
|
|
104
|
+
bytes memory poolConfig = _defaultPoolConfig(address(backingCreatorCoin));
|
|
105
|
+
|
|
106
|
+
// Generate unique salt
|
|
107
|
+
bytes32 uniqueSalt = keccak256(abi.encodePacked("content", address(backingCreatorCoin), block.timestamp, gasleft()));
|
|
108
|
+
|
|
109
|
+
vm.prank(users.creator);
|
|
110
|
+
(address contentCoinAddress, ) = factory.deploy(
|
|
111
|
+
users.creator,
|
|
112
|
+
_getDefaultOwners(),
|
|
113
|
+
"https://content.com",
|
|
114
|
+
"ContentCoin",
|
|
115
|
+
"CONTENT",
|
|
116
|
+
poolConfig,
|
|
117
|
+
hasPlatformReferrer ? platformReferrer : address(0),
|
|
118
|
+
address(0), // postDeployHook
|
|
119
|
+
bytes(""), // postDeployHookData
|
|
120
|
+
uniqueSalt
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
contentCoin = ContentCoin(contentCoinAddress);
|
|
124
|
+
vm.label(address(contentCoin), "TEST_CONTENT_COIN");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Helper function to deploy creator coin (backing for content coin)
|
|
128
|
+
function _deployCreatorCoin() internal returns (address) {
|
|
129
|
+
// Use the same multi-curve config as CreatorCoinRewards.t.sol
|
|
130
|
+
int24[] memory tickLower = new int24[](1);
|
|
131
|
+
int24[] memory tickUpper = new int24[](1);
|
|
132
|
+
uint16[] memory numDiscoveryPositions = new uint16[](1);
|
|
133
|
+
uint256[] memory maxDiscoverySupplyShare = new uint256[](1);
|
|
134
|
+
|
|
135
|
+
tickLower[0] = -138_000;
|
|
136
|
+
tickUpper[0] = 81_000;
|
|
137
|
+
numDiscoveryPositions[0] = 11;
|
|
138
|
+
maxDiscoverySupplyShare[0] = 0.25e18;
|
|
139
|
+
|
|
140
|
+
bytes memory poolConfig = abi.encode(
|
|
141
|
+
CoinConfigurationVersions.DOPPLER_MULTICURVE_UNI_V4_POOL_VERSION,
|
|
142
|
+
address(zoraToken),
|
|
143
|
+
tickLower,
|
|
144
|
+
tickUpper,
|
|
145
|
+
numDiscoveryPositions,
|
|
146
|
+
maxDiscoverySupplyShare
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
// Generate unique salt
|
|
150
|
+
bytes32 uniqueSalt = keccak256(abi.encodePacked("creator", block.timestamp, gasleft()));
|
|
151
|
+
|
|
152
|
+
vm.prank(users.creator);
|
|
153
|
+
address creatorCoinAddress = factory.deployCreatorCoin(
|
|
154
|
+
users.creator,
|
|
155
|
+
_getDefaultOwners(),
|
|
156
|
+
"https://creator.com",
|
|
157
|
+
"CreatorCoin",
|
|
158
|
+
"CREATOR",
|
|
159
|
+
poolConfig,
|
|
160
|
+
address(0),
|
|
161
|
+
uniqueSalt
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
return creatorCoinAddress;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/// @notice Test that fee estimation matches actual reward distribution
|
|
168
|
+
function test_estimateAfterSwapCurrencyAmount() public {
|
|
169
|
+
// Deploy content coin backed by creator coin
|
|
170
|
+
_deployContentCoin(true);
|
|
171
|
+
|
|
172
|
+
uint128 tradeAmount = 1000 ether;
|
|
173
|
+
|
|
174
|
+
// First, get trader some backing creator coins
|
|
175
|
+
address trader = users.buyer;
|
|
176
|
+
deal(address(zoraToken), trader, tradeAmount * 2);
|
|
177
|
+
_swapSomeCurrencyForCoin(ICoin(address(backingCreatorCoin)), address(zoraToken), tradeAmount, trader);
|
|
178
|
+
|
|
179
|
+
// Record initial balances
|
|
180
|
+
RewardBalances memory initialBalances = _recordZoraBalances();
|
|
181
|
+
|
|
182
|
+
// Build swap command: Creator Coin -> Content Coin
|
|
183
|
+
uint128 backingBalance = uint128(backingCreatorCoin.balanceOf(trader));
|
|
184
|
+
|
|
185
|
+
vm.startPrank(trader);
|
|
186
|
+
UniV4SwapHelper.approveTokenWithPermit2(permit2, address(router), address(backingCreatorCoin), backingBalance, uint48(block.timestamp + 1 days));
|
|
187
|
+
|
|
188
|
+
(bytes memory commands, bytes[] memory inputs) = UniV4SwapHelper.buildExactInputSingleSwapCommand(
|
|
189
|
+
address(backingCreatorCoin),
|
|
190
|
+
backingBalance,
|
|
191
|
+
address(contentCoin),
|
|
192
|
+
0,
|
|
193
|
+
contentCoin.getPoolKey(),
|
|
194
|
+
bytes("") // No trade referrer
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
// Estimate fees using the same pattern as CoinUniV4.t.sol
|
|
198
|
+
FeeEstimatorHook.FeeEstimatorState memory feeState = _estimateLpFees(commands, inputs);
|
|
199
|
+
|
|
200
|
+
// Execute actual swap
|
|
201
|
+
router.execute(commands, inputs, block.timestamp + 20);
|
|
202
|
+
vm.stopPrank();
|
|
203
|
+
|
|
204
|
+
// Calculate actual total rewards distributed
|
|
205
|
+
RewardBalances memory finalRewards = _calculateZoraRewardDeltas(initialBalances);
|
|
206
|
+
uint256 totalActualRewards = RewardTestHelpers.getTotalRewards(finalRewards);
|
|
207
|
+
|
|
208
|
+
// Verify that total actual rewards match the estimated afterSwapCurrencyAmount
|
|
209
|
+
assertApproxEqRel(totalActualRewards, feeState.afterSwapCurrencyAmount, 0.25e18, "Total rewards should match estimated afterSwapCurrencyAmount");
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/// @notice Test reward distribution with creator referrer only (no trade referrer, no platform referrer)
|
|
213
|
+
function test_rewards_creator_referrer_only() public {
|
|
214
|
+
// Deploy content coin backed by creator coin with creator referrer (inherits creator referrer)
|
|
215
|
+
_deployContentCoin(true);
|
|
216
|
+
|
|
217
|
+
uint128 tradeAmount = 1000 ether; // 1000 ZORA tokens
|
|
218
|
+
|
|
219
|
+
// First, trader needs to get some backing creator coins to trade for content coin
|
|
220
|
+
address trader = users.buyer;
|
|
221
|
+
deal(address(zoraToken), trader, tradeAmount * 2); // Give extra for initial swap
|
|
222
|
+
|
|
223
|
+
// Step 1: Swap ZORA for backing creator coin
|
|
224
|
+
_swapSomeCurrencyForCoin(ICoin(address(backingCreatorCoin)), address(zoraToken), tradeAmount, trader);
|
|
225
|
+
|
|
226
|
+
// Step 2: Record balances before content coin trade and perform the actual test trade
|
|
227
|
+
RewardBalances memory initialBalances = _recordZoraBalances();
|
|
228
|
+
|
|
229
|
+
// Swap backing creator coin for content coin
|
|
230
|
+
uint128 backingBalance = uint128(backingCreatorCoin.balanceOf(trader));
|
|
231
|
+
uint256 rewardsAmount = _buyContentCoin(address(backingCreatorCoin), backingBalance, false);
|
|
232
|
+
|
|
233
|
+
RewardBalances memory rewards = _calculateZoraRewardDeltas(initialBalances);
|
|
234
|
+
|
|
235
|
+
// Calculate expected rewards based on actual reward deltas (like creator coin tests do)
|
|
236
|
+
uint256 totalRewards = rewardsAmount;
|
|
237
|
+
RewardBalances memory expected = RewardTestHelpers.calculateExpectedRewards(totalRewards, true, false);
|
|
238
|
+
RewardTestHelpers.assertRewardsApproxEqRelWithTolerance(rewards, expected, 0.25e18);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/// @notice Test reward distribution with trade referrer only (no creator referrer, no platform referrer)
|
|
242
|
+
function test_rewards_trade_referrer_only() public {
|
|
243
|
+
_deployContentCoin(false); // Deploy without platform referrer
|
|
244
|
+
|
|
245
|
+
uint128 tradeAmount = 1000 ether;
|
|
246
|
+
address trader = users.buyer;
|
|
247
|
+
deal(address(zoraToken), trader, tradeAmount * 2);
|
|
248
|
+
|
|
249
|
+
// Step 1: Get backing creator coins
|
|
250
|
+
_swapSomeCurrencyForCoin(ICoin(address(backingCreatorCoin)), address(zoraToken), tradeAmount, trader);
|
|
251
|
+
|
|
252
|
+
// Step 2: Test content coin trade
|
|
253
|
+
RewardBalances memory initialBalances = _recordZoraBalances();
|
|
254
|
+
uint128 backingBalance = uint128(backingCreatorCoin.balanceOf(trader));
|
|
255
|
+
uint256 rewardsAmount = _buyContentCoin(address(backingCreatorCoin), backingBalance, true);
|
|
256
|
+
RewardBalances memory rewards = _calculateZoraRewardDeltas(initialBalances);
|
|
257
|
+
|
|
258
|
+
// Step 3: Validate rewards
|
|
259
|
+
RewardBalances memory expected = RewardTestHelpers.calculateExpectedRewards(rewardsAmount, false, true);
|
|
260
|
+
RewardTestHelpers.assertRewardsApproxEqRelWithTolerance(rewards, expected, 0.25e18);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/// @notice Test reward distribution with creator referrer + trade referrer (no platform referrer)
|
|
264
|
+
function test_rewards_platform_and_trade_referrers() public {
|
|
265
|
+
_deployContentCoin(true); // Deploy with platform referrer
|
|
266
|
+
|
|
267
|
+
uint128 tradeAmount = 1000 ether;
|
|
268
|
+
address trader = users.buyer;
|
|
269
|
+
deal(address(zoraToken), trader, tradeAmount * 2);
|
|
270
|
+
|
|
271
|
+
// Step 1: Get backing creator coins
|
|
272
|
+
_swapSomeCurrencyForCoin(ICoin(address(backingCreatorCoin)), address(zoraToken), tradeAmount, trader);
|
|
273
|
+
|
|
274
|
+
// Step 2: Test content coin trade
|
|
275
|
+
RewardBalances memory initialBalances = _recordZoraBalances();
|
|
276
|
+
uint128 backingBalance = uint128(backingCreatorCoin.balanceOf(trader));
|
|
277
|
+
uint256 rewardsAmount = _buyContentCoin(address(backingCreatorCoin), backingBalance, true);
|
|
278
|
+
RewardBalances memory rewards = _calculateZoraRewardDeltas(initialBalances);
|
|
279
|
+
|
|
280
|
+
// Step 3: Validate rewards
|
|
281
|
+
RewardBalances memory expected = RewardTestHelpers.calculateExpectedRewards(rewardsAmount, true, true);
|
|
282
|
+
console.log("protocol rewards", rewards.protocol);
|
|
283
|
+
console.log("expected protocol rewards", expected.protocol);
|
|
284
|
+
RewardTestHelpers.assertRewardsApproxEqRelWithTolerance(rewards, expected, 0.25e18);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/// @notice Test reward distribution with no referrers (all address(0))
|
|
288
|
+
function test_rewards_no_referrers() public {
|
|
289
|
+
_deployContentCoin(false); // Deploy without platform referrer
|
|
290
|
+
|
|
291
|
+
uint128 tradeAmount = 1000 ether;
|
|
292
|
+
address trader = users.buyer;
|
|
293
|
+
deal(address(zoraToken), trader, tradeAmount * 2);
|
|
294
|
+
|
|
295
|
+
// Step 1: Get backing creator coins
|
|
296
|
+
_swapSomeCurrencyForCoin(ICoin(address(backingCreatorCoin)), address(zoraToken), tradeAmount, trader);
|
|
297
|
+
|
|
298
|
+
// Step 2: Test content coin trade
|
|
299
|
+
RewardBalances memory initialBalances = _recordZoraBalances();
|
|
300
|
+
uint128 backingBalance = uint128(backingCreatorCoin.balanceOf(trader));
|
|
301
|
+
uint256 rewardsAmount = _buyContentCoin(address(backingCreatorCoin), backingBalance, false);
|
|
302
|
+
RewardBalances memory rewards = _calculateZoraRewardDeltas(initialBalances);
|
|
303
|
+
|
|
304
|
+
// Step 3: Validate rewards
|
|
305
|
+
RewardBalances memory expected = RewardTestHelpers.calculateExpectedRewards(rewardsAmount, false, false);
|
|
306
|
+
RewardTestHelpers.assertRewardsApproxEqRelWithTolerance(rewards, expected, 0.25e18);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function test_isNotLegacyCreatorCoinCategorization() public {
|
|
310
|
+
vm.createSelectFork("base", 31835069);
|
|
311
|
+
|
|
312
|
+
// Use the same content coin from the upgrades test
|
|
313
|
+
address contentCoinAddress = 0x4E93A01c90f812284F71291a8d1415a904957156;
|
|
314
|
+
|
|
315
|
+
// Test that the content coin is NOT categorized as a legacy creator coin
|
|
316
|
+
bool isLegacy = CoinRewardsV4.isLegacyCreatorCoin(IHasRewardsRecipients(contentCoinAddress));
|
|
317
|
+
|
|
318
|
+
assertFalse(isLegacy, "Content coin should NOT be categorized as legacy creator coin");
|
|
319
|
+
}
|
|
320
|
+
}
|
package/test/CreatorCoin.t.sol
CHANGED
|
@@ -69,7 +69,7 @@ contract CreatorCoinTest is BaseTest {
|
|
|
69
69
|
assertEq(creatorCoin.totalSupply(), CreatorCoinConstants.TOTAL_SUPPLY);
|
|
70
70
|
|
|
71
71
|
assertEq(creatorCoin.balanceOf(address(creatorCoin)), CreatorCoinConstants.CREATOR_VESTING_SUPPLY);
|
|
72
|
-
assertEq(creatorCoin.balanceOf(address(creatorCoin.poolManager())),
|
|
72
|
+
assertEq(creatorCoin.balanceOf(address(creatorCoin.poolManager())), MarketConstants.CREATOR_COIN_MARKET_SUPPLY);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
function test_deploy_creator_coin_with_invalid_currency_reverts() public {
|