@ballkidz/defifa 0.0.24 → 0.0.26

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 (50) hide show
  1. package/AUDIT_INSTRUCTIONS.md +6 -2
  2. package/README.md +11 -2
  3. package/RISKS.md +3 -1
  4. package/STYLE_GUIDE.md +14 -11
  5. package/package.json +31 -14
  6. package/script/Deploy.s.sol +4 -1
  7. package/src/DefifaDeployer.sol +74 -46
  8. package/src/DefifaGovernor.sol +53 -11
  9. package/src/DefifaHook.sol +79 -25
  10. package/src/DefifaTokenUriResolver.sol +111 -19
  11. package/src/interfaces/IDefifaDeployer.sol +5 -0
  12. package/src/interfaces/IDefifaGovernor.sol +4 -0
  13. package/src/interfaces/IDefifaHook.sol +5 -0
  14. package/src/libraries/DefifaHookLib.sol +9 -10
  15. package/src/structs/DefifaLaunchProjectData.sol +0 -3
  16. package/CRYPTO_ECON.pdf +0 -0
  17. package/CRYPTO_ECON.tex +0 -997
  18. package/foundry.lock +0 -17
  19. package/references/operations.md +0 -32
  20. package/references/runtime.md +0 -43
  21. package/slither-ci.config.json +0 -10
  22. package/sphinx.lock +0 -521
  23. package/test/BWAFunctionComparison.t.sol +0 -1320
  24. package/test/DefifaAdversarialQuorum.t.sol +0 -617
  25. package/test/DefifaAuditLowGuards.t.sol +0 -308
  26. package/test/DefifaFeeAccounting.t.sol +0 -581
  27. package/test/DefifaGovernanceHardening.t.sol +0 -1315
  28. package/test/DefifaGovernor.t.sol +0 -1378
  29. package/test/DefifaHookRegressions.t.sol +0 -415
  30. package/test/DefifaMintCostInvariant.t.sol +0 -319
  31. package/test/DefifaNoContest.t.sol +0 -941
  32. package/test/DefifaSecurity.t.sol +0 -741
  33. package/test/DefifaUSDC.t.sol +0 -480
  34. package/test/Fork.t.sol +0 -2388
  35. package/test/TestAuditGaps.sol +0 -984
  36. package/test/TestQALastMile.t.sol +0 -514
  37. package/test/audit/AttestationDoubleCount.t.sol +0 -218
  38. package/test/audit/CodexNemesisCurrencyMismatchBypass.t.sol +0 -112
  39. package/test/audit/CodexNemesisNoContestReserveDrain.t.sol +0 -238
  40. package/test/audit/CodexRegistryMismatch.t.sol +0 -191
  41. package/test/audit/CodexTierCapMismatch.t.sol +0 -171
  42. package/test/audit/CurrencyMismatchFix.t.sol +0 -265
  43. package/test/audit/FixPendingReserveDilution.t.sol +0 -366
  44. package/test/audit/H5TierCapValidation.t.sol +0 -184
  45. package/test/audit/PendingReserveDilution.t.sol +0 -298
  46. package/test/audit/PendingReserveQuorumGrief.t.sol +0 -355
  47. package/test/audit/PendingReserveSnapshotBypass.t.sol +0 -319
  48. package/test/regression/AttestationDelegateBeneficiary.t.sol +0 -271
  49. package/test/regression/FulfillmentBlocksRatification.t.sol +0 -279
  50. package/test/regression/GracePeriodBypass.t.sol +0 -302
@@ -1,308 +0,0 @@
1
- // SPDX-License-Identifier: UNLICENSED
2
- pragma solidity 0.8.28;
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, timelockDuration: 0
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, timelockDuration: 0
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, timelockDuration: 0
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,
182
- attestationStartTime: block.timestamp,
183
- attestationGracePeriod: overflowGracePeriod,
184
- timelockDuration: 0
185
- });
186
- }
187
-
188
- // =========================================================================
189
- // 4. DefifaHook_DelegateAddressZero in setTierDelegateTo
190
- // =========================================================================
191
- function testRevert_setTierDelegateTo_zeroAddress() external {
192
- _setupGame(4, 1 ether);
193
-
194
- // _users[0] owns an NFT in tier 1 during the MINT phase.
195
- vm.prank(_users[0]);
196
- vm.expectRevert(DefifaHook.DefifaHook_DelegateAddressZero.selector);
197
- _nft.setTierDelegateTo({delegatee: address(0), tierId: 1});
198
- }
199
-
200
- // =========================================================================
201
- // 5. DefifaHook_DelegateAddressZero in setTierDelegatesTo (batch)
202
- // =========================================================================
203
- function testRevert_setTierDelegatesTo_zeroAddress() external {
204
- _setupGame(4, 1 ether);
205
-
206
- DefifaDelegation[] memory delegations = new DefifaDelegation[](1);
207
- delegations[0] = DefifaDelegation({delegatee: address(0), tierId: 1});
208
-
209
- vm.prank(_users[0]);
210
- vm.expectRevert(DefifaHook.DefifaHook_DelegateAddressZero.selector);
211
- _nft.setTierDelegatesTo(delegations);
212
- }
213
-
214
- // =========================================================================
215
- // 5b. Batch delegation reverts on address(0) even in second element
216
- // =========================================================================
217
- function testRevert_setTierDelegatesTo_zeroAddress_secondElement() external {
218
- _setupGame(4, 1 ether);
219
-
220
- // First delegation is valid, second has address(0).
221
- DefifaDelegation[] memory delegations = new DefifaDelegation[](2);
222
- delegations[0] = DefifaDelegation({delegatee: _users[0], tierId: 1});
223
- delegations[1] = DefifaDelegation({delegatee: address(0), tierId: 2});
224
-
225
- vm.prank(_users[0]);
226
- vm.expectRevert(DefifaHook.DefifaHook_DelegateAddressZero.selector);
227
- _nft.setTierDelegatesTo(delegations);
228
- }
229
-
230
- // =========================================================================
231
- // SETUP HELPERS (adapted from DefifaSecurity.t.sol)
232
- // =========================================================================
233
-
234
- function _setupGame(uint8 nTiers, uint256 tierPrice) internal {
235
- DefifaLaunchProjectData memory d = _launchData(nTiers, tierPrice);
236
- (_pid, _nft, _gov) = _launch(d);
237
- vm.warp(d.start - d.mintPeriodDuration - d.refundPeriodDuration);
238
- _users = new address[](nTiers);
239
- for (uint256 i; i < nTiers; i++) {
240
- _users[i] = _addr(i);
241
- _mint(_users[i], i + 1, tierPrice);
242
- vm.warp(block.timestamp + 1);
243
- }
244
- }
245
-
246
- function _launchData(uint8 n, uint256 tierPrice) internal returns (DefifaLaunchProjectData memory) {
247
- DefifaTierParams[] memory tp = new DefifaTierParams[](n);
248
- for (uint256 i; i < n; i++) {
249
- tp[i] = DefifaTierParams({
250
- reservedRate: 1001,
251
- reservedTokenBeneficiary: address(0),
252
- encodedIPFSUri: bytes32(0),
253
- shouldUseReservedTokenBeneficiaryAsDefault: false,
254
- name: "DEFIFA"
255
- });
256
- }
257
- return DefifaLaunchProjectData({
258
- name: "DEFIFA",
259
- projectUri: "",
260
- contractUri: "",
261
- baseUri: "",
262
- token: JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: JBCurrencyIds.ETH}),
263
- mintPeriodDuration: 1 days,
264
- start: uint48(block.timestamp + 3 days),
265
- refundPeriodDuration: 1 days,
266
- store: new JB721TiersHookStore(),
267
- splits: new JBSplit[](0),
268
- attestationStartTime: 0,
269
- attestationGracePeriod: 100_381,
270
- defaultAttestationDelegate: address(0),
271
- // forge-lint: disable-next-line(unsafe-typecast)
272
- tierPrice: uint104(tierPrice),
273
- tiers: tp,
274
- defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
275
- terminal: jbMultiTerminal(),
276
- minParticipation: 0,
277
- scorecardTimeout: 0,
278
- timelockDuration: 0
279
- });
280
- }
281
-
282
- function _launch(DefifaLaunchProjectData memory d) internal returns (uint256 p, DefifaHook n, DefifaGovernor g) {
283
- g = governor;
284
- p = deployer.launchGameWith(d);
285
- JBRuleset memory fc = jbRulesets().currentOf(p);
286
- if (fc.dataHook() == address(0)) (fc,) = jbRulesets().latestQueuedOf(p);
287
- n = DefifaHook(fc.dataHook());
288
- }
289
-
290
- function _addr(uint256 i) internal pure returns (address) {
291
- return address(bytes20(keccak256(abi.encode("su", i))));
292
- }
293
-
294
- function _mint(address user, uint256 tid, uint256 amt) internal {
295
- vm.deal(user, amt);
296
- uint16[] memory m = new uint16[](1);
297
- // forge-lint: disable-next-line(unsafe-typecast)
298
- m[0] = uint16(tid);
299
- bytes[] memory data = new bytes[](1);
300
- data[0] = abi.encode(user, m);
301
- bytes4[] memory ids = new bytes4[](1);
302
- ids[0] = metadataHelper().getId("pay", address(hook));
303
- vm.prank(user);
304
- jbMultiTerminal().pay{value: amt}(
305
- _pid, JBConstants.NATIVE_TOKEN, amt, user, 0, "", metadataHelper().createMetadata(ids, data)
306
- );
307
- }
308
- }