@bananapus/721-hook-v6 0.0.41 → 0.0.43
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.
- package/foundry.lock +1 -7
- package/foundry.toml +1 -1
- package/package.json +20 -9
- package/script/Deploy.s.sol +2 -2
- package/src/JB721Checkpoints.sol +60 -18
- package/src/JB721CheckpointsDeployer.sol +10 -5
- package/src/JB721TiersHook.sol +4 -1
- package/src/JB721TiersHookProjectDeployer.sol +68 -30
- package/src/JB721TiersHookStore.sol +1 -4
- package/src/interfaces/IJB721Checkpoints.sol +21 -14
- package/src/interfaces/IJB721CheckpointsDeployer.sol +6 -2
- package/src/interfaces/IJB721TiersHookProjectDeployer.sol +2 -0
- package/test/utils/AccessJBLib.sol +49 -0
- package/test/utils/ForTest_JB721TiersHook.sol +246 -0
- package/test/utils/TestBaseWorkflow.sol +213 -0
- package/test/utils/UnitTestSetup.sol +805 -0
- package/.gas-snapshot +0 -152
- package/ADMINISTRATION.md +0 -87
- package/ARCHITECTURE.md +0 -98
- package/AUDIT_INSTRUCTIONS.md +0 -77
- package/RISKS.md +0 -118
- package/SKILLS.md +0 -43
- package/STYLE_GUIDE.md +0 -610
- package/USER_JOURNEYS.md +0 -121
- package/assets/findings/nana-721-hook-v6-pashov-ai-audit-report-20260330-091257.md +0 -83
- package/slither-ci.config.json +0 -10
- package/test/721HookAttacks.t.sol +0 -408
- package/test/E2E/Pay_Mint_Redeem_E2E.t.sol +0 -985
- package/test/Fork.t.sol +0 -2346
- package/test/TestAuditGaps.sol +0 -1075
- package/test/TestCheckpoints.t.sol +0 -341
- package/test/TestSafeTransferReentrancy.t.sol +0 -305
- package/test/TestVotingUnitsLifecycle.t.sol +0 -313
- package/test/audit/AuditRegressions.t.sol +0 -83
- package/test/audit/CrossCurrencySplitNoPrices.t.sol +0 -123
- package/test/audit/FreshAudit.t.sol +0 -197
- package/test/audit/FutureTierPoC.t.sol +0 -39
- package/test/audit/FutureTierRemoval.t.sol +0 -47
- package/test/audit/Pass12L18.t.sol +0 -80
- package/test/audit/PayCreditsBypassTierSplits.t.sol +0 -200
- package/test/audit/ProjectDeployerAuth.t.sol +0 -266
- package/test/audit/RepoFindings.t.sol +0 -195
- package/test/audit/ReserveActivation.t.sol +0 -87
- package/test/audit/RetroactiveReserveBeneficiaryDilution.t.sol +0 -149
- package/test/audit/SameCurrencyDecimalMismatch.t.sol +0 -249
- package/test/audit/SplitCreditsMismatch.t.sol +0 -219
- package/test/audit/SplitFailureRedistribution.t.sol +0 -143
- package/test/audit/USDTVoidReturnCompat.t.sol +0 -301
- package/test/fork/ERC20CashOutFork.t.sol +0 -633
- package/test/fork/ERC20TierSplitFork.t.sol +0 -596
- package/test/fork/IssueTokensForSplitsFork.t.sol +0 -516
- package/test/invariants/TierLifecycleInvariant.t.sol +0 -188
- package/test/invariants/TieredHookStoreInvariant.t.sol +0 -86
- package/test/invariants/handlers/TierLifecycleHandler.sol +0 -300
- package/test/invariants/handlers/TierStoreHandler.sol +0 -165
- package/test/regression/BrokenTerminalDoesNotDos.t.sol +0 -277
- package/test/regression/CacheTierLookup.t.sol +0 -190
- package/test/regression/ProjectDeployerRulesets.t.sol +0 -358
- package/test/regression/ReserveBeneficiaryOverwrite.t.sol +0 -155
- package/test/regression/SplitDistributionBugs.t.sol +0 -751
- package/test/regression/SplitNoBeneficiary.t.sol +0 -140
- package/test/unit/AuditFixes_Unit.t.sol +0 -624
- package/test/unit/JB721CheckpointsDeployer_AccessControl.t.sol +0 -116
- package/test/unit/JB721TiersRulesetMetadataResolver.t.sol +0 -144
- package/test/unit/JBBitmap.t.sol +0 -170
- package/test/unit/JBIpfsDecoder.t.sol +0 -136
- package/test/unit/TierSupplyReserveCheck.t.sol +0 -221
- package/test/unit/adjustTier_Unit.t.sol +0 -1942
- package/test/unit/deployer_Unit.t.sol +0 -114
- package/test/unit/getters_constructor_Unit.t.sol +0 -593
- package/test/unit/mintFor_mintReservesFor_Unit.t.sol +0 -452
- package/test/unit/pay_CrossCurrency_Unit.t.sol +0 -530
- package/test/unit/pay_Unit.t.sol +0 -1661
- package/test/unit/redeem_Unit.t.sol +0 -473
- package/test/unit/relayBeneficiary_Unit.t.sol +0 -182
- package/test/unit/splitHookDistribution_Unit.t.sol +0 -604
- package/test/unit/tierSplitRouting_Unit.t.sol +0 -757
package/.gas-snapshot
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
NFTHookAttacks:test_adjustTiers_noPermission_reverts() (gas: 355534)
|
|
2
|
-
NFTHookAttacks:test_cannotIncreaseDiscountPercent_enforcement() (gas: 371175)
|
|
3
|
-
NFTHookAttacks:test_cashOutWeight_afterTierRemoval() (gas: 9879224)
|
|
4
|
-
NFTHookAttacks:test_duplicateTierIdsInMetadata_mintsMultiple() (gas: 9844592)
|
|
5
|
-
NFTHookAttacks:test_invalidTierIdInMetadata_reverts() (gas: 401784)
|
|
6
|
-
NFTHookAttacks:test_maxDiscountPercent_effectivePrice() (gas: 362841)
|
|
7
|
-
NFTHookAttacks:test_maxSupplyTier_noOverflow() (gas: 357301)
|
|
8
|
-
NFTHookAttacks:test_reserveDrain_highFrequency() (gas: 10193674)
|
|
9
|
-
NFTHookAttacks:test_supplyExhaustion_noOvermint() (gas: 9847419)
|
|
10
|
-
NFTHookAttacks:test_zeroPriceTier_mintBehavior() (gas: 9846210)
|
|
11
|
-
TestJB721TiersRulesetMetadataResolver:testFuzz_mintPendingReservesPaused_bitIsolation(uint256) (runs: 256, μ: 488, ~: 488)
|
|
12
|
-
TestJB721TiersRulesetMetadataResolver:testFuzz_packExpandRoundTrip(bool,bool) (runs: 256, μ: 1090, ~: 1091)
|
|
13
|
-
TestJB721TiersRulesetMetadataResolver:testFuzz_pack_onlyUsesLow2Bits(bool,bool) (runs: 256, μ: 733, ~: 734)
|
|
14
|
-
TestJB721TiersRulesetMetadataResolver:testFuzz_transfersPaused_bitIsolation(uint256) (runs: 256, μ: 459, ~: 459)
|
|
15
|
-
TestJB721TiersRulesetMetadataResolver:test_expandMetadata_one() (gas: 453)
|
|
16
|
-
TestJB721TiersRulesetMetadataResolver:test_expandMetadata_three() (gas: 475)
|
|
17
|
-
TestJB721TiersRulesetMetadataResolver:test_expandMetadata_two() (gas: 485)
|
|
18
|
-
TestJB721TiersRulesetMetadataResolver:test_expandMetadata_zero() (gas: 455)
|
|
19
|
-
TestJB721TiersRulesetMetadataResolver:test_mintPendingReservesPaused() (gas: 457)
|
|
20
|
-
TestJB721TiersRulesetMetadataResolver:test_packExpandRoundTrip_allCombinations() (gas: 2977)
|
|
21
|
-
TestJB721TiersRulesetMetadataResolver:test_pack_allFalse() (gas: 514)
|
|
22
|
-
TestJB721TiersRulesetMetadataResolver:test_pack_bothTrue() (gas: 477)
|
|
23
|
-
TestJB721TiersRulesetMetadataResolver:test_pack_pauseMintPendingReservesOnly() (gas: 505)
|
|
24
|
-
TestJB721TiersRulesetMetadataResolver:test_pack_pauseTransfersOnly() (gas: 486)
|
|
25
|
-
TestJB721TiersRulesetMetadataResolver:test_transfersPaused() (gas: 434)
|
|
26
|
-
TestJBBitmap:testFuzz_readId_depthMatchesIndex(uint16) (runs: 256, μ: 2886, ~: 2886)
|
|
27
|
-
TestJBBitmap:testFuzz_refreshBitmapNeeded_consistency(uint16,uint16) (runs: 256, μ: 3127, ~: 3127)
|
|
28
|
-
TestJBBitmap:testFuzz_removeTier_isolatedBit(uint16,uint16) (runs: 256, μ: 28176, ~: 28755)
|
|
29
|
-
TestJBBitmap:testFuzz_removeTier_multipleBits(uint8,uint8,uint8) (runs: 256, μ: 28174, ~: 28174)
|
|
30
|
-
TestJBBitmap:testFuzz_removeTier_roundTrip(uint16) (runs: 256, μ: 23824, ~: 23824)
|
|
31
|
-
TestJBBitmap:test_isTierIdRemoved_memoryStruct() (gas: 23394)
|
|
32
|
-
TestJBBitmap:test_isTierIdRemoved_wrongDepthReturnsWrong() (gas: 25144)
|
|
33
|
-
TestJBBitmap:test_readId_depthCalculation() (gas: 7636)
|
|
34
|
-
TestJBBitmap:test_readId_initiallyZero() (gas: 2859)
|
|
35
|
-
TestJBBitmap:test_refreshBitmapNeeded_differentDepth() (gas: 2965)
|
|
36
|
-
TestJBBitmap:test_refreshBitmapNeeded_sameDepth() (gas: 3052)
|
|
37
|
-
TestJBBitmap:test_removeTier_acrossWords() (gas: 70159)
|
|
38
|
-
TestJBBitmap:test_removeTier_doesNotAffectOtherBits() (gas: 24281)
|
|
39
|
-
TestJBBitmap:test_removeTier_idempotent() (gas: 23479)
|
|
40
|
-
TestJBBitmap:test_removeTier_multipleBitsInSameWord() (gas: 25337)
|
|
41
|
-
TestJBBitmap:test_removeTier_setsbit() (gas: 23638)
|
|
42
|
-
TestJBIpfsDecoder:testFuzz_decode_alwaysProduces46Chars(bytes32) (runs: 256, μ: 359415, ~: 359415)
|
|
43
|
-
TestJBIpfsDecoder:testFuzz_decode_alwaysStartsWithQm(bytes32) (runs: 256, μ: 359671, ~: 359671)
|
|
44
|
-
TestJBIpfsDecoder:testFuzz_decode_onlyBase58Chars(bytes32) (runs: 256, μ: 647995, ~: 649242)
|
|
45
|
-
TestJBIpfsDecoder:testFuzz_decode_prependsBaseUri(bytes32,uint8) (runs: 256, μ: 369117, ~: 362596)
|
|
46
|
-
TestJBIpfsDecoder:test_decode_deterministic() (gas: 718939)
|
|
47
|
-
TestJBIpfsDecoder:test_decode_differentHashesDifferentOutput() (gas: 718729)
|
|
48
|
-
TestJBIpfsDecoder:test_decode_emptyBaseUri() (gas: 359299)
|
|
49
|
-
TestJBIpfsDecoder:test_decode_onlyBase58Chars() (gas: 626479)
|
|
50
|
-
TestJBIpfsDecoder:test_decode_outputLength() (gas: 359327)
|
|
51
|
-
TestJBIpfsDecoder:test_decode_outputStartsWithQm() (gas: 359626)
|
|
52
|
-
TestJBIpfsDecoder:test_decode_prependsBaseUri() (gas: 361561)
|
|
53
|
-
TestTieredHookStoreInvariant:invariant_maxTierIdMonotonic() (runs: 256, calls: 128000, reverts: 0)
|
|
54
|
-
TestTieredHookStoreInvariant:invariant_reserveMintBounds() (runs: 256, calls: 128000, reverts: 0)
|
|
55
|
-
TestTieredHookStoreInvariant:invariant_supplyConservation() (runs: 256, calls: 128000, reverts: 0)
|
|
56
|
-
Test_Getters_Constructor_Unit:test_balanceOf_returnsCompleteBalance(uint256,address) (runs: 256, μ: 11423292, ~: 11326514)
|
|
57
|
-
Test_Getters_Constructor_Unit:test_bools_doesPackingAndUnpackingWork(bool,bool,bool,bool,bool) (runs: 256, μ: 3439343, ~: 3439343)
|
|
58
|
-
Test_Getters_Constructor_Unit:test_cashOutWeightOf_returnsCorrectWeightAsCumSumOfPrices(uint256,uint256,uint256) (runs: 256, μ: 11195261, ~: 10992258)
|
|
59
|
-
Test_Getters_Constructor_Unit:test_constructor_deployIfInitialSuppliesNotEmpty(uint256) (runs: 256, μ: 10167481, ~: 10200751)
|
|
60
|
-
Test_Getters_Constructor_Unit:test_constructor_revertDeploymentIfOneEmptyInitialSupply(uint256,uint256) (runs: 256, μ: 487693, ~: 400030)
|
|
61
|
-
Test_Getters_Constructor_Unit:test_firstOwnerOf_shouldReturnCurrentOwnerIfFirstOwner(uint256,address) (runs: 256, μ: 10587416, ~: 10587416)
|
|
62
|
-
Test_Getters_Constructor_Unit:test_firstOwnerOf_shouldReturnFirstOwnerIfOwnerChanged(address,address) (runs: 256, μ: 10485438, ~: 10485438)
|
|
63
|
-
Test_Getters_Constructor_Unit:test_firstOwnerOf_shouldReturnZeroAddressIfNotMinted(uint256) (runs: 256, μ: 10566284, ~: 10566284)
|
|
64
|
-
Test_Getters_Constructor_Unit:test_numberOfPendingReservesFor_returnsPendingReserves() (gas: 10915529)
|
|
65
|
-
Test_Getters_Constructor_Unit:test_pricingContext_packingFunctionsAsExpected(uint32,uint8,address,bytes32) (runs: 256, μ: 991314, ~: 991314)
|
|
66
|
-
Test_Getters_Constructor_Unit:test_setEncodedIPFSUriOf_returnsCorrectEncodedURI() (gas: 10971375)
|
|
67
|
-
Test_Getters_Constructor_Unit:test_tierOfTokenId_returnsCorrectTierNumber(uint16,uint16) (runs: 256, μ: 29544, ~: 29544)
|
|
68
|
-
Test_Getters_Constructor_Unit:test_tierOf_returnsAGivenTier(uint256,uint16) (runs: 256, μ: 11097249, ~: 11056900)
|
|
69
|
-
Test_Getters_Constructor_Unit:test_tiersOf_returnsAllTiers(uint256) (runs: 256, μ: 11333900, ~: 11133203)
|
|
70
|
-
Test_Getters_Constructor_Unit:test_tiersOf_returnsAllTiersExcludingRemovedOnes(uint256,uint256,uint256) (runs: 256, μ: 11587343, ~: 11564906)
|
|
71
|
-
Test_Getters_Constructor_Unit:test_tiersOf_returnsAllTiersWithResolver(uint256) (runs: 256, μ: 11605638, ~: 11393755)
|
|
72
|
-
Test_Getters_Constructor_Unit:test_tokenURI_returnsCorrectUriWithResolver(uint256) (runs: 256, μ: 10641767, ~: 10641767)
|
|
73
|
-
Test_Getters_Constructor_Unit:test_tokenURI_returnsCorrectUriWithoutResolver() (gas: 14291263)
|
|
74
|
-
Test_Getters_Constructor_Unit:test_totalCashOutWeight_returnsCorrectTotalWeightAsCumSumOfPrices(uint256) (runs: 256, μ: 11051332, ~: 10917296)
|
|
75
|
-
Test_Getters_Constructor_Unit:test_totalSupplyOf_returnsTotalSupply(uint256) (runs: 256, μ: 11036700, ~: 10904015)
|
|
76
|
-
Test_Getters_Constructor_Unit:test_votingUnitsOf_returnsVotingUnitsCorrectly(uint256,uint256,uint256) (runs: 256, μ: 11413665, ~: 11289995)
|
|
77
|
-
Test_ProjectDeployer_Unit:test_launchProjectFor_shouldLaunchProject(uint256,bytes32) (runs: 256, μ: 1007027, ~: 1006740)
|
|
78
|
-
Test_TiersHook_E2E:testCashOutAll(bytes32) (runs: 256, μ: 2638007, ~: 2638007)
|
|
79
|
-
Test_TiersHook_E2E:testCashOutToken(uint256,bytes32) (runs: 256, μ: 2384922, ~: 2389496)
|
|
80
|
-
Test_TiersHook_E2E:testFuzzMintWithDiscountOnPayIfOneTierIsPassed(uint256,uint256) (runs: 257, μ: 1265656, ~: 1308144)
|
|
81
|
-
Test_TiersHook_E2E:testLaunchProjectAndAddHookToRegistry(bytes32) (runs: 256, μ: 4570480, ~: 4570480)
|
|
82
|
-
Test_TiersHook_E2E:testMintOnPayIfMultipleTiersArePassed(bytes32) (runs: 256, μ: 2444650, ~: 2444650)
|
|
83
|
-
Test_TiersHook_E2E:testMintOnPayIfOneTierIsPassed(uint256,bytes32) (runs: 256, μ: 2049940, ~: 2050860)
|
|
84
|
-
Test_TiersHook_E2E:testMintReservedNft(uint256,bytes32) (runs: 256, μ: 2140927, ~: 2141363)
|
|
85
|
-
Test_TiersHook_E2E:testNoMintOnPayWhenNotIncludingMetadata(uint256,bytes32) (runs: 256, μ: 1868459, ~: 1868581)
|
|
86
|
-
Test_TiersHook_E2E:testNoMintOnPayWhenNotIncludingTierIds(uint256,bytes32) (runs: 256, μ: 1874747, ~: 1874869)
|
|
87
|
-
Test_adjustTier_Unit:test_adjustTiers_addAndRemoveTiers() (gas: 1343154)
|
|
88
|
-
Test_adjustTier_Unit:test_adjustTiers_addNewTiers(uint256,uint256,uint256) (runs: 256, μ: 2340387, ~: 2352813)
|
|
89
|
-
Test_adjustTier_Unit:test_adjustTiers_addNewTiersWithNonSequentialCategories(uint256,uint256,uint256) (runs: 256, μ: 2581968, ~: 2563953)
|
|
90
|
-
Test_adjustTier_Unit:test_adjustTiers_addNewTiers_fetchSpecificTier(uint256,uint256,uint256) (runs: 256, μ: 1660417, ~: 1683246)
|
|
91
|
-
Test_adjustTier_Unit:test_adjustTiers_removeTiers(uint256,uint256,uint256) (runs: 256, μ: 10170249, ~: 10150499)
|
|
92
|
-
Test_adjustTier_Unit:test_adjustTiers_removeTiersMultipleTimes(uint256,uint256,uint256) (runs: 256, μ: 2285592, ~: 2265940)
|
|
93
|
-
Test_adjustTier_Unit:test_adjustTiers_revertIfAddingWithReserveFrequency(uint256,uint256) (runs: 256, μ: 10169685, ~: 10166640)
|
|
94
|
-
Test_adjustTier_Unit:test_adjustTiers_revertIfAddingWithVotingPower(uint256,uint256) (runs: 256, μ: 10168360, ~: 10165321)
|
|
95
|
-
Test_adjustTier_Unit:test_adjustTiers_revertIfCannotRemoveTier() (gas: 394356)
|
|
96
|
-
Test_adjustTier_Unit:test_adjustTiers_revertIfEmptyQuantity(uint256,uint256) (runs: 256, μ: 10169424, ~: 10166381)
|
|
97
|
-
Test_adjustTier_Unit:test_adjustTiers_revertIfInvalidCategorySortOrder(uint256,uint256) (runs: 256, μ: 10897255, ~: 10925524)
|
|
98
|
-
Test_adjustTier_Unit:test_adjustTiers_revertIfMoreVotingUnitsNotAllowedUsingVotingUnits(uint256,uint256) (runs: 256, μ: 10778370, ~: 10808162)
|
|
99
|
-
Test_adjustTier_Unit:test_adjustTiers_revertIfMoreVotingUnitsNotAllowedWithPriceChange(uint256,uint256) (runs: 256, μ: 10141122, ~: 10138435)
|
|
100
|
-
Test_adjustTier_Unit:test_adjustTiers_withDifferentCategories(uint256,uint256,uint256) (runs: 256, μ: 2609853, ~: 2601407)
|
|
101
|
-
Test_adjustTier_Unit:test_adjustTiers_withDifferentCategoriesAndFetchedTogether(uint256,uint256,uint256) (runs: 256, μ: 2651662, ~: 2655539)
|
|
102
|
-
Test_adjustTier_Unit:test_adjustTiers_withSameCategoryMultipleTimes(uint256,uint256,uint256) (runs: 256, μ: 3211356, ~: 3174714)
|
|
103
|
-
Test_adjustTier_Unit:test_adjustTiers_withZeroCategory(uint256,uint256,uint256) (runs: 256, μ: 2019794, ~: 1998614)
|
|
104
|
-
Test_adjustTier_Unit:test_cleanTiers_removeInactiveTiers(uint256,uint256,uint256) (runs: 256, μ: 10396186, ~: 10378896)
|
|
105
|
-
Test_adjustTier_Unit:test_setDiscountPercentOf_revertIfCannotIncreaseDiscount() (gas: 338824)
|
|
106
|
-
Test_adjustTier_Unit:test_setDiscountPercentsOf_revertIfCannotIncreaseDiscounts() (gas: 395153)
|
|
107
|
-
Test_adjustTier_Unit:test_tiersOf_emptyArrayIfNoInitializedTiers(uint256) (runs: 256, μ: 217659, ~: 217659)
|
|
108
|
-
Test_adjustTier_Unit:test_tiersOf_recentlyAddedTiersFetchedFirstWhenSorted(uint256,uint256,uint256) (runs: 256, μ: 2200972, ~: 2196814)
|
|
109
|
-
Test_adjustTier_Unit:test_tiersOf_recentlyAddedTiersFetchedFirstWhenSortedAfterTiersCleaned(uint256,uint256,uint256) (runs: 256, μ: 3616874, ~: 3631859)
|
|
110
|
-
Test_afterPayRecorded_Unit:test_afterCashOutRecordedWith_cashOutEvenIfTransfersPausedInRuleset() (gas: 1385297)
|
|
111
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_doNotMintIfNotUsingCorrectToken(address) (runs: 257, μ: 85884, ~: 85884)
|
|
112
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_doNotMintWithSomeoneElsesCredits() (gas: 514975)
|
|
113
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_doesNotRevertOnAmountBelowPriceIfNoMetadata() (gas: 65557)
|
|
114
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_mintAndReserveCorrectAmounts(uint256,uint256,uint256) (runs: 256, μ: 14417219, ~: 14622413)
|
|
115
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_mintCorrectTier() (gas: 344650)
|
|
116
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_mintCorrectTierWithAnotherCurrency() (gas: 1574686)
|
|
117
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_mintCorrectTiersWhenPartiallyUsingPayCredits() (gas: 553961)
|
|
118
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_mintNoneIfNonePassed(uint8) (runs: 256, μ: 126870, ~: 130887)
|
|
119
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_mintTierAndTrackLeftover() (gas: 190328)
|
|
120
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_mintWithExistingCreditsWhenMoreExistingCreditsThanNewCredits() (gas: 439389)
|
|
121
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_revertIfAllowanceRunsOutInSpecifiedTier() (gas: 9359196)
|
|
122
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_revertIfAmountTooLow() (gas: 150759)
|
|
123
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_revertIfCallerIsNotATerminalOfProjectId(address) (runs: 256, μ: 25585, ~: 25585)
|
|
124
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_revertIfTierDoesNotExist(uint256) (runs: 256, μ: 177275, ~: 177754)
|
|
125
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_revertIfTierRemoved() (gas: 170846)
|
|
126
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_revertIfUnexpectedLeftover() (gas: 64790)
|
|
127
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_revertIfUnexpectedLeftoverAndOverspendingPrevented(bool) (runs: 256, μ: 65853, ~: 53252)
|
|
128
|
-
Test_afterPayRecorded_Unit:test_afterPayRecorded_revertsOnAmountBelowPriceIfNoMetadataAndOverspendingIsPrevented() (gas: 1325309)
|
|
129
|
-
Test_afterPayRecorded_Unit:test_transferFrom_pauseFlagOverridesRuleset() (gas: 1603935)
|
|
130
|
-
Test_afterPayRecorded_Unit:test_transferFrom_revertTransferIfPausedInRuleset() (gas: 1568089)
|
|
131
|
-
Test_cashOut_Unit:test_afterCashOutRecordedWith_burnCashOutNft(uint256) (runs: 256, μ: 13781545, ~: 13639188)
|
|
132
|
-
Test_cashOut_Unit:test_afterCashOutRecordedWith_revertIfCallerIsNotATerminalOfTheProject() (gas: 27783)
|
|
133
|
-
Test_cashOut_Unit:test_afterCashOutRecordedWith_revertIfNotCorrectProjectId(uint8) (runs: 256, μ: 28421, ~: 28421)
|
|
134
|
-
Test_cashOut_Unit:test_afterCashOutRecordedWith_revertIfWrongHolder(address,uint8) (runs: 256, μ: 9677720, ~: 9677720)
|
|
135
|
-
Test_cashOut_Unit:test_beforeCashOutContext_returnsCorrectAmount() (gas: 10828929)
|
|
136
|
-
Test_cashOut_Unit:test_beforeCashOutContext_returnsPartOfOverflowOwnedIfCashOutTaxRateIsMaximum() (gas: 10830525)
|
|
137
|
-
Test_cashOut_Unit:test_beforeCashOutContext_returnsZeroAmountIfReserveFrequencyIsZero() (gas: 10812126)
|
|
138
|
-
Test_cashOut_Unit:test_beforeCashOutContext_revertIfNonZeroTokenCount(uint256) (runs: 256, μ: 19456, ~: 19456)
|
|
139
|
-
Test_mintFor_mintReservesFor_Unit:test_mintFor_mintArrayOfTiers() (gas: 10129100)
|
|
140
|
-
Test_mintFor_mintReservesFor_Unit:test_mintFor_revertIfManualMintNotAllowed() (gas: 10585321)
|
|
141
|
-
Test_mintFor_mintReservesFor_Unit:test_mintPendingReservesFor_mintMultipleReservedTokens() (gas: 9977856)
|
|
142
|
-
Test_mintFor_mintReservesFor_Unit:test_mintPendingReservesFor_mintOddReservedTokens() (gas: 10344857)
|
|
143
|
-
Test_mintFor_mintReservesFor_Unit:test_mintPendingReservesFor_mintsCorrectly() (gas: 9984341)
|
|
144
|
-
Test_mintFor_mintReservesFor_Unit:test_mintPendingReservesFor_revertIfNotEnoughPendingReserves() (gas: 11010767)
|
|
145
|
-
Test_mintFor_mintReservesFor_Unit:test_mintPendingReservesFor_revertIfReservedMintingIsPausedInRuleset() (gas: 9954862)
|
|
146
|
-
Test_mintFor_mintReservesFor_Unit:test_numberOfPendingReservesFor_noReservesIfNoBeneficiarySet() (gas: 10812175)
|
|
147
|
-
TierLifecycleInvariant_Local:invariant_721_1_perTierSupplyAccounting() (runs: 256, calls: 128000, reverts: 0)
|
|
148
|
-
TierLifecycleInvariant_Local:invariant_721_2_totalCashOutWeightConsistency() (runs: 256, calls: 128000, reverts: 0)
|
|
149
|
-
TierLifecycleInvariant_Local:invariant_721_3_payCreditsNonNegative() (runs: 256, calls: 128000, reverts: 0)
|
|
150
|
-
TierLifecycleInvariant_Local:invariant_721_4_reserveMintsBounded() (runs: 256, calls: 128000, reverts: 0)
|
|
151
|
-
TierLifecycleInvariant_Local:invariant_721_5_removedTiersExcluded() (runs: 256, calls: 128000, reverts: 0)
|
|
152
|
-
TierLifecycleInvariant_Local:invariant_721_6_cashOutWeightBoundedByPrice() (runs: 256, calls: 128000, reverts: 0)
|
package/ADMINISTRATION.md
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
# Administration
|
|
2
|
-
|
|
3
|
-
## At A Glance
|
|
4
|
-
|
|
5
|
-
| Item | Details |
|
|
6
|
-
| --- | --- |
|
|
7
|
-
| Scope | Tiered NFT hook configuration, tier adjustment, and deployer wiring |
|
|
8
|
-
| Control posture | Mixed project-owner and delegated control |
|
|
9
|
-
| Highest-risk actions | Adjusting tiers, setting discount or metadata behavior, and wiring the wrong hook or resolver |
|
|
10
|
-
| Recovery posture | Some configuration is mutable, but many tier properties are intentionally one-way |
|
|
11
|
-
|
|
12
|
-
## Purpose
|
|
13
|
-
|
|
14
|
-
`nana-721-hook-v6` splits control between project-level hook ownership and the tier rules enforced by the store. Many important settings can be changed only in limited ways after launch.
|
|
15
|
-
|
|
16
|
-
## Control Model
|
|
17
|
-
|
|
18
|
-
- project owners or delegates control hook-level configuration
|
|
19
|
-
- tier creation and mutation are permissioned and partially one-way
|
|
20
|
-
- the store trusts the calling hook for its own state namespace
|
|
21
|
-
- deployers package setup, but do not remove the need for runtime review
|
|
22
|
-
|
|
23
|
-
## Roles
|
|
24
|
-
|
|
25
|
-
| Role | How Assigned | Scope | Notes |
|
|
26
|
-
| --- | --- | --- | --- |
|
|
27
|
-
| Project owner | `owner()` or project control surface | Per hook | Main authority |
|
|
28
|
-
| Tier delegate | `JBPermissions` grant | Per project | Usually tier, mint, discount, or metadata permissions |
|
|
29
|
-
| Reserve beneficiary | Tier config | Per tier | Receives reserve NFTs |
|
|
30
|
-
|
|
31
|
-
## Privileged Surfaces
|
|
32
|
-
|
|
33
|
-
- `adjustTiers(...)`
|
|
34
|
-
- `mintFor(...)`
|
|
35
|
-
- `setDiscountPercentOf(...)`
|
|
36
|
-
- `setMetadata(...)`
|
|
37
|
-
- deployer setup and hook ownership transfer paths
|
|
38
|
-
|
|
39
|
-
## Deployer Permission Model
|
|
40
|
-
|
|
41
|
-
`JB721TiersHookProjectDeployer` requires callers to hold the correct Juicebox permission for each operation:
|
|
42
|
-
|
|
43
|
-
| Function | Required Permissions |
|
|
44
|
-
| --- | --- |
|
|
45
|
-
| `launchProjectFor(...)` | None (creates a new project) |
|
|
46
|
-
| `launchRulesetsFor(...)` | `LAUNCH_RULESETS` + `SET_TERMINALS` |
|
|
47
|
-
| `queueRulesetsOf(...)` | `QUEUE_RULESETS` |
|
|
48
|
-
|
|
49
|
-
Permissions are checked against the project owner via `_requirePermissionFrom`. The deployer calls the controller on the caller's behalf, so the controller sees the deployer as `msg.sender`.
|
|
50
|
-
|
|
51
|
-
## Immutable And One-Way
|
|
52
|
-
|
|
53
|
-
- many tier properties are immutable once created
|
|
54
|
-
- removed tiers do not reduce `maxTierIdOf`
|
|
55
|
-
- pool-like mutable rescue does not exist here; bad tier design is often expensive to unwind
|
|
56
|
-
|
|
57
|
-
## Operational Notes
|
|
58
|
-
|
|
59
|
-
- review tier parameters before launch as if they were economic policy
|
|
60
|
-
- treat discount changes and metadata changes as meaningful authority, not cosmetic controls
|
|
61
|
-
- be explicit about whether the hook participates in pay, cash out, or both
|
|
62
|
-
- separate resolver trust from hook and store trust
|
|
63
|
-
|
|
64
|
-
## Machine Notes
|
|
65
|
-
|
|
66
|
-
- do not reason from the hook alone when the bug may live in the store
|
|
67
|
-
- if a resolver is involved, inspect it separately
|
|
68
|
-
- if tier counts are large, re-check gas-sensitive reads and writes before operational changes
|
|
69
|
-
|
|
70
|
-
## Recovery
|
|
71
|
-
|
|
72
|
-
- some mistakes can be corrected through allowed metadata or discount changes
|
|
73
|
-
- many tier-design mistakes are effectively permanent once live
|
|
74
|
-
- deployer mistakes may require a new hook path rather than in-place repair
|
|
75
|
-
|
|
76
|
-
## Admin Boundaries
|
|
77
|
-
|
|
78
|
-
- no one can rewrite immutable tier properties after creation
|
|
79
|
-
- deployers do not bypass runtime permissions after setup
|
|
80
|
-
- resolver behavior cannot fix broken hook accounting
|
|
81
|
-
|
|
82
|
-
## Source Map
|
|
83
|
-
|
|
84
|
-
- `src/JB721TiersHook.sol`
|
|
85
|
-
- `src/JB721TiersHookStore.sol`
|
|
86
|
-
- `src/JB721TiersHookDeployer.sol`
|
|
87
|
-
- `src/JB721TiersHookProjectDeployer.sol`
|
package/ARCHITECTURE.md
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
# Architecture
|
|
2
|
-
|
|
3
|
-
## Purpose
|
|
4
|
-
|
|
5
|
-
`nana-721-hook-v6` is the shared tiered NFT layer for Juicebox V6. It lets projects sell NFT tiers, track reserves, route split payouts, and cash out NFTs without replacing core treasury accounting.
|
|
6
|
-
|
|
7
|
-
## System Overview
|
|
8
|
-
|
|
9
|
-
`JB721TiersHook` is the runtime hook. `JB721TiersHookStore` is the accounting backend for tiers, supply, reserves, and lookup. The deployers package that hook into reusable flows for existing projects and new project launches.
|
|
10
|
-
|
|
11
|
-
Custom token URI resolvers usually live outside this repo, but they still affect the trusted surface seen by users.
|
|
12
|
-
|
|
13
|
-
## Core Invariants
|
|
14
|
-
|
|
15
|
-
- the hook must not create alternate treasury accounting
|
|
16
|
-
- tier supply, burned counts, and reserves must stay coherent
|
|
17
|
-
- cash-out weight must reflect the intended tier economics
|
|
18
|
-
- reserve minting and split routing must not drift from stored tier state
|
|
19
|
-
- store-linked list and bitmap assumptions must stay valid under tier add, remove, and clean operations
|
|
20
|
-
- deployer wiring must preserve the expected ruleset and hook shape
|
|
21
|
-
|
|
22
|
-
## Modules
|
|
23
|
-
|
|
24
|
-
| Module | Responsibility | Notes |
|
|
25
|
-
| --- | --- | --- |
|
|
26
|
-
| `JB721TiersHook` | Pay hook, cash-out hook, permissions, and project-facing execution | Runtime core |
|
|
27
|
-
| `JB721TiersHookStore` | Tier definitions, balances, reserve tracking, and accounting | Shared state |
|
|
28
|
-
| `JB721TiersHookDeployer` | Clone deployer for existing projects | Wiring helper |
|
|
29
|
-
| `JB721TiersHookProjectDeployer` | Project-launch deployer with hook setup | Launch helper |
|
|
30
|
-
| `JB721Hook` | Abstract 721 hook base | Shared behavior |
|
|
31
|
-
|
|
32
|
-
## Trust Boundaries
|
|
33
|
-
|
|
34
|
-
- core accounting, pricing, and terminal authentication remain in `nana-core-v6`
|
|
35
|
-
- metadata resolvers can be project-specific and should be treated as trusted external surfaces
|
|
36
|
-
- the store is trusted by every hook that uses it
|
|
37
|
-
- deployers are trusted to wire the hook into the intended project and ruleset shape
|
|
38
|
-
|
|
39
|
-
## Critical Flows
|
|
40
|
-
|
|
41
|
-
### Pay And Mint
|
|
42
|
-
|
|
43
|
-
```text
|
|
44
|
-
payment arrives
|
|
45
|
-
-> hook decodes metadata and tier choices
|
|
46
|
-
-> store records mints, credits, supply changes, and reserve effects
|
|
47
|
-
-> hook may route split payouts from forwarded funds
|
|
48
|
-
-> collection state and balances update for the beneficiary
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### Cash Out
|
|
52
|
-
|
|
53
|
-
```text
|
|
54
|
-
cash out requested
|
|
55
|
-
-> hook checks NFT-specific metadata and selected token IDs
|
|
56
|
-
-> hook burns NFTs
|
|
57
|
-
-> store records burn and supply effects
|
|
58
|
-
-> terminal reclaims value using hook-aware cash-out math
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Accounting Model
|
|
62
|
-
|
|
63
|
-
This repo owns tier accounting and NFT lifecycle logic. It does not own the canonical project ledger for balances, fees, or surplus.
|
|
64
|
-
|
|
65
|
-
The most important state lives in the store: remaining supply, burned counts, reserve tracking, and per-tier configuration.
|
|
66
|
-
|
|
67
|
-
## Security Model
|
|
68
|
-
|
|
69
|
-
- store corruption has ecosystem-wide blast radius because many products reuse it
|
|
70
|
-
- reserve logic, discounts, and cash-out weight are the main economic risk surfaces
|
|
71
|
-
- split distribution and fallback behavior are part of correctness, not a secondary concern
|
|
72
|
-
- gas costs matter because some reads and writes scale with tier count
|
|
73
|
-
|
|
74
|
-
## Safe Change Guide
|
|
75
|
-
|
|
76
|
-
- review hook and store behavior together when changing tier lifecycle logic
|
|
77
|
-
- if reserve logic changes, re-check cash-out weight and pending reserve effects together
|
|
78
|
-
- if deployer behavior changes, re-check ruleset wiring and ownership transfer paths
|
|
79
|
-
- do not treat resolver behavior as proof that hook accounting is correct
|
|
80
|
-
|
|
81
|
-
## Canonical Checks
|
|
82
|
-
|
|
83
|
-
- pay, mint, and redeem end-to-end behavior:
|
|
84
|
-
`test/E2E/Pay_Mint_Redeem_E2E.t.sol`
|
|
85
|
-
- store and lifecycle invariants:
|
|
86
|
-
`test/invariants/TierLifecycleInvariant.t.sol`
|
|
87
|
-
`test/invariants/TieredHookStoreInvariant.t.sol`
|
|
88
|
-
- split-credit and deployer regressions:
|
|
89
|
-
`test/audit/CodexSplitCreditsMismatch.t.sol`
|
|
90
|
-
`test/regression/ProjectDeployerRulesets.t.sol`
|
|
91
|
-
|
|
92
|
-
## Source Map
|
|
93
|
-
|
|
94
|
-
- `src/JB721TiersHook.sol`
|
|
95
|
-
- `src/JB721TiersHookStore.sol`
|
|
96
|
-
- `src/JB721TiersHookDeployer.sol`
|
|
97
|
-
- `src/JB721TiersHookProjectDeployer.sol`
|
|
98
|
-
- `src/libraries/JB721TiersHookLib.sol`
|
package/AUDIT_INSTRUCTIONS.md
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
# Audit Instructions
|
|
2
|
-
|
|
3
|
-
This repo adds tiered NFT issuance and cash-out behavior to Juicebox projects. Audit it as a shared accounting layer whose mistakes can affect many downstream products.
|
|
4
|
-
|
|
5
|
-
## Audit Objective
|
|
6
|
-
|
|
7
|
-
Find issues that:
|
|
8
|
-
|
|
9
|
-
- corrupt tier supply, reserve state, or burn accounting
|
|
10
|
-
- misprice cash outs or split routing
|
|
11
|
-
- let permissions or deployer wiring create unsafe lifecycle changes
|
|
12
|
-
- create gas or liveness failures in tier-heavy deployments
|
|
13
|
-
- break trust boundaries between hook, store, and resolver behavior
|
|
14
|
-
|
|
15
|
-
## Scope
|
|
16
|
-
|
|
17
|
-
In scope:
|
|
18
|
-
|
|
19
|
-
- `src/JB721TiersHook.sol`
|
|
20
|
-
- `src/JB721TiersHookStore.sol`
|
|
21
|
-
- deployers, libraries, interfaces, and structs under `src/`
|
|
22
|
-
- deployment scripts in `script/`
|
|
23
|
-
|
|
24
|
-
## Start Here
|
|
25
|
-
|
|
26
|
-
1. `src/JB721TiersHook.sol`
|
|
27
|
-
2. `src/JB721TiersHookStore.sol`
|
|
28
|
-
3. `src/libraries/JB721TiersHookLib.sol`
|
|
29
|
-
|
|
30
|
-
## Security Model
|
|
31
|
-
|
|
32
|
-
The hook:
|
|
33
|
-
|
|
34
|
-
- mints and burns tiered NFTs through Juicebox flows
|
|
35
|
-
- records tier lifecycle state in a shared store
|
|
36
|
-
- can route split payouts from forwarded value
|
|
37
|
-
- composes with project-specific metadata resolvers
|
|
38
|
-
|
|
39
|
-
## Roles And Privileges
|
|
40
|
-
|
|
41
|
-
| Role | Powers | How constrained |
|
|
42
|
-
|------|--------|-----------------|
|
|
43
|
-
| Project authority | Configure tiers, metadata, and minting policy | Must stay inside explicit permission checks |
|
|
44
|
-
| Store caller | Mutate store state in its own namespace | Must not corrupt tier accounting |
|
|
45
|
-
| Resolver | Serve metadata and URI behavior | Must not be confused with accounting truth |
|
|
46
|
-
|
|
47
|
-
## Integration Assumptions
|
|
48
|
-
|
|
49
|
-
| Dependency | Assumption | What breaks if wrong |
|
|
50
|
-
|------------|------------|----------------------|
|
|
51
|
-
| `nana-core-v6` | Terminal auth and pricing behavior are accurate | Pay and cash-out behavior drift |
|
|
52
|
-
| Resolver repo | Metadata reads behave as expected | UI and marketplace behavior break |
|
|
53
|
-
|
|
54
|
-
## Critical Invariants
|
|
55
|
-
|
|
56
|
-
1. Tier supply stays coherent.
|
|
57
|
-
Remaining supply, burned counts, and outstanding ownership must reconcile.
|
|
58
|
-
2. Reserve logic stays bounded.
|
|
59
|
-
Pending reserves and reserve minting must not over-allocate.
|
|
60
|
-
3. Cash-out weight is consistent.
|
|
61
|
-
NFT reclaim value must match the tier model the hook and store intend.
|
|
62
|
-
4. Split and fallback behavior is safe.
|
|
63
|
-
Failed split paths must not silently corrupt value or lifecycle state.
|
|
64
|
-
|
|
65
|
-
## Attack Surfaces
|
|
66
|
-
|
|
67
|
-
- pay and cash-out hook entrypoints
|
|
68
|
-
- tier add, remove, and clean flows
|
|
69
|
-
- reserve minting
|
|
70
|
-
- split distribution and fallback paths
|
|
71
|
-
- resolver integration
|
|
72
|
-
|
|
73
|
-
## Verification
|
|
74
|
-
|
|
75
|
-
- `npm install`
|
|
76
|
-
- `forge build`
|
|
77
|
-
- `forge test`
|
package/RISKS.md
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
# Juicebox 721 Hook Risk Register
|
|
2
|
-
|
|
3
|
-
This file covers the tiered-NFT accounting, reserve-mint, and cash-out risks in the shared 721 hook used across multiple higher-level products.
|
|
4
|
-
|
|
5
|
-
## How To Use This File
|
|
6
|
-
|
|
7
|
-
- Read `Priority risks` first. They summarize the shared 721-hook risks with the widest blast radius.
|
|
8
|
-
- Use the later sections for reentrancy, gas, tier accounting, and integration reasoning.
|
|
9
|
-
- Treat `Invariants to verify` as required coverage for any hook or store change.
|
|
10
|
-
|
|
11
|
-
## Priority Risks
|
|
12
|
-
|
|
13
|
-
| Priority | Risk | Why it matters | Primary controls |
|
|
14
|
-
|----------|------|----------------|------------------|
|
|
15
|
-
| P0 | Shared store corruption or accounting drift | `JB721TiersHookStore` is reused across products. A tier-accounting bug can affect many repos at once. | Heavy store testing, invariants, and cautious deployment review. |
|
|
16
|
-
| P1 | Gas and iteration ceilings around tier state | Tier operations can iterate over reserves, pricing state, and cash-out weights. | Gas tests, tier-count limits, and DoS review. |
|
|
17
|
-
| P1 | Cash-out and reserve math mismatch | Fair redemption depends on tier supply, pending reserves, and pricing state staying aligned. | Detailed invariants, fuzzing, and integration tests. |
|
|
18
|
-
|
|
19
|
-
## 1. Trust Assumptions
|
|
20
|
-
|
|
21
|
-
- **The store is trusted.** It keys state by `msg.sender`, so a hook can only affect its own namespace, but that namespace is fully trusted.
|
|
22
|
-
- **Tier configuration is partly immutable.** Price, supply, reserve frequency, category, voting units, and split percent are permanent after creation.
|
|
23
|
-
- **Category ordering matters.** The store's linked-list assumptions depend on correct sorted insertion.
|
|
24
|
-
- **`useReserveBeneficiaryAsDefault` has wide effects.** Setting it on a new tier can change the default reserve beneficiary for older tiers without their own explicit beneficiary.
|
|
25
|
-
- **Clone initialization is one-shot.** Clones are deployed and initialized atomically.
|
|
26
|
-
- **Directory and prices are trusted.** Terminal authentication and cross-currency behavior depend on core.
|
|
27
|
-
|
|
28
|
-
## 2. Economic Risks
|
|
29
|
-
|
|
30
|
-
- **Cash-out weight uses full undiscounted price.**
|
|
31
|
-
- **Pending reserves inflate the cash-out denominator before reserves are minted.**
|
|
32
|
-
- **Pay credits can accumulate without a cap.**
|
|
33
|
-
- **Zero-price tiers are valid.**
|
|
34
|
-
- **Discount math uses a denominator of 200, not 10,000.**
|
|
35
|
-
- **Currency mismatch can silently skip minting when no prices contract is configured.**
|
|
36
|
-
- **`splitPercent` can reduce fungible-token minting weight.**
|
|
37
|
-
- **Reserve minting is permissionless.**
|
|
38
|
-
|
|
39
|
-
## 3. Reentrancy Surface
|
|
40
|
-
|
|
41
|
-
- **Split hook callbacks execute arbitrary code.**
|
|
42
|
-
- **Split beneficiary ETH sends can fail softly and reroute value.**
|
|
43
|
-
- **Terminal `pay` and `addToBalanceOf` calls during split distribution can reenter external systems.**
|
|
44
|
-
- **Split fallback can still strand value if the project terminal rejects leftovers.**
|
|
45
|
-
- **There is no `ReentrancyGuard`.** Safety depends on state ordering, terminal auth, and wrapped external calls.
|
|
46
|
-
|
|
47
|
-
## 4. Gas And DoS Vectors
|
|
48
|
-
|
|
49
|
-
- **`totalCashOutWeight` iterates all tier IDs.**
|
|
50
|
-
- **`balanceOf`, `votingUnitsOf`, and `totalSupplyOf` also iterate all tiers.**
|
|
51
|
-
- **Large tier catalogs are technically allowed but not the supported operating shape.**
|
|
52
|
-
- **`tiersOf` still traverses removed tiers until cleanup runs.**
|
|
53
|
-
- **Minting across many tiers in one payment can get expensive fast.**
|
|
54
|
-
- **Reserve minting is loop-based and should be batched when large.**
|
|
55
|
-
|
|
56
|
-
## 5. Access Control
|
|
57
|
-
|
|
58
|
-
- **`adjustTiers` is permissioned and respects append-only restrictions.**
|
|
59
|
-
- **`mintFor` is permissioned and still depends on per-tier owner-mint flags.**
|
|
60
|
-
- **`setDiscountPercentOf` is permissioned and can be one-way constrained.**
|
|
61
|
-
- **`setMetadata` is permissioned and changes name, symbol, URIs, resolver, and tier URIs.**
|
|
62
|
-
- **Transfer pause is tier-sensitive.**
|
|
63
|
-
- **`mintPendingReservesFor` and `cleanTiers` are permissionless by design.**
|
|
64
|
-
|
|
65
|
-
## 6. Integration Risks
|
|
66
|
-
|
|
67
|
-
- **Hook weight can override fungible-token minting.**
|
|
68
|
-
- **Metadata encoding is fragile.**
|
|
69
|
-
- **`beforeCashOutRecordedWith` rejects mixed fungible-token cash outs.**
|
|
70
|
-
- **Split group IDs are tightly coupled to the hook address.**
|
|
71
|
-
- **ERC-20 split distribution depends on terminal allowance behavior.**
|
|
72
|
-
- **Forwarded funds with empty hook metadata can skip distribution and remain in the hook.**
|
|
73
|
-
- **Token URI resolver calls can block metadata reads if the resolver reverts.**
|
|
74
|
-
|
|
75
|
-
## 7. Invariants To Verify
|
|
76
|
-
|
|
77
|
-
- per-tier supply conservation holds
|
|
78
|
-
- total cash-out weight stays consistent with outstanding NFTs and pending reserves
|
|
79
|
-
- reserve minting stays bounded by reserve frequency
|
|
80
|
-
- token IDs remain unique
|
|
81
|
-
- credits track leftovers correctly
|
|
82
|
-
- removed tiers stay excluded from active listings
|
|
83
|
-
- store balance views match ERC-721 balances
|
|
84
|
-
- discount monotonicity is enforced when locked
|
|
85
|
-
|
|
86
|
-
## 8. Accepted Behaviors
|
|
87
|
-
|
|
88
|
-
### 8.1 Pending reserves dilute cash-out value before minting
|
|
89
|
-
|
|
90
|
-
This is intentional. Including pending reserves in the denominator prevents reserve front-running.
|
|
91
|
-
|
|
92
|
-
### 8.2 Cash-out weight uses full price regardless of discount
|
|
93
|
-
|
|
94
|
-
This is intentional. The cash-out weight represents treasury share, not purchase price.
|
|
95
|
-
|
|
96
|
-
### 8.3 Currency mismatch can skip minting when no prices surface exists
|
|
97
|
-
|
|
98
|
-
If currencies differ and `PRICES == address(0)`, payments can increase project balance without minting NFTs. That is an accepted degradation rather than a revert path.
|
|
99
|
-
|
|
100
|
-
### 8.4 Tiny split allocations can round down to zero
|
|
101
|
-
|
|
102
|
-
Dust-sized split allocations can become economically lossy after rounding.
|
|
103
|
-
|
|
104
|
-
### 8.5 Failed split payouts only degrade cleanly if the fallback terminal path works
|
|
105
|
-
|
|
106
|
-
If both the primary split path and the fallback `addToBalanceOf` path fail, the hook can retain assets with no built-in rescue path.
|
|
107
|
-
|
|
108
|
-
### 8.6 Credit-funded tier purchases may underfund split obligations
|
|
109
|
-
|
|
110
|
-
Pay credits can be used to buy tiers that carry a `splitPercent`. When credits satisfy part of the tier price, the fresh ETH forwarded to splits may be less than the split obligation implied by the full tier price. Project owners who consider this a problem should enable the `preventBuyingTierWithCredits` flag on affected tiers. This is accepted behavior.
|
|
111
|
-
|
|
112
|
-
### 8.7 Changing the default reserve beneficiary redirects pending reserves
|
|
113
|
-
|
|
114
|
-
When the default reserve beneficiary is updated, any pending (unminted) reserves across all tiers that rely on the default will be distributed to the new beneficiary once minted. This is by design — the project owner controls reserve distribution targets and may intentionally redirect pending reserves by updating the default.
|
|
115
|
-
|
|
116
|
-
### 8.8 Discounted credit mints retain full cash-out weight
|
|
117
|
-
|
|
118
|
-
Tokens minted at a discounted price via credits still carry the full undiscounted tier price as their cash-out weight. This means a holder who purchased at a discount receives the same treasury share as a holder who paid full price. Project owners should factor this into discount percentage decisions, as aggressive discounts can create favorable cash-out economics for discounted buyers.
|
package/SKILLS.md
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# Juicebox 721 Hook
|
|
2
|
-
|
|
3
|
-
## Use This File For
|
|
4
|
-
|
|
5
|
-
- Use this file when the task involves tiered NFT minting, reserve minting, tier adjustments, deployer wiring, or 721-aware cash-out behavior.
|
|
6
|
-
- Start here, then decide whether the issue is in hook execution, store accounting, deployer setup, or resolver behavior.
|
|
7
|
-
|
|
8
|
-
## Read This Next
|
|
9
|
-
|
|
10
|
-
| If you need... | Open this next |
|
|
11
|
-
|---|---|
|
|
12
|
-
| Repo overview and architecture | [`README.md`](./README.md), [`ARCHITECTURE.md`](./ARCHITECTURE.md) |
|
|
13
|
-
| Runtime hook behavior | [`src/JB721TiersHook.sol`](./src/JB721TiersHook.sol) |
|
|
14
|
-
| Tier accounting | [`src/JB721TiersHookStore.sol`](./src/JB721TiersHookStore.sol) |
|
|
15
|
-
| Shared math and metadata helpers | [`src/libraries/`](./src/libraries/), [`src/interfaces/`](./src/interfaces/), [`src/structs/`](./src/structs/) |
|
|
16
|
-
| Deployer flows | [`src/JB721TiersHookDeployer.sol`](./src/JB721TiersHookDeployer.sol), [`src/JB721TiersHookProjectDeployer.sol`](./src/JB721TiersHookProjectDeployer.sol) |
|
|
17
|
-
| Lifecycle, invariant, and audit coverage | [`test/E2E/Pay_Mint_Redeem_E2E.t.sol`](./test/E2E/Pay_Mint_Redeem_E2E.t.sol), [`test/invariants/TierLifecycleInvariant.t.sol`](./test/invariants/TierLifecycleInvariant.t.sol), [`test/invariants/TieredHookStoreInvariant.t.sol`](./test/invariants/TieredHookStoreInvariant.t.sol), [`test/audit/CodexSplitCreditsMismatch.t.sol`](./test/audit/CodexSplitCreditsMismatch.t.sol) |
|
|
18
|
-
|
|
19
|
-
## Repo Map
|
|
20
|
-
|
|
21
|
-
| Area | Where to look |
|
|
22
|
-
|---|---|
|
|
23
|
-
| Main contracts | [`src/`](./src/) |
|
|
24
|
-
| Libraries, interfaces, and structs | [`src/libraries/`](./src/libraries/), [`src/interfaces/`](./src/interfaces/), [`src/structs/`](./src/structs/) |
|
|
25
|
-
| Scripts | [`script/`](./script/) |
|
|
26
|
-
| Tests | [`test/`](./test/) |
|
|
27
|
-
|
|
28
|
-
## Purpose
|
|
29
|
-
|
|
30
|
-
Tiered NFT hook for Juicebox V6. This repo handles priced NFT tiers, reserve logic, tier-aware cash outs, and deployer flows that wire those hooks into projects.
|
|
31
|
-
|
|
32
|
-
## Reference Files
|
|
33
|
-
|
|
34
|
-
- Open [`references/runtime.md`](./references/runtime.md) when you need hook and store roles, cash-out weight behavior, or main invariants.
|
|
35
|
-
- Open [`references/operations.md`](./references/operations.md) when you need permission paths, tier-adjustment rules, test breadcrumbs, or common stale assumptions.
|
|
36
|
-
|
|
37
|
-
## Working Rules
|
|
38
|
-
|
|
39
|
-
- Start in [`src/JB721TiersHookStore.sol`](./src/JB721TiersHookStore.sol) for tier accounting questions.
|
|
40
|
-
- Keep hook behavior, store behavior, and resolver behavior separate.
|
|
41
|
-
- Reserve logic, split routing, and cash-out weight calculations are part of the economic surface.
|
|
42
|
-
- Tier adjustments are high-risk because many tier properties are intentionally immutable after creation.
|
|
43
|
-
- If a problem looks like metadata only, verify it is not actually a hook or store issue first.
|