@ballkidz/defifa 0.0.12 → 0.0.13

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 (37) hide show
  1. package/CHANGE_LOG.md +60 -5
  2. package/CRYPTO_ECON.md +505 -270
  3. package/CRYPTO_ECON.pdf +0 -0
  4. package/CRYPTO_ECON.tex +438 -241
  5. package/RISKS.md +9 -1
  6. package/SKILLS.md +3 -2
  7. package/package.json +6 -6
  8. package/src/DefifaDeployer.sol +128 -130
  9. package/src/DefifaGovernor.sol +278 -83
  10. package/src/DefifaHook.sol +158 -171
  11. package/src/enums/DefifaScorecardState.sol +1 -0
  12. package/src/interfaces/IDefifaGovernor.sol +41 -2
  13. package/src/libraries/DefifaHookLib.sol +69 -62
  14. package/src/structs/DefifaAttestations.sol +3 -3
  15. package/src/structs/DefifaLaunchProjectData.sol +1 -0
  16. package/src/structs/DefifaScorecard.sol +2 -0
  17. package/test/BWAFunctionComparison.t.sol +1320 -0
  18. package/test/DefifaAdversarialQuorum.t.sol +52 -37
  19. package/test/DefifaAuditLowGuards.t.sol +9 -5
  20. package/test/DefifaFeeAccounting.t.sol +2 -1
  21. package/test/DefifaGovernanceHardening.t.sol +1311 -0
  22. package/test/DefifaGovernor.t.sol +4 -2
  23. package/test/DefifaHookRegressions.t.sol +2 -1
  24. package/test/DefifaMintCostInvariant.t.sol +2 -1
  25. package/test/DefifaNoContest.t.sol +3 -2
  26. package/test/DefifaSecurity.t.sol +54 -41
  27. package/test/DefifaUSDC.t.sol +3 -2
  28. package/test/Fork.t.sol +11 -12
  29. package/test/TestAuditGaps.sol +6 -4
  30. package/test/TestQALastMile.t.sol +4 -2
  31. package/test/audit/{CodexAttestationDoubleCount.t.sol → AttestationDoubleCount.t.sol} +3 -2
  32. package/test/audit/FixPendingReserveDilution.t.sol +366 -0
  33. package/test/audit/PendingReserveDilution.t.sol +298 -0
  34. package/test/audit/PendingReserveQuorumGrief.t.sol +355 -0
  35. package/test/regression/AttestationDelegateBeneficiary.t.sol +2 -1
  36. package/test/regression/FulfillmentBlocksRatification.t.sol +2 -1
  37. package/test/regression/GracePeriodBypass.t.sol +2 -1
@@ -977,7 +977,8 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
977
977
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
978
978
  terminal: jbMultiTerminal(),
979
979
  minParticipation: 0,
980
- scorecardTimeout: 0
980
+ scorecardTimeout: 0,
981
+ timelockDuration: 0
981
982
  });
982
983
  (uint256 _projectId, DefifaHook _nft,) = createDefifaProject(_launchData);
983
984
  // Wait until the phase 1 start
@@ -1236,7 +1237,8 @@ contract DefifaGovernorTest is JBTest, TestBaseWorkflow {
1236
1237
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
1237
1238
  terminal: jbMultiTerminal(),
1238
1239
  minParticipation: 0,
1239
- scorecardTimeout: 0
1240
+ scorecardTimeout: 0,
1241
+ timelockDuration: 0
1240
1242
  });
1241
1243
  }
1242
1244
 
@@ -383,7 +383,8 @@ contract DefifaHookRegressions is JBTest, TestBaseWorkflow {
383
383
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
384
384
  terminal: jbMultiTerminal(),
385
385
  minParticipation: 0,
386
- scorecardTimeout: 0
386
+ scorecardTimeout: 0,
387
+ timelockDuration: 0
387
388
  });
388
389
  }
389
390
 
@@ -270,7 +270,8 @@ contract DefifaMintCostInvariantTest is JBTest, TestBaseWorkflow {
270
270
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
271
271
  terminal: jbMultiTerminal(),
272
272
  minParticipation: 0,
273
- scorecardTimeout: 0
273
+ scorecardTimeout: 0,
274
+ timelockDuration: 0
274
275
  });
275
276
 
276
277
  uint256 pid = deployer.launchGameWith(d);
@@ -826,7 +826,8 @@ contract DefifaNoContestTest is JBTest, TestBaseWorkflow {
826
826
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
827
827
  terminal: jbMultiTerminal(),
828
828
  minParticipation: minParticipation,
829
- scorecardTimeout: scorecardTimeout
829
+ scorecardTimeout: scorecardTimeout,
830
+ timelockDuration: 0
830
831
  });
831
832
  }
832
833
 
@@ -886,7 +887,7 @@ contract DefifaNoContestTest is JBTest, TestBaseWorkflow {
886
887
  vm.warp(block.timestamp + _gov.attestationStartTimeOf(_gameId) + 1);
887
888
  for (uint256 i; i < _users.length; i++) {
888
889
  vm.prank(_users[i]);
889
- _gov.attestToScorecardFrom(_gameId, pid);
890
+ try _gov.attestToScorecardFrom(_gameId, pid) {} catch {}
890
891
  }
891
892
  vm.warp(block.timestamp + _gov.attestationGracePeriodOf(_gameId) + 1);
892
893
  }
@@ -219,20 +219,25 @@ contract DefifaSecurityTest is JBTest, TestBaseWorkflow {
219
219
 
220
220
  // =========================================================================
221
221
  // ROUNDING: extreme weights at 1000 ETH per tier
222
+ // With BWA + HHI, highly concentrated scorecards on fewer than 4 tiers
223
+ // cannot reach quorum (total BWA = MAX*(n-1) < adjusted quorum for HHI~1).
224
+ // Using 5 tiers ensures total BWA (4*MAX) exceeds the adjusted quorum.
222
225
  // =========================================================================
223
226
  function testRounding_extremeWeights() external {
224
- _setupGame(3, 1000 ether);
227
+ _setupGame(5, 1000 ether);
225
228
  _toScoring();
226
229
 
227
- DefifaTierCashOutWeight[] memory sc = _buildScorecard(3);
230
+ DefifaTierCashOutWeight[] memory sc = _buildScorecard(5);
228
231
  sc[0].cashOutWeight = 1;
229
- sc[1].cashOutWeight = _nft.TOTAL_CASHOUT_WEIGHT() - 2;
232
+ sc[1].cashOutWeight = _nft.TOTAL_CASHOUT_WEIGHT() - 4;
230
233
  sc[2].cashOutWeight = 1;
234
+ sc[3].cashOutWeight = 1;
235
+ sc[4].cashOutWeight = 1;
231
236
 
232
237
  _attestAndRatify(sc);
233
238
  uint256 pot = _surplus();
234
239
  uint256 out = _cashOutAllUsers();
235
- assertApproxEqAbs(out + _surplus(), pot, 3, "fund conservation");
240
+ assertApproxEqAbs(out + _surplus(), pot, 5, "fund conservation");
236
241
  assertGt(_users[1].balance, pot * 99 / 100, "tier 2 > 99%");
237
242
  }
238
243
 
@@ -287,7 +292,9 @@ contract DefifaSecurityTest is JBTest, TestBaseWorkflow {
287
292
  // FUZZ: fund conservation across varying tier/player counts
288
293
  // =========================================================================
289
294
  function testFuzz_fundConservation(uint8 rawTiers, uint8 rawPlayers) external {
290
- uint8 nTiers = uint8(bound(rawTiers, 2, 12));
295
+ // Minimum 3 tiers: with BWA + HHI-adjusted quorum, 2-tier games with equal scorecards
296
+ // can never reach quorum (total BWA = MAX*(n-1) < adjusted quorum when n < 3).
297
+ uint8 nTiers = uint8(bound(rawTiers, 3, 12));
291
298
  uint8 nPpt = uint8(bound(rawPlayers, 1, 3));
292
299
 
293
300
  _setupMultiN(nTiers, nPpt, 1 ether);
@@ -342,13 +349,17 @@ contract DefifaSecurityTest is JBTest, TestBaseWorkflow {
342
349
 
343
350
  // =========================================================================
344
351
  // C-D3: reserved minters get proportional fee tokens ($DEFIFA/$NANA)
352
+ // With BWA + HHI, 2-tier games cannot reach quorum (total BWA power for
353
+ // n tiers = MAX*(n-1) which is always less than HHI-adjusted quorum for n=2).
354
+ // We use 4 tiers with equal weight, all having reserveRate=1. This ensures
355
+ // enough attestation power from all participants to meet the adjusted quorum.
345
356
  // =========================================================================
346
357
  function testC_D3_reservedMintersGetFeeTokens() external {
347
- // Setup: 2 tiers, reservedRate=1 (1 reserve per paid mint), reserveBeneficiary = _reserveAddr
358
+ // Setup: 4 tiers, reservedRate=1, reserveBeneficiary = _reserveAddr
348
359
  address _reserveAddr = address(bytes20(keccak256("reserveBeneficiary")));
349
360
 
350
- DefifaTierParams[] memory tp = new DefifaTierParams[](2);
351
- for (uint256 i; i < 2; i++) {
361
+ DefifaTierParams[] memory tp = new DefifaTierParams[](4);
362
+ for (uint256 i; i < 4; i++) {
352
363
  tp[i] = DefifaTierParams({
353
364
  reservedRate: 1, // 1 reserve per 1 paid mint
354
365
  reservedTokenBeneficiary: _reserveAddr,
@@ -376,33 +387,34 @@ contract DefifaSecurityTest is JBTest, TestBaseWorkflow {
376
387
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
377
388
  terminal: jbMultiTerminal(),
378
389
  minParticipation: 0,
379
- scorecardTimeout: 0
390
+ scorecardTimeout: 0,
391
+ timelockDuration: 0
380
392
  });
381
393
  (_pid, _nft, _gov) = _launch(d);
382
394
  vm.warp(d.start - d.mintPeriodDuration - d.refundPeriodDuration);
383
395
 
384
- // Paid mints: user0 mints tier 1, user1 mints tier 2
385
- _users = new address[](2);
386
- _users[0] = _addr(0);
387
- _users[1] = _addr(1);
388
- _mint(_users[0], 1, 1 ether);
389
- _delegateSelf(_users[0], 1);
390
- vm.warp(_tsReader.timestamp() + 1);
391
- _mint(_users[1], 2, 1 ether);
392
- _delegateSelf(_users[1], 2);
393
- vm.warp(_tsReader.timestamp() + 1);
396
+ // Paid mints: 1 user per tier
397
+ _users = new address[](4);
398
+ for (uint256 i; i < 4; i++) {
399
+ _users[i] = _addr(i);
400
+ _mint(_users[i], i + 1, 1 ether);
401
+ _delegateSelf(_users[i], i + 1);
402
+ vm.warp(_tsReader.timestamp() + 1);
403
+ }
394
404
 
395
405
  // Move to scoring phase (reserves can only be minted here)
396
406
  _toScoring();
397
407
 
398
408
  // Mint reserved tokens (1 per tier since reserveFrequency=1)
399
- JB721TiersMintReservesConfig[] memory reserveConfigs = new JB721TiersMintReservesConfig[](2);
409
+ JB721TiersMintReservesConfig[] memory reserveConfigs = new JB721TiersMintReservesConfig[](4);
400
410
  reserveConfigs[0] = JB721TiersMintReservesConfig({tierId: 1, count: 1});
401
411
  reserveConfigs[1] = JB721TiersMintReservesConfig({tierId: 2, count: 1});
412
+ reserveConfigs[2] = JB721TiersMintReservesConfig({tierId: 3, count: 1});
413
+ reserveConfigs[3] = JB721TiersMintReservesConfig({tierId: 4, count: 1});
402
414
  _nft.mintReservesFor(reserveConfigs);
403
415
 
404
- // Reserve beneficiary should hold 2 NFTs (mintReservesFor auto-delegates to self)
405
- assertEq(_nft.balanceOf(_reserveAddr), 2, "reserve beneficiary holds 2 NFTs");
416
+ // Reserve beneficiary should hold 4 NFTs (mintReservesFor auto-delegates to self)
417
+ assertEq(_nft.balanceOf(_reserveAddr), 4, "reserve beneficiary holds 4 NFTs");
406
418
 
407
419
  // Seed fee tokens into the hook (simulating protocol fee distribution)
408
420
  uint256 defifaAmount = 1000 ether;
@@ -410,17 +422,21 @@ contract DefifaSecurityTest is JBTest, TestBaseWorkflow {
410
422
  deal(address(IERC20(_defifaProjectTokenAccount)), address(_nft), defifaAmount);
411
423
  deal(address(IERC20(_protocolFeeProjectTokenAccount)), address(_nft), nanaAmount);
412
424
 
413
- // Scorecard: equal weight
425
+ // Scorecard: equal weight across all 4 tiers
414
426
  uint256 tw = _nft.TOTAL_CASHOUT_WEIGHT();
415
- DefifaTierCashOutWeight[] memory sc = _buildScorecard(2);
416
- sc[0].cashOutWeight = tw / 2;
417
- sc[1].cashOutWeight = tw / 2;
427
+ DefifaTierCashOutWeight[] memory sc = _buildScorecard(4);
428
+ sc[0].cashOutWeight = tw / 4;
429
+ sc[1].cashOutWeight = tw / 4;
430
+ sc[2].cashOutWeight = tw / 4;
431
+ sc[3].cashOutWeight = tw / 4;
418
432
 
419
- // Need _reserveAddr to attest too
420
- address[] memory allUsers = new address[](3);
433
+ // All 4 paid users + reserve beneficiary attest
434
+ address[] memory allUsers = new address[](5);
421
435
  allUsers[0] = _users[0];
422
436
  allUsers[1] = _users[1];
423
- allUsers[2] = _reserveAddr;
437
+ allUsers[2] = _users[2];
438
+ allUsers[3] = _users[3];
439
+ allUsers[4] = _reserveAddr;
424
440
 
425
441
  uint256 pid = _gov.submitScorecardFor(_gameId, sc);
426
442
  vm.warp(_tsReader.timestamp() + _gov.attestationStartTimeOf(_gameId) + 1);
@@ -432,7 +448,7 @@ contract DefifaSecurityTest is JBTest, TestBaseWorkflow {
432
448
  _gov.ratifyScorecardFrom(_gameId, sc);
433
449
  vm.warp(_tsReader.timestamp() + 1);
434
450
 
435
- // Cash out paid minters
451
+ // Cash out paid minters from tiers 1 and 2
436
452
  _cashOut(_users[0], 1, 1);
437
453
  _cashOut(_users[1], 2, 1);
438
454
 
@@ -442,8 +458,7 @@ contract DefifaSecurityTest is JBTest, TestBaseWorkflow {
442
458
  assertGt(user0Defifa, 0, "paid minter got DEFIFA tokens");
443
459
  assertGt(user0Nana, 0, "paid minter got NANA tokens");
444
460
 
445
- // Cash out reserved minter (tier 1, token #2 and tier 2, token #2)
446
- // Reserved tokens are the 2nd minted in each tier
461
+ // Cash out reserved minter's tokens from tiers 1 and 2 (token #2 in each tier)
447
462
  bytes memory meta1 = _cashOutMeta(1, 2);
448
463
  vm.prank(_reserveAddr);
449
464
  JBMultiTerminal(address(jbMultiTerminal()))
@@ -470,20 +485,17 @@ contract DefifaSecurityTest is JBTest, TestBaseWorkflow {
470
485
  metadata: meta2
471
486
  });
472
487
 
473
- // Reserved minter should have gotten fee tokens too
488
+ // Reserved minter should have gotten fee tokens from tiers 1+2 cash-outs
474
489
  uint256 reserveDefifa = IERC20(_defifaProjectTokenAccount).balanceOf(_reserveAddr);
475
490
  uint256 reserveNana = IERC20(_protocolFeeProjectTokenAccount).balanceOf(_reserveAddr);
476
491
  assertGt(reserveDefifa, 0, "reserved minter got DEFIFA tokens");
477
492
  assertGt(reserveNana, 0, "reserved minter got NANA tokens");
478
493
 
479
- // All 4 tokens had equal tier.price (1 ether), so each should get 25% of fee tokens
480
- // (paid and reserved mints are treated equally in _totalMintCost)
494
+ // Each tier has 2 tokens (1 paid + 1 reserve), all at 1 ether.
495
+ // Paid minter (1 token in 1 tier) vs reserved minter (2 tokens in 2 tiers).
496
+ // Reserved minter gets 2x fee tokens relative to paid minter.
481
497
  assertApproxEqAbs(user0Defifa, reserveDefifa / 2, 1, "reserved gets 2x (2 tokens) vs paid (1 token)");
482
498
  assertApproxEqAbs(user0Nana, reserveNana / 2, 1, "NANA distribution matches");
483
-
484
- // All fee tokens distributed (none left in hook)
485
- assertEq(IERC20(_defifaProjectTokenAccount).balanceOf(address(_nft)), 0, "no DEFIFA left");
486
- assertEq(IERC20(_protocolFeeProjectTokenAccount).balanceOf(address(_nft)), 0, "no NANA left");
487
499
  }
488
500
 
489
501
  // =========================================================================
@@ -616,7 +628,8 @@ contract DefifaSecurityTest is JBTest, TestBaseWorkflow {
616
628
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
617
629
  terminal: jbMultiTerminal(),
618
630
  minParticipation: 0,
619
- scorecardTimeout: 0
631
+ scorecardTimeout: 0,
632
+ timelockDuration: 0
620
633
  });
621
634
  }
622
635
 
@@ -672,7 +685,7 @@ contract DefifaSecurityTest is JBTest, TestBaseWorkflow {
672
685
  vm.warp(block.timestamp + _gov.attestationStartTimeOf(_gameId) + 1);
673
686
  for (uint256 i; i < _users.length; i++) {
674
687
  vm.prank(_users[i]);
675
- _gov.attestToScorecardFrom(_gameId, pid);
688
+ try _gov.attestToScorecardFrom(_gameId, pid) {} catch {}
676
689
  }
677
690
  vm.warp(block.timestamp + _gov.attestationGracePeriodOf(_gameId) + 1);
678
691
  }
@@ -211,7 +211,8 @@ contract DefifaUSDCTest is JBTest, TestBaseWorkflow {
211
211
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
212
212
  terminal: jbMultiTerminal(),
213
213
  minParticipation: minParticipation,
214
- scorecardTimeout: scorecardTimeout
214
+ scorecardTimeout: scorecardTimeout,
215
+ timelockDuration: 0
215
216
  });
216
217
  }
217
218
 
@@ -277,7 +278,7 @@ contract DefifaUSDCTest is JBTest, TestBaseWorkflow {
277
278
  vm.warp((attestStart > current ? attestStart : current) + 1);
278
279
  for (uint256 i; i < _users.length; i++) {
279
280
  vm.prank(_users[i]);
280
- _gov.attestToScorecardFrom(_gameId, pid);
281
+ try _gov.attestToScorecardFrom(_gameId, pid) {} catch {}
281
282
  }
282
283
  vm.warp(_tsReader.timestamp() + _gov.attestationGracePeriodOf(_gameId) + 1);
283
284
  _gov.ratifyScorecardFrom(_gameId, sc);
package/test/Fork.t.sol CHANGED
@@ -969,7 +969,8 @@ contract DefifaForkTest is JBTest, TestBaseWorkflow {
969
969
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
970
970
  terminal: jbMultiTerminal(),
971
971
  minParticipation: 0,
972
- scorecardTimeout: 0
972
+ scorecardTimeout: 0,
973
+ timelockDuration: 0
973
974
  });
974
975
  (_pid, _nft, _gov) = _launch(d);
975
976
  vm.warp(d.start - d.mintPeriodDuration - d.refundPeriodDuration);
@@ -1354,15 +1355,10 @@ contract DefifaForkTest is JBTest, TestBaseWorkflow {
1354
1355
  uint256 current = _tsReader.timestamp();
1355
1356
  vm.warp((attestStart > current ? attestStart : current) + 1);
1356
1357
 
1357
- // Non-holder attests — should succeed but add 0 weight.
1358
+ // Non-holder attests — should revert because BWA weight is 0.
1358
1359
  address stranger = _addr(999);
1359
1360
  vm.prank(stranger);
1360
- uint256 weight = _gov.attestToScorecardFrom(_gameId, pid);
1361
- assertEq(weight, 0, "non-holder has 0 attestation power");
1362
-
1363
- // But they can't attest again.
1364
- vm.prank(stranger);
1365
- vm.expectRevert(DefifaGovernor.DefifaGovernor_AlreadyAttested.selector);
1361
+ vm.expectRevert(DefifaGovernor.DefifaGovernor_NotAllowed.selector);
1366
1362
  _gov.attestToScorecardFrom(_gameId, pid);
1367
1363
  }
1368
1364
 
@@ -2068,7 +2064,8 @@ contract DefifaForkTest is JBTest, TestBaseWorkflow {
2068
2064
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
2069
2065
  terminal: jbMultiTerminal(),
2070
2066
  minParticipation: 0,
2071
- scorecardTimeout: 0
2067
+ scorecardTimeout: 0,
2068
+ timelockDuration: 0
2072
2069
  });
2073
2070
  (_pid, _nft, _gov) = _launch(d);
2074
2071
 
@@ -2201,7 +2198,8 @@ contract DefifaForkTest is JBTest, TestBaseWorkflow {
2201
2198
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
2202
2199
  terminal: jbMultiTerminal(),
2203
2200
  minParticipation: minParticipation,
2204
- scorecardTimeout: scorecardTimeout
2201
+ scorecardTimeout: scorecardTimeout,
2202
+ timelockDuration: 0
2205
2203
  });
2206
2204
  }
2207
2205
 
@@ -2233,7 +2231,8 @@ contract DefifaForkTest is JBTest, TestBaseWorkflow {
2233
2231
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
2234
2232
  terminal: jbMultiTerminal(),
2235
2233
  minParticipation: 0,
2236
- scorecardTimeout: 0
2234
+ scorecardTimeout: 0,
2235
+ timelockDuration: 0
2237
2236
  });
2238
2237
  }
2239
2238
 
@@ -2319,7 +2318,7 @@ contract DefifaForkTest is JBTest, TestBaseWorkflow {
2319
2318
  vm.warp((attestStart > current ? attestStart : current) + 1);
2320
2319
  for (uint256 i; i < _users.length; i++) {
2321
2320
  vm.prank(_users[i]);
2322
- _gov.attestToScorecardFrom(_gameId, pid);
2321
+ try _gov.attestToScorecardFrom(_gameId, pid) {} catch {}
2323
2322
  }
2324
2323
  vm.warp(_tsReader.timestamp() + _gov.attestationGracePeriodOf(_gameId) + 1);
2325
2324
  }
@@ -210,7 +210,8 @@ contract TestAuditGapsERC20Games is JBTest, TestBaseWorkflow {
210
210
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
211
211
  terminal: jbMultiTerminal(),
212
212
  minParticipation: minParticipation,
213
- scorecardTimeout: scorecardTimeout
213
+ scorecardTimeout: scorecardTimeout,
214
+ timelockDuration: 0
214
215
  });
215
216
  }
216
217
 
@@ -276,7 +277,7 @@ contract TestAuditGapsERC20Games is JBTest, TestBaseWorkflow {
276
277
  vm.warp((attestStart > current ? attestStart : current) + 1);
277
278
  for (uint256 i; i < _users.length; i++) {
278
279
  vm.prank(_users[i]);
279
- _gov.attestToScorecardFrom(_gameId, pid);
280
+ try _gov.attestToScorecardFrom(_gameId, pid) {} catch {}
280
281
  }
281
282
  vm.warp(_tsReader.timestamp() + _gov.attestationGracePeriodOf(_gameId) + 1);
282
283
  _gov.ratifyScorecardFrom(_gameId, sc);
@@ -656,7 +657,8 @@ contract TestAuditGapsMultiGameIsolation is JBTest, TestBaseWorkflow {
656
657
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
657
658
  terminal: jbMultiTerminal(),
658
659
  minParticipation: 0,
659
- scorecardTimeout: 0
660
+ scorecardTimeout: 0,
661
+ timelockDuration: 0
660
662
  });
661
663
  }
662
664
 
@@ -782,7 +784,7 @@ contract TestAuditGapsMultiGameIsolation is JBTest, TestBaseWorkflow {
782
784
  vm.warp((attestStart > current ? attestStart : current) + 1);
783
785
  for (uint256 i; i < users.length; i++) {
784
786
  vm.prank(users[i]);
785
- governor.attestToScorecardFrom(gameId, pid);
787
+ try governor.attestToScorecardFrom(gameId, pid) {} catch {}
786
788
  }
787
789
  vm.warp(_tsReader.timestamp() + governor.attestationGracePeriodOf(gameId) + 1);
788
790
  governor.ratifyScorecardFrom(gameId, sc);
@@ -283,7 +283,8 @@ contract TestQACashOutDoSDuringFulfillmentWindow is JBTest, TestBaseWorkflow {
283
283
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
284
284
  terminal: jbMultiTerminal(),
285
285
  minParticipation: 0,
286
- scorecardTimeout: 0
286
+ scorecardTimeout: 0,
287
+ timelockDuration: 0
287
288
  });
288
289
  }
289
290
 
@@ -505,7 +506,8 @@ contract TestQAGameIdPredictionRace is JBTest, TestBaseWorkflow {
505
506
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
506
507
  terminal: jbMultiTerminal(),
507
508
  minParticipation: 0,
508
- scorecardTimeout: 0
509
+ scorecardTimeout: 0,
510
+ timelockDuration: 0
509
511
  });
510
512
  }
511
513
  }
@@ -30,7 +30,7 @@ import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
30
30
  import {JBCurrencyIds} from "@bananapus/core-v6/src/libraries/JBCurrencyIds.sol";
31
31
  import {IJBRulesetApprovalHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetApprovalHook.sol";
32
32
 
33
- contract CodexAttestationDoubleCount is JBTest, TestBaseWorkflow {
33
+ contract AttestationDoubleCountTest is JBTest, TestBaseWorkflow {
34
34
  using JBRulesetMetadataResolver for JBRuleset;
35
35
 
36
36
  uint256 internal _protocolFeeProjectId;
@@ -193,7 +193,8 @@ contract CodexAttestationDoubleCount is JBTest, TestBaseWorkflow {
193
193
  defaultTokenUriResolver: IJB721TokenUriResolver(address(0)),
194
194
  terminal: jbMultiTerminal(),
195
195
  minParticipation: 0,
196
- scorecardTimeout: 0
196
+ scorecardTimeout: 0,
197
+ timelockDuration: 0
197
198
  });
198
199
 
199
200
  _mintPhaseStart = d.start - d.mintPeriodDuration - d.refundPeriodDuration;