@ballkidz/defifa 0.0.7 → 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.
Files changed (46) hide show
  1. package/ADMINISTRATION.md +3 -3
  2. package/AUDIT_INSTRUCTIONS.md +422 -0
  3. package/CRYPTO_ECON.md +5 -5
  4. package/RISKS.md +38 -335
  5. package/SKILLS.md +1 -1
  6. package/USER_JOURNEYS.md +691 -0
  7. package/package.json +7 -7
  8. package/script/Deploy.s.sol +14 -3
  9. package/script/helpers/DefifaDeploymentLib.sol +13 -15
  10. package/src/DefifaDeployer.sol +221 -192
  11. package/src/DefifaGovernor.sol +286 -276
  12. package/src/DefifaHook.sol +65 -32
  13. package/src/DefifaProjectOwner.sol +27 -4
  14. package/src/DefifaTokenUriResolver.sol +136 -134
  15. package/src/enums/DefifaGamePhase.sol +1 -1
  16. package/src/enums/DefifaScorecardState.sol +1 -1
  17. package/src/interfaces/IDefifaDeployer.sol +52 -50
  18. package/src/interfaces/IDefifaGamePhaseReporter.sol +2 -2
  19. package/src/interfaces/IDefifaGamePotReporter.sol +1 -1
  20. package/src/interfaces/IDefifaGovernor.sol +53 -54
  21. package/src/interfaces/IDefifaHook.sol +104 -103
  22. package/src/interfaces/IDefifaTokenUriResolver.sol +2 -2
  23. package/src/libraries/DefifaFontImporter.sol +11 -9
  24. package/src/libraries/DefifaHookLib.sol +66 -53
  25. package/src/structs/DefifaAttestations.sol +1 -1
  26. package/src/structs/DefifaDelegation.sol +1 -1
  27. package/src/structs/DefifaLaunchProjectData.sol +4 -4
  28. package/src/structs/DefifaOpsData.sol +1 -1
  29. package/src/structs/DefifaScorecard.sol +1 -1
  30. package/src/structs/DefifaTierCashOutWeight.sol +1 -1
  31. package/src/structs/DefifaTierParams.sol +2 -1
  32. package/test/DefifaAdversarialQuorum.t.sol +602 -0
  33. package/test/DefifaAuditLowGuards.t.sol +304 -0
  34. package/test/DefifaFeeAccounting.t.sol +37 -16
  35. package/test/DefifaGovernor.t.sol +37 -11
  36. package/test/DefifaHookRegressions.t.sol +14 -12
  37. package/test/DefifaMintCostInvariant.t.sol +31 -12
  38. package/test/DefifaNoContest.t.sol +33 -13
  39. package/test/DefifaSecurity.t.sol +45 -25
  40. package/test/DefifaUSDC.t.sol +44 -34
  41. package/test/Fork.t.sol +42 -40
  42. package/test/SVG.t.sol +2 -2
  43. package/test/TestAuditGaps.sol +982 -0
  44. package/test/TestQALastMile.t.sol +511 -0
  45. package/test/regression/FulfillmentBlocksRatification.t.sol +36 -30
  46. 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 "forge-std/Test.sol";
5
- import "../src/DefifaGovernor.sol";
6
- import "../src/DefifaDeployer.sol";
7
- import "../src/DefifaHook.sol";
8
- import "../src/DefifaTokenUriResolver.sol";
9
- import "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
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/721-hook-v6/src/libraries/JB721TiersRulesetMetadataResolver.sol";
17
- import "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
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 _tokenURIResolver = new DefifaTokenUriResolver(ITypeface(address(0)));
112
+ DefifaTokenUriResolver _tokenUriResolver = new DefifaTokenUriResolver(ITypeface(address(0)));
96
113
  deployer = new DefifaDeployer(
97
114
  address(hook),
98
- _tokenURIResolver,
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), projectId: uint64(_defifaProjectId), permissionIds: permissionIds
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
- // solhint-disable-next-line no-unused-import
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 _tokenURIResolver = new DefifaTokenUriResolver(ITypeface(address(0)));
125
+ DefifaTokenUriResolver _tokenUriResolver = new DefifaTokenUriResolver(ITypeface(address(0)));
122
126
  deployer = new DefifaDeployer(
123
127
  address(hook),
124
- _tokenURIResolver,
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