@ballkidz/defifa 0.0.12 → 0.0.14

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 (44) hide show
  1. package/ADMINISTRATION.md +3 -3
  2. package/ARCHITECTURE.md +3 -2
  3. package/AUDIT_INSTRUCTIONS.md +5 -5
  4. package/CHANGE_LOG.md +62 -5
  5. package/CRYPTO_ECON.md +506 -271
  6. package/CRYPTO_ECON.pdf +0 -0
  7. package/CRYPTO_ECON.tex +438 -241
  8. package/RISKS.md +13 -1
  9. package/SKILLS.md +5 -3
  10. package/USER_JOURNEYS.md +4 -3
  11. package/package.json +6 -6
  12. package/src/DefifaDeployer.sol +128 -130
  13. package/src/DefifaGovernor.sol +304 -83
  14. package/src/DefifaHook.sol +184 -171
  15. package/src/enums/DefifaScorecardState.sol +1 -0
  16. package/src/interfaces/IDefifaGovernor.sol +42 -2
  17. package/src/libraries/DefifaHookLib.sol +69 -62
  18. package/src/structs/DefifaAttestations.sol +3 -3
  19. package/src/structs/DefifaLaunchProjectData.sol +1 -0
  20. package/src/structs/DefifaScorecard.sol +2 -0
  21. package/test/BWAFunctionComparison.t.sol +1320 -0
  22. package/test/DefifaAdversarialQuorum.t.sol +52 -37
  23. package/test/DefifaAuditLowGuards.t.sol +9 -5
  24. package/test/DefifaFeeAccounting.t.sol +2 -1
  25. package/test/DefifaGovernanceHardening.t.sol +1315 -0
  26. package/test/DefifaGovernor.t.sol +8 -4
  27. package/test/DefifaHookRegressions.t.sol +2 -1
  28. package/test/DefifaMintCostInvariant.t.sol +2 -1
  29. package/test/DefifaNoContest.t.sol +3 -2
  30. package/test/DefifaSecurity.t.sol +55 -47
  31. package/test/DefifaUSDC.t.sol +3 -2
  32. package/test/Fork.t.sol +37 -32
  33. package/test/TestAuditGaps.sol +6 -4
  34. package/test/TestQALastMile.t.sol +6 -3
  35. package/test/audit/{CodexAttestationDoubleCount.t.sol → AttestationDoubleCount.t.sol} +3 -2
  36. package/test/audit/FixPendingReserveDilution.t.sol +366 -0
  37. package/test/audit/PendingReserveDilution.t.sol +298 -0
  38. package/test/audit/PendingReserveQuorumGrief.t.sol +355 -0
  39. package/test/audit/PendingReserveSnapshotBypass.t.sol +279 -0
  40. package/test/regression/AttestationDelegateBeneficiary.t.sol +2 -1
  41. package/test/regression/FulfillmentBlocksRatification.t.sol +2 -1
  42. package/test/regression/GracePeriodBypass.t.sol +2 -1
  43. package/test/SVG.t.sol +0 -164
  44. package/test/deployScript.t.sol +0 -144
@@ -143,22 +143,22 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
143
143
  returns (uint256, address, uint256)
144
144
  {
145
145
  // Get a reference to the token being used by the project.
146
- address _token = _opsOf[gameId].token;
146
+ address token = _opsOf[gameId].token;
147
147
 
148
148
  // Get a reference to the terminal.
149
- IJBTerminal _terminal = CONTROLLER.DIRECTORY().primaryTerminalOf({projectId: gameId, token: _token});
149
+ IJBTerminal terminal = CONTROLLER.DIRECTORY().primaryTerminalOf({projectId: gameId, token: token});
150
150
 
151
151
  // Get the accounting context for the project.
152
- JBAccountingContext memory _context = _terminal.accountingContextForTokenOf({projectId: gameId, token: _token});
152
+ JBAccountingContext memory context = terminal.accountingContextForTokenOf({projectId: gameId, token: token});
153
153
 
154
154
  // Get the current balance.
155
- uint256 _pot = IJBMultiTerminal(address(_terminal)).STORE()
156
- .balanceOf({terminal: address(_terminal), projectId: gameId, token: _token});
155
+ uint256 pot = IJBMultiTerminal(address(terminal)).STORE()
156
+ .balanceOf({terminal: address(terminal), projectId: gameId, token: token});
157
157
 
158
158
  // Add any fulfilled commitments.
159
- if (includeCommitments) _pot += fulfilledCommitmentsOf[gameId];
159
+ if (includeCommitments) pot += fulfilledCommitmentsOf[gameId];
160
160
 
161
- return (_pot, _token, _context.decimals);
161
+ return (pot, token, context.decimals);
162
162
  }
163
163
 
164
164
  /// @notice Whether or not the next phase still needs queuing.
@@ -166,13 +166,13 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
166
166
  /// @return Whether or not the next phase still needs queuing.
167
167
  function nextPhaseNeedsQueueing(uint256 gameId) external view override returns (bool) {
168
168
  // Get the game's current funding cycle along with its metadata.
169
- JBRuleset memory _currentRuleset = CONTROLLER.RULESETS().currentOf(gameId);
169
+ JBRuleset memory currentRuleset = CONTROLLER.RULESETS().currentOf(gameId);
170
170
  // Get the game's queued funding cycle along with its metadata.
171
171
  // slither-disable-next-line unused-return
172
- (JBRuleset memory _queuedRuleset,) = CONTROLLER.RULESETS().latestQueuedOf(gameId);
172
+ (JBRuleset memory queuedRuleset,) = CONTROLLER.RULESETS().latestQueuedOf(gameId);
173
173
 
174
174
  // If the configurations are the same and the game hasn't ended, queueing is still needed.
175
- return _currentRuleset.duration != 0 && _currentRuleset.id == _queuedRuleset.id;
175
+ return currentRuleset.duration != 0 && currentRuleset.id == queuedRuleset.id;
176
176
  }
177
177
 
178
178
  /// @notice The safety mechanism parameters of a game.
@@ -185,8 +185,8 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
185
185
  override
186
186
  returns (uint256 minParticipation, uint32 scorecardTimeout)
187
187
  {
188
- DefifaOpsData memory _ops = _opsOf[gameId];
189
- return (_ops.minParticipation, _ops.scorecardTimeout);
188
+ DefifaOpsData memory ops = _opsOf[gameId];
189
+ return (ops.minParticipation, ops.scorecardTimeout);
190
190
  }
191
191
 
192
192
  /// @notice The game times.
@@ -195,8 +195,8 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
195
195
  /// @return The game's minting period duration, in seconds.
196
196
  /// @return The game's refund period duration, in seconds.
197
197
  function timesFor(uint256 gameId) external view override returns (uint48, uint24, uint24) {
198
- DefifaOpsData memory _ops = _opsOf[gameId];
199
- return (_ops.start, _ops.mintPeriodDuration, _ops.refundPeriodDuration);
198
+ DefifaOpsData memory ops = _opsOf[gameId];
199
+ return (ops.start, ops.mintPeriodDuration, ops.refundPeriodDuration);
200
200
  }
201
201
 
202
202
  /// @notice The token of a game.
@@ -218,36 +218,36 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
218
218
  /// @return The game phase.
219
219
  function currentGamePhaseOf(uint256 gameId) public view override returns (DefifaGamePhase) {
220
220
  // Get the game's current funding cycle along with its metadata.
221
- (JBRuleset memory _currentRuleset, JBRulesetMetadata memory _metadata) = CONTROLLER.currentRulesetOf(gameId);
221
+ (JBRuleset memory currentRuleset, JBRulesetMetadata memory metadata) = CONTROLLER.currentRulesetOf(gameId);
222
222
 
223
- if (_currentRuleset.cycleNumber == 0) return DefifaGamePhase.COUNTDOWN;
224
- if (_currentRuleset.cycleNumber == 1) return DefifaGamePhase.MINT;
225
- if (_currentRuleset.cycleNumber == 2 && _opsOf[gameId].refundPeriodDuration != 0) {
223
+ if (currentRuleset.cycleNumber == 0) return DefifaGamePhase.COUNTDOWN;
224
+ if (currentRuleset.cycleNumber == 1) return DefifaGamePhase.MINT;
225
+ if (currentRuleset.cycleNumber == 2 && _opsOf[gameId].refundPeriodDuration != 0) {
226
226
  return DefifaGamePhase.REFUND;
227
227
  }
228
228
 
229
229
  // Check if the scorecard has been ratified (game is COMPLETE).
230
230
  // This takes priority over all NO_CONTEST checks — a ratified scorecard is final.
231
- if (IDefifaHook(_metadata.dataHook).cashOutWeightIsSet()) return DefifaGamePhase.COMPLETE;
231
+ if (IDefifaHook(metadata.dataHook).cashOutWeightIsSet()) return DefifaGamePhase.COMPLETE;
232
232
 
233
233
  // If no-contest has already been triggered, stay in NO_CONTEST.
234
234
  if (noContestTriggeredFor[gameId]) return DefifaGamePhase.NO_CONTEST;
235
235
 
236
236
  // Get the game's ops data for the safety mechanism checks.
237
- DefifaOpsData memory _ops = _opsOf[gameId];
237
+ DefifaOpsData memory ops = _opsOf[gameId];
238
238
 
239
239
  // Check minimum participation threshold: if the treasury balance is below the threshold, the game is
240
240
  // NO_CONTEST.
241
- if (_ops.minParticipation > 0) {
242
- IJBTerminal _terminal = CONTROLLER.DIRECTORY().primaryTerminalOf({projectId: gameId, token: _ops.token});
243
- uint256 _balance = IJBMultiTerminal(address(_terminal)).STORE()
244
- .balanceOf({terminal: address(_terminal), projectId: gameId, token: _ops.token});
245
- if (_balance < _ops.minParticipation) return DefifaGamePhase.NO_CONTEST;
241
+ if (ops.minParticipation > 0) {
242
+ IJBTerminal terminal = CONTROLLER.DIRECTORY().primaryTerminalOf({projectId: gameId, token: ops.token});
243
+ uint256 balance = IJBMultiTerminal(address(terminal)).STORE()
244
+ .balanceOf({terminal: address(terminal), projectId: gameId, token: ops.token});
245
+ if (balance < ops.minParticipation) return DefifaGamePhase.NO_CONTEST;
246
246
  }
247
247
 
248
248
  // Check scorecard ratification timeout: if enough time has passed without a ratified scorecard, the game is
249
249
  // NO_CONTEST.
250
- if (_ops.scorecardTimeout > 0 && block.timestamp > _currentRuleset.start + _ops.scorecardTimeout) {
250
+ if (ops.scorecardTimeout > 0 && block.timestamp > currentRuleset.start + ops.scorecardTimeout) {
251
251
  return DefifaGamePhase.NO_CONTEST;
252
252
  }
253
253
 
@@ -297,48 +297,48 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
297
297
 
298
298
  // Get the game's current funding cycle along with its metadata.
299
299
  // slither-disable-next-line unused-return
300
- (, JBRulesetMetadata memory _metadata) = CONTROLLER.currentRulesetOf(gameId);
300
+ (, JBRulesetMetadata memory metadata) = CONTROLLER.currentRulesetOf(gameId);
301
301
 
302
302
  // Make sure the game's commitments can be fulfilled.
303
- if (!IDefifaHook(_metadata.dataHook).cashOutWeightIsSet()) {
303
+ if (!IDefifaHook(metadata.dataHook).cashOutWeightIsSet()) {
304
304
  revert DefifaDeployer_CantFulfillYet();
305
305
  }
306
306
 
307
307
  // Get the game token and the terminal.
308
- address _token = _opsOf[gameId].token;
309
- IJBMultiTerminal _terminal =
310
- IJBMultiTerminal(address(CONTROLLER.DIRECTORY().primaryTerminalOf({projectId: gameId, token: _token})));
308
+ address token = _opsOf[gameId].token;
309
+ IJBMultiTerminal terminal =
310
+ IJBMultiTerminal(address(CONTROLLER.DIRECTORY().primaryTerminalOf({projectId: gameId, token: token})));
311
311
 
312
312
  // Get the current pot and store it. This also prevents re-entrance since the check above will return early.
313
- uint256 _pot = _terminal.STORE().balanceOf({terminal: address(_terminal), projectId: gameId, token: _token});
313
+ uint256 pot = terminal.STORE().balanceOf({terminal: address(terminal), projectId: gameId, token: token});
314
314
 
315
315
  // If the pot is empty, set the sentinel and queue the final ruleset without attempting payouts.
316
316
  // slither-disable-next-line incorrect-equality
317
- if (_pot == 0) {
317
+ if (pot == 0) {
318
318
  fulfilledCommitmentsOf[gameId] = 1;
319
- _queueFinalRuleset({gameId: gameId, metadata: _metadata});
319
+ _queueFinalRuleset({gameId: gameId, metadata: metadata});
320
320
  emit FulfilledCommitments({gameId: gameId, pot: 0, caller: msg.sender});
321
321
  return;
322
322
  }
323
323
 
324
324
  // Compute the fee amount based on the total absolute split percent stored at game creation.
325
- uint256 _feeAmount =
326
- mulDiv({x: _pot, y: _commitmentPercentOf[gameId], denominator: JBConstants.SPLITS_TOTAL_PERCENT});
325
+ uint256 feeAmount =
326
+ mulDiv({x: pot, y: _commitmentPercentOf[gameId], denominator: JBConstants.SPLITS_TOTAL_PERCENT});
327
327
 
328
328
  // Store the actual fee amount for accurate currentGamePotOf reporting.
329
329
  // Use max(feeAmount, 1) to preserve the reentrancy guard when pot is 0.
330
- fulfilledCommitmentsOf[gameId] = _feeAmount > 0 ? _feeAmount : 1;
330
+ fulfilledCommitmentsOf[gameId] = feeAmount > 0 ? feeAmount : 1;
331
331
 
332
332
  // Send only the fee portion as payouts. The remaining balance stays as surplus for cash-outs.
333
333
  // Wrapped in try-catch so the final ruleset is always queued even if payout fails.
334
334
  // slither-disable-next-line unused-return,reentrancy-no-eth
335
- try _terminal.sendPayoutsOf({
335
+ try terminal.sendPayoutsOf({
336
336
  projectId: gameId,
337
- token: _token,
338
- amount: _feeAmount,
337
+ token: token,
338
+ amount: feeAmount,
339
339
  // Casting address to uint32 via uint160 is the standard Juicebox token-to-currency conversion.
340
340
  // forge-lint: disable-next-line(unsafe-typecast)
341
- currency: _token == JBConstants.NATIVE_TOKEN ? _metadata.baseCurrency : uint32(uint160(_token)),
341
+ currency: token == JBConstants.NATIVE_TOKEN ? metadata.baseCurrency : uint32(uint160(token)),
342
342
  minTokensPaidOut: 0
343
343
  }) {}
344
344
  catch (bytes memory reason) {
@@ -346,14 +346,14 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
346
346
  // doesn't double-count the fee, while preserving the reentrancy guard.
347
347
  fulfilledCommitmentsOf[gameId] = 1;
348
348
  // slither-disable-next-line reentrancy-events
349
- emit CommitmentPayoutFailed({gameId: gameId, amount: _feeAmount, reason: reason});
349
+ emit CommitmentPayoutFailed({gameId: gameId, amount: feeAmount, reason: reason});
350
350
  }
351
351
 
352
352
  // Queue the final ruleset and emit.
353
- _queueFinalRuleset({gameId: gameId, metadata: _metadata});
353
+ _queueFinalRuleset({gameId: gameId, metadata: metadata});
354
354
 
355
355
  // slither-disable-next-line reentrancy-events
356
- emit FulfilledCommitments({gameId: gameId, pot: _pot, caller: msg.sender});
356
+ emit FulfilledCommitments({gameId: gameId, pot: pot, caller: msg.sender});
357
357
  }
358
358
 
359
359
  /// @notice Launches a new game owned by this contract with a DefifaHook attached.
@@ -390,7 +390,7 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
390
390
  // Get the game ID, optimistically knowing it will be one greater than the current count.
391
391
  // Note: this prediction can race with other concurrent project deployments. If another project is
392
392
  // created between reading count() and launchProjectFor(), the actual ID will differ. This is
393
- // caught by the equality check after launch (gameId != _actualGameId reverts).
393
+ // caught by the equality check after launch (gameId != actualGameId reverts).
394
394
  gameId = CONTROLLER.PROJECTS().count() + 1;
395
395
 
396
396
  {
@@ -405,24 +405,24 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
405
405
  });
406
406
 
407
407
  // Keep a reference to the number of splits.
408
- uint256 _numberOfSplits = launchProjectData.splits.length;
408
+ uint256 numberOfSplits = launchProjectData.splits.length;
409
409
 
410
410
  // If there are splits being added, store the fee alongside. The fee will otherwise be added later.
411
- if (_numberOfSplits != 0) {
411
+ if (numberOfSplits != 0) {
412
412
  // Make a new splits where fees will be added to.
413
- JBSplit[] memory _splits = new JBSplit[](launchProjectData.splits.length + 1);
413
+ JBSplit[] memory splits = new JBSplit[](launchProjectData.splits.length + 1);
414
414
 
415
415
  // Copy the splits over.
416
- for (uint256 _i; _i < _numberOfSplits;) {
416
+ for (uint256 i; i < numberOfSplits;) {
417
417
  // Copy the split over.
418
- _splits[_i] = launchProjectData.splits[_i];
418
+ splits[i] = launchProjectData.splits[i];
419
419
  unchecked {
420
- ++_i;
420
+ ++i;
421
421
  }
422
422
  }
423
423
 
424
424
  // Add a split for the fee.
425
- _splits[_numberOfSplits] = JBSplit({
425
+ splits[numberOfSplits] = JBSplit({
426
426
  preferAddToBalance: false,
427
427
  // forge-lint: disable-next-line(unsafe-typecast)
428
428
  percent: uint32(JBConstants.SPLITS_TOTAL_PERCENT / DEFIFA_FEE_DIVISOR),
@@ -434,44 +434,44 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
434
434
  });
435
435
 
436
436
  // Store the splits.
437
- JBSplitGroup[] memory _groupedSplits = new JBSplitGroup[](1);
438
- _groupedSplits[0] = JBSplitGroup({groupId: SPLIT_GROUP, splits: _splits});
437
+ JBSplitGroup[] memory groupedSplits = new JBSplitGroup[](1);
438
+ groupedSplits[0] = JBSplitGroup({groupId: SPLIT_GROUP, splits: splits});
439
439
 
440
440
  // This contract must have SET_SPLIT_GROUPS permission from the defifa project owner.
441
441
  CONTROLLER.setSplitGroupsOf({
442
- projectId: DEFIFA_PROJECT_ID, rulesetId: gameId, splitGroups: _groupedSplits
442
+ projectId: DEFIFA_PROJECT_ID, rulesetId: gameId, splitGroups: groupedSplits
443
443
  });
444
444
  }
445
445
  }
446
446
 
447
447
  // Keep track of the number of tiers.
448
- uint256 _numberOfTiers = launchProjectData.tiers.length;
448
+ uint256 numberOfTiers = launchProjectData.tiers.length;
449
449
 
450
450
  // Create the standard tiers struct that will be populated from the defifa tiers.
451
- JB721TierConfig[] memory _hookTiers = new JB721TierConfig[](launchProjectData.tiers.length);
451
+ JB721TierConfig[] memory hookTiers = new JB721TierConfig[](launchProjectData.tiers.length);
452
452
 
453
453
  // Group all the tier names together.
454
- string[] memory _tierNames = new string[](launchProjectData.tiers.length);
454
+ string[] memory tierNames = new string[](launchProjectData.tiers.length);
455
455
 
456
456
  // Keep a reference to the tier being iterated on.
457
- DefifaTierParams memory _defifaTier;
457
+ DefifaTierParams memory defifaTier;
458
458
 
459
459
  // Create the hook tiers from the Defifa tiers.
460
- for (uint256 _i; _i < _numberOfTiers;) {
461
- _defifaTier = launchProjectData.tiers[_i];
460
+ for (uint256 i; i < numberOfTiers;) {
461
+ defifaTier = launchProjectData.tiers[i];
462
462
 
463
463
  // Set the tier. All tiers use the same price so that price-based voting power is equal.
464
- _hookTiers[_i] = JB721TierConfig({
464
+ hookTiers[i] = JB721TierConfig({
465
465
  price: launchProjectData.tierPrice,
466
466
  initialSupply: 999_999_999, // Uncapped minting — max value allowed by the 721 store.
467
467
  votingUnits: 0,
468
- reserveFrequency: _defifaTier.reservedRate,
469
- reserveBeneficiary: _defifaTier.reservedTokenBeneficiary,
470
- encodedIPFSUri: _defifaTier.encodedIPFSUri,
468
+ reserveFrequency: defifaTier.reservedRate,
469
+ reserveBeneficiary: defifaTier.reservedTokenBeneficiary,
470
+ encodedIPFSUri: defifaTier.encodedIPFSUri,
471
471
  category: 0,
472
472
  discountPercent: 0,
473
473
  allowOwnerMint: false,
474
- useReserveBeneficiaryAsDefault: _defifaTier.shouldUseReservedTokenBeneficiaryAsDefault,
474
+ useReserveBeneficiaryAsDefault: defifaTier.shouldUseReservedTokenBeneficiaryAsDefault,
475
475
  transfersPausable: false,
476
476
  useVotingUnits: false,
477
477
  cannotBeRemoved: true,
@@ -481,72 +481,73 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
481
481
  });
482
482
 
483
483
  // Set the name.
484
- _tierNames[_i] = _defifaTier.name;
484
+ tierNames[i] = defifaTier.name;
485
485
 
486
486
  unchecked {
487
- ++_i;
487
+ ++i;
488
488
  }
489
489
  }
490
490
 
491
491
  // Increment the nonce for this deployment.
492
- uint256 _currentNonce = ++_nonce;
492
+ uint256 currentNonce = ++_nonce;
493
493
 
494
494
  // Clone deterministically using sender and nonce to prevent front-running.
495
495
  // Clones.clone() creates the proxy before initialize() is called, allowing an
496
496
  // attacker to front-run initialization and DOS the game deployment. Using
497
497
  // cloneDeterministic with msg.sender in the salt prevents this since a different
498
498
  // caller produces a different address.
499
- DefifaHook _hook = DefifaHook(
499
+ DefifaHook hook = DefifaHook(
500
500
  Clones.cloneDeterministic({
501
- implementation: HOOK_CODE_ORIGIN, salt: keccak256(abi.encodePacked(msg.sender, _currentNonce))
501
+ implementation: HOOK_CODE_ORIGIN, salt: keccak256(abi.encodePacked(msg.sender, currentNonce))
502
502
  })
503
503
  );
504
504
 
505
505
  // Use the default uri resolver if provided, else use the hardcoded generic default.
506
- IJB721TokenUriResolver _uriResolver = launchProjectData.defaultTokenUriResolver
506
+ IJB721TokenUriResolver uriResolver = launchProjectData.defaultTokenUriResolver
507
507
  != IJB721TokenUriResolver(address(0))
508
508
  ? launchProjectData.defaultTokenUriResolver
509
509
  : TOKEN_URI_RESOLVER;
510
510
 
511
- _hook.initialize({
511
+ hook.initialize({
512
512
  _gameId: gameId,
513
513
  _name: launchProjectData.name,
514
514
  _symbol: string.concat("DEFIFA #", gameId.toString()),
515
515
  _rulesets: CONTROLLER.RULESETS(),
516
516
  _baseUri: launchProjectData.baseUri,
517
- _tokenUriResolver: _uriResolver,
517
+ _tokenUriResolver: uriResolver,
518
518
  _contractUri: launchProjectData.contractUri,
519
- _tiers: _hookTiers,
519
+ _tiers: hookTiers,
520
520
  _currency: launchProjectData.token.currency,
521
521
  _store: launchProjectData.store,
522
522
  _gamePhaseReporter: this,
523
523
  _gamePotReporter: this,
524
524
  _defaultAttestationDelegate: launchProjectData.defaultAttestationDelegate,
525
- _tierNames: _tierNames
525
+ _tierNames: tierNames
526
526
  });
527
527
 
528
528
  // Launch the Juicebox project.
529
- uint256 _actualGameId =
530
- _launchGame({launchProjectData: launchProjectData, _gameId: gameId, _dataHook: address(_hook)});
529
+ uint256 actualGameId =
530
+ _launchGame({launchProjectData: launchProjectData, gameId: gameId, dataHook: address(hook)});
531
531
 
532
532
  // Revert if the game ID does not match (e.g. front-run by another project creation).
533
- if (gameId != _actualGameId) revert DefifaDeployer_InvalidGameConfiguration();
533
+ if (gameId != actualGameId) revert DefifaDeployer_InvalidGameConfiguration();
534
534
 
535
535
  // Clone and initialize the new governor.
536
536
  GOVERNOR.initializeGame({
537
537
  gameId: gameId,
538
538
  attestationStartTime: uint256(launchProjectData.attestationStartTime),
539
- attestationGracePeriod: uint256(launchProjectData.attestationGracePeriod)
539
+ attestationGracePeriod: uint256(launchProjectData.attestationGracePeriod),
540
+ timelockDuration: launchProjectData.timelockDuration
540
541
  });
541
542
 
542
543
  // Transfer ownership to the specified owner.
543
- _hook.transferOwnership(address(GOVERNOR));
544
+ hook.transferOwnership(address(GOVERNOR));
544
545
 
545
546
  // Add the hook to the registry, contract nonce starts at 1
546
- REGISTRY.registerAddress({deployer: address(this), nonce: _currentNonce});
547
+ REGISTRY.registerAddress({deployer: address(this), nonce: currentNonce});
547
548
 
548
549
  // slither-disable-next-line reentrancy-events
549
- emit LaunchGame(gameId, _hook, GOVERNOR, _uriResolver, msg.sender);
550
+ emit LaunchGame(gameId, hook, GOVERNOR, uriResolver, msg.sender);
550
551
  }
551
552
 
552
553
  /// @notice Allows this contract to receive 721s.
@@ -577,7 +578,7 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
577
578
 
578
579
  // Get the game's current ruleset metadata for the data hook address.
579
580
  // slither-disable-next-line unused-return
580
- (, JBRulesetMetadata memory _metadata) = CONTROLLER.currentRulesetOf(gameId);
581
+ (, JBRulesetMetadata memory metadata) = CONTROLLER.currentRulesetOf(gameId);
581
582
 
582
583
  // Queue a new ruleset without payout limits so surplus = balance, enabling refunds.
583
584
  JBRulesetConfig[] memory rulesetConfigs = new JBRulesetConfig[](1);
@@ -590,7 +591,7 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
590
591
  metadata: JBRulesetMetadata({
591
592
  reservedPercent: 0,
592
593
  cashOutTaxRate: 0,
593
- baseCurrency: _metadata.baseCurrency,
594
+ baseCurrency: metadata.baseCurrency,
594
595
  pausePay: true,
595
596
  pauseCreditTransfers: false,
596
597
  allowOwnerMinting: false,
@@ -605,7 +606,7 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
605
606
  useTotalSurplusForCashOuts: false,
606
607
  useDataHookForPay: true,
607
608
  useDataHookForCashOut: true,
608
- dataHook: _metadata.dataHook,
609
+ dataHook: metadata.dataHook,
609
610
  metadata: uint16(
610
611
  JB721TiersRulesetMetadataResolver.pack721TiersRulesetMetadata(
611
612
  JB721TiersRulesetMetadata({pauseTransfers: false, pauseMintPendingReserves: false})
@@ -631,93 +632,90 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
631
632
  //*********************************************************************//
632
633
 
633
634
  function _buildSplits(
634
- uint256 _gameId,
635
- address _dataHook,
636
- address _token,
637
- JBSplit[] memory _initialSplits
635
+ uint256 gameId,
636
+ address dataHook,
637
+ address token,
638
+ JBSplit[] memory initialSplits
638
639
  )
639
640
  internal
640
641
  returns (JBSplitGroup[] memory)
641
642
  {
642
- uint256 _numberOfUserSplits = _initialSplits.length;
643
+ uint256 numberOfUserSplits = initialSplits.length;
643
644
 
644
645
  // Compute absolute percents for protocol fees.
645
- uint256 _nanaAbsolutePercent = JBConstants.SPLITS_TOTAL_PERCENT / BASE_PROTOCOL_FEE_DIVISOR;
646
- uint256 _defifaAbsolutePercent = JBConstants.SPLITS_TOTAL_PERCENT / DEFIFA_FEE_DIVISOR;
646
+ uint256 nanaAbsolutePercent = JBConstants.SPLITS_TOTAL_PERCENT / BASE_PROTOCOL_FEE_DIVISOR;
647
+ uint256 defifaAbsolutePercent = JBConstants.SPLITS_TOTAL_PERCENT / DEFIFA_FEE_DIVISOR;
647
648
 
648
649
  // Sum all absolute percents.
649
- uint256 _totalAbsolutePercent = _nanaAbsolutePercent + _defifaAbsolutePercent;
650
- for (uint256 _i; _i < _numberOfUserSplits; _i++) {
651
- _totalAbsolutePercent += _initialSplits[_i].percent;
650
+ uint256 totalAbsolutePercent = nanaAbsolutePercent + defifaAbsolutePercent;
651
+ for (uint256 i; i < numberOfUserSplits; i++) {
652
+ totalAbsolutePercent += initialSplits[i].percent;
652
653
  }
653
654
 
654
655
  // Validate that total fee splits don't exceed 100%.
655
- if (_totalAbsolutePercent > JBConstants.SPLITS_TOTAL_PERCENT) revert DefifaDeployer_SplitsDontAddUp();
656
+ if (totalAbsolutePercent > JBConstants.SPLITS_TOTAL_PERCENT) revert DefifaDeployer_SplitsDontAddUp();
656
657
 
657
658
  // Store the total absolute percent for use in fulfillCommitmentsOf.
658
- _commitmentPercentOf[_gameId] = _totalAbsolutePercent;
659
+ _commitmentPercentOf[gameId] = totalAbsolutePercent;
659
660
 
660
661
  // Build the splits array: user splits + Defifa + NANA (NANA last to absorb rounding).
661
- uint256 _splitCount = _numberOfUserSplits + 2;
662
- JBSplit[] memory _splits = new JBSplit[](_splitCount);
662
+ uint256 splitCount = numberOfUserSplits + 2;
663
+ JBSplit[] memory splits = new JBSplit[](splitCount);
663
664
 
664
665
  // Normalize user splits and copy them over.
665
- uint256 _normalizedTotal;
666
- for (uint256 _i; _i < _numberOfUserSplits; _i++) {
667
- _splits[_i] = _initialSplits[_i];
668
- _splits[_i].percent = uint32(
666
+ uint256 normalizedTotal;
667
+ for (uint256 i; i < numberOfUserSplits; i++) {
668
+ splits[i] = initialSplits[i];
669
+ splits[i].percent = uint32(
669
670
  mulDiv({
670
- x: _initialSplits[_i].percent,
671
- y: JBConstants.SPLITS_TOTAL_PERCENT,
672
- denominator: _totalAbsolutePercent
671
+ x: initialSplits[i].percent, y: JBConstants.SPLITS_TOTAL_PERCENT, denominator: totalAbsolutePercent
673
672
  })
674
673
  );
675
- _normalizedTotal += _splits[_i].percent;
674
+ normalizedTotal += splits[i].percent;
676
675
  }
677
676
 
678
677
  // Add Defifa fee split (normalized).
679
- uint256 _defifaNormalized = mulDiv({
680
- x: _defifaAbsolutePercent, y: JBConstants.SPLITS_TOTAL_PERCENT, denominator: _totalAbsolutePercent
681
- });
682
- _splits[_numberOfUserSplits] = JBSplit({
678
+ uint256 defifaNormalized =
679
+ mulDiv({x: defifaAbsolutePercent, y: JBConstants.SPLITS_TOTAL_PERCENT, denominator: totalAbsolutePercent});
680
+ splits[numberOfUserSplits] = JBSplit({
683
681
  preferAddToBalance: false,
684
682
  // forge-lint: disable-next-line(unsafe-typecast)
685
- percent: uint32(_defifaNormalized),
683
+ percent: uint32(defifaNormalized),
686
684
  // forge-lint: disable-next-line(unsafe-typecast)
687
685
  projectId: uint64(DEFIFA_PROJECT_ID),
688
- beneficiary: payable(address(_dataHook)),
686
+ beneficiary: payable(address(dataHook)),
689
687
  lockedUntil: 0,
690
688
  hook: IJBSplitHook(address(0))
691
689
  });
692
- _normalizedTotal += _defifaNormalized;
690
+ normalizedTotal += defifaNormalized;
693
691
 
694
692
  // Add NANA protocol fee split last — absorbs rounding remainder from normalization.
695
693
  // Because mulDiv rounds down, the sum of normalized percents can be slightly less than SPLITS_TOTAL_PERCENT.
696
694
  // The NANA split receives the difference, so its effective percent may be a few basis points above its
697
695
  // proportional share. This is economically negligible (< 1 bps at typical split counts).
698
696
  // Beneficiary is the data hook so the hook receives NANA tokens for distribution during cash-outs.
699
- _splits[_splitCount - 1] = JBSplit({
697
+ splits[splitCount - 1] = JBSplit({
700
698
  preferAddToBalance: false,
701
699
  // forge-lint: disable-next-line(unsafe-typecast)
702
- percent: uint32(JBConstants.SPLITS_TOTAL_PERCENT - _normalizedTotal),
700
+ percent: uint32(JBConstants.SPLITS_TOTAL_PERCENT - normalizedTotal),
703
701
  // forge-lint: disable-next-line(unsafe-typecast)
704
702
  projectId: uint64(BASE_PROTOCOL_PROJECT_ID),
705
- beneficiary: payable(address(_dataHook)),
703
+ beneficiary: payable(address(dataHook)),
706
704
  lockedUntil: 0,
707
705
  hook: IJBSplitHook(address(0))
708
706
  });
709
707
 
710
708
  // Build the grouped split for the payment of the game token.
711
- JBSplitGroup[] memory _groupedSplits = new JBSplitGroup[](1);
712
- _groupedSplits[0] = JBSplitGroup({groupId: uint256(uint160(_token)), splits: _splits});
709
+ JBSplitGroup[] memory groupedSplits = new JBSplitGroup[](1);
710
+ groupedSplits[0] = JBSplitGroup({groupId: uint256(uint160(token)), splits: splits});
713
711
 
714
- return _groupedSplits;
712
+ return groupedSplits;
715
713
  }
716
714
 
717
715
  function _launchGame(
718
716
  DefifaLaunchProjectData memory launchProjectData,
719
- uint256 _gameId,
720
- address _dataHook
717
+ uint256 gameId,
718
+ address dataHook
721
719
  )
722
720
  internal
723
721
  returns (uint256 projectId)
@@ -761,7 +759,7 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
761
759
  useTotalSurplusForCashOuts: false,
762
760
  useDataHookForPay: true,
763
761
  useDataHookForCashOut: true,
764
- dataHook: _dataHook,
762
+ dataHook: dataHook,
765
763
  metadata: uint16(
766
764
  JB721TiersRulesetMetadataResolver.pack721TiersRulesetMetadata(
767
765
  JB721TiersRulesetMetadata({
@@ -804,7 +802,7 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
804
802
  useTotalSurplusForCashOuts: false,
805
803
  useDataHookForPay: true,
806
804
  useDataHookForCashOut: true,
807
- dataHook: _dataHook,
805
+ dataHook: dataHook,
808
806
  metadata: uint16(
809
807
  JB721TiersRulesetMetadataResolver.pack721TiersRulesetMetadata(
810
808
  JB721TiersRulesetMetadata({
@@ -862,7 +860,7 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
862
860
  useTotalSurplusForCashOuts: false,
863
861
  useDataHookForPay: true,
864
862
  useDataHookForCashOut: true,
865
- dataHook: _dataHook,
863
+ dataHook: dataHook,
866
864
  metadata: uint16(
867
865
  JB721TiersRulesetMetadataResolver.pack721TiersRulesetMetadata(
868
866
  JB721TiersRulesetMetadata({pauseTransfers: false, pauseMintPendingReserves: false})
@@ -870,10 +868,10 @@ contract DefifaDeployer is IDefifaDeployer, IDefifaGamePhaseReporter, IDefifaGam
870
868
  )
871
869
  }),
872
870
  splitGroups: _buildSplits({
873
- _gameId: _gameId,
874
- _dataHook: _dataHook,
875
- _token: launchProjectData.token.token,
876
- _initialSplits: launchProjectData.splits
871
+ gameId: gameId,
872
+ dataHook: dataHook,
873
+ token: launchProjectData.token.token,
874
+ initialSplits: launchProjectData.splits
877
875
  }),
878
876
  fundAccessLimitGroups: fundAccessConstraints
879
877
  });