@ballkidz/defifa 0.0.6 → 0.0.8
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/ADMINISTRATION.md +3 -3
- package/AUDIT_INSTRUCTIONS.md +422 -0
- package/CRYPTO_ECON.md +5 -5
- package/RISKS.md +38 -335
- package/SKILLS.md +1 -1
- package/STYLE_GUIDE.md +14 -1
- package/USER_JOURNEYS.md +691 -0
- package/package.json +7 -5
- package/script/Deploy.s.sol +26 -13
- package/script/helpers/DefifaDeploymentLib.sol +30 -14
- package/src/DefifaDeployer.sol +225 -187
- package/src/DefifaGovernor.sol +291 -281
- package/src/DefifaHook.sol +81 -42
- package/src/DefifaProjectOwner.sol +27 -4
- package/src/DefifaTokenUriResolver.sol +137 -134
- package/src/enums/DefifaGamePhase.sol +1 -1
- package/src/enums/DefifaScorecardState.sol +1 -1
- package/src/interfaces/IDefifaDeployer.sol +52 -50
- package/src/interfaces/IDefifaGamePhaseReporter.sol +2 -2
- package/src/interfaces/IDefifaGamePotReporter.sol +1 -1
- package/src/interfaces/IDefifaGovernor.sol +53 -54
- package/src/interfaces/IDefifaHook.sol +104 -103
- package/src/interfaces/IDefifaTokenUriResolver.sol +2 -2
- package/src/libraries/DefifaFontImporter.sol +11 -9
- package/src/libraries/DefifaHookLib.sol +68 -53
- package/src/structs/DefifaAttestations.sol +1 -1
- package/src/structs/DefifaDelegation.sol +1 -1
- package/src/structs/DefifaLaunchProjectData.sol +4 -4
- package/src/structs/DefifaOpsData.sol +1 -1
- package/src/structs/DefifaScorecard.sol +1 -1
- package/src/structs/DefifaTierCashOutWeight.sol +1 -1
- package/src/structs/DefifaTierParams.sol +2 -1
- package/test/DefifaAdversarialQuorum.t.sol +602 -0
- package/test/DefifaAuditLowGuards.t.sol +304 -0
- package/test/DefifaFeeAccounting.t.sol +37 -16
- package/test/DefifaGovernor.t.sol +37 -11
- package/test/DefifaHookRegressions.t.sol +14 -12
- package/test/DefifaMintCostInvariant.t.sol +31 -12
- package/test/DefifaNoContest.t.sol +33 -13
- package/test/DefifaSecurity.t.sol +45 -25
- package/test/DefifaUSDC.t.sol +44 -34
- package/test/Fork.t.sol +42 -40
- package/test/SVG.t.sol +2 -2
- package/test/TestAuditGaps.sol +982 -0
- package/test/TestQALastMile.t.sol +511 -0
- package/test/regression/FulfillmentBlocksRatification.t.sol +36 -30
- package/test/regression/GracePeriodBypass.t.sol +15 -10
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
// SPDX-License-Identifier: UNLICENSED
|
|
2
|
+
pragma solidity 0.8.26;
|
|
3
|
+
|
|
4
|
+
import {TestBaseWorkflow} from "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
|
|
5
|
+
|
|
6
|
+
import {DefifaGovernor} from "../src/DefifaGovernor.sol";
|
|
7
|
+
import {DefifaDeployer} from "../src/DefifaDeployer.sol";
|
|
8
|
+
import {DefifaHook} from "../src/DefifaHook.sol";
|
|
9
|
+
import {DefifaTokenUriResolver} from "../src/DefifaTokenUriResolver.sol";
|
|
10
|
+
import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
|
|
11
|
+
|
|
12
|
+
import {JBTest} from "@bananapus/core-v6/test/helpers/JBTest.sol";
|
|
13
|
+
import {JBRulesetMetadataResolver} from "@bananapus/core-v6/src/libraries/JBRulesetMetadataResolver.sol";
|
|
14
|
+
import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
15
|
+
import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
|
|
16
|
+
|
|
17
|
+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
18
|
+
import {ITypeface} from "lib/typeface/contracts/interfaces/ITypeface.sol";
|
|
19
|
+
import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
|
|
20
|
+
import {DefifaDelegation} from "../src/structs/DefifaDelegation.sol";
|
|
21
|
+
import {DefifaLaunchProjectData} from "../src/structs/DefifaLaunchProjectData.sol";
|
|
22
|
+
import {DefifaTierParams} from "../src/structs/DefifaTierParams.sol";
|
|
23
|
+
import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
|
|
24
|
+
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
25
|
+
import {JBCurrencyIds} from "@bananapus/core-v6/src/libraries/JBCurrencyIds.sol";
|
|
26
|
+
import {JBFundAccessLimitGroup} from "@bananapus/core-v6/src/structs/JBFundAccessLimitGroup.sol";
|
|
27
|
+
import {JBRulesetConfig, JBTerminalConfig} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
28
|
+
import {JBRulesetMetadata} from "@bananapus/core-v6/src/structs/JBRulesetMetadata.sol";
|
|
29
|
+
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
30
|
+
import {JBSplitGroup} from "@bananapus/core-v6/src/structs/JBSplitGroup.sol";
|
|
31
|
+
import {IJBRulesetApprovalHook} from "@bananapus/core-v6/src/interfaces/IJBRulesets.sol";
|
|
32
|
+
|
|
33
|
+
/// @title DefifaAuditLowGuardsTest
|
|
34
|
+
/// @notice Tests for validation guards added in the audit/low-findings branch:
|
|
35
|
+
/// - DefifaGovernor_AlreadyInitialized (re-initialization guard)
|
|
36
|
+
/// - uint48 overflow checks on attestationStartTime and attestationGracePeriod
|
|
37
|
+
/// - DefifaHook_DelegateAddressZero (address(0) delegation guard)
|
|
38
|
+
contract DefifaAuditLowGuardsTest is JBTest, TestBaseWorkflow {
|
|
39
|
+
using JBRulesetMetadataResolver for JBRuleset;
|
|
40
|
+
|
|
41
|
+
address _protocolFeeProjectTokenAccount;
|
|
42
|
+
address _defifaProjectTokenAccount;
|
|
43
|
+
uint256 _protocolFeeProjectId;
|
|
44
|
+
uint256 _defifaProjectId;
|
|
45
|
+
uint256 _gameId = 3;
|
|
46
|
+
|
|
47
|
+
DefifaDeployer deployer;
|
|
48
|
+
DefifaHook hook;
|
|
49
|
+
DefifaGovernor governor;
|
|
50
|
+
address projectOwner = address(bytes20(keccak256("projectOwner")));
|
|
51
|
+
|
|
52
|
+
// Shared test state (set by _setupGame)
|
|
53
|
+
uint256 _pid;
|
|
54
|
+
DefifaHook _nft;
|
|
55
|
+
DefifaGovernor _gov;
|
|
56
|
+
address[] _users;
|
|
57
|
+
|
|
58
|
+
function setUp() public virtual override {
|
|
59
|
+
super.setUp();
|
|
60
|
+
|
|
61
|
+
JBAccountingContext[] memory _tokens = new JBAccountingContext[](1);
|
|
62
|
+
_tokens[0] = JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: JBCurrencyIds.ETH});
|
|
63
|
+
JBTerminalConfig[] memory tc = new JBTerminalConfig[](1);
|
|
64
|
+
tc[0] = JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: _tokens});
|
|
65
|
+
JBRulesetConfig[] memory rc = new JBRulesetConfig[](1);
|
|
66
|
+
rc[0] = JBRulesetConfig({
|
|
67
|
+
mustStartAtOrAfter: 0,
|
|
68
|
+
duration: 10 days,
|
|
69
|
+
weight: 1e18,
|
|
70
|
+
weightCutPercent: 0,
|
|
71
|
+
approvalHook: IJBRulesetApprovalHook(address(0)),
|
|
72
|
+
metadata: JBRulesetMetadata({
|
|
73
|
+
reservedPercent: 0,
|
|
74
|
+
cashOutTaxRate: 0,
|
|
75
|
+
baseCurrency: JBCurrencyIds.ETH,
|
|
76
|
+
pausePay: false,
|
|
77
|
+
pauseCreditTransfers: false,
|
|
78
|
+
allowOwnerMinting: false,
|
|
79
|
+
allowSetCustomToken: false,
|
|
80
|
+
allowTerminalMigration: false,
|
|
81
|
+
allowSetTerminals: false,
|
|
82
|
+
allowSetController: false,
|
|
83
|
+
allowAddAccountingContext: false,
|
|
84
|
+
allowAddPriceFeed: false,
|
|
85
|
+
ownerMustSendPayouts: false,
|
|
86
|
+
holdFees: false,
|
|
87
|
+
useTotalSurplusForCashOuts: false,
|
|
88
|
+
useDataHookForPay: true,
|
|
89
|
+
useDataHookForCashOut: true,
|
|
90
|
+
dataHook: address(0),
|
|
91
|
+
metadata: 0
|
|
92
|
+
}),
|
|
93
|
+
splitGroups: new JBSplitGroup[](0),
|
|
94
|
+
fundAccessLimitGroups: new JBFundAccessLimitGroup[](0)
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
_protocolFeeProjectId = jbController().launchProjectFor(projectOwner, "", rc, tc, "");
|
|
98
|
+
vm.prank(projectOwner);
|
|
99
|
+
_protocolFeeProjectTokenAccount =
|
|
100
|
+
address(jbController().deployERC20For(_protocolFeeProjectId, "Bananapus", "NANA", bytes32(0)));
|
|
101
|
+
_defifaProjectId = jbController().launchProjectFor(projectOwner, "", rc, tc, "");
|
|
102
|
+
vm.prank(projectOwner);
|
|
103
|
+
_defifaProjectTokenAccount =
|
|
104
|
+
address(jbController().deployERC20For(_defifaProjectId, "Defifa", "DEFIFA", bytes32(0)));
|
|
105
|
+
|
|
106
|
+
hook =
|
|
107
|
+
new DefifaHook(jbDirectory(), IERC20(_defifaProjectTokenAccount), IERC20(_protocolFeeProjectTokenAccount));
|
|
108
|
+
governor = new DefifaGovernor(jbController(), address(this));
|
|
109
|
+
deployer = new DefifaDeployer(
|
|
110
|
+
address(hook),
|
|
111
|
+
new DefifaTokenUriResolver(ITypeface(address(0))),
|
|
112
|
+
governor,
|
|
113
|
+
jbController(),
|
|
114
|
+
new JBAddressRegistry(),
|
|
115
|
+
_protocolFeeProjectId,
|
|
116
|
+
_defifaProjectId
|
|
117
|
+
);
|
|
118
|
+
hook.transferOwnership(address(deployer));
|
|
119
|
+
governor.transferOwnership(address(deployer));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// =========================================================================
|
|
123
|
+
// 1. DefifaGovernor_AlreadyInitialized: re-initialization blocked
|
|
124
|
+
// =========================================================================
|
|
125
|
+
function testRevert_initializeGame_alreadyInitialized() external {
|
|
126
|
+
// Deploy a standalone governor where this test contract is the owner, so we can call initializeGame directly.
|
|
127
|
+
DefifaGovernor _standaloneGov = new DefifaGovernor(jbController(), address(this));
|
|
128
|
+
|
|
129
|
+
// First initialization should succeed.
|
|
130
|
+
uint256 gameId = 42;
|
|
131
|
+
_standaloneGov.initializeGame({
|
|
132
|
+
gameId: gameId, attestationStartTime: block.timestamp, attestationGracePeriod: 2 days
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Second initialization for the same gameId should revert.
|
|
136
|
+
vm.expectRevert(DefifaGovernor.DefifaGovernor_AlreadyInitialized.selector);
|
|
137
|
+
_standaloneGov.initializeGame({
|
|
138
|
+
gameId: gameId, attestationStartTime: block.timestamp, attestationGracePeriod: 2 days
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// =========================================================================
|
|
143
|
+
// 1b. Re-initialization blocked even through the deployer (integration)
|
|
144
|
+
// =========================================================================
|
|
145
|
+
function testRevert_initializeGame_alreadyInitialized_viaDeployer() external {
|
|
146
|
+
// Launch a game (this calls initializeGame internally).
|
|
147
|
+
_setupGame(4, 1 ether);
|
|
148
|
+
|
|
149
|
+
// The governor is now owned by the deployer. Trying to initialize the same game again
|
|
150
|
+
// via the deployer is not possible because there is no public re-init path. But we
|
|
151
|
+
// verify the packed info is non-zero, confirming the guard would trigger.
|
|
152
|
+
assertTrue(_gov.attestationStartTimeOf(_gameId) > 0 || _gov.attestationGracePeriodOf(_gameId) > 0);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// =========================================================================
|
|
156
|
+
// 2. uint48 overflow on attestationStartTime
|
|
157
|
+
// =========================================================================
|
|
158
|
+
function testRevert_initializeGame_attestationStartTimeOverflow() external {
|
|
159
|
+
DefifaGovernor _standaloneGov = new DefifaGovernor(jbController(), address(this));
|
|
160
|
+
|
|
161
|
+
// type(uint48).max + 1 should overflow the 48-bit packing.
|
|
162
|
+
uint256 overflowStartTime = uint256(type(uint48).max) + 1;
|
|
163
|
+
|
|
164
|
+
vm.expectRevert(DefifaGovernor.DefifaGovernor_Uint48Overflow.selector);
|
|
165
|
+
_standaloneGov.initializeGame({
|
|
166
|
+
gameId: 99, attestationStartTime: overflowStartTime, attestationGracePeriod: 2 days
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// =========================================================================
|
|
171
|
+
// 3. uint48 overflow on attestationGracePeriod
|
|
172
|
+
// =========================================================================
|
|
173
|
+
function testRevert_initializeGame_attestationGracePeriodOverflow() external {
|
|
174
|
+
DefifaGovernor _standaloneGov = new DefifaGovernor(jbController(), address(this));
|
|
175
|
+
|
|
176
|
+
// type(uint48).max + 1 should overflow the 48-bit packing.
|
|
177
|
+
uint256 overflowGracePeriod = uint256(type(uint48).max) + 1;
|
|
178
|
+
|
|
179
|
+
vm.expectRevert(DefifaGovernor.DefifaGovernor_Uint48Overflow.selector);
|
|
180
|
+
_standaloneGov.initializeGame({
|
|
181
|
+
gameId: 100, attestationStartTime: block.timestamp, attestationGracePeriod: overflowGracePeriod
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// =========================================================================
|
|
186
|
+
// 4. DefifaHook_DelegateAddressZero in setTierDelegateTo
|
|
187
|
+
// =========================================================================
|
|
188
|
+
function testRevert_setTierDelegateTo_zeroAddress() external {
|
|
189
|
+
_setupGame(4, 1 ether);
|
|
190
|
+
|
|
191
|
+
// _users[0] owns an NFT in tier 1 during the MINT phase.
|
|
192
|
+
vm.prank(_users[0]);
|
|
193
|
+
vm.expectRevert(DefifaHook.DefifaHook_DelegateAddressZero.selector);
|
|
194
|
+
_nft.setTierDelegateTo({delegatee: address(0), tierId: 1});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// =========================================================================
|
|
198
|
+
// 5. DefifaHook_DelegateAddressZero in setTierDelegatesTo (batch)
|
|
199
|
+
// =========================================================================
|
|
200
|
+
function testRevert_setTierDelegatesTo_zeroAddress() external {
|
|
201
|
+
_setupGame(4, 1 ether);
|
|
202
|
+
|
|
203
|
+
DefifaDelegation[] memory delegations = new DefifaDelegation[](1);
|
|
204
|
+
delegations[0] = DefifaDelegation({delegatee: address(0), tierId: 1});
|
|
205
|
+
|
|
206
|
+
vm.prank(_users[0]);
|
|
207
|
+
vm.expectRevert(DefifaHook.DefifaHook_DelegateAddressZero.selector);
|
|
208
|
+
_nft.setTierDelegatesTo(delegations);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// =========================================================================
|
|
212
|
+
// 5b. Batch delegation reverts on address(0) even in second element
|
|
213
|
+
// =========================================================================
|
|
214
|
+
function testRevert_setTierDelegatesTo_zeroAddress_secondElement() external {
|
|
215
|
+
_setupGame(4, 1 ether);
|
|
216
|
+
|
|
217
|
+
// First delegation is valid, second has address(0).
|
|
218
|
+
DefifaDelegation[] memory delegations = new DefifaDelegation[](2);
|
|
219
|
+
delegations[0] = DefifaDelegation({delegatee: _users[0], tierId: 1});
|
|
220
|
+
delegations[1] = DefifaDelegation({delegatee: address(0), tierId: 2});
|
|
221
|
+
|
|
222
|
+
vm.prank(_users[0]);
|
|
223
|
+
vm.expectRevert(DefifaHook.DefifaHook_DelegateAddressZero.selector);
|
|
224
|
+
_nft.setTierDelegatesTo(delegations);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// =========================================================================
|
|
228
|
+
// SETUP HELPERS (adapted from DefifaSecurity.t.sol)
|
|
229
|
+
// =========================================================================
|
|
230
|
+
|
|
231
|
+
function _setupGame(uint8 nTiers, uint256 tierPrice) internal {
|
|
232
|
+
DefifaLaunchProjectData memory d = _launchData(nTiers, tierPrice);
|
|
233
|
+
(_pid, _nft, _gov) = _launch(d);
|
|
234
|
+
vm.warp(d.start - d.mintPeriodDuration - d.refundPeriodDuration);
|
|
235
|
+
_users = new address[](nTiers);
|
|
236
|
+
for (uint256 i; i < nTiers; i++) {
|
|
237
|
+
_users[i] = _addr(i);
|
|
238
|
+
_mint(_users[i], i + 1, tierPrice);
|
|
239
|
+
vm.warp(block.timestamp + 1);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function _launchData(uint8 n, uint256 tierPrice) internal returns (DefifaLaunchProjectData memory) {
|
|
244
|
+
DefifaTierParams[] memory tp = new DefifaTierParams[](n);
|
|
245
|
+
for (uint256 i; i < n; i++) {
|
|
246
|
+
tp[i] = DefifaTierParams({
|
|
247
|
+
reservedRate: 1001,
|
|
248
|
+
reservedTokenBeneficiary: address(0),
|
|
249
|
+
encodedIPFSUri: bytes32(0),
|
|
250
|
+
shouldUseReservedTokenBeneficiaryAsDefault: false,
|
|
251
|
+
name: "DEFIFA"
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
return DefifaLaunchProjectData({
|
|
255
|
+
name: "DEFIFA",
|
|
256
|
+
projectUri: "",
|
|
257
|
+
contractUri: "",
|
|
258
|
+
baseUri: "",
|
|
259
|
+
token: JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: JBCurrencyIds.ETH}),
|
|
260
|
+
mintPeriodDuration: 1 days,
|
|
261
|
+
start: uint48(block.timestamp + 3 days),
|
|
262
|
+
refundPeriodDuration: 1 days,
|
|
263
|
+
store: new JB721TiersHookStore(),
|
|
264
|
+
splits: new JBSplit[](0),
|
|
265
|
+
attestationStartTime: 0,
|
|
266
|
+
attestationGracePeriod: 100_381,
|
|
267
|
+
defaultAttestationDelegate: address(0),
|
|
268
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
269
|
+
tierPrice: uint104(tierPrice),
|
|
270
|
+
tiers: tp,
|
|
271
|
+
defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
|
|
272
|
+
terminal: jbMultiTerminal(),
|
|
273
|
+
minParticipation: 0,
|
|
274
|
+
scorecardTimeout: 0
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function _launch(DefifaLaunchProjectData memory d) internal returns (uint256 p, DefifaHook n, DefifaGovernor g) {
|
|
279
|
+
g = governor;
|
|
280
|
+
p = deployer.launchGameWith(d);
|
|
281
|
+
JBRuleset memory fc = jbRulesets().currentOf(p);
|
|
282
|
+
if (fc.dataHook() == address(0)) (fc,) = jbRulesets().latestQueuedOf(p);
|
|
283
|
+
n = DefifaHook(fc.dataHook());
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function _addr(uint256 i) internal pure returns (address) {
|
|
287
|
+
return address(bytes20(keccak256(abi.encode("su", i))));
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function _mint(address user, uint256 tid, uint256 amt) internal {
|
|
291
|
+
vm.deal(user, amt);
|
|
292
|
+
uint16[] memory m = new uint16[](1);
|
|
293
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
294
|
+
m[0] = uint16(tid);
|
|
295
|
+
bytes[] memory data = new bytes[](1);
|
|
296
|
+
data[0] = abi.encode(user, m);
|
|
297
|
+
bytes4[] memory ids = new bytes4[](1);
|
|
298
|
+
ids[0] = metadataHelper().getId("pay", address(hook));
|
|
299
|
+
vm.prank(user);
|
|
300
|
+
jbMultiTerminal().pay{value: amt}(
|
|
301
|
+
_pid, JBConstants.NATIVE_TOKEN, amt, user, 0, "", metadataHelper().createMetadata(ids, data)
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
@@ -1,21 +1,38 @@
|
|
|
1
1
|
// SPDX-License-Identifier: UNLICENSED
|
|
2
2
|
pragma solidity 0.8.26;
|
|
3
3
|
|
|
4
|
-
import "
|
|
5
|
-
import "../src/
|
|
6
|
-
import "../src/
|
|
7
|
-
import "../src/
|
|
8
|
-
import "
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import {JBMetadataResolver} from "@bananapus/core-v6/src/libraries/JBMetadataResolver.sol";
|
|
12
|
-
import {MetadataResolverHelper} from "@bananapus/core-v6/test/helpers/MetadataResolverHelper.sol";
|
|
13
|
-
import "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
|
|
4
|
+
import {DefifaGovernor} from "../src/DefifaGovernor.sol";
|
|
5
|
+
import {DefifaDeployer} from "../src/DefifaDeployer.sol";
|
|
6
|
+
import {DefifaHook} from "../src/DefifaHook.sol";
|
|
7
|
+
import {DefifaTokenUriResolver} from "../src/DefifaTokenUriResolver.sol";
|
|
8
|
+
import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
|
|
9
|
+
|
|
10
|
+
import {TestBaseWorkflow} from "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
|
|
14
11
|
import {JBTest} from "@bananapus/core-v6/test/helpers/JBTest.sol";
|
|
15
|
-
import "@bananapus/core-v6/src/libraries/JBRulesetMetadataResolver.sol";
|
|
16
|
-
import "@bananapus/
|
|
17
|
-
|
|
12
|
+
import {JBRulesetMetadataResolver} from "@bananapus/core-v6/src/libraries/JBRulesetMetadataResolver.sol";
|
|
13
|
+
import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
14
|
+
|
|
15
|
+
import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
|
|
18
16
|
import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
|
|
17
|
+
import {DefifaLaunchProjectData} from "../src/structs/DefifaLaunchProjectData.sol";
|
|
18
|
+
import {DefifaTierParams} from "../src/structs/DefifaTierParams.sol";
|
|
19
|
+
import {DefifaTierCashOutWeight} from "../src/structs/DefifaTierCashOutWeight.sol";
|
|
20
|
+
import {DefifaDelegation} from "../src/structs/DefifaDelegation.sol";
|
|
21
|
+
import {IJBSplitHook} from "@bananapus/core-v6/src/interfaces/IJBSplitHook.sol";
|
|
22
|
+
import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
|
|
23
|
+
import {IJBRulesetApprovalHook} from "@bananapus/core-v6/src/interfaces/IJBRulesets.sol";
|
|
24
|
+
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
25
|
+
import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
|
|
26
|
+
import {JBRulesetMetadata} from "@bananapus/core-v6/src/structs/JBRulesetMetadata.sol";
|
|
27
|
+
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
28
|
+
import {JBSplitGroup} from "@bananapus/core-v6/src/structs/JBSplitGroup.sol";
|
|
29
|
+
import {JBFundAccessLimitGroup} from "@bananapus/core-v6/src/structs/JBFundAccessLimitGroup.sol";
|
|
30
|
+
import {JBRulesetConfig, JBTerminalConfig} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
31
|
+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
32
|
+
import {JBMultiTerminal} from "@bananapus/core-v6/src/JBMultiTerminal.sol";
|
|
33
|
+
import {JBPermissionsData} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
|
|
34
|
+
import {JBCurrencyIds} from "@bananapus/core-v6/src/libraries/JBCurrencyIds.sol";
|
|
35
|
+
import {ITypeface} from "lib/typeface/contracts/interfaces/ITypeface.sol";
|
|
19
36
|
|
|
20
37
|
/// @notice Tests for PR #22 (M-D8): fee accounting after removing duplicate nana fee.
|
|
21
38
|
/// Verifies that only the fee portion of the pot is sent as payouts during fulfillment,
|
|
@@ -92,10 +109,10 @@ contract DefifaFeeAccountingTest is JBTest, TestBaseWorkflow {
|
|
|
92
109
|
hook = new DefifaHook(jbDirectory(), IERC20(_defifaToken), IERC20(_nanaToken));
|
|
93
110
|
governor = new DefifaGovernor(jbController(), address(this));
|
|
94
111
|
JBAddressRegistry _registry = new JBAddressRegistry();
|
|
95
|
-
DefifaTokenUriResolver
|
|
112
|
+
DefifaTokenUriResolver _tokenUriResolver = new DefifaTokenUriResolver(ITypeface(address(0)));
|
|
96
113
|
deployer = new DefifaDeployer(
|
|
97
114
|
address(hook),
|
|
98
|
-
|
|
115
|
+
_tokenUriResolver,
|
|
99
116
|
governor,
|
|
100
117
|
jbController(),
|
|
101
118
|
_registry,
|
|
@@ -112,7 +129,10 @@ contract DefifaFeeAccountingTest is JBTest, TestBaseWorkflow {
|
|
|
112
129
|
.setPermissionsFor(
|
|
113
130
|
projectOwner,
|
|
114
131
|
JBPermissionsData({
|
|
115
|
-
operator: address(deployer),
|
|
132
|
+
operator: address(deployer),
|
|
133
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
134
|
+
projectId: uint64(_defifaProjectId),
|
|
135
|
+
permissionIds: permissionIds
|
|
116
136
|
})
|
|
117
137
|
);
|
|
118
138
|
|
|
@@ -476,6 +496,7 @@ contract DefifaFeeAccountingTest is JBTest, TestBaseWorkflow {
|
|
|
476
496
|
vm.deal(users[i], 1 ether);
|
|
477
497
|
|
|
478
498
|
uint16[] memory rawMetadata = new uint16[](1);
|
|
499
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
479
500
|
rawMetadata[0] = uint16(i + 1);
|
|
480
501
|
bytes memory metadata = _buildPayMetadata(abi.encode(users[i], rawMetadata));
|
|
481
502
|
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: UNLICENSED
|
|
2
2
|
pragma solidity 0.8.26;
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
import "forge-std/Test.sol";
|
|
6
|
-
// solhint-disable-next-line no-unused-import
|
|
7
|
-
import "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
|
|
4
|
+
import {TestBaseWorkflow} from "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
|
|
8
5
|
|
|
9
6
|
import {DefifaGovernor} from "../src/DefifaGovernor.sol";
|
|
10
7
|
import {DefifaDeployer} from "../src/DefifaDeployer.sol";
|
|
@@ -12,13 +9,9 @@ import {DefifaHook} from "../src/DefifaHook.sol";
|
|
|
12
9
|
import {DefifaTokenUriResolver} from "../src/DefifaTokenUriResolver.sol";
|
|
13
10
|
import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
|
|
14
11
|
|
|
15
|
-
import {JBMetadataResolver} from "@bananapus/core-v6/src/libraries/JBMetadataResolver.sol";
|
|
16
|
-
import {MetadataResolverHelper} from "@bananapus/core-v6/test/helpers/MetadataResolverHelper.sol";
|
|
17
12
|
import {JBTest} from "@bananapus/core-v6/test/helpers/JBTest.sol";
|
|
18
13
|
import {JBRulesetMetadataResolver} from "@bananapus/core-v6/src/libraries/JBRulesetMetadataResolver.sol";
|
|
19
|
-
import {
|
|
20
|
-
JB721TiersRulesetMetadataResolver
|
|
21
|
-
} from "@bananapus/721-hook-v6/src/libraries/JB721TiersRulesetMetadataResolver.sol";
|
|
14
|
+
import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
22
15
|
import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
|
|
23
16
|
|
|
24
17
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
@@ -30,6 +23,17 @@ import {DefifaDelegation} from "../src/structs/DefifaDelegation.sol";
|
|
|
30
23
|
import {DefifaLaunchProjectData} from "../src/structs/DefifaLaunchProjectData.sol";
|
|
31
24
|
import {DefifaTierParams} from "../src/structs/DefifaTierParams.sol";
|
|
32
25
|
import {DefifaTierCashOutWeight} from "../src/structs/DefifaTierCashOutWeight.sol";
|
|
26
|
+
import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
|
|
27
|
+
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
28
|
+
import {JBCurrencyIds} from "@bananapus/core-v6/src/libraries/JBCurrencyIds.sol";
|
|
29
|
+
import {JBFundAccessLimitGroup} from "@bananapus/core-v6/src/structs/JBFundAccessLimitGroup.sol";
|
|
30
|
+
import {JBMultiTerminal} from "@bananapus/core-v6/src/JBMultiTerminal.sol";
|
|
31
|
+
import {JBRulesetConfig, JBTerminalConfig} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
32
|
+
import {JBRulesetMetadata} from "@bananapus/core-v6/src/structs/JBRulesetMetadata.sol";
|
|
33
|
+
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
34
|
+
import {JBSplitGroup} from "@bananapus/core-v6/src/structs/JBSplitGroup.sol";
|
|
35
|
+
import {IJBRulesetApprovalHook} from "@bananapus/core-v6/src/interfaces/IJBRulesets.sol";
|
|
36
|
+
import {JBTerminalStore} from "@bananapus/core-v6/src/JBTerminalStore.sol";
|
|
33
37
|
|
|
34
38
|
/// @dev Helper to read block.timestamp via an external call, bypassing the via-ir optimizer's timestamp caching.
|
|
35
39
|
contract TimestampReader {
|
|
@@ -118,10 +122,10 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
118
122
|
);
|
|
119
123
|
governor = new DefifaGovernor(jbController(), address(this));
|
|
120
124
|
JBAddressRegistry _registry = new JBAddressRegistry();
|
|
121
|
-
DefifaTokenUriResolver
|
|
125
|
+
DefifaTokenUriResolver _tokenUriResolver = new DefifaTokenUriResolver(ITypeface(address(0)));
|
|
122
126
|
deployer = new DefifaDeployer(
|
|
123
127
|
address(hook),
|
|
124
|
-
|
|
128
|
+
_tokenUriResolver,
|
|
125
129
|
governor,
|
|
126
130
|
jbController(),
|
|
127
131
|
_registry,
|
|
@@ -300,6 +304,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
300
304
|
vm.deal(_users[i], 1 ether);
|
|
301
305
|
// Build metadata to buy specific NFT
|
|
302
306
|
uint16[] memory rawMetadata = new uint16[](1);
|
|
307
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
303
308
|
rawMetadata[0] = uint16(i + 1); // reward tier, 1 indexed
|
|
304
309
|
bytes memory metadata = _buildPayMetadata(abi.encode(_users[i], rawMetadata));
|
|
305
310
|
// Pay to the project and mint an NFT
|
|
@@ -316,6 +321,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
316
321
|
vm.deal(_users[i], 1 ether);
|
|
317
322
|
// Build metadata to buy specific NFT
|
|
318
323
|
uint16[] memory rawMetadata = new uint16[](1);
|
|
324
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
319
325
|
rawMetadata[0] = uint16(i + 1); // reward tier, 1 indexed
|
|
320
326
|
bytes memory metadata = _buildPayMetadata(abi.encode(_users[i], rawMetadata));
|
|
321
327
|
// Pay to the project and mint an NFT
|
|
@@ -399,6 +405,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
399
405
|
vm.deal(_users[i], 1 ether);
|
|
400
406
|
// Build metadata to buy specific NFT
|
|
401
407
|
uint16[] memory rawMetadata = new uint16[](1);
|
|
408
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
402
409
|
rawMetadata[0] = uint16(i + 1); // reward tier, 1 indexed
|
|
403
410
|
bytes memory metadata = _buildPayMetadata(abi.encode(_users[i], rawMetadata));
|
|
404
411
|
// Pay to the project and mint an NFT
|
|
@@ -415,6 +422,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
415
422
|
vm.warp(_tsReader.timestamp() + 1);
|
|
416
423
|
assertEq(
|
|
417
424
|
_governor.MAX_ATTESTATION_POWER_TIER(),
|
|
425
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
418
426
|
_governor.getAttestationWeight(_gameId, _users[i], uint48(_tsReader.timestamp()))
|
|
419
427
|
);
|
|
420
428
|
}
|
|
@@ -468,6 +476,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
468
476
|
bytes memory metadata;
|
|
469
477
|
{
|
|
470
478
|
uint16[] memory rawMetadata = new uint16[](1);
|
|
479
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
471
480
|
rawMetadata[0] = uint16(i + 1); // reward tier, 1 indexed
|
|
472
481
|
metadata = _buildPayMetadata(abi.encode(_users[i], rawMetadata));
|
|
473
482
|
}
|
|
@@ -481,6 +490,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
481
490
|
vm.warp(block.timestamp + 1);
|
|
482
491
|
assertEq(
|
|
483
492
|
_governor.MAX_ATTESTATION_POWER_TIER(),
|
|
493
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
484
494
|
_governor.getAttestationWeight(_gameId, _users[i], uint48(block.timestamp))
|
|
485
495
|
);
|
|
486
496
|
// Have a user mint and refund the tier
|
|
@@ -621,6 +631,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
621
631
|
|
|
622
632
|
function testVotingPowerDecreasesAfterRefund() public {
|
|
623
633
|
uint256 nOfOtherTiers = 31;
|
|
634
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
624
635
|
DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(uint8(nOfOtherTiers + 1));
|
|
625
636
|
(uint256 _projectId, DefifaHook _hook, DefifaGovernor _governor) = createDefifaProject(defifaData);
|
|
626
637
|
|
|
@@ -697,6 +708,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
697
708
|
vm.assume(totalWeight > 1);
|
|
698
709
|
|
|
699
710
|
address[] memory _users = new address[](nOfOtherTiers + nUsersWithWinningTier);
|
|
711
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
700
712
|
DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(uint8(nOfOtherTiers + 1));
|
|
701
713
|
(uint256 _projectId, DefifaHook _nft, DefifaGovernor _governor) = createDefifaProject(defifaData);
|
|
702
714
|
// Phase 1: minting
|
|
@@ -711,6 +723,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
711
723
|
if (i < nOfOtherTiers) {
|
|
712
724
|
// Build metadata to buy specific NFT
|
|
713
725
|
uint16[] memory rawMetadata = new uint16[](1);
|
|
726
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
714
727
|
rawMetadata[0] = uint16(i + 1); // reward tier, 1 indexed
|
|
715
728
|
bytes memory metadata = _buildPayMetadata(abi.encode(_users[i], rawMetadata));
|
|
716
729
|
// Pay to the project and mint an NFT
|
|
@@ -722,11 +735,13 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
722
735
|
vm.warp(block.timestamp + 1);
|
|
723
736
|
assertEq(
|
|
724
737
|
_governor.MAX_ATTESTATION_POWER_TIER(),
|
|
738
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
725
739
|
_governor.getAttestationWeight(_gameId, _users[i], uint48(block.timestamp))
|
|
726
740
|
);
|
|
727
741
|
} else {
|
|
728
742
|
// Build metadata to buy specific NFT
|
|
729
743
|
uint16[] memory rawMetadata = new uint16[](1);
|
|
744
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
730
745
|
rawMetadata[0] = uint16(nOfOtherTiers + 1); // reward tier, 1 indexed
|
|
731
746
|
bytes memory metadata = _buildPayMetadata(abi.encode(_users[i], rawMetadata));
|
|
732
747
|
// Pay to the project and mint an NFT
|
|
@@ -738,6 +753,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
738
753
|
vm.warp(block.timestamp + 1);
|
|
739
754
|
assertEq(
|
|
740
755
|
_governor.MAX_ATTESTATION_POWER_TIER() / (i - nOfOtherTiers + 1),
|
|
756
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
741
757
|
_governor.getAttestationWeight(_gameId, _users[i], uint48(block.timestamp))
|
|
742
758
|
);
|
|
743
759
|
}
|
|
@@ -764,6 +780,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
764
780
|
vm.assume(totalWeight > 1);
|
|
765
781
|
|
|
766
782
|
address[] memory _users = new address[](nOfOtherTiers + nUsersWithWinningTier);
|
|
783
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
767
784
|
DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(uint8(nOfOtherTiers + 1));
|
|
768
785
|
(uint256 _projectId, DefifaHook _nft, DefifaGovernor _governor) = createDefifaProject(defifaData);
|
|
769
786
|
// Phase 1: minting
|
|
@@ -778,6 +795,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
778
795
|
if (i < nOfOtherTiers) {
|
|
779
796
|
// Build metadata to buy specific NFT
|
|
780
797
|
uint16[] memory rawMetadata = new uint16[](1);
|
|
798
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
781
799
|
rawMetadata[0] = uint16(i + 1); // reward tier, 1 indexed
|
|
782
800
|
bytes memory metadata = _buildPayMetadata(abi.encode(_users[i], rawMetadata));
|
|
783
801
|
// Pay to the project and mint an NFT
|
|
@@ -789,11 +807,13 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
789
807
|
vm.warp(block.timestamp + 1);
|
|
790
808
|
assertEq(
|
|
791
809
|
_governor.MAX_ATTESTATION_POWER_TIER(),
|
|
810
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
792
811
|
_governor.getAttestationWeight(_gameId, _users[i], uint48(block.timestamp))
|
|
793
812
|
);
|
|
794
813
|
} else {
|
|
795
814
|
// Build metadata to buy specific NFT
|
|
796
815
|
uint16[] memory rawMetadata = new uint16[](1);
|
|
816
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
797
817
|
rawMetadata[0] = uint16(nOfOtherTiers + 1); // reward tier, 1 indexed
|
|
798
818
|
bytes memory metadata = _buildPayMetadata(abi.encode(_users[i], rawMetadata));
|
|
799
819
|
// Pay to the project and mint an NFT
|
|
@@ -805,6 +825,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
805
825
|
vm.warp(block.timestamp + 1);
|
|
806
826
|
assertEq(
|
|
807
827
|
_governor.MAX_ATTESTATION_POWER_TIER() / (i - nOfOtherTiers + 1),
|
|
828
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
808
829
|
_governor.getAttestationWeight(_gameId, _users[i], uint48(block.timestamp))
|
|
809
830
|
);
|
|
810
831
|
}
|
|
@@ -1061,6 +1082,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
1061
1082
|
vm.deal(_users[i], 1 ether);
|
|
1062
1083
|
// Build metadata to buy specific NFT
|
|
1063
1084
|
uint16[] memory rawMetadata = new uint16[](1);
|
|
1085
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
1064
1086
|
rawMetadata[0] = uint16(i + 1); // reward tier, 1 indexed
|
|
1065
1087
|
bytes memory metadata = _buildPayMetadata(abi.encode(_users[i], rawMetadata));
|
|
1066
1088
|
// Pay to the project and mint an NFT
|
|
@@ -1077,6 +1099,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
1077
1099
|
vm.warp(_tsReader.timestamp() + 1);
|
|
1078
1100
|
assertEq(
|
|
1079
1101
|
_governor.MAX_ATTESTATION_POWER_TIER(),
|
|
1102
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
1080
1103
|
_governor.getAttestationWeight(_gameId, _users[i], uint48(_tsReader.timestamp()))
|
|
1081
1104
|
);
|
|
1082
1105
|
}
|
|
@@ -1124,6 +1147,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
1124
1147
|
vm.deal(_users[i], 1 ether);
|
|
1125
1148
|
// Build metadata to buy specific NFT
|
|
1126
1149
|
uint16[] memory rawMetadata = new uint16[](1);
|
|
1150
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
1127
1151
|
rawMetadata[0] = uint16(i + 1); // reward tier, 1 indexed
|
|
1128
1152
|
bytes memory metadata = _buildPayMetadata(abi.encode(_users[i], rawMetadata));
|
|
1129
1153
|
// Pay to the project and mint an NFT
|
|
@@ -1139,6 +1163,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
1139
1163
|
// Forward 1 block, user should receive all the voting power of the tier, as its the only NFT
|
|
1140
1164
|
assertEq(
|
|
1141
1165
|
_governor.MAX_ATTESTATION_POWER_TIER(),
|
|
1166
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
1142
1167
|
_governor.getAttestationWeight(_gameId, _users[i], uint48(block.timestamp))
|
|
1143
1168
|
);
|
|
1144
1169
|
}
|
|
@@ -1241,6 +1266,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
|
|
|
1241
1266
|
assertEq(_hook.balanceOf(_refundUser), 0);
|
|
1242
1267
|
// Build metadata to buy specific NFT
|
|
1243
1268
|
uint16[] memory rawMetadata = new uint16[](1);
|
|
1269
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
1244
1270
|
rawMetadata[0] = uint16(_tierId); // reward tier, 1 indexed
|
|
1245
1271
|
bytes memory metadata = _buildPayMetadata(abi.encode(_refundUser, rawMetadata));
|
|
1246
1272
|
// Pay to the project and mint an NFT
|