@ballkidz/defifa 0.0.28 → 0.0.30

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.
@@ -47,24 +47,19 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
47
47
  // --------------------------- custom errors ------------------------- //
48
48
  //*********************************************************************//
49
49
 
50
- error DefifaHook_BadTierOrder();
51
- error DefifaHook_IdenticalTokens();
52
- error DefifaHook_DelegateAddressZero();
53
- error DefifaHook_DelegateChangesUnavailableInThisPhase();
54
- error DefifaHook_GameIsntScoringYet();
55
- error DefifaHook_InvalidTierId();
56
- error DefifaHook_InvalidCashoutWeights();
57
- error DefifaHook_NothingToClaim();
58
- error DefifaHook_NothingToMint();
59
- error DefifaHook_WrongCurrency();
60
- error DefifaHook_Overspending();
61
- error DefifaHook_CashoutWeightsAlreadySet();
62
- error DefifaHook_ReservedTokenMintingPaused();
63
- error DefifaHook_TransfersPaused();
50
+ error DefifaHook_IdenticalTokens(address defifaToken, address baseProtocolToken);
51
+ error DefifaHook_DelegateAddressZero(uint256 tierId);
52
+ error DefifaHook_DelegateChangesUnavailableInThisPhase(uint256 projectId, DefifaGamePhase phase);
53
+ error DefifaHook_GameIsntScoringYet(uint256 projectId, DefifaGamePhase phase);
54
+ error DefifaHook_NothingToClaim(uint256 reclaimedAmount, bool beneficiaryReceivedTokens);
55
+ error DefifaHook_NothingToMint(bool metadataFound, uint256 tierCount);
56
+ error DefifaHook_WrongCurrency(uint256 expectedCurrency, uint256 actualCurrency);
57
+ error DefifaHook_Overspending(uint256 leftoverAmount);
58
+ error DefifaHook_CashoutWeightsAlreadySet(uint256 projectId);
59
+ error DefifaHook_ReservedTokenMintingPaused(uint256 projectId, uint256 tierId);
60
+ error DefifaHook_TransfersPaused(uint256 projectId, uint256 tokenId, address from, address to);
64
61
  error DefifaHook_Unauthorized(uint256 tokenId, address owner, address caller);
65
62
 
66
- event PricingCurrencySet(uint256 currency, address caller);
67
-
68
63
  //*********************************************************************//
69
64
  // --------------------- public constant properties ------------------ //
70
65
  //*********************************************************************//
@@ -175,34 +170,10 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
175
170
  /// between burns and reserves is not linear — it depends on the tier's reserve frequency.
176
171
  /// @param tierId The tier ID.
177
172
  /// @return The adjusted pending reserve count (floored at 0).
178
- // slither-disable-next-line calls-loop
179
173
  function adjustedPendingReservesFor(uint256 tierId) public view returns (uint256) {
180
- uint256 refundBurns = refundedBurnsFrom[tierId];
181
-
182
- // If no refund burns, return the store's value directly.
183
- if (refundBurns == 0) return store.numberOfPendingReservesFor({hook: address(this), tierId: tierId});
184
-
185
- // Get the tier to access reserveFrequency and supply data.
186
- JB721Tier memory tier = store.tierOf({hook: address(this), id: tierId, includeResolvedUri: false});
187
-
188
- // No reserves if no reserve frequency.
189
- if (tier.reserveFrequency == 0) return 0;
190
-
191
- // Calculate the number of reserves already minted.
192
- uint256 reservesMinted = store.numberOfReservesMintedFor({hook: address(this), tierId: tierId});
193
-
194
- // Calculate non-reserve mints: initialSupply - remainingSupply - reservesMinted.
195
- uint256 nonReserveMints = tier.initialSupply - tier.remainingSupply - reservesMinted;
196
-
197
- // Subtract refund burns from non-reserve mints (burns can't exceed non-reserve mints).
198
- uint256 adjustedMints = nonReserveMints > refundBurns ? nonReserveMints - refundBurns : 0;
199
-
200
- // Recalculate available reserves: ceil(adjustedMints / reserveFrequency).
201
- uint256 availableReserves = adjustedMints / tier.reserveFrequency;
202
- if (adjustedMints % tier.reserveFrequency > 0) ++availableReserves;
203
-
204
- // Return pending = available - already minted (floored at 0).
205
- return availableReserves > reservesMinted ? availableReserves - reservesMinted : 0;
174
+ return DefifaHookLib.adjustedPendingReservesFor({
175
+ tierId: tierId, hookStore: store, hook: address(this), refundBurns: refundedBurnsFrom[tierId]
176
+ });
206
177
  }
207
178
 
208
179
  /// @notice The first owner of each token ID, which corresponds to the address that originally contributed to the
@@ -332,30 +303,14 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
332
303
  // Cache the store reference in a local variable to avoid repeated SLOAD.
333
304
  IJB721TiersHookStore hookStore = store;
334
305
 
335
- // Calculate the amount paid to mint the tokens that are being burned.
336
- uint256 cumulativeMintPrice = DefifaHookLib.computeCumulativeMintPrice({
337
- tokenIds: decodedTokenIds, hookStore: hookStore, hook: address(this)
338
- });
339
-
340
- // During refund phases, exclude reserve-minted tokens — they were minted for free and have no paid amount
341
- // to refund.
342
- if (
343
- gamePhase == DefifaGamePhase.MINT || gamePhase == DefifaGamePhase.REFUND
306
+ // During refund phases, reserve-minted tokens were minted for free and have no paid amount to refund.
307
+ uint256 cumulativeMintPrice = DefifaHookLib.computeCumulativeMintPriceForCashOut({
308
+ tokenIds: decodedTokenIds,
309
+ hookStore: hookStore,
310
+ hook: address(this),
311
+ excludeReserveMints: gamePhase == DefifaGamePhase.MINT || gamePhase == DefifaGamePhase.REFUND
344
312
  || gamePhase == DefifaGamePhase.NO_CONTEST
345
- ) {
346
- for (uint256 i; i < decodedTokenIds.length;) {
347
- if (isReserveMint[decodedTokenIds[i]]) {
348
- // slither-disable-next-line calls-loop
349
- cumulativeMintPrice -= hookStore.tierOfTokenId({
350
- hook: address(this), tokenId: decodedTokenIds[i], includeResolvedUri: false
351
- }).price;
352
- }
353
-
354
- unchecked {
355
- ++i;
356
- }
357
- }
358
- }
313
+ });
359
314
 
360
315
  // Use this contract as the only cash out hook.
361
316
  hookSpecifications = new JBCashOutHookSpecification[](1);
@@ -428,18 +383,6 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
428
383
  return interfaceId == type(IDefifaHook).interfaceId || super.supportsInterface(interfaceId);
429
384
  }
430
385
 
431
- /// @notice The amount of $DEFIFA and $BASE_PROTOCOL tokens this game was allocated from paying the network fee.
432
- /// @return defifaTokenAllocation The $DEFIFA token allocation.
433
- /// @return baseProtocolTokenAllocation The $BASE_PROTOCOL token allocation.
434
- function tokenAllocations()
435
- public
436
- view
437
- returns (uint256 defifaTokenAllocation, uint256 baseProtocolTokenAllocation)
438
- {
439
- defifaTokenAllocation = DEFIFA_TOKEN.balanceOf(address(this));
440
- baseProtocolTokenAllocation = BASE_PROTOCOL_TOKEN.balanceOf(address(this));
441
- }
442
-
443
386
  /// @notice The metadata URI of the provided token ID.
444
387
  /// @dev Defer to the tokenUriResolver if set, otherwise, use the tokenUri set with the token's tier.
445
388
  /// @param tokenId The ID of the token to get the tier URI for.
@@ -459,12 +402,11 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
459
402
  returns (uint256 defifaTokenAmount, uint256 baseProtocolTokenAmount)
460
403
  {
461
404
  // If the game isn't complete, we do not have any tokens to claim.
462
- if (gamePhaseReporter.currentGamePhaseOf(PROJECT_ID) != DefifaGamePhase.COMPLETE) return (0, 0);
405
+ if (_currentGamePhaseOf(PROJECT_ID) != DefifaGamePhase.COMPLETE) return (0, 0);
463
406
 
464
407
  // Include unminted reserves in the denominator. Once reserves are pending, their future recipients are
465
408
  // entitled to fee-token claims as if the reserve NFTs had already been minted; otherwise paid holders could
466
409
  // claim too large a share before the reserve mint transaction lands.
467
- // slither-disable-next-line unused-return
468
410
  return DefifaHookLib.computeTokensClaim({
469
411
  tokenIds: tokenIds,
470
412
  hookStore: store,
@@ -495,7 +437,11 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
495
437
  JB721Hook(_directory)
496
438
  Ownable(msg.sender)
497
439
  {
498
- if (address(_defifaToken) == address(_baseProtocolToken)) revert DefifaHook_IdenticalTokens();
440
+ if (address(_defifaToken) == address(_baseProtocolToken)) {
441
+ revert DefifaHook_IdenticalTokens({
442
+ defifaToken: address(_defifaToken), baseProtocolToken: address(_baseProtocolToken)
443
+ });
444
+ }
499
445
 
500
446
  CODE_ORIGIN = address(this);
501
447
  DEFIFA_TOKEN = _defifaToken;
@@ -509,7 +455,6 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
509
455
  /// @notice Mints one or more NFTs to the `context.beneficiary` upon payment if conditions are met.
510
456
  /// @dev Reverts if the calling contract is not one of the project's terminals.
511
457
  /// @param context The payment context passed in by the terminal.
512
- // slither-disable-next-line locked-ether
513
458
  function afterPayRecordedWith(JBAfterPayRecordedContext calldata context)
514
459
  external
515
460
  payable
@@ -520,10 +465,9 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
520
465
 
521
466
  // Make sure the caller is a terminal of the project, and that the call is being made on behalf of an
522
467
  // interaction with the correct project.
523
- if (
524
- msg.value != 0 || !DIRECTORY.isTerminalOf({projectId: projectId, terminal: IJBTerminal(msg.sender)})
525
- || context.projectId != projectId
526
- ) revert JB721Hook_InvalidPay();
468
+ if (msg.value != 0 || !_isProjectTerminal(projectId) || context.projectId != projectId) {
469
+ revert JB721Hook_InvalidPay();
470
+ }
527
471
 
528
472
  // Process the payment.
529
473
  _processPayment(context);
@@ -582,7 +526,6 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
582
526
  pricingCurrency = _currency;
583
527
  gamePhaseReporter = _gamePhaseReporter;
584
528
  gamePotReporter = _gamePotReporter;
585
- // slither-disable-next-line missing-zero-check
586
529
  defaultAttestationDelegate = _defaultAttestationDelegate;
587
530
 
588
531
  // Store the base URI if provided.
@@ -597,7 +540,6 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
597
540
  }
598
541
 
599
542
  // Record the provided tiers.
600
- // slither-disable-next-line unused-return
601
543
  _store.recordAddTiers(_tiers);
602
544
 
603
545
  // Keep a reference to the number of tier names.
@@ -615,26 +557,21 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
615
557
 
616
558
  // Transfer ownership to the initializer.
617
559
  _transferOwnership(msg.sender);
618
-
619
- emit PricingCurrencySet(_currency, msg.sender);
620
560
  }
621
561
 
622
562
  /// @notice Mint reserved tokens within the tier for the provided value.
623
563
  /// @param tierId The ID of the tier to mint within.
624
564
  /// @param count The number of reserved tokens to mint.
625
- // slither-disable-next-line reentrancy-benign,reentrancy-no-eth
626
565
  function mintReservesFor(uint256 tierId, uint256 count) public override {
627
566
  // Minting reserves must not be paused.
628
- // slither-disable-next-line calls-loop
629
- if (JB721TiersRulesetMetadataResolver.mintPendingReservesPaused(
630
- (JBRulesetMetadataResolver.metadata(rulesets.currentOf(PROJECT_ID)))
631
- )) revert DefifaHook_ReservedTokenMintingPaused();
567
+ if (JB721TiersRulesetMetadataResolver.mintPendingReservesPaused(_rulesetMetadata())) {
568
+ revert DefifaHook_ReservedTokenMintingPaused({projectId: PROJECT_ID, tierId: tierId});
569
+ }
632
570
 
633
571
  // Cache the store reference in a local variable to avoid repeated SLOAD.
634
572
  IJB721TiersHookStore hookStore = store;
635
573
 
636
574
  // Keep a reference to the reserved token beneficiary.
637
- // slither-disable-next-line calls-loop
638
575
  address reservedTokenBeneficiary = hookStore.reserveBeneficiaryOf({hook: address(this), tierId: tierId});
639
576
 
640
577
  // Get a reference to the old delegate.
@@ -652,21 +589,18 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
652
589
  }
653
590
 
654
591
  // Record the minted reserves for the tier.
655
- // slither-disable-next-line calls-loop
656
592
  uint256[] memory tokenIds = hookStore.recordMintReservesFor({tierId: tierId, count: count});
657
593
 
658
594
  // Keep a reference to the token ID being iterated on.
659
595
  uint256 tokenId;
660
596
 
661
597
  // Fetch the tier details (needed for votingUnits below).
662
- // slither-disable-next-line calls-loop
663
598
  JB721Tier memory tier = hookStore.tierOf({hook: address(this), id: tierId, includeResolvedUri: false});
664
599
 
665
600
  // Increment _totalMintCost so reserved recipients can claim their share of fee tokens ($DEFIFA/$NANA).
666
601
  // Note: reserved mints dilute existing fee token claimants because they increase the total mint cost
667
602
  // denominator without contributing new funds to the fee token balances. This is the intended design —
668
603
  // reserved recipients receive a proportional claim on fee tokens as if they had paid to mint.
669
- // slither-disable-next-line reentrancy-benign
670
604
  _totalMintCost += tier.price * count;
671
605
 
672
606
  for (uint256 i; i < count;) {
@@ -677,10 +611,11 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
677
611
  isReserveMint[tokenId] = true;
678
612
 
679
613
  // Mint the token to the reserve beneficiary.
680
- // slither-disable-next-line reentrancy-no-eth
681
614
  _mint({to: reservedTokenBeneficiary, tokenId: tokenId});
682
615
 
683
- emit MintReservedToken(tokenId, tierId, reservedTokenBeneficiary, msg.sender);
616
+ emit MintReservedToken({
617
+ tokenId: tokenId, tierId: tierId, beneficiary: reservedTokenBeneficiary, caller: msg.sender
618
+ });
684
619
 
685
620
  unchecked {
686
621
  ++i;
@@ -688,7 +623,6 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
688
623
  }
689
624
 
690
625
  // Transfer the attestation units to the delegate.
691
- // slither-disable-next-line reentrancy-no-eth
692
626
  _transferTierAttestationUnits({
693
627
  from: address(0), to: reservedTokenBeneficiary, tierId: tierId, amount: tier.votingUnits * tokenIds.length
694
628
  });
@@ -710,10 +644,9 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
710
644
  {
711
645
  // Make sure the caller is a terminal of the project, and that the call is being made on behalf of an
712
646
  // interaction with the correct project.
713
- if (
714
- msg.value != 0 || !DIRECTORY.isTerminalOf({projectId: PROJECT_ID, terminal: IJBTerminal(msg.sender)})
715
- || context.projectId != PROJECT_ID
716
- ) revert JB721Hook_InvalidCashOut();
647
+ if (msg.value != 0 || !_isProjectTerminal(PROJECT_ID) || context.projectId != PROJECT_ID) {
648
+ revert JB721Hook_InvalidCashOut();
649
+ }
717
650
 
718
651
  // Fetch the cash out hook metadata using the corresponding metadata ID.
719
652
  (bool metadataExists, bytes memory metadata) = JBMetadataResolver.getDataFor({
@@ -735,7 +668,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
735
668
  uint256 tokenId;
736
669
 
737
670
  // Keep track of whether the cashOut is happening during the complete phase.
738
- bool isComplete = gamePhaseReporter.currentGamePhaseOf(PROJECT_ID) == DefifaGamePhase.COMPLETE;
671
+ bool isComplete = _currentGamePhaseOf(PROJECT_ID) == DefifaGamePhase.COMPLETE;
739
672
 
740
673
  // Cache the store reference in a local variable to avoid repeated SLOAD in the loop.
741
674
  IJB721TiersHookStore hookStore = store;
@@ -752,10 +685,8 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
752
685
  }
753
686
 
754
687
  // Burn the token.
755
- // slither-disable-next-line reentrancy-no-eth
756
688
  _burn(tokenId);
757
689
 
758
- // slither-disable-next-line calls-loop
759
690
  uint256 tierId = hookStore.tierIdOfToken(tokenId);
760
691
  if (isComplete) {
761
692
  // Track per-tier redemptions during the complete phase.
@@ -783,13 +714,11 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
783
714
  // Increment the amount redeemed if this is the complete phase.
784
715
  bool beneficiaryReceivedTokens;
785
716
  if (isComplete) {
786
- // slither-disable-next-line reentrancy-benign
787
717
  amountRedeemed += context.reclaimedAmount.value;
788
718
 
789
719
  // Claim the $DEFIFA and $NANA tokens for the user.
790
720
  // Include pending reserve mint cost in the denominator so that unminted reserves
791
721
  // are accounted for, preventing paid holders from claiming a disproportionate share.
792
- // slither-disable-next-line reentrancy-events
793
722
  beneficiaryReceivedTokens = _claimTokensFor({
794
723
  beneficiary: context.beneficiary,
795
724
  shareToBeneficiary: cumulativeMintPrice,
@@ -801,10 +730,13 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
801
730
  // Tokens in 0-weight tiers (losing teams) cannot burn to reclaim fees if no fee tokens were
802
731
  // distributed. This is correct behavior — 0-weight means the tier has no claim on the pot. Burning would
803
732
  // return 0 value regardless.
804
- if (context.reclaimedAmount.value == 0 && !beneficiaryReceivedTokens) revert DefifaHook_NothingToClaim();
733
+ if (context.reclaimedAmount.value == 0 && !beneficiaryReceivedTokens) {
734
+ revert DefifaHook_NothingToClaim({
735
+ reclaimedAmount: context.reclaimedAmount.value, beneficiaryReceivedTokens: beneficiaryReceivedTokens
736
+ });
737
+ }
805
738
 
806
739
  // Decrement the paid mint cost by the cumulative mint price of the tokens being burned.
807
- // slither-disable-next-line reentrancy-benign
808
740
  _totalMintCost -= cumulativeMintPrice;
809
741
  }
810
742
 
@@ -819,7 +751,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
819
751
  JB721TiersMintReservesConfig memory data = mintReservesForTiersData[i];
820
752
 
821
753
  // Mint for the tier.
822
- mintReservesFor(data.tierId, data.count);
754
+ mintReservesFor({tierId: data.tierId, count: data.count});
823
755
 
824
756
  unchecked {
825
757
  ++i;
@@ -832,15 +764,15 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
832
764
  /// @param tierWeights The tier weights to set.
833
765
  function setTierCashOutWeightsTo(DefifaTierCashOutWeight[] memory tierWeights) external override onlyOwner {
834
766
  // Get a reference to the game phase.
835
- DefifaGamePhase gamePhase = gamePhaseReporter.currentGamePhaseOf(PROJECT_ID);
767
+ DefifaGamePhase gamePhase = _currentGamePhaseOf(PROJECT_ID);
836
768
 
837
769
  // Make sure the game has ended.
838
770
  if (gamePhase != DefifaGamePhase.SCORING) {
839
- revert DefifaHook_GameIsntScoringYet();
771
+ revert DefifaHook_GameIsntScoringYet({projectId: PROJECT_ID, phase: gamePhase});
840
772
  }
841
773
 
842
774
  // Make sure the cashOut weights haven't already been set.
843
- if (cashOutWeightIsSet) revert DefifaHook_CashoutWeightsAlreadySet();
775
+ if (cashOutWeightIsSet) revert DefifaHook_CashoutWeightsAlreadySet({projectId: PROJECT_ID});
844
776
 
845
777
  // Validate weights and build the array. Reverts on invalid input.
846
778
  _tierCashOutWeights =
@@ -849,7 +781,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
849
781
  // Mark the cashOut weight as set.
850
782
  cashOutWeightIsSet = true;
851
783
 
852
- emit TierCashOutWeightsSet(tierWeights, msg.sender);
784
+ emit TierCashOutWeightsSet({tierWeights: tierWeights, caller: msg.sender});
853
785
  }
854
786
 
855
787
  /// @notice Delegate this account's voting power for a single tier to a specified delegate.
@@ -857,11 +789,12 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
857
789
  /// @param tierId The ID of the tier to delegate attestation units for.
858
790
  function setTierDelegateTo(address delegatee, uint256 tierId) public virtual override {
859
791
  // Make sure a delegate is specified.
860
- if (delegatee == address(0)) revert DefifaHook_DelegateAddressZero();
792
+ if (delegatee == address(0)) revert DefifaHook_DelegateAddressZero({tierId: tierId});
861
793
 
862
794
  // Make sure the current game phase is the minting phase.
863
- if (gamePhaseReporter.currentGamePhaseOf(PROJECT_ID) != DefifaGamePhase.MINT) {
864
- revert DefifaHook_DelegateChangesUnavailableInThisPhase();
795
+ DefifaGamePhase gamePhase = _currentGamePhaseOf(PROJECT_ID);
796
+ if (gamePhase != DefifaGamePhase.MINT) {
797
+ revert DefifaHook_DelegateChangesUnavailableInThisPhase({projectId: PROJECT_ID, phase: gamePhase});
865
798
  }
866
799
 
867
800
  _delegateTier({account: msg.sender, delegatee: delegatee, tierId: tierId});
@@ -871,8 +804,9 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
871
804
  /// @param delegations An array of tiers to set delegates for.
872
805
  function setTierDelegatesTo(DefifaDelegation[] memory delegations) external virtual override {
873
806
  // Make sure the current game phase is the minting phase.
874
- if (gamePhaseReporter.currentGamePhaseOf(PROJECT_ID) != DefifaGamePhase.MINT) {
875
- revert DefifaHook_DelegateChangesUnavailableInThisPhase();
807
+ DefifaGamePhase gamePhase = _currentGamePhaseOf(PROJECT_ID);
808
+ if (gamePhase != DefifaGamePhase.MINT) {
809
+ revert DefifaHook_DelegateChangesUnavailableInThisPhase({projectId: PROJECT_ID, phase: gamePhase});
876
810
  }
877
811
 
878
812
  // Keep a reference to the number of tier delegates.
@@ -886,7 +820,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
886
820
  data = delegations[i];
887
821
 
888
822
  // Make sure a delegate is specified.
889
- if (data.delegatee == address(0)) revert DefifaHook_DelegateAddressZero();
823
+ if (data.delegatee == address(0)) revert DefifaHook_DelegateAddressZero({tierId: data.tierId});
890
824
 
891
825
  _delegateTier({account: msg.sender, delegatee: data.delegatee, tierId: data.tierId});
892
826
 
@@ -897,33 +831,9 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
897
831
  }
898
832
 
899
833
  //*********************************************************************//
900
- // ------------------------ internal functions ----------------------- //
834
+ // ---------------------- internal transactions ---------------------- //
901
835
  //*********************************************************************//
902
836
 
903
- /// @notice Computes the total mint cost of all pending (unminted) reserve NFTs across all tiers.
904
- /// @dev Used to include pending reserves in the fee token claim denominator so that paid holders
905
- /// cannot claim a disproportionate share before reserves are minted.
906
- /// @return cost The total mint cost of pending reserves.
907
- function _pendingReserveMintCost() internal view returns (uint256 cost) {
908
- IJB721TiersHookStore hookStore = store;
909
- uint256 numberOfTiers = hookStore.maxTierIdOf(address(this));
910
-
911
- for (uint256 i; i < numberOfTiers;) {
912
- uint256 tierId = i + 1;
913
- uint256 pendingReserves = adjustedPendingReservesFor(tierId);
914
- if (pendingReserves != 0) {
915
- // slither-disable-next-line calls-loop
916
- JB721Tier memory tier = hookStore.tierOf({hook: address(this), id: tierId, includeResolvedUri: false});
917
-
918
- // Pending reserves dilute claims by the same economic weight as paid mints at this tier's price.
919
- cost += pendingReserves * tier.price;
920
- }
921
- unchecked {
922
- ++i;
923
- }
924
- }
925
- }
926
-
927
837
  /// @notice Claims the defifa and base protocol tokens for a beneficiary.
928
838
  /// @param beneficiary The address to claim tokens for.
929
839
  /// @param shareToBeneficiary The share relative to the `outOfTotal` to send the user.
@@ -957,7 +867,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
957
867
  // Store the new delegatee
958
868
  _tierDelegation[account][tierId] = delegatee;
959
869
 
960
- emit DelegateChanged(account, oldDelegate, delegatee);
870
+ emit DelegateChanged({delegator: account, fromDelegate: oldDelegate, toDelegate: delegatee});
961
871
 
962
872
  // Move the attestations.
963
873
  _moveTierDelegateAttestations({
@@ -975,15 +885,6 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
975
885
  store.recordBurn(tokenIds);
976
886
  }
977
887
 
978
- /// @notice Gets the amount of attestation units an address has for a particular tier.
979
- /// @param account The account to get attestation units for.
980
- /// @param tierId The ID of the tier to get attestation units for.
981
- /// @return The attestation units.
982
- function _getTierAttestationUnits(address account, uint256 tierId) internal view virtual returns (uint256) {
983
- // slither-disable-next-line calls-loop
984
- return store.tierVotingUnitsOf({hook: address(this), account: account, tierId: tierId});
985
- }
986
-
987
888
  /// @notice Mints a token in all provided tiers.
988
889
  /// @param amount The amount to base the mints on. All mints' price floors must fit in this amount.
989
890
  /// @param mintTierIds An array of tier IDs that are intended to be minted.
@@ -1001,7 +902,6 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
1001
902
  uint256[] memory tokenIds;
1002
903
 
1003
904
  // Record the mint. The returned token IDs correspond to the tiers passed in.
1004
- // slither-disable-next-line unused-return,reentrancy-benign
1005
905
  (tokenIds, leftoverAmount,) = store.recordMint({
1006
906
  amount: amount,
1007
907
  tierIds: mintTierIds,
@@ -1025,7 +925,13 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
1025
925
  // Mint the tokens.
1026
926
  _mint({to: beneficiary, tokenId: tokenId});
1027
927
 
1028
- emit Mint(tokenId, mintTierIds[i], beneficiary, amount, msg.sender);
928
+ emit Mint({
929
+ tokenId: tokenId,
930
+ tierId: mintTierIds[i],
931
+ beneficiary: beneficiary,
932
+ totalAmountContributed: amount,
933
+ caller: msg.sender
934
+ });
1029
935
 
1030
936
  unchecked {
1031
937
  ++i;
@@ -1056,7 +962,9 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
1056
962
  // forge-lint: disable-next-line(unsafe-typecast)
1057
963
  value: current - uint208(amount)
1058
964
  });
1059
- emit TierDelegateAttestationsChanged(from, tierId, oldValue, newValue, msg.sender);
965
+ emit TierDelegateAttestationsChanged({
966
+ delegate: from, tierId: tierId, previousBalance: oldValue, newBalance: newValue, caller: msg.sender
967
+ });
1060
968
  }
1061
969
 
1062
970
  // If not moving to the zero address, update the checkpoints to add the amount.
@@ -1071,7 +979,9 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
1071
979
  // forge-lint: disable-next-line(unsafe-typecast)
1072
980
  value: current + uint208(amount)
1073
981
  });
1074
- emit TierDelegateAttestationsChanged(to, tierId, oldValue, newValue, msg.sender);
982
+ emit TierDelegateAttestationsChanged({
983
+ delegate: to, tierId: tierId, previousBalance: oldValue, newBalance: newValue, caller: msg.sender
984
+ });
1075
985
  }
1076
986
  }
1077
987
 
@@ -1079,14 +989,18 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
1079
989
  /// @param context The Juicebox standard project payment data.
1080
990
  function _processPayment(JBAfterPayRecordedContext calldata context) internal override {
1081
991
  // Make sure the game is being played in the correct currency.
1082
- if (context.amount.currency != pricingCurrency) revert DefifaHook_WrongCurrency();
992
+ if (context.amount.currency != pricingCurrency) {
993
+ revert DefifaHook_WrongCurrency({
994
+ expectedCurrency: pricingCurrency, actualCurrency: context.amount.currency
995
+ });
996
+ }
1083
997
 
1084
998
  // Resolve the metadata.
1085
999
  (bool found, bytes memory metadata) = JBMetadataResolver.getDataFor({
1086
1000
  id: JBMetadataResolver.getId({purpose: "pay", target: CODE_ORIGIN}), metadata: context.payerMetadata
1087
1001
  });
1088
1002
 
1089
- if (!found) revert DefifaHook_NothingToMint();
1003
+ if (!found) revert DefifaHook_NothingToMint({metadataFound: found, tierCount: 0});
1090
1004
 
1091
1005
  // Decode the metadata.
1092
1006
  (address attestationDelegate, uint16[] memory tierIdsToMint) = abi.decode(metadata, (address, uint16[]));
@@ -1098,7 +1012,9 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
1098
1012
  }
1099
1013
 
1100
1014
  // Make sure something is being minted.
1101
- if (tierIdsToMint.length == 0) revert DefifaHook_NothingToMint();
1015
+ if (tierIdsToMint.length == 0) {
1016
+ revert DefifaHook_NothingToMint({metadataFound: found, tierCount: tierIdsToMint.length});
1017
+ }
1102
1018
 
1103
1019
  // Compute attestation units per unique tier (validates ascending order, reverts on bad order).
1104
1020
  (uint256[] memory tierIds, uint256[] memory attestationAmounts, uint256 uniqueTierCount) =
@@ -1138,7 +1054,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
1138
1054
  _mintAll({amount: context.amount.value, mintTierIds: tierIdsToMint, beneficiary: context.beneficiary});
1139
1055
 
1140
1056
  // Make sure the buyer isn't overspending.
1141
- if (leftoverAmount != 0) revert DefifaHook_Overspending();
1057
+ if (leftoverAmount != 0) revert DefifaHook_Overspending({leftoverAmount: leftoverAmount});
1142
1058
  }
1143
1059
 
1144
1060
  /// @notice Transfers, mints, or burns tier attestation units. To register a mint, `from` should be zero. To
@@ -1158,7 +1074,6 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
1158
1074
  // forge-lint: disable-next-line(unsafe-typecast)
1159
1075
  uint208 newValue = current + uint208(amount);
1160
1076
  // forge-lint: disable-next-line(unsafe-typecast)
1161
- // slither-disable-next-line unused-return
1162
1077
  _totalTierCheckpoints[tierId].push({key: uint48(block.timestamp), value: newValue});
1163
1078
  }
1164
1079
 
@@ -1168,7 +1083,6 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
1168
1083
  // forge-lint: disable-next-line(unsafe-typecast)
1169
1084
  uint208 newValue = current - uint208(amount);
1170
1085
  // forge-lint: disable-next-line(unsafe-typecast)
1171
- // slither-disable-next-line unused-return
1172
1086
  _totalTierCheckpoints[tierId].push({key: uint48(block.timestamp), value: newValue});
1173
1087
  }
1174
1088
  }
@@ -1183,7 +1097,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
1183
1097
  if (toDelegate == address(0) && to != address(0)) {
1184
1098
  toDelegate = to;
1185
1099
  _tierDelegation[to][tierId] = to;
1186
- emit DelegateChanged(to, address(0), to);
1100
+ emit DelegateChanged({delegator: to, fromDelegate: address(0), toDelegate: to});
1187
1101
  }
1188
1102
 
1189
1103
  // Move delegated attestations.
@@ -1202,7 +1116,6 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
1202
1116
  IJB721TiersHookStore hookStore = store;
1203
1117
 
1204
1118
  // Get a reference to the tier.
1205
- // slither-disable-next-line calls-loop
1206
1119
  JB721Tier memory tier =
1207
1120
  hookStore.tierOfTokenId({hook: address(this), tokenId: tokenId, includeResolvedUri: false});
1208
1121
 
@@ -1213,21 +1126,13 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
1213
1126
  if (from != address(0)) {
1214
1127
  // If transfers are pausable, check if they're paused.
1215
1128
  if (tier.flags.transfersPausable) {
1216
- // Get a reference to the project's current ruleset.
1217
- // slither-disable-next-line calls-loop
1218
- JBRuleset memory ruleset = rulesets.currentOf(PROJECT_ID);
1219
-
1220
1129
  // If transfers are paused and the NFT isn't being transferred to the zero address, revert.
1221
- if (
1222
- to != address(0)
1223
- && JB721TiersRulesetMetadataResolver.transfersPaused(
1224
- (JBRulesetMetadataResolver.metadata(ruleset))
1225
- )
1226
- ) revert DefifaHook_TransfersPaused();
1130
+ if (to != address(0) && JB721TiersRulesetMetadataResolver.transfersPaused(_rulesetMetadata())) {
1131
+ revert DefifaHook_TransfersPaused({projectId: PROJECT_ID, tokenId: tokenId, from: from, to: to});
1132
+ }
1227
1133
  }
1228
1134
 
1229
1135
  // If the token isn't already associated with a first owner, store the sender as the first owner.
1230
- // slither-disable-next-line calls-loop
1231
1136
  if (_firstOwnerOf[tokenId] == address(0)) _firstOwnerOf[tokenId] = from;
1232
1137
  }
1233
1138
 
@@ -1237,9 +1142,48 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
1237
1142
  }
1238
1143
 
1239
1144
  // Record the transfer after local delegation state has been finalized.
1240
- // slither-disable-next-line calls-loop
1241
1145
  hookStore.recordTransferForTier({tierId: tier.id, from: from, to: to});
1242
1146
 
1243
1147
  return from;
1244
1148
  }
1149
+
1150
+ //*********************************************************************//
1151
+ // -------------------------- internal views ------------------------- //
1152
+ //*********************************************************************//
1153
+
1154
+ /// @notice Returns the current phase for the project.
1155
+ /// @param projectId The project ID to check.
1156
+ /// @return The current game phase.
1157
+ function _currentGamePhaseOf(uint256 projectId) internal view returns (DefifaGamePhase) {
1158
+ return gamePhaseReporter.currentGamePhaseOf(projectId);
1159
+ }
1160
+
1161
+ /// @notice Gets the amount of attestation units an address has for a particular tier.
1162
+ /// @param account The account to get attestation units for.
1163
+ /// @param tierId The ID of the tier to get attestation units for.
1164
+ /// @return The attestation units.
1165
+ function _getTierAttestationUnits(address account, uint256 tierId) internal view virtual returns (uint256) {
1166
+ return store.tierVotingUnitsOf({hook: address(this), account: account, tierId: tierId});
1167
+ }
1168
+
1169
+ /// @notice Returns whether the caller is a terminal for the project.
1170
+ /// @param projectId The project ID to check.
1171
+ /// @return True if the caller is a terminal of the project.
1172
+ function _isProjectTerminal(uint256 projectId) internal view returns (bool) {
1173
+ return DIRECTORY.isTerminalOf({projectId: projectId, terminal: IJBTerminal(msg.sender)});
1174
+ }
1175
+
1176
+ /// @notice Computes the total mint cost of all pending (unminted) reserve NFTs across all tiers.
1177
+ /// @dev Used to include pending reserves in the fee token claim denominator so that paid holders
1178
+ /// cannot claim a disproportionate share before reserves are minted.
1179
+ /// @return cost The total mint cost of pending reserves.
1180
+ function _pendingReserveMintCost() internal view returns (uint256 cost) {
1181
+ return DefifaHookLib.pendingReserveMintCost({hookStore: store, hook: address(this)});
1182
+ }
1183
+
1184
+ /// @notice Returns the current ruleset metadata for this project.
1185
+ /// @return The packed ruleset metadata.
1186
+ function _rulesetMetadata() internal view returns (uint256) {
1187
+ return JBRulesetMetadataResolver.metadata(rulesets.currentOf(PROJECT_ID));
1188
+ }
1245
1189
  }