@ballkidz/defifa 0.0.25 → 0.0.27

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 (65) 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 +79 -47
  8. package/src/DefifaGovernor.sol +57 -12
  9. package/src/DefifaHook.sol +83 -26
  10. package/src/DefifaProjectOwner.sol +4 -3
  11. package/src/DefifaTokenUriResolver.sol +113 -20
  12. package/src/enums/DefifaGamePhase.sol +6 -0
  13. package/src/enums/DefifaScorecardState.sol +4 -0
  14. package/src/interfaces/IDefifaDeployer.sol +5 -0
  15. package/src/interfaces/IDefifaGamePhaseReporter.sol +4 -0
  16. package/src/interfaces/IDefifaGamePotReporter.sol +10 -0
  17. package/src/interfaces/IDefifaGovernor.sol +4 -0
  18. package/src/interfaces/IDefifaHook.sol +5 -0
  19. package/src/interfaces/IDefifaTokenUriResolver.sol +3 -0
  20. package/src/libraries/DefifaFontImporter.sol +1 -1
  21. package/src/libraries/DefifaHookLib.sol +9 -10
  22. package/src/structs/DefifaAttestations.sol +3 -2
  23. package/src/structs/DefifaDelegation.sol +1 -0
  24. package/src/structs/DefifaLaunchProjectData.sol +2 -3
  25. package/src/structs/DefifaOpsData.sol +1 -0
  26. package/src/structs/DefifaScorecard.sol +2 -0
  27. package/src/structs/DefifaTierCashOutWeight.sol +3 -1
  28. package/src/structs/DefifaTierParams.sol +1 -0
  29. package/CRYPTO_ECON.pdf +0 -0
  30. package/CRYPTO_ECON.tex +0 -997
  31. package/foundry.lock +0 -17
  32. package/references/operations.md +0 -32
  33. package/references/runtime.md +0 -43
  34. package/slither-ci.config.json +0 -10
  35. package/sphinx.lock +0 -521
  36. package/test/BWAFunctionComparison.t.sol +0 -1320
  37. package/test/DefifaAdversarialQuorum.t.sol +0 -617
  38. package/test/DefifaAuditLowGuards.t.sol +0 -308
  39. package/test/DefifaFeeAccounting.t.sol +0 -581
  40. package/test/DefifaGovernanceHardening.t.sol +0 -1315
  41. package/test/DefifaGovernor.t.sol +0 -1378
  42. package/test/DefifaHookRegressions.t.sol +0 -415
  43. package/test/DefifaMintCostInvariant.t.sol +0 -319
  44. package/test/DefifaNoContest.t.sol +0 -941
  45. package/test/DefifaSecurity.t.sol +0 -741
  46. package/test/DefifaUSDC.t.sol +0 -480
  47. package/test/Fork.t.sol +0 -2388
  48. package/test/TestAuditGaps.sol +0 -984
  49. package/test/TestQALastMile.t.sol +0 -514
  50. package/test/audit/AttestationDoubleCount.t.sol +0 -218
  51. package/test/audit/CodexNemesisCurrencyMismatchBypass.t.sol +0 -112
  52. package/test/audit/CodexNemesisNoContestReserveDrain.t.sol +0 -238
  53. package/test/audit/CodexNemesisOneTierZeroTimeoutLockVerified.t.sol +0 -218
  54. package/test/audit/CodexNemesisSingleTierTimeoutLock.t.sol +0 -237
  55. package/test/audit/CodexRegistryMismatch.t.sol +0 -191
  56. package/test/audit/CodexTierCapMismatch.t.sol +0 -171
  57. package/test/audit/CurrencyMismatchFix.t.sol +0 -265
  58. package/test/audit/FixPendingReserveDilution.t.sol +0 -366
  59. package/test/audit/H5TierCapValidation.t.sol +0 -184
  60. package/test/audit/PendingReserveDilution.t.sol +0 -298
  61. package/test/audit/PendingReserveQuorumGrief.t.sol +0 -355
  62. package/test/audit/PendingReserveSnapshotBypass.t.sol +0 -319
  63. package/test/regression/AttestationDelegateBeneficiary.t.sol +0 -271
  64. package/test/regression/FulfillmentBlocksRatification.t.sol +0 -279
  65. package/test/regression/GracePeriodBypass.t.sol +0 -302
@@ -1,415 +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
- /// @dev Helper to read block.timestamp via an external call, bypassing the via-ir optimizer's timestamp caching.
34
- contract TimestampReaderRegressions {
35
- function timestamp() external view returns (uint256) {
36
- return block.timestamp;
37
- }
38
- }
39
-
40
- /// @title DefifaHookRegressions
41
- /// @notice Regression tests for audit findings in DefifaHook.
42
- contract DefifaHookRegressions is JBTest, TestBaseWorkflow {
43
- using JBRulesetMetadataResolver for JBRuleset;
44
-
45
- TimestampReaderRegressions private _tsReader = new TimestampReaderRegressions();
46
-
47
- address _protocolFeeProjectTokenAccount;
48
- address _defifaProjectTokenAccount;
49
- uint256 _protocolFeeProjectId;
50
- uint256 _defifaProjectId;
51
- uint256 _gameId = 3;
52
-
53
- DefifaDeployer deployer;
54
- DefifaHook hook;
55
- DefifaGovernor governor;
56
-
57
- address projectOwner = address(bytes20(keccak256("projectOwner")));
58
-
59
- function setUp() public virtual override {
60
- super.setUp();
61
-
62
- JBAccountingContext[] memory _tokens = new JBAccountingContext[](1);
63
- _tokens[0] = JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: JBCurrencyIds.ETH});
64
-
65
- JBTerminalConfig[] memory terminalConfigs = new JBTerminalConfig[](1);
66
- terminalConfigs[0] = JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: _tokens});
67
-
68
- JBRulesetConfig[] memory rulesetConfigs = new JBRulesetConfig[](1);
69
- rulesetConfigs[0] = JBRulesetConfig({
70
- mustStartAtOrAfter: 0,
71
- duration: 10 days,
72
- weight: 1e18,
73
- weightCutPercent: 0,
74
- approvalHook: IJBRulesetApprovalHook(address(0)),
75
- metadata: JBRulesetMetadata({
76
- reservedPercent: 0,
77
- cashOutTaxRate: 0,
78
- baseCurrency: JBCurrencyIds.ETH,
79
- pausePay: false,
80
- pauseCreditTransfers: false,
81
- allowOwnerMinting: false,
82
- allowSetCustomToken: false,
83
- allowTerminalMigration: false,
84
- allowSetTerminals: false,
85
- allowSetController: false,
86
- allowAddAccountingContext: false,
87
- allowAddPriceFeed: false,
88
- ownerMustSendPayouts: false,
89
- holdFees: false,
90
- useTotalSurplusForCashOuts: false,
91
- useDataHookForPay: true,
92
- useDataHookForCashOut: true,
93
- dataHook: address(0),
94
- metadata: 0
95
- }),
96
- splitGroups: new JBSplitGroup[](0),
97
- fundAccessLimitGroups: new JBFundAccessLimitGroup[](0)
98
- });
99
-
100
- _protocolFeeProjectId =
101
- jbController().launchProjectFor(address(projectOwner), "", rulesetConfigs, terminalConfigs, "");
102
- vm.prank(projectOwner);
103
- _protocolFeeProjectTokenAccount =
104
- address(jbController().deployERC20For(_protocolFeeProjectId, "Bananapus", "NANA", bytes32(0)));
105
-
106
- _defifaProjectId =
107
- jbController().launchProjectFor(address(projectOwner), "", rulesetConfigs, terminalConfigs, "");
108
- vm.prank(projectOwner);
109
- _defifaProjectTokenAccount =
110
- address(jbController().deployERC20For(_defifaProjectId, "Defifa", "DEFIFA", bytes32(0)));
111
-
112
- hook = new DefifaHook(
113
- jbDirectory(), IERC20(address(_defifaProjectTokenAccount)), IERC20(_protocolFeeProjectTokenAccount)
114
- );
115
- governor = new DefifaGovernor(jbController(), address(this));
116
- JBAddressRegistry _registry = new JBAddressRegistry();
117
- DefifaTokenUriResolver _tokenUriResolver = new DefifaTokenUriResolver(ITypeface(address(0)));
118
- deployer = new DefifaDeployer(
119
- address(hook),
120
- _tokenUriResolver,
121
- governor,
122
- jbController(),
123
- _registry,
124
- _defifaProjectId,
125
- _protocolFeeProjectId
126
- );
127
-
128
- hook.transferOwnership(address(deployer));
129
- governor.transferOwnership(address(deployer));
130
- }
131
-
132
- /// @notice Attestation units must be preserved when transferring an NFT to an undelegated recipient.
133
- /// @dev Before the fix, transferring to a recipient with no delegate set would cause attestation units to vanish:
134
- /// the sender's delegate lost units but no delegate gained them (because address(0) was skipped).
135
- /// After the fix, the recipient auto-delegates to themselves, preserving total attestation power.
136
- function test_M5_attestationUnitsPreservedOnTransferToUndelegatedRecipient() public {
137
- uint8 nTiers = 4;
138
- address playerA = address(bytes20(keccak256("playerA")));
139
- address playerB = address(bytes20(keccak256("playerB")));
140
-
141
- DefifaLaunchProjectData memory defifaData = _getBasicLaunchData(nTiers);
142
- (uint256 _projectId, DefifaHook _nft,) = _createProject(defifaData);
143
-
144
- // Phase 1: Mint — both players buy tier 1 NFTs.
145
- vm.warp(defifaData.start - defifaData.mintPeriodDuration - defifaData.refundPeriodDuration);
146
-
147
- // Player A mints tier 1.
148
- vm.deal(playerA, 1 ether);
149
- {
150
- uint16[] memory rawMetadata = new uint16[](1);
151
- rawMetadata[0] = 1;
152
- bytes memory metadata = _buildPayMetadata(abi.encode(playerA, rawMetadata));
153
- vm.prank(playerA);
154
- jbMultiTerminal().pay{value: 1 ether}(
155
- _projectId, JBConstants.NATIVE_TOKEN, 1 ether, playerA, 0, "", metadata
156
- );
157
- }
158
- assertEq(_nft.balanceOf(playerA), 1, "Player A should own 1 NFT");
159
-
160
- // Player A explicitly sets delegation to self.
161
- {
162
- DefifaDelegation[] memory delegations = new DefifaDelegation[](1);
163
- delegations[0] = DefifaDelegation({delegatee: playerA, tierId: 1});
164
- vm.prank(playerA);
165
- _nft.setTierDelegatesTo(delegations);
166
- }
167
-
168
- // Player B mints tier 1 — uses self as attestation delegate (via pay metadata).
169
- vm.deal(playerB, 1 ether);
170
- {
171
- uint16[] memory rawMetadata = new uint16[](1);
172
- rawMetadata[0] = 1;
173
- bytes memory metadata = _buildPayMetadata(abi.encode(playerB, rawMetadata));
174
- vm.prank(playerB);
175
- jbMultiTerminal().pay{value: 1 ether}(
176
- _projectId, JBConstants.NATIVE_TOKEN, 1 ether, playerB, 0, "", metadata
177
- );
178
- }
179
- assertEq(_nft.balanceOf(playerB), 1, "Player B should own 1 NFT");
180
-
181
- // Advance 1 second so checkpoints are recorded.
182
- vm.warp(_tsReader.timestamp() + 1);
183
-
184
- // Get the tier's voting units per NFT.
185
- uint256 votingUnitsPerNft = _nft.store().tierOf(address(_nft), 1, false).votingUnits;
186
- assertTrue(votingUnitsPerNft > 0, "Voting units should be non-zero");
187
-
188
- // Capture the total tier attestation supply before transfer.
189
- uint256 totalBefore = _nft.getTierTotalAttestationUnitsOf(1);
190
- assertEq(totalBefore, votingUnitsPerNft * 2, "Total should be 2 NFTs worth of voting units");
191
-
192
- // Verify Player A's delegate has attestation units.
193
- uint256 playerADelegateUnitsBefore = _nft.getTierAttestationUnitsOf(playerA, 1);
194
- assertEq(playerADelegateUnitsBefore, votingUnitsPerNft, "Player A delegate should have 1 NFT of voting units");
195
-
196
- // Now create a NEW recipient (playerC) who has NEVER set delegation.
197
- address playerC = address(bytes20(keccak256("playerC")));
198
-
199
- // Warp to REFUND phase — delegation changes are locked (only MINT phase allows setTierDelegatesTo).
200
- vm.warp(defifaData.start - defifaData.refundPeriodDuration);
201
- // Confirm we are in REFUND phase by verifying setTierDelegatesTo reverts.
202
- {
203
- DefifaDelegation[] memory delegations = new DefifaDelegation[](1);
204
- delegations[0] = DefifaDelegation({delegatee: playerC, tierId: 1});
205
- vm.prank(playerC);
206
- vm.expectRevert(DefifaHook.DefifaHook_DelegateChangesUnavailableInThisPhase.selector);
207
- _nft.setTierDelegatesTo(delegations);
208
- }
209
-
210
- // Player A transfers their NFT to playerC (who has no delegate set).
211
- uint256 tokenId = _generateTokenId(1, 1); // Tier 1, token #1
212
- vm.prank(playerA);
213
- _nft.transferFrom(playerA, playerC, tokenId);
214
-
215
- // Advance 1 second so checkpoints are recorded.
216
- vm.warp(_tsReader.timestamp() + 1);
217
-
218
- // After fix: playerC should be auto-delegated to themselves.
219
- address playerCDelegate = _nft.getTierDelegateOf(playerC, 1);
220
- assertEq(playerCDelegate, playerC, "Player C should be auto-delegated to self after receiving NFT");
221
-
222
- // Player A's delegate should have lost the voting units.
223
- uint256 playerADelegateUnitsAfter = _nft.getTierAttestationUnitsOf(playerA, 1);
224
- assertEq(playerADelegateUnitsAfter, 0, "Player A delegate should have 0 voting units after transfer");
225
-
226
- // Player C (auto-delegated to self) should have gained the voting units.
227
- uint256 playerCDelegateUnits = _nft.getTierAttestationUnitsOf(playerC, 1);
228
- assertEq(playerCDelegateUnits, votingUnitsPerNft, "Player C should have gained the transferred voting units");
229
-
230
- // The total attestation supply should be unchanged — no units lost.
231
- uint256 totalAfter = _nft.getTierTotalAttestationUnitsOf(1);
232
- assertEq(totalAfter, totalBefore, "Total attestation units must be conserved across the transfer");
233
-
234
- // Verify conservation: sum of all delegate attestation units for tier 1 == total.
235
- uint256 sumOfDelegates = _nft.getTierAttestationUnitsOf(playerA, 1) + _nft.getTierAttestationUnitsOf(playerB, 1)
236
- + _nft.getTierAttestationUnitsOf(playerC, 1);
237
- assertEq(sumOfDelegates, totalAfter, "Sum of all delegate attestation units must equal total supply");
238
- }
239
-
240
- /// @notice Multiple sequential transfers to undelegated recipients should all preserve units.
241
- function test_M5_multipleTransfersToUndelegatedRecipientsPreserveUnits() public {
242
- uint8 nTiers = 2;
243
- address playerA = address(bytes20(keccak256("playerA")));
244
-
245
- DefifaLaunchProjectData memory defifaData = _getBasicLaunchData(nTiers);
246
- (uint256 _projectId, DefifaHook _nft,) = _createProject(defifaData);
247
-
248
- // Phase 1: Mint
249
- vm.warp(defifaData.start - defifaData.mintPeriodDuration - defifaData.refundPeriodDuration);
250
-
251
- // Player A mints tier 1.
252
- vm.deal(playerA, 1 ether);
253
- {
254
- uint16[] memory rawMetadata = new uint16[](1);
255
- rawMetadata[0] = 1;
256
- bytes memory metadata = _buildPayMetadata(abi.encode(playerA, rawMetadata));
257
- vm.prank(playerA);
258
- jbMultiTerminal().pay{value: 1 ether}(
259
- _projectId, JBConstants.NATIVE_TOKEN, 1 ether, playerA, 0, "", metadata
260
- );
261
- }
262
-
263
- // Player A sets delegation.
264
- {
265
- DefifaDelegation[] memory delegations = new DefifaDelegation[](1);
266
- delegations[0] = DefifaDelegation({delegatee: playerA, tierId: 1});
267
- vm.prank(playerA);
268
- _nft.setTierDelegatesTo(delegations);
269
- }
270
-
271
- vm.warp(_tsReader.timestamp() + 1);
272
-
273
- uint256 votingUnitsPerNft = _nft.store().tierOf(address(_nft), 1, false).votingUnits;
274
- uint256 totalBefore = _nft.getTierTotalAttestationUnitsOf(1);
275
- assertEq(totalBefore, votingUnitsPerNft, "Total should be 1 NFT worth of voting units");
276
-
277
- // Warp to REFUND phase.
278
- vm.warp(defifaData.start - defifaData.refundPeriodDuration);
279
-
280
- uint256 tokenId = _generateTokenId(1, 1);
281
-
282
- // Transfer through 3 undelegated recipients sequentially.
283
- address currentHolder = playerA;
284
- for (uint256 i = 0; i < 3; i++) {
285
- // forge-lint: disable-next-line(unsafe-typecast)
286
- address nextRecipient = address(uint160(0xBEEF0000 + i));
287
-
288
- vm.prank(currentHolder);
289
- _nft.transferFrom(currentHolder, nextRecipient, tokenId);
290
- vm.warp(_tsReader.timestamp() + 1);
291
-
292
- // Verify the recipient auto-delegated to self.
293
- assertEq(
294
- _nft.getTierDelegateOf(nextRecipient, 1), nextRecipient, "Each recipient should auto-delegate to self"
295
- );
296
-
297
- // Verify the recipient has the voting units.
298
- assertEq(
299
- _nft.getTierAttestationUnitsOf(nextRecipient, 1),
300
- votingUnitsPerNft,
301
- "Each recipient should hold the voting units"
302
- );
303
-
304
- // Verify total is conserved.
305
- assertEq(
306
- _nft.getTierTotalAttestationUnitsOf(1),
307
- totalBefore,
308
- "Total attestation units must remain constant across chain of transfers"
309
- );
310
-
311
- currentHolder = nextRecipient;
312
- }
313
- }
314
-
315
- /// @notice Paying for another account mints the NFT to the beneficiary and defaults attestation power to the
316
- /// beneficiary (not the payer) when no explicit delegate is provided.
317
- /// @dev When the metadata leaves the attestation delegate as address(0) and defaultAttestationDelegate is unset,
318
- /// the source code falls back to context.beneficiary. This proves that NFT ownership and attestation power
319
- /// both land on the beneficiary by default, and the payer retains neither.
320
- function test_attestationUnitsFollowBeneficiaryByDefault() public {
321
- DefifaLaunchProjectData memory defifaData = _getBasicLaunchData(2);
322
- (uint256 projectId, DefifaHook nft, DefifaGovernor _governor) = _createProject(defifaData);
323
-
324
- address payer = address(bytes20(keccak256("payer")));
325
- address beneficiary = address(bytes20(keccak256("beneficiary")));
326
-
327
- // Phase 1: Mint.
328
- vm.warp(defifaData.start - defifaData.mintPeriodDuration - defifaData.refundPeriodDuration);
329
-
330
- vm.deal(payer, 1 ether);
331
-
332
- uint16[] memory rawMetadata = new uint16[](1);
333
- rawMetadata[0] = 1;
334
- bytes memory metadata = _buildPayMetadata(abi.encode(address(0), rawMetadata));
335
-
336
- vm.prank(payer);
337
- jbMultiTerminal().pay{value: 1 ether}(
338
- projectId, JBConstants.NATIVE_TOKEN, 1 ether, beneficiary, 0, "", metadata
339
- );
340
-
341
- assertEq(nft.balanceOf(beneficiary), 1, "beneficiary should receive the NFT");
342
- assertEq(nft.balanceOf(payer), 0, "payer should not receive the NFT");
343
-
344
- vm.warp(_tsReader.timestamp() + 1);
345
-
346
- uint256 payerWeight = _governor.getAttestationWeight(projectId, payer, uint48(block.timestamp));
347
- uint256 beneficiaryWeight = _governor.getAttestationWeight(projectId, beneficiary, uint48(block.timestamp));
348
-
349
- assertEq(payerWeight, 0, "payer receives no attestation power when delegate defaults to beneficiary");
350
- assertGt(beneficiaryWeight, 0, "beneficiary receives the default attestation power");
351
- }
352
-
353
- // ----- Internal helpers ------
354
-
355
- function _getBasicLaunchData(uint8 nTiers) internal returns (DefifaLaunchProjectData memory) {
356
- DefifaTierParams[] memory tierParams = new DefifaTierParams[](nTiers);
357
- for (uint256 i = 0; i < nTiers; i++) {
358
- tierParams[i] = DefifaTierParams({
359
- reservedRate: 1001,
360
- reservedTokenBeneficiary: address(0),
361
- encodedIPFSUri: bytes32(0),
362
- shouldUseReservedTokenBeneficiaryAsDefault: false,
363
- name: "DEFIFA"
364
- });
365
- }
366
-
367
- return DefifaLaunchProjectData({
368
- name: "DEFIFA",
369
- projectUri: "",
370
- contractUri: "",
371
- baseUri: "",
372
- tierPrice: 1 ether,
373
- token: JBAccountingContext({token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: JBCurrencyIds.ETH}),
374
- mintPeriodDuration: 1 days,
375
- start: uint48(block.timestamp + 3 days),
376
- refundPeriodDuration: 1 days,
377
- store: new JB721TiersHookStore(),
378
- splits: new JBSplit[](0),
379
- attestationStartTime: 0,
380
- attestationGracePeriod: 100_381,
381
- defaultAttestationDelegate: address(0),
382
- tiers: tierParams,
383
- defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
384
- terminal: jbMultiTerminal(),
385
- minParticipation: 0,
386
- scorecardTimeout: 0,
387
- timelockDuration: 0
388
- });
389
- }
390
-
391
- function _createProject(DefifaLaunchProjectData memory defifaLaunchData)
392
- internal
393
- returns (uint256 projectId, DefifaHook nft, DefifaGovernor _governor)
394
- {
395
- _governor = governor;
396
- (projectId) = deployer.launchGameWith(defifaLaunchData);
397
- JBRuleset memory _fc = jbRulesets().currentOf(projectId);
398
- if (_fc.dataHook() == address(0)) {
399
- (_fc,) = jbRulesets().latestQueuedOf(projectId);
400
- }
401
- nft = DefifaHook(_fc.dataHook());
402
- }
403
-
404
- function _generateTokenId(uint256 _tierId, uint256 _tokenNumber) internal pure returns (uint256) {
405
- return (_tierId * 1_000_000_000) + _tokenNumber;
406
- }
407
-
408
- function _buildPayMetadata(bytes memory metadata) internal view returns (bytes memory) {
409
- bytes[] memory data = new bytes[](1);
410
- data[0] = metadata;
411
- bytes4[] memory ids = new bytes4[](1);
412
- ids[0] = metadataHelper().getId("pay", address(hook));
413
- return metadataHelper().createMetadata(ids, data);
414
- }
415
- }