@bananapus/721-hook-v6 0.0.32 → 0.0.34

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 (35) hide show
  1. package/USER_JOURNEYS.md +11 -0
  2. package/package.json +3 -3
  3. package/script/Deploy.s.sol +53 -19
  4. package/src/JB721Checkpoints.sol +92 -0
  5. package/src/JB721CheckpointsDeployer.sol +45 -0
  6. package/src/JB721TiersHook.sol +90 -116
  7. package/src/abstract/JB721Hook.sol +5 -0
  8. package/src/interfaces/IJB721Checkpoints.sol +34 -0
  9. package/src/interfaces/IJB721CheckpointsDeployer.sol +20 -0
  10. package/src/interfaces/IJB721TiersHook.sol +8 -0
  11. package/src/libraries/JB721Constants.sol +6 -0
  12. package/src/libraries/JB721TiersHookLib.sol +353 -146
  13. package/test/E2E/Pay_Mint_Redeem_E2E.t.sol +11 -1
  14. package/test/Fork.t.sol +11 -2
  15. package/test/TestAuditGaps.sol +1 -1
  16. package/test/TestCheckpoints.t.sol +329 -0
  17. package/test/audit/CodexNemesisRepoFindings.t.sol +270 -0
  18. package/test/audit/CodexRetroactiveReserveBeneficiaryDilution.t.sol +161 -0
  19. package/test/audit/CodexSplitCreditsMismatch.t.sol +2 -1
  20. package/test/audit/CrossCurrencySplitNoPrices.t.sol +1 -0
  21. package/test/audit/SameCurrencyDecimalMismatch.t.sol +249 -0
  22. package/test/audit/SplitFailureRedistribution.t.sol +2 -1
  23. package/test/fork/ERC20CashOutFork.t.sol +11 -2
  24. package/test/fork/ERC20TierSplitFork.t.sol +11 -2
  25. package/test/fork/IssueTokensForSplitsFork.t.sol +11 -2
  26. package/test/regression/BrokenTerminalDoesNotDos.t.sol +2 -2
  27. package/test/regression/SplitDistributionBugs.t.sol +5 -5
  28. package/test/regression/SplitNoBeneficiary.t.sol +1 -1
  29. package/test/unit/AuditFixes_Unit.t.sol +5 -5
  30. package/test/unit/pay_CrossCurrency_Unit.t.sol +1 -0
  31. package/test/unit/pay_Unit.t.sol +1 -0
  32. package/test/unit/redeem_Unit.t.sol +3 -3
  33. package/test/unit/relayBeneficiary_Unit.t.sol +182 -0
  34. package/test/unit/splitHookDistribution_Unit.t.sol +6 -6
  35. package/test/unit/tierSplitRouting_Unit.t.sol +2 -2
@@ -77,6 +77,7 @@ abstract contract JB721Hook is ERC721, IJB721Hook {
77
77
  /// @return cashOutTaxRate The cash out tax rate influencing the reclaim amount.
78
78
  /// @return cashOutCount The amount of tokens that should be considered cashed out.
79
79
  /// @return totalSupply The total amount of tokens that are considered to be existing.
80
+ /// @return effectiveSurplusValue The surplus to use for reclaim calculation.
80
81
  /// @return hookSpecifications The amount and data to send to cash out hooks (this contract) instead of returning to
81
82
  /// the beneficiary.
82
83
  function beforeCashOutRecordedWith(JBBeforeCashOutRecordedContext calldata context)
@@ -88,6 +89,7 @@ abstract contract JB721Hook is ERC721, IJB721Hook {
88
89
  uint256 cashOutTaxRate,
89
90
  uint256 cashOutCount,
90
91
  uint256 totalSupply,
92
+ uint256 effectiveSurplusValue,
91
93
  JBCashOutHookSpecification[] memory hookSpecifications
92
94
  )
93
95
  {
@@ -114,6 +116,9 @@ abstract contract JB721Hook is ERC721, IJB721Hook {
114
116
  // Use the total cash out weight of the 721s.
115
117
  totalSupply = totalCashOutWeight();
116
118
 
119
+ // Use the surplus from the context.
120
+ effectiveSurplusValue = context.surplus.value;
121
+
117
122
  // Use the cash out tax rate from the context.
118
123
  cashOutTaxRate = context.cashOutTaxRate;
119
124
  }
@@ -0,0 +1,34 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {IERC5805} from "@openzeppelin/contracts/interfaces/IERC5805.sol";
5
+ import {IJB721TiersHookStore} from "./IJB721TiersHookStore.sol";
6
+
7
+ /// @notice A checkpoint module that provides IVotes-compatible checkpointed voting power for a JB721TiersHook.
8
+ /// @dev Deployed as a clone via JB721CheckpointsDeployer during hook initialization. One module per hook.
9
+ /// Pass this address to JBTokenDistributor as the IVotes token.
10
+ interface IJB721Checkpoints is IERC5805 {
11
+ /// @notice Called by the hook after every NFT transfer to update checkpointed voting power.
12
+ /// @dev Looks up the token's tier voting units from the store internally.
13
+ /// Auto-self-delegates on first receive so checkpoints work without manual delegation.
14
+ /// @param from The previous owner (address(0) on mint).
15
+ /// @param to The new owner (address(0) on burn).
16
+ /// @param tokenId The token ID being transferred (used to look up tier voting units).
17
+ function onTransfer(address from, address to, uint256 tokenId) external;
18
+
19
+ /// @notice Initializes a cloned module with its hook and store references.
20
+ /// @dev Can only be called once. Called by the deployer after cloning.
21
+ /// @param hook The hook this module serves.
22
+ /// @param store The store that holds tier data for the hook's NFTs.
23
+ function initialize(address hook, IJB721TiersHookStore store) external;
24
+
25
+ /// @notice The hook that this module tracks voting power for.
26
+ /// @return The hook address.
27
+ // forge-lint: disable-next-line(mixed-case-function)
28
+ function HOOK() external view returns (address);
29
+
30
+ /// @notice The store that holds tier and voting data for the hook's NFTs.
31
+ /// @return The store contract.
32
+ // forge-lint: disable-next-line(mixed-case-function)
33
+ function STORE() external view returns (IJB721TiersHookStore);
34
+ }
@@ -0,0 +1,20 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {IJB721Checkpoints} from "./IJB721Checkpoints.sol";
5
+ import {IJB721TiersHookStore} from "./IJB721TiersHookStore.sol";
6
+
7
+ /// @notice Deploys JB721Checkpoints clones for JB721TiersHook instances.
8
+ interface IJB721CheckpointsDeployer {
9
+ /// @notice The implementation contract that clones are based on.
10
+ /// @return The implementation address.
11
+ // forge-lint: disable-next-line(mixed-case-function)
12
+ function IMPLEMENTATION() external view returns (address);
13
+
14
+ /// @notice Deploys a new deterministic checkpoint clone for the given hook.
15
+ /// @dev Uses CREATE2 with the hook address as salt so the clone address is the same across chains.
16
+ /// @param hook The hook address the module will serve.
17
+ /// @param store The store that holds tier data for the hook's NFTs.
18
+ /// @return module The newly deployed and initialized checkpoint module.
19
+ function deploy(address hook, IJB721TiersHookStore store) external returns (IJB721Checkpoints module);
20
+ }
@@ -6,6 +6,8 @@ import {IJBRulesets} from "@bananapus/core-v6/src/interfaces/IJBRulesets.sol";
6
6
  import {IJBSplits} from "@bananapus/core-v6/src/interfaces/IJBSplits.sol";
7
7
  import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
8
8
 
9
+ import {IJB721Checkpoints} from "./IJB721Checkpoints.sol";
10
+ import {IJB721CheckpointsDeployer} from "./IJB721CheckpointsDeployer.sol";
9
11
  import {IJB721Hook} from "./IJB721Hook.sol";
10
12
  import {IJB721TiersHookStore} from "./IJB721TiersHookStore.sol";
11
13
  import {IJB721TokenUriResolver} from "./IJB721TokenUriResolver.sol";
@@ -144,6 +146,12 @@ interface IJB721TiersHook is IJB721Hook {
144
146
  /// @return decimals The amount of decimals being used in tier prices.
145
147
  function pricingContext() external view returns (uint256 currency, uint256 decimals);
146
148
 
149
+ /// @notice The checkpoint module that manages IVotes-compatible checkpointed voting power for this hook's NFTs.
150
+ /// @dev Deployed lazily on first mint. Pass this to JBTokenDistributor as the IVotes token.
151
+ /// @return The checkpoint module.
152
+ // forge-lint: disable-next-line(mixed-case-function)
153
+ function CHECKPOINTS() external view returns (IJB721Checkpoints);
154
+
147
155
  /// @notice The contract that exposes price feeds for currency conversions.
148
156
  /// @return The prices contract.
149
157
  function PRICES() external view returns (IJBPrices);
@@ -4,4 +4,10 @@ pragma solidity 0.8.28;
4
4
  /// @notice Global constants used across 721 hook contracts.
5
5
  library JB721Constants {
6
6
  uint16 public constant DISCOUNT_DENOMINATOR = 200;
7
+
8
+ /// @notice The metadata ID used to identify the 721 beneficiary entry in payment metadata.
9
+ /// @dev When a sucker pays on behalf of a remote user, the real user's address is embedded under this key
10
+ /// so NFTs mint to the correct recipient.
11
+ // forge-lint: disable-next-line(mixed-case-variable)
12
+ bytes4 public constant BENEFICIARY_METADATA_ID = bytes4(keccak256("JB_721_BENEFICIARY"));
7
13
  }