@ballkidz/defifa 0.0.7 → 0.0.9

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 (48) hide show
  1. package/ADMINISTRATION.md +3 -3
  2. package/ARCHITECTURE.md +2 -0
  3. package/AUDIT_INSTRUCTIONS.md +422 -0
  4. package/CRYPTO_ECON.md +5 -5
  5. package/README.md +1 -1
  6. package/RISKS.md +38 -335
  7. package/SKILLS.md +1 -1
  8. package/USER_JOURNEYS.md +691 -0
  9. package/package.json +7 -7
  10. package/script/Deploy.s.sol +14 -3
  11. package/script/helpers/DefifaDeploymentLib.sol +13 -15
  12. package/src/DefifaDeployer.sol +221 -192
  13. package/src/DefifaGovernor.sol +286 -276
  14. package/src/DefifaHook.sol +68 -34
  15. package/src/DefifaProjectOwner.sol +27 -4
  16. package/src/DefifaTokenUriResolver.sol +136 -134
  17. package/src/enums/DefifaGamePhase.sol +1 -1
  18. package/src/enums/DefifaScorecardState.sol +1 -1
  19. package/src/interfaces/IDefifaDeployer.sol +52 -50
  20. package/src/interfaces/IDefifaGamePhaseReporter.sol +2 -2
  21. package/src/interfaces/IDefifaGamePotReporter.sol +1 -1
  22. package/src/interfaces/IDefifaGovernor.sol +53 -54
  23. package/src/interfaces/IDefifaHook.sol +104 -103
  24. package/src/interfaces/IDefifaTokenUriResolver.sol +2 -2
  25. package/src/libraries/DefifaFontImporter.sol +11 -9
  26. package/src/libraries/DefifaHookLib.sol +66 -53
  27. package/src/structs/DefifaAttestations.sol +1 -1
  28. package/src/structs/DefifaDelegation.sol +1 -1
  29. package/src/structs/DefifaLaunchProjectData.sol +4 -4
  30. package/src/structs/DefifaOpsData.sol +1 -1
  31. package/src/structs/DefifaScorecard.sol +1 -1
  32. package/src/structs/DefifaTierCashOutWeight.sol +1 -1
  33. package/src/structs/DefifaTierParams.sol +2 -1
  34. package/test/DefifaAdversarialQuorum.t.sol +602 -0
  35. package/test/DefifaAuditLowGuards.t.sol +304 -0
  36. package/test/DefifaFeeAccounting.t.sol +37 -16
  37. package/test/DefifaGovernor.t.sol +43 -19
  38. package/test/DefifaHookRegressions.t.sol +14 -12
  39. package/test/DefifaMintCostInvariant.t.sol +31 -12
  40. package/test/DefifaNoContest.t.sol +34 -16
  41. package/test/DefifaSecurity.t.sol +46 -28
  42. package/test/DefifaUSDC.t.sol +45 -36
  43. package/test/Fork.t.sol +43 -43
  44. package/test/SVG.t.sol +2 -2
  45. package/test/TestAuditGaps.sol +982 -0
  46. package/test/TestQALastMile.t.sol +511 -0
  47. package/test/regression/FulfillmentBlocksRatification.t.sol +36 -30
  48. 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
@@ -548,8 +558,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
548
558
  )
549
559
  internal
550
560
  {
551
- uint256 _pot = jbMultiTerminal()
552
- .currentSurplusOf(_projectId, jbMultiTerminal().accountingContextsOf(_projectId), 18, JBCurrencyIds.ETH);
561
+ uint256 _pot = jbMultiTerminal().currentSurplusOf(_projectId, new address[](0), 18, JBCurrencyIds.ETH);
553
562
  // Assert that the deployer did *NOT* receive any fee tokens.
554
563
  assertEq(IERC20(_protocolFeeProjectTokenAccount).balanceOf(address(deployer)), 0);
555
564
  assertEq(IERC20(_defifaProjectTokenAccount).balanceOf(address(deployer)), 0);
@@ -559,8 +568,8 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
559
568
  _verifySingleCashOut(_projectId, _nft, scorecards[i], _users[i], _pot, _sumDistribution, distribution, i);
560
569
  }
561
570
  // All NFTs should have been redeemed, only some dust should be left
562
- uint256 remainingSurplus = jbMultiTerminal()
563
- .currentSurplusOf(_projectId, jbMultiTerminal().accountingContextsOf(_projectId), 18, JBCurrencyIds.ETH);
571
+ uint256 remainingSurplus =
572
+ jbMultiTerminal().currentSurplusOf(_projectId, new address[](0), 18, JBCurrencyIds.ETH);
564
573
  uint256 _expected = _pot * (_nft.TOTAL_CASHOUT_WEIGHT() - assignedCashOutWeight) / _nft.TOTAL_CASHOUT_WEIGHT();
565
574
  assertApproxEqAbs(remainingSurplus, _expected, 10 ** 14);
566
575
 
@@ -621,6 +630,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
621
630
 
622
631
  function testVotingPowerDecreasesAfterRefund() public {
623
632
  uint256 nOfOtherTiers = 31;
633
+ // forge-lint: disable-next-line(unsafe-typecast)
624
634
  DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(uint8(nOfOtherTiers + 1));
625
635
  (uint256 _projectId, DefifaHook _hook, DefifaGovernor _governor) = createDefifaProject(defifaData);
626
636
 
@@ -697,6 +707,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
697
707
  vm.assume(totalWeight > 1);
698
708
 
699
709
  address[] memory _users = new address[](nOfOtherTiers + nUsersWithWinningTier);
710
+ // forge-lint: disable-next-line(unsafe-typecast)
700
711
  DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(uint8(nOfOtherTiers + 1));
701
712
  (uint256 _projectId, DefifaHook _nft, DefifaGovernor _governor) = createDefifaProject(defifaData);
702
713
  // Phase 1: minting
@@ -711,6 +722,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
711
722
  if (i < nOfOtherTiers) {
712
723
  // Build metadata to buy specific NFT
713
724
  uint16[] memory rawMetadata = new uint16[](1);
725
+ // forge-lint: disable-next-line(unsafe-typecast)
714
726
  rawMetadata[0] = uint16(i + 1); // reward tier, 1 indexed
715
727
  bytes memory metadata = _buildPayMetadata(abi.encode(_users[i], rawMetadata));
716
728
  // Pay to the project and mint an NFT
@@ -722,11 +734,13 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
722
734
  vm.warp(block.timestamp + 1);
723
735
  assertEq(
724
736
  _governor.MAX_ATTESTATION_POWER_TIER(),
737
+ // forge-lint: disable-next-line(unsafe-typecast)
725
738
  _governor.getAttestationWeight(_gameId, _users[i], uint48(block.timestamp))
726
739
  );
727
740
  } else {
728
741
  // Build metadata to buy specific NFT
729
742
  uint16[] memory rawMetadata = new uint16[](1);
743
+ // forge-lint: disable-next-line(unsafe-typecast)
730
744
  rawMetadata[0] = uint16(nOfOtherTiers + 1); // reward tier, 1 indexed
731
745
  bytes memory metadata = _buildPayMetadata(abi.encode(_users[i], rawMetadata));
732
746
  // Pay to the project and mint an NFT
@@ -738,6 +752,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
738
752
  vm.warp(block.timestamp + 1);
739
753
  assertEq(
740
754
  _governor.MAX_ATTESTATION_POWER_TIER() / (i - nOfOtherTiers + 1),
755
+ // forge-lint: disable-next-line(unsafe-typecast)
741
756
  _governor.getAttestationWeight(_gameId, _users[i], uint48(block.timestamp))
742
757
  );
743
758
  }
@@ -764,6 +779,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
764
779
  vm.assume(totalWeight > 1);
765
780
 
766
781
  address[] memory _users = new address[](nOfOtherTiers + nUsersWithWinningTier);
782
+ // forge-lint: disable-next-line(unsafe-typecast)
767
783
  DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(uint8(nOfOtherTiers + 1));
768
784
  (uint256 _projectId, DefifaHook _nft, DefifaGovernor _governor) = createDefifaProject(defifaData);
769
785
  // Phase 1: minting
@@ -778,6 +794,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
778
794
  if (i < nOfOtherTiers) {
779
795
  // Build metadata to buy specific NFT
780
796
  uint16[] memory rawMetadata = new uint16[](1);
797
+ // forge-lint: disable-next-line(unsafe-typecast)
781
798
  rawMetadata[0] = uint16(i + 1); // reward tier, 1 indexed
782
799
  bytes memory metadata = _buildPayMetadata(abi.encode(_users[i], rawMetadata));
783
800
  // Pay to the project and mint an NFT
@@ -789,11 +806,13 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
789
806
  vm.warp(block.timestamp + 1);
790
807
  assertEq(
791
808
  _governor.MAX_ATTESTATION_POWER_TIER(),
809
+ // forge-lint: disable-next-line(unsafe-typecast)
792
810
  _governor.getAttestationWeight(_gameId, _users[i], uint48(block.timestamp))
793
811
  );
794
812
  } else {
795
813
  // Build metadata to buy specific NFT
796
814
  uint16[] memory rawMetadata = new uint16[](1);
815
+ // forge-lint: disable-next-line(unsafe-typecast)
797
816
  rawMetadata[0] = uint16(nOfOtherTiers + 1); // reward tier, 1 indexed
798
817
  bytes memory metadata = _buildPayMetadata(abi.encode(_users[i], rawMetadata));
799
818
  // Pay to the project and mint an NFT
@@ -805,6 +824,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
805
824
  vm.warp(block.timestamp + 1);
806
825
  assertEq(
807
826
  _governor.MAX_ATTESTATION_POWER_TIER() / (i - nOfOtherTiers + 1),
827
+ // forge-lint: disable-next-line(unsafe-typecast)
808
828
  _governor.getAttestationWeight(_gameId, _users[i], uint48(block.timestamp))
809
829
  );
810
830
  }
@@ -863,8 +883,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
863
883
  _governor.ratifyScorecardFrom(_gameId, scorecards);
864
884
  vm.warp(block.timestamp + 1);
865
885
 
866
- uint256 _pot = jbMultiTerminal()
867
- .currentSurplusOf(_projectId, jbMultiTerminal().accountingContextsOf(_projectId), 18, JBCurrencyIds.ETH);
886
+ uint256 _pot = jbMultiTerminal().currentSurplusOf(_projectId, new address[](0), 18, JBCurrencyIds.ETH);
868
887
 
869
888
  // Verify that the cashOutWeights actually changed
870
889
  for (uint256 i = 0; i < _users.length; i++) {
@@ -911,8 +930,8 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
911
930
  }
912
931
  // All NFTs should have been redeemed, only some dust should be left
913
932
  // Max allowed dust is 0.0001
914
- uint256 remainingSurplus = jbMultiTerminal()
915
- .currentSurplusOf(_projectId, jbMultiTerminal().accountingContextsOf(_projectId), 18, JBCurrencyIds.ETH);
933
+ uint256 remainingSurplus =
934
+ jbMultiTerminal().currentSurplusOf(_projectId, new address[](0), 18, JBCurrencyIds.ETH);
916
935
  assertApproxEqAbs(
917
936
  remainingSurplus, _pot * (totalCashOutWeight - assignedCashOutWeight) / totalCashOutWeight, 10 ** 14
918
937
  );
@@ -1061,6 +1080,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
1061
1080
  vm.deal(_users[i], 1 ether);
1062
1081
  // Build metadata to buy specific NFT
1063
1082
  uint16[] memory rawMetadata = new uint16[](1);
1083
+ // forge-lint: disable-next-line(unsafe-typecast)
1064
1084
  rawMetadata[0] = uint16(i + 1); // reward tier, 1 indexed
1065
1085
  bytes memory metadata = _buildPayMetadata(abi.encode(_users[i], rawMetadata));
1066
1086
  // Pay to the project and mint an NFT
@@ -1077,6 +1097,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
1077
1097
  vm.warp(_tsReader.timestamp() + 1);
1078
1098
  assertEq(
1079
1099
  _governor.MAX_ATTESTATION_POWER_TIER(),
1100
+ // forge-lint: disable-next-line(unsafe-typecast)
1080
1101
  _governor.getAttestationWeight(_gameId, _users[i], uint48(_tsReader.timestamp()))
1081
1102
  );
1082
1103
  }
@@ -1124,6 +1145,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
1124
1145
  vm.deal(_users[i], 1 ether);
1125
1146
  // Build metadata to buy specific NFT
1126
1147
  uint16[] memory rawMetadata = new uint16[](1);
1148
+ // forge-lint: disable-next-line(unsafe-typecast)
1127
1149
  rawMetadata[0] = uint16(i + 1); // reward tier, 1 indexed
1128
1150
  bytes memory metadata = _buildPayMetadata(abi.encode(_users[i], rawMetadata));
1129
1151
  // Pay to the project and mint an NFT
@@ -1139,6 +1161,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
1139
1161
  // Forward 1 block, user should receive all the voting power of the tier, as its the only NFT
1140
1162
  assertEq(
1141
1163
  _governor.MAX_ATTESTATION_POWER_TIER(),
1164
+ // forge-lint: disable-next-line(unsafe-typecast)
1142
1165
  _governor.getAttestationWeight(_gameId, _users[i], uint48(block.timestamp))
1143
1166
  );
1144
1167
  }
@@ -1241,6 +1264,7 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
1241
1264
  assertEq(_hook.balanceOf(_refundUser), 0);
1242
1265
  // Build metadata to buy specific NFT
1243
1266
  uint16[] memory rawMetadata = new uint16[](1);
1267
+ // forge-lint: disable-next-line(unsafe-typecast)
1244
1268
  rawMetadata[0] = uint16(_tierId); // reward tier, 1 indexed
1245
1269
  bytes memory metadata = _buildPayMetadata(abi.encode(_refundUser, rawMetadata));
1246
1270
  // Pay to the project and mint an NFT