@ballkidz/defifa 0.0.1 → 0.0.3

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 (26) hide show
  1. package/package.json +5 -5
  2. package/src/DefifaDeployer.sol +125 -124
  3. package/src/DefifaGovernor.sol +160 -145
  4. package/src/DefifaHook.sol +287 -293
  5. package/src/DefifaTokenUriResolver.sol +30 -30
  6. package/src/interfaces/IDefifaGovernor.sol +2 -0
  7. package/test/regression/M35_GracePeriodBypass.t.sol +296 -0
  8. package/test/regression/M36_FulfillmentBlocksRatification.t.sol +272 -0
  9. package/.gas-snapshot +0 -2
  10. package/deployments/defifa-v5/arbitrum_sepolia/DefifaDelegate.json +0 -4867
  11. package/deployments/defifa-v5/arbitrum_sepolia/DefifaDeployer.json +0 -1719
  12. package/deployments/defifa-v5/arbitrum_sepolia/DefifaGovernor.json +0 -1535
  13. package/deployments/defifa-v5/arbitrum_sepolia/DefifaTokenUriResolver.json +0 -295
  14. package/deployments/defifa-v5/base_sepolia/DefifaDelegate.json +0 -4875
  15. package/deployments/defifa-v5/base_sepolia/DefifaDeployer.json +0 -1725
  16. package/deployments/defifa-v5/base_sepolia/DefifaGovernor.json +0 -1543
  17. package/deployments/defifa-v5/base_sepolia/DefifaTokenUriResolver.json +0 -301
  18. package/deployments/defifa-v5/optimism_sepolia/DefifaDelegate.json +0 -4875
  19. package/deployments/defifa-v5/optimism_sepolia/DefifaDeployer.json +0 -1725
  20. package/deployments/defifa-v5/optimism_sepolia/DefifaGovernor.json +0 -1543
  21. package/deployments/defifa-v5/optimism_sepolia/DefifaTokenUriResolver.json +0 -301
  22. package/deployments/defifa-v5/sepolia/DefifaDelegate.json +0 -4875
  23. package/deployments/defifa-v5/sepolia/DefifaDeployer.json +0 -1725
  24. package/deployments/defifa-v5/sepolia/DefifaGovernor.json +0 -1543
  25. package/deployments/defifa-v5/sepolia/DefifaTokenUriResolver.json +0 -301
  26. package/foundry.lock +0 -17
@@ -54,7 +54,6 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
54
54
  error DefifaHook_NothingToClaim();
55
55
  error DefifaHook_NothingToMint();
56
56
  error DefifaHook_WrongCurrency();
57
- error DefifaHook_NoContest();
58
57
  error DefifaHook_Overspending();
59
58
  error DefifaHook_CashoutWeightsAlreadySet();
60
59
  error DefifaHook_ReservedTokenMintingPaused();
@@ -157,24 +156,19 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
157
156
  // ------------------------- external views -------------------------- //
158
157
  //*********************************************************************//
159
158
 
160
- /// @notice The cashOut weight for each tier.
161
- /// @return The array of weights, indexed by tier.
162
- function tierCashOutWeights() external view override returns (uint256[128] memory) {
163
- return _tierCashOutWeights;
164
- }
159
+ /// @notice The first owner of each token ID, which corresponds to the address that originally contributed to the
160
+ /// project to receive the NFT.
161
+ /// @param tokenId The ID of the token to get the first owner of.
162
+ /// @return The first owner of the token.
163
+ function firstOwnerOf(uint256 tokenId) external view override returns (address) {
164
+ // Get a reference to the first owner.
165
+ address _storedFirstOwner = _firstOwnerOf[tokenId];
165
166
 
166
- /// @notice Returns the delegate of an account for specific tier.
167
- /// @param account The account to check for a delegate of.
168
- /// @param tier The tier to check within.
169
- function getTierDelegateOf(address account, uint256 tier) external view override returns (address) {
170
- return _tierDelegation[account][tier];
171
- }
167
+ // If the stored first owner is set, return it.
168
+ if (_storedFirstOwner != address(0)) return _storedFirstOwner;
172
169
 
173
- /// @notice Returns the current attestation power of an address for a specific tier.
174
- /// @param account The address to check.
175
- /// @param tier The tier to check within.
176
- function getTierAttestationUnitsOf(address account, uint256 tier) external view override returns (uint256) {
177
- return _delegateTierCheckpoints[account][tier].latest();
170
+ // Otherwise, the first owner must be the current owner.
171
+ return _owners[tokenId];
178
172
  }
179
173
 
180
174
  /// @notice Returns the past attestation units of a specific address for a specific tier.
@@ -194,12 +188,6 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
194
188
  return _delegateTierCheckpoints[account][tier].upperLookup(timestamp);
195
189
  }
196
190
 
197
- /// @notice Returns the total amount of attestation units that exists for a tier.
198
- /// @param tier The tier to check.
199
- function getTierTotalAttestationUnitsOf(uint256 tier) external view override returns (uint256) {
200
- return _totalTierCheckpoints[tier].latest();
201
- }
202
-
203
191
  /// @notice Returns the total amount of attestation units that has existed for a tier.
204
192
  /// @param tier The tier to check.
205
193
  /// @param timestamp The timestamp to check the total attestation units at.
@@ -215,19 +203,30 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
215
203
  return _totalTierCheckpoints[tier].upperLookup(timestamp);
216
204
  }
217
205
 
218
- /// @notice The first owner of each token ID, which corresponds to the address that originally contributed to the
219
- /// project to receive the NFT.
220
- /// @param tokenId The ID of the token to get the first owner of.
221
- /// @return The first owner of the token.
222
- function firstOwnerOf(uint256 tokenId) external view override returns (address) {
223
- // Get a reference to the first owner.
224
- address _storedFirstOwner = _firstOwnerOf[tokenId];
206
+ /// @notice Returns the current attestation power of an address for a specific tier.
207
+ /// @param account The address to check.
208
+ /// @param tier The tier to check within.
209
+ function getTierAttestationUnitsOf(address account, uint256 tier) external view override returns (uint256) {
210
+ return _delegateTierCheckpoints[account][tier].latest();
211
+ }
225
212
 
226
- // If the stored first owner is set, return it.
227
- if (_storedFirstOwner != address(0)) return _storedFirstOwner;
213
+ /// @notice Returns the delegate of an account for specific tier.
214
+ /// @param account The account to check for a delegate of.
215
+ /// @param tier The tier to check within.
216
+ function getTierDelegateOf(address account, uint256 tier) external view override returns (address) {
217
+ return _tierDelegation[account][tier];
218
+ }
228
219
 
229
- // Otherwise, the first owner must be the current owner.
230
- return _owners[tokenId];
220
+ /// @notice Returns the total amount of attestation units that exists for a tier.
221
+ /// @param tier The tier to check.
222
+ function getTierTotalAttestationUnitsOf(uint256 tier) external view override returns (uint256) {
223
+ return _totalTierCheckpoints[tier].latest();
224
+ }
225
+
226
+ /// @notice The cashOut weight for each tier.
227
+ /// @return The array of weights, indexed by tier.
228
+ function tierCashOutWeights() external view override returns (uint256[128] memory) {
229
+ return _tierCashOutWeights;
231
230
  }
232
231
 
233
232
  /// @notice The name of the tier with the specified ID.
@@ -240,72 +239,6 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
240
239
  // -------------------------- public views --------------------------- //
241
240
  //*********************************************************************//
242
241
 
243
- /// @notice The metadata URI of the provided token ID.
244
- /// @dev Defer to the tokenUriResolver if set, otherwise, use the tokenUri set with the token's tier.
245
- /// @param tokenId The ID of the token to get the tier URI for.
246
- /// @return The token URI corresponding with the tier or the tokenUriResolver URI.
247
- function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
248
- // Use the resolver.
249
- return store.tokenUriResolverOf(address(this)).tokenUriOf(address(this), tokenId);
250
- }
251
-
252
- /// @notice The cumulative weight the given token IDs have in cashOuts compared to the `totalCashOutWeight`.
253
- /// @param tokenIds The IDs of the tokens to get the cumulative cashOut weight of.
254
- /// @return cumulativeWeight The weight.
255
- function cashOutWeightOf(uint256[] memory tokenIds)
256
- public
257
- view
258
- virtual
259
- override
260
- returns (uint256 cumulativeWeight)
261
- {
262
- cumulativeWeight = DefifaHookLib.computeCashOutWeightBatch({
263
- tokenIds: tokenIds,
264
- _store: store,
265
- hook: address(this),
266
- tierCashOutWeights: _tierCashOutWeights,
267
- tokensRedeemedFrom: tokensRedeemedFrom
268
- });
269
- }
270
-
271
- /// @notice The weight the given token ID has in cashOuts.
272
- /// @param tokenId The ID of the token to get the cashOut weight of.
273
- /// @return The weight.
274
- function cashOutWeightOf(uint256 tokenId) public view override returns (uint256) {
275
- return DefifaHookLib.computeCashOutWeight({
276
- tokenId: tokenId,
277
- _store: store,
278
- hook: address(this),
279
- tierCashOutWeights: _tierCashOutWeights,
280
- tokensRedeemedFrom: tokensRedeemedFrom
281
- });
282
- }
283
-
284
- /// @notice The amount of tokens of a tier that are currently in circulation.
285
- /// @param tierId The ID of the tier to get the current supply of.
286
- function currentSupplyOfTier(uint256 tierId) public view returns (uint256) {
287
- return DefifaHookLib.computeCurrentSupply({_store: store, hook: address(this), tierId: tierId});
288
- }
289
-
290
- /// @notice The combined cash out weight of all outstanding NFTs.
291
- /// @dev An NFT's cash out weight is its price.
292
- /// @return The total cash out weight.
293
- function totalCashOutWeight() public view virtual override returns (uint256) {
294
- return TOTAL_CASHOUT_WEIGHT;
295
- }
296
-
297
- /// @notice The amount of $DEFIFA and $BASE_PROTOCOL tokens this game was allocated from paying the network fee.
298
- /// @return defifaTokenAllocation The $DEFIFA token allocation.
299
- /// @return baseProtocolTokenAllocation The $BASE_PROTOCOL token allocation.
300
- function tokenAllocations()
301
- public
302
- view
303
- returns (uint256 defifaTokenAllocation, uint256 baseProtocolTokenAllocation)
304
- {
305
- defifaTokenAllocation = defifaToken.balanceOf(address(this));
306
- baseProtocolTokenAllocation = baseProtocolToken.balanceOf(address(this));
307
- }
308
-
309
242
  /// @notice The data calculated before a cash out is recorded in the terminal store. This data is provided to the
310
243
  /// terminal's `cashOutTokensOf(...)` transaction.
311
244
  /// @dev Sets this contract as the cash out hook. Part of `IJBRulesetDataHook`.
@@ -368,6 +301,72 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
368
301
  cashOutTaxRate = context.cashOutTaxRate;
369
302
  }
370
303
 
304
+ /// @notice The cumulative weight the given token IDs have in cashOuts compared to the `totalCashOutWeight`.
305
+ /// @param tokenIds The IDs of the tokens to get the cumulative cashOut weight of.
306
+ /// @return cumulativeWeight The weight.
307
+ function cashOutWeightOf(uint256[] memory tokenIds)
308
+ public
309
+ view
310
+ virtual
311
+ override
312
+ returns (uint256 cumulativeWeight)
313
+ {
314
+ cumulativeWeight = DefifaHookLib.computeCashOutWeightBatch({
315
+ tokenIds: tokenIds,
316
+ _store: store,
317
+ hook: address(this),
318
+ tierCashOutWeights: _tierCashOutWeights,
319
+ tokensRedeemedFrom: tokensRedeemedFrom
320
+ });
321
+ }
322
+
323
+ /// @notice The weight the given token ID has in cashOuts.
324
+ /// @param tokenId The ID of the token to get the cashOut weight of.
325
+ /// @return The weight.
326
+ function cashOutWeightOf(uint256 tokenId) public view override returns (uint256) {
327
+ return DefifaHookLib.computeCashOutWeight({
328
+ tokenId: tokenId,
329
+ _store: store,
330
+ hook: address(this),
331
+ tierCashOutWeights: _tierCashOutWeights,
332
+ tokensRedeemedFrom: tokensRedeemedFrom
333
+ });
334
+ }
335
+
336
+ /// @notice The amount of tokens of a tier that are currently in circulation.
337
+ /// @param tierId The ID of the tier to get the current supply of.
338
+ function currentSupplyOfTier(uint256 tierId) public view returns (uint256) {
339
+ return DefifaHookLib.computeCurrentSupply({_store: store, hook: address(this), tierId: tierId});
340
+ }
341
+
342
+ /// @notice Indicates if this contract adheres to the specified interface.
343
+ /// @dev See {IERC165-supportsInterface}.
344
+ /// @param interfaceId The ID of the interface to check for adherence to.
345
+ function supportsInterface(bytes4 interfaceId) public view override(JB721Hook, IERC165) returns (bool) {
346
+ return interfaceId == type(IDefifaHook).interfaceId || super.supportsInterface(interfaceId);
347
+ }
348
+
349
+ /// @notice The amount of $DEFIFA and $BASE_PROTOCOL tokens this game was allocated from paying the network fee.
350
+ /// @return defifaTokenAllocation The $DEFIFA token allocation.
351
+ /// @return baseProtocolTokenAllocation The $BASE_PROTOCOL token allocation.
352
+ function tokenAllocations()
353
+ public
354
+ view
355
+ returns (uint256 defifaTokenAllocation, uint256 baseProtocolTokenAllocation)
356
+ {
357
+ defifaTokenAllocation = defifaToken.balanceOf(address(this));
358
+ baseProtocolTokenAllocation = baseProtocolToken.balanceOf(address(this));
359
+ }
360
+
361
+ /// @notice The metadata URI of the provided token ID.
362
+ /// @dev Defer to the tokenUriResolver if set, otherwise, use the tokenUri set with the token's tier.
363
+ /// @param tokenId The ID of the token to get the tier URI for.
364
+ /// @return The token URI corresponding with the tier or the tokenUriResolver URI.
365
+ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
366
+ // Use the resolver.
367
+ return store.tokenUriResolverOf(address(this)).tokenUriOf(address(this), tokenId);
368
+ }
369
+
371
370
  /// @notice The amount of $DEFIFA and $BASE_PROTOCOL tokens claimable for a set of token IDs.
372
371
  /// @param tokenIds The IDs of the tokens that justify a $DEFIFA claim.
373
372
  /// @return defifaTokenAmount The amount of $DEFIFA that can be claimed.
@@ -391,11 +390,11 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
391
390
  });
392
391
  }
393
392
 
394
- /// @notice Indicates if this contract adheres to the specified interface.
395
- /// @dev See {IERC165-supportsInterface}.
396
- /// @param interfaceId The ID of the interface to check for adherence to.
397
- function supportsInterface(bytes4 interfaceId) public view override(JB721Hook, IERC165) returns (bool) {
398
- return interfaceId == type(IDefifaHook).interfaceId || super.supportsInterface(interfaceId);
393
+ /// @notice The combined cash out weight of all outstanding NFTs.
394
+ /// @dev An NFT's cash out weight is its price.
395
+ /// @return The total cash out weight.
396
+ function totalCashOutWeight() public view virtual override returns (uint256) {
397
+ return TOTAL_CASHOUT_WEIGHT;
399
398
  }
400
399
 
401
400
  //*********************************************************************//
@@ -595,36 +594,6 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
595
594
  // ---------------------- external transactions ---------------------- //
596
595
  //*********************************************************************//
597
596
 
598
- /// @notice Stores the cashOut weights that should be used in the end game phase.
599
- /// @dev Only this contract's owner can set tier cashOut weights.
600
- /// @param tierWeights The tier weights to set.
601
- function setTierCashOutWeightsTo(DefifaTierCashOutWeight[] memory tierWeights) external override onlyOwner {
602
- // Get a reference to the game phase.
603
- DefifaGamePhase _gamePhase = gamePhaseReporter.currentGamePhaseOf(PROJECT_ID);
604
-
605
- // Make sure the game has ended.
606
- if (_gamePhase != DefifaGamePhase.SCORING) {
607
- revert DefifaHook_GameIsntScoringYet();
608
- }
609
-
610
- // Make sure the cashOut weights haven't already been set.
611
- if (cashOutWeightIsSet) revert DefifaHook_CashoutWeightsAlreadySet();
612
-
613
- // Make sure the game is not in no contest.
614
- if (_gamePhase == DefifaGamePhase.NO_CONTEST) {
615
- revert DefifaHook_NoContest();
616
- }
617
-
618
- // Validate weights and build the array. Reverts on invalid input.
619
- _tierCashOutWeights =
620
- DefifaHookLib.validateAndBuildWeights({tierWeights: tierWeights, _store: store, hook: address(this)});
621
-
622
- // Mark the cashOut weight as set.
623
- cashOutWeightIsSet = true;
624
-
625
- emit TierCashOutWeightsSet(tierWeights, msg.sender);
626
- }
627
-
628
597
  /// @notice Burns the specified NFTs upon token holder cash out, reclaiming funds from the project's balance for
629
598
  /// `context.beneficiary`. Part of `IJBCashOutHook`.
630
599
  /// @dev Reverts if the calling contract is not one of the project's terminals.
@@ -728,18 +697,55 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
728
697
  }
729
698
  }
730
699
 
731
- /// @notice Delegate attestations.
732
- /// @param delegations An array of tiers to set delegates for.
733
- function setTierDelegatesTo(DefifaDelegation[] memory delegations) external virtual override {
734
- // Make sure the current game phase is the minting phase.
735
- if (gamePhaseReporter.currentGamePhaseOf(PROJECT_ID) != DefifaGamePhase.MINT) {
736
- revert DefifaHook_DelegateChangesUnavailableInThisPhase();
700
+ /// @notice Stores the cashOut weights that should be used in the end game phase.
701
+ /// @dev Only this contract's owner can set tier cashOut weights.
702
+ /// @param tierWeights The tier weights to set.
703
+ function setTierCashOutWeightsTo(DefifaTierCashOutWeight[] memory tierWeights) external override onlyOwner {
704
+ // Get a reference to the game phase.
705
+ DefifaGamePhase _gamePhase = gamePhaseReporter.currentGamePhaseOf(PROJECT_ID);
706
+
707
+ // Make sure the game has ended.
708
+ if (_gamePhase != DefifaGamePhase.SCORING) {
709
+ revert DefifaHook_GameIsntScoringYet();
737
710
  }
738
711
 
739
- // Keep a reference to the number of tier delegates.
740
- uint256 _numberOfTierDelegates = delegations.length;
712
+ // Make sure the cashOut weights haven't already been set.
713
+ if (cashOutWeightIsSet) revert DefifaHook_CashoutWeightsAlreadySet();
741
714
 
742
- // Keep a reference to the data being iterated on.
715
+ // Validate weights and build the array. Reverts on invalid input.
716
+ _tierCashOutWeights =
717
+ DefifaHookLib.validateAndBuildWeights({tierWeights: tierWeights, _store: store, hook: address(this)});
718
+
719
+ // Mark the cashOut weight as set.
720
+ cashOutWeightIsSet = true;
721
+
722
+ emit TierCashOutWeightsSet(tierWeights, msg.sender);
723
+ }
724
+
725
+ /// @notice Delegate attestations.
726
+ /// @param delegatee The account to delegate tier attestation units to.
727
+ /// @param tierId The ID of the tier to delegate attestation units for.
728
+ function setTierDelegateTo(address delegatee, uint256 tierId) public virtual override {
729
+ // Make sure the current game phase is the minting phase.
730
+ if (gamePhaseReporter.currentGamePhaseOf(PROJECT_ID) != DefifaGamePhase.MINT) {
731
+ revert DefifaHook_DelegateChangesUnavailableInThisPhase();
732
+ }
733
+
734
+ _delegateTier({_account: msg.sender, _delegatee: delegatee, _tierId: tierId});
735
+ }
736
+
737
+ /// @notice Delegate attestations.
738
+ /// @param delegations An array of tiers to set delegates for.
739
+ function setTierDelegatesTo(DefifaDelegation[] memory delegations) external virtual override {
740
+ // Make sure the current game phase is the minting phase.
741
+ if (gamePhaseReporter.currentGamePhaseOf(PROJECT_ID) != DefifaGamePhase.MINT) {
742
+ revert DefifaHook_DelegateChangesUnavailableInThisPhase();
743
+ }
744
+
745
+ // Keep a reference to the number of tier delegates.
746
+ uint256 _numberOfTierDelegates = delegations.length;
747
+
748
+ // Keep a reference to the data being iterated on.
743
749
  DefifaDelegation memory _data;
744
750
 
745
751
  for (uint256 _i; _i < _numberOfTierDelegates;) {
@@ -757,22 +763,147 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
757
763
  }
758
764
  }
759
765
 
760
- /// @notice Delegate attestations.
761
- /// @param delegatee The account to delegate tier attestation units to.
762
- /// @param tierId The ID of the tier to delegate attestation units for.
763
- function setTierDelegateTo(address delegatee, uint256 tierId) public virtual override {
764
- // Make sure the current game phase is the minting phase.
765
- if (gamePhaseReporter.currentGamePhaseOf(PROJECT_ID) != DefifaGamePhase.MINT) {
766
- revert DefifaHook_DelegateChangesUnavailableInThisPhase();
767
- }
768
-
769
- _delegateTier({_account: msg.sender, _delegatee: delegatee, _tierId: tierId});
770
- }
771
-
772
766
  //*********************************************************************//
773
767
  // ------------------------ internal functions ----------------------- //
774
768
  //*********************************************************************//
775
769
 
770
+ /// @notice Claims the defifa and base protocol tokens for a beneficiary.
771
+ /// @param _beneficiary The address to claim tokens for.
772
+ /// @param shareToBeneficiary The share relative to the `outOfTotal` to send the user.
773
+ /// @param outOfTotal The total share that the `shareToBeneficiary` is relative to.
774
+ /// @return beneficiaryReceivedTokens A flag indicating if the beneficiary received any tokens.
775
+ function _claimTokensFor(
776
+ address _beneficiary,
777
+ uint256 shareToBeneficiary,
778
+ uint256 outOfTotal
779
+ )
780
+ internal
781
+ returns (bool beneficiaryReceivedTokens)
782
+ {
783
+ return DefifaHookLib.claimTokensFor({
784
+ _beneficiary: _beneficiary,
785
+ shareToBeneficiary: shareToBeneficiary,
786
+ outOfTotal: outOfTotal,
787
+ _defifaToken: defifaToken,
788
+ _baseProtocolToken: baseProtocolToken
789
+ });
790
+ }
791
+
792
+ /// @notice Delegate all attestation units for the specified tier.
793
+ /// @param _account The account delegating tier attestation units.
794
+ /// @param _delegatee The account to delegate tier attestation units to.
795
+ /// @param _tierId The ID of the tier for which attestation units are being transferred.
796
+ function _delegateTier(address _account, address _delegatee, uint256 _tierId) internal virtual {
797
+ // Get the current delegatee
798
+ address _oldDelegate = _tierDelegation[_account][_tierId];
799
+
800
+ // Store the new delegatee
801
+ _tierDelegation[_account][_tierId] = _delegatee;
802
+
803
+ emit DelegateChanged(_account, _oldDelegate, _delegatee);
804
+
805
+ // Move the attestations.
806
+ _moveTierDelegateAttestations({
807
+ _from: _oldDelegate,
808
+ _to: _delegatee,
809
+ _tierId: _tierId,
810
+ _amount: _getTierAttestationUnits({_account: _account, _tierId: _tierId})
811
+ });
812
+ }
813
+
814
+ /// @notice A function that will run when tokens are burned via cashOut.
815
+ /// @param _tokenIds The IDs of the tokens that were burned.
816
+ function _didBurn(uint256[] memory _tokenIds) internal virtual override {
817
+ // Add to burned counter.
818
+ store.recordBurn(_tokenIds);
819
+ }
820
+
821
+ /// @notice Gets the amount of attestation units an address has for a particular tier.
822
+ /// @param _account The account to get attestation units for.
823
+ /// @param _tierId The ID of the tier to get attestation units for.
824
+ /// @return The attestation units.
825
+ function _getTierAttestationUnits(address _account, uint256 _tierId) internal view virtual returns (uint256) {
826
+ return store.tierVotingUnitsOf({hook: address(this), account: _account, tierId: _tierId});
827
+ }
828
+
829
+ /// @notice Mints a token in all provided tiers.
830
+ /// @param _amount The amount to base the mints on. All mints' price floors must fit in this amount.
831
+ /// @param _mintTierIds An array of tier IDs that are intended to be minted.
832
+ /// @param _beneficiary The address to mint for.
833
+ /// @return leftoverAmount The amount leftover after the mint.
834
+ function _mintAll(
835
+ uint256 _amount,
836
+ uint16[] memory _mintTierIds,
837
+ address _beneficiary
838
+ )
839
+ internal
840
+ returns (uint256 leftoverAmount)
841
+ {
842
+ // Keep a reference to the token ID.
843
+ uint256[] memory _tokenIds;
844
+
845
+ // Record the mint. The returned token IDs correspond to the tiers passed in.
846
+ (_tokenIds, leftoverAmount) = store.recordMint({
847
+ amount: _amount,
848
+ tierIds: _mintTierIds,
849
+ isOwnerMint: false // Not a manual mint
850
+ });
851
+
852
+ // Get a reference to the number of mints.
853
+ uint256 _mintsLength = _tokenIds.length;
854
+
855
+ // Keep a reference to the token ID being iterated on.
856
+ uint256 _tokenId;
857
+
858
+ // Increment the paid mint cost.
859
+ _totalMintCost += _amount;
860
+
861
+ // Loop through each token ID and mint.
862
+ for (uint256 _i; _i < _mintsLength;) {
863
+ // Get a reference to the tier being iterated on.
864
+ _tokenId = _tokenIds[_i];
865
+
866
+ // Mint the tokens.
867
+ _mint(_beneficiary, _tokenId);
868
+
869
+ emit Mint(_tokenId, _mintTierIds[_i], _beneficiary, _amount, msg.sender);
870
+
871
+ unchecked {
872
+ ++_i;
873
+ }
874
+ }
875
+ }
876
+
877
+ /// @notice Moves delegated tier attestations from one delegate to another.
878
+ /// @param _from The account to transfer tier attestation units from.
879
+ /// @param _to The account to transfer tier attestation units to.
880
+ /// @param _tierId The ID of the tier for which attestation units are being transferred.
881
+ /// @param _amount The amount of attestation units to delegate.
882
+ function _moveTierDelegateAttestations(address _from, address _to, uint256 _tierId, uint256 _amount) internal {
883
+ // Nothing to do if moving to the same account, or no amount is being moved.
884
+ if (_from == _to || _amount == 0) return;
885
+
886
+ // If not moving from the zero address, update the checkpoints to subtract the amount.
887
+ if (_from != address(0)) {
888
+ // Get the current amount for the sending delegate.
889
+ uint208 _current = _delegateTierCheckpoints[_from][_tierId].latest();
890
+ // Set the new amount for the sending delegate.
891
+ (uint256 _oldValue, uint256 _newValue) =
892
+ _delegateTierCheckpoints[_from][_tierId].push(uint48(block.timestamp), _current - uint208(_amount));
893
+ emit TierDelegateAttestationsChanged(_from, _tierId, _oldValue, _newValue, msg.sender);
894
+ }
895
+
896
+ // If not moving to the zero address, update the checkpoints to add the amount.
897
+ if (_to != address(0)) {
898
+ // Get the current amount for the receiving delegate.
899
+ uint208 _current = _delegateTierCheckpoints[_to][_tierId].latest();
900
+ // Set the new amount for the receiving delegate.
901
+ (uint256 _oldValue, uint256 _newValue) =
902
+ _delegateTierCheckpoints[_to][_tierId].push(uint48(block.timestamp), _current + uint208(_amount));
903
+ emit TierDelegateAttestationsChanged(_to, _tierId, _oldValue, _newValue, msg.sender);
904
+ }
905
+ }
906
+
776
907
  /// @notice Process an incoming payment.
777
908
  /// @param context The Juicebox standard project payment data.
778
909
  function _processPayment(JBAfterPayRecordedContext calldata context) internal override {
@@ -833,36 +964,6 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
833
964
  if (_leftoverAmount != 0) revert DefifaHook_Overspending();
834
965
  }
835
966
 
836
- /// @notice Gets the amount of attestation units an address has for a particular tier.
837
- /// @param _account The account to get attestation units for.
838
- /// @param _tierId The ID of the tier to get attestation units for.
839
- /// @return The attestation units.
840
- function _getTierAttestationUnits(address _account, uint256 _tierId) internal view virtual returns (uint256) {
841
- return store.tierVotingUnitsOf({hook: address(this), account: _account, tierId: _tierId});
842
- }
843
-
844
- /// @notice Delegate all attestation units for the specified tier.
845
- /// @param _account The account delegating tier attestation units.
846
- /// @param _delegatee The account to delegate tier attestation units to.
847
- /// @param _tierId The ID of the tier for which attestation units are being transferred.
848
- function _delegateTier(address _account, address _delegatee, uint256 _tierId) internal virtual {
849
- // Get the current delegatee
850
- address _oldDelegate = _tierDelegation[_account][_tierId];
851
-
852
- // Store the new delegatee
853
- _tierDelegation[_account][_tierId] = _delegatee;
854
-
855
- emit DelegateChanged(_account, _oldDelegate, _delegatee);
856
-
857
- // Move the attestations.
858
- _moveTierDelegateAttestations({
859
- _from: _oldDelegate,
860
- _to: _delegatee,
861
- _tierId: _tierId,
862
- _amount: _getTierAttestationUnits({_account: _account, _tierId: _tierId})
863
- });
864
- }
865
-
866
967
  /// @notice Transfers, mints, or burns tier attestation units. To register a mint, `_from` should be zero. To
867
968
  /// register a burn, `_to` should be zero. Total supply of attestation units will be adjusted with mints and burns.
868
969
  /// @param _from The account to transfer tier attestation units from.
@@ -904,113 +1005,6 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
904
1005
  });
905
1006
  }
906
1007
 
907
- /// @notice Moves delegated tier attestations from one delegate to another.
908
- /// @param _from The account to transfer tier attestation units from.
909
- /// @param _to The account to transfer tier attestation units to.
910
- /// @param _tierId The ID of the tier for which attestation units are being transferred.
911
- /// @param _amount The amount of attestation units to delegate.
912
- function _moveTierDelegateAttestations(address _from, address _to, uint256 _tierId, uint256 _amount) internal {
913
- // Nothing to do if moving to the same account, or no amount is being moved.
914
- if (_from == _to || _amount == 0) return;
915
-
916
- // If not moving from the zero address, update the checkpoints to subtract the amount.
917
- if (_from != address(0)) {
918
- // Get the current amount for the sending delegate.
919
- uint208 _current = _delegateTierCheckpoints[_from][_tierId].latest();
920
- // Set the new amount for the sending delegate.
921
- (uint256 _oldValue, uint256 _newValue) =
922
- _delegateTierCheckpoints[_from][_tierId].push(uint48(block.timestamp), _current - uint208(_amount));
923
- emit TierDelegateAttestationsChanged(_from, _tierId, _oldValue, _newValue, msg.sender);
924
- }
925
-
926
- // If not moving to the zero address, update the checkpoints to add the amount.
927
- if (_to != address(0)) {
928
- // Get the current amount for the receiving delegate.
929
- uint208 _current = _delegateTierCheckpoints[_to][_tierId].latest();
930
- // Set the new amount for the receiving delegate.
931
- (uint256 _oldValue, uint256 _newValue) =
932
- _delegateTierCheckpoints[_to][_tierId].push(uint48(block.timestamp), _current + uint208(_amount));
933
- emit TierDelegateAttestationsChanged(_to, _tierId, _oldValue, _newValue, msg.sender);
934
- }
935
- }
936
-
937
- /// @notice A function that will run when tokens are burned via cashOut.
938
- /// @param _tokenIds The IDs of the tokens that were burned.
939
- function _didBurn(uint256[] memory _tokenIds) internal virtual override {
940
- // Add to burned counter.
941
- store.recordBurn(_tokenIds);
942
- }
943
-
944
- /// @notice Mints a token in all provided tiers.
945
- /// @param _amount The amount to base the mints on. All mints' price floors must fit in this amount.
946
- /// @param _mintTierIds An array of tier IDs that are intended to be minted.
947
- /// @param _beneficiary The address to mint for.
948
- /// @return leftoverAmount The amount leftover after the mint.
949
- function _mintAll(
950
- uint256 _amount,
951
- uint16[] memory _mintTierIds,
952
- address _beneficiary
953
- )
954
- internal
955
- returns (uint256 leftoverAmount)
956
- {
957
- // Keep a reference to the token ID.
958
- uint256[] memory _tokenIds;
959
-
960
- // Record the mint. The returned token IDs correspond to the tiers passed in.
961
- (_tokenIds, leftoverAmount) = store.recordMint({
962
- amount: _amount,
963
- tierIds: _mintTierIds,
964
- isOwnerMint: false // Not a manual mint
965
- });
966
-
967
- // Get a reference to the number of mints.
968
- uint256 _mintsLength = _tokenIds.length;
969
-
970
- // Keep a reference to the token ID being iterated on.
971
- uint256 _tokenId;
972
-
973
- // Increment the paid mint cost.
974
- _totalMintCost += _amount;
975
-
976
- // Loop through each token ID and mint.
977
- for (uint256 _i; _i < _mintsLength;) {
978
- // Get a reference to the tier being iterated on.
979
- _tokenId = _tokenIds[_i];
980
-
981
- // Mint the tokens.
982
- _mint(_beneficiary, _tokenId);
983
-
984
- emit Mint(_tokenId, _mintTierIds[_i], _beneficiary, _amount, msg.sender);
985
-
986
- unchecked {
987
- ++_i;
988
- }
989
- }
990
- }
991
-
992
- /// @notice Claims the defifa and base protocol tokens for a beneficiary.
993
- /// @param _beneficiary The address to claim tokens for.
994
- /// @param shareToBeneficiary The share relative to the `outOfTotal` to send the user.
995
- /// @param outOfTotal The total share that the `shareToBeneficiary` is relative to.
996
- /// @return beneficiaryReceivedTokens A flag indicating if the beneficiary received any tokens.
997
- function _claimTokensFor(
998
- address _beneficiary,
999
- uint256 shareToBeneficiary,
1000
- uint256 outOfTotal
1001
- )
1002
- internal
1003
- returns (bool beneficiaryReceivedTokens)
1004
- {
1005
- return DefifaHookLib.claimTokensFor({
1006
- _beneficiary: _beneficiary,
1007
- shareToBeneficiary: shareToBeneficiary,
1008
- outOfTotal: outOfTotal,
1009
- _defifaToken: defifaToken,
1010
- _baseProtocolToken: baseProtocolToken
1011
- });
1012
- }
1013
-
1014
1008
  /// @notice Before transferring an NFT, register its first owner (if necessary).
1015
1009
  /// @param to The address the NFT is being transferred to.
1016
1010
  /// @param tokenId The token ID of the NFT being transferred.