@bananapus/721-hook-v6 0.0.41 → 0.0.42

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bananapus/721-hook-v6",
3
- "version": "0.0.41",
3
+ "version": "0.0.42",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -725,9 +725,6 @@ contract JB721TiersHookStore is IJB721TiersHookStore {
725
725
  || reserveBeneficiaryOf({hook: hook, tierId: tierId}) == address(0)
726
726
  ) return 0;
727
727
 
728
- // A sold-out tier cannot have mintable pending reserves — minting would underflow remainingSupply.
729
- if (storedTier.remainingSupply == 0) return 0;
730
-
731
728
  // The number of reserve NFTs which have already been minted from the tier.
732
729
  uint256 numberOfReserveMints = numberOfReservesMintedFor[hook][tierId];
733
730
 
@@ -1232,7 +1229,7 @@ contract JB721TiersHookStore is IJB721TiersHookStore {
1232
1229
  if (storedTier.remainingSupply == 0) revert JB721TiersHookStore_InsufficientSupplyRemaining(tierId);
1233
1230
 
1234
1231
  // Mint the 721 — decrement remaining supply first so the reserve check below
1235
- // sees the post-mint state (this non-reserve mint may increase pending reserves).
1232
+ // sees the correct post-mint non-reserve-mint count.
1236
1233
  unchecked {
1237
1234
  // Keep a reference to its token ID.
1238
1235
  tokenIds[i] = _generateTokenId({
@@ -275,15 +275,15 @@ contract TestVotingUnitsLifecycle is UnitTestSetup {
275
275
  address(testHook),
276
276
  2,
277
277
  JBStored721Tier({
278
- price: uint104(20),
279
- remainingSupply: uint32(100),
280
- initialSupply: uint32(100),
281
- reserveFrequency: uint16(0),
282
- category: uint24(100),
283
- discountPercent: uint8(0),
284
- packedBools: testHook.test_store().ForTest_packBools(true, false, false, false, false, false),
285
- splitPercent: 0
286
- })
278
+ price: uint104(20),
279
+ remainingSupply: uint32(100),
280
+ initialSupply: uint32(100),
281
+ reserveFrequency: uint16(0),
282
+ category: uint24(100),
283
+ discountPercent: uint8(0),
284
+ packedBools: testHook.test_store().ForTest_packBools(true, false, false, false, false, false),
285
+ splitPercent: 0
286
+ })
287
287
  );
288
288
  // Clear tier 2's custom voting units (so it falls back to price).
289
289
  testHook.test_store().ForTest_setTierVotingUnits(address(testHook), 2, 0);
@@ -0,0 +1,66 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.28;
3
+
4
+ import {Test} from "forge-std/Test.sol";
5
+ import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
6
+
7
+ import {JB721TiersHookStore} from "../../src/JB721TiersHookStore.sol";
8
+ import {JB721Tier} from "../../src/structs/JB721Tier.sol";
9
+ import {JB721TierConfig} from "../../src/structs/JB721TierConfig.sol";
10
+ import {JB721TierConfigFlags} from "../../src/structs/JB721TierConfigFlags.sol";
11
+
12
+ contract CodexNemesisReserveSellout is Test {
13
+ JB721TiersHookStore internal store;
14
+
15
+ function setUp() public {
16
+ store = new JB721TiersHookStore();
17
+ }
18
+
19
+ /// @notice Verifies that a paid mint cannot consume the last slot when it is reserved.
20
+ /// @dev Previously this test demonstrated the bug (paid mint succeeded). Now it confirms the fix.
21
+ function test_paidMintCannotConsumeReservedFinalSlot() public {
22
+ JB721TierConfig[] memory tiers = new JB721TierConfig[](1);
23
+ tiers[0] = JB721TierConfig({
24
+ price: 1 ether,
25
+ initialSupply: 2,
26
+ votingUnits: 0,
27
+ reserveFrequency: 1,
28
+ reserveBeneficiary: address(0xBEEF),
29
+ encodedIPFSUri: bytes32(0),
30
+ category: 0,
31
+ discountPercent: 0,
32
+ flags: JB721TierConfigFlags({
33
+ allowOwnerMint: false,
34
+ useReserveBeneficiaryAsDefault: false,
35
+ transfersPausable: false,
36
+ useVotingUnits: false,
37
+ cantBeRemoved: false,
38
+ cantIncreaseDiscountPercent: false,
39
+ cantBuyWithCredits: false
40
+ }),
41
+ splitPercent: 0,
42
+ splits: new JBSplit[](0)
43
+ });
44
+
45
+ store.recordAddTiers(tiers);
46
+
47
+ uint16[] memory tierIds = new uint16[](1);
48
+ tierIds[0] = 1;
49
+
50
+ store.recordMint({amount: 1 ether, tierIds: tierIds, isOwnerMint: false});
51
+
52
+ JB721Tier memory tier = store.tierOf(address(this), 1, false);
53
+ assertEq(tier.remainingSupply, 1, "one paid mint leaves one slot");
54
+ assertEq(store.numberOfPendingReservesFor(address(this), 1), 1, "one reserve is pending");
55
+
56
+ // With the fix, the second paid mint reverts because the remaining slot is reserved.
57
+ vm.expectRevert(
58
+ abi.encodeWithSelector(JB721TiersHookStore.JB721TiersHookStore_InsufficientSupplyRemaining.selector, 1)
59
+ );
60
+ store.recordMint({amount: 1 ether, tierIds: tierIds, isOwnerMint: false});
61
+
62
+ // Reserve beneficiary can still claim their entitled mint.
63
+ store.recordMintReservesFor({tierId: 1, count: 1});
64
+ assertEq(store.numberOfReservesMintedFor(address(this), 1), 1, "reserve beneficiary got their token");
65
+ }
66
+ }
@@ -0,0 +1,273 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.28;
3
+
4
+ import {Test} from "forge-std/Test.sol";
5
+ import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
6
+
7
+ import {JB721TiersHookStore} from "../../src/JB721TiersHookStore.sol";
8
+ import {JB721Tier} from "../../src/structs/JB721Tier.sol";
9
+ import {JB721TierConfig} from "../../src/structs/JB721TierConfig.sol";
10
+ import {JB721TierConfigFlags} from "../../src/structs/JB721TierConfigFlags.sol";
11
+
12
+ /// @notice Tests that paid mints cannot consume slots reserved for the reserve beneficiary.
13
+ /// @dev Regression test for the vulnerability where `_numberOfPendingReservesFor` returns 0
14
+ /// when `remainingSupply == 0` (sold-out early-return), allowing the post-decrement guard
15
+ /// `0 < 0` to pass and permanently stealing reserved slots from the beneficiary.
16
+ /// The fix uses `_numberOfPendingReservesForMintGuard` which omits the sold-out early-return.
17
+ contract ReserveSlotProtection is Test {
18
+ JB721TiersHookStore internal store;
19
+
20
+ function setUp() public {
21
+ store = new JB721TiersHookStore();
22
+ }
23
+
24
+ /// @notice Proves the fix: a paid mint that would consume the last reserved slot reverts.
25
+ /// Scenario: tier with initialSupply=2, reserveFrequency=1 (1 reserve per paid mint).
26
+ /// After 1 paid mint, 1 slot remains but it's reserved. Second paid mint must revert.
27
+ /// Post-decrement trace: remaining goes 2->1, pending=ceil(1/1)=1, check 1<1 = false -> ok.
28
+ /// Second mint: remaining goes 1->0, _numberOfPendingReservesForMintGuard returns 2
29
+ /// (ceil(2/1)-0=2), check 0<2 -> true -> reverts.
30
+ function test_paidMintRevertsWhenOnlyReservedSlotsRemain() public {
31
+ JB721TierConfig[] memory tiers = new JB721TierConfig[](1);
32
+ tiers[0] = JB721TierConfig({
33
+ price: 1 ether,
34
+ initialSupply: 2,
35
+ votingUnits: 0,
36
+ reserveFrequency: 1,
37
+ reserveBeneficiary: address(0xBEEF),
38
+ encodedIPFSUri: bytes32(0),
39
+ category: 0,
40
+ discountPercent: 0,
41
+ flags: JB721TierConfigFlags({
42
+ allowOwnerMint: false,
43
+ useReserveBeneficiaryAsDefault: false,
44
+ transfersPausable: false,
45
+ useVotingUnits: false,
46
+ cantBeRemoved: false,
47
+ cantIncreaseDiscountPercent: false,
48
+ cantBuyWithCredits: false
49
+ }),
50
+ splitPercent: 0,
51
+ splits: new JBSplit[](0)
52
+ });
53
+
54
+ store.recordAddTiers(tiers);
55
+
56
+ uint16[] memory tierIds = new uint16[](1);
57
+ tierIds[0] = 1;
58
+
59
+ // First paid mint succeeds — uses 1 of 2 slots, leaving 1 for the pending reserve.
60
+ store.recordMint({amount: 1 ether, tierIds: tierIds, isOwnerMint: false});
61
+
62
+ // Verify state: 1 remaining supply, 1 pending reserve.
63
+ JB721Tier memory tier = store.tierOf(address(this), 1, false);
64
+ assertEq(tier.remainingSupply, 1, "should have 1 slot remaining after first mint");
65
+ assertEq(store.numberOfPendingReservesFor(address(this), 1), 1, "should have 1 pending reserve");
66
+
67
+ // Second paid mint MUST revert — the only remaining slot belongs to the reserve beneficiary.
68
+ vm.expectRevert(
69
+ abi.encodeWithSelector(JB721TiersHookStore.JB721TiersHookStore_InsufficientSupplyRemaining.selector, 1)
70
+ );
71
+ store.recordMint({amount: 1 ether, tierIds: tierIds, isOwnerMint: false});
72
+ }
73
+
74
+ /// @notice Proves that the reserve beneficiary can still mint their reserved slot after fix.
75
+ function test_reserveBeneficiaryCanMintAfterPaidSlotsExhausted() public {
76
+ JB721TierConfig[] memory tiers = new JB721TierConfig[](1);
77
+ tiers[0] = JB721TierConfig({
78
+ price: 1 ether,
79
+ initialSupply: 2,
80
+ votingUnits: 0,
81
+ reserveFrequency: 1,
82
+ reserveBeneficiary: address(0xBEEF),
83
+ encodedIPFSUri: bytes32(0),
84
+ category: 0,
85
+ discountPercent: 0,
86
+ flags: JB721TierConfigFlags({
87
+ allowOwnerMint: false,
88
+ useReserveBeneficiaryAsDefault: false,
89
+ transfersPausable: false,
90
+ useVotingUnits: false,
91
+ cantBeRemoved: false,
92
+ cantIncreaseDiscountPercent: false,
93
+ cantBuyWithCredits: false
94
+ }),
95
+ splitPercent: 0,
96
+ splits: new JBSplit[](0)
97
+ });
98
+
99
+ store.recordAddTiers(tiers);
100
+
101
+ uint16[] memory tierIds = new uint16[](1);
102
+ tierIds[0] = 1;
103
+
104
+ // First paid mint.
105
+ store.recordMint({amount: 1 ether, tierIds: tierIds, isOwnerMint: false});
106
+
107
+ // Reserve beneficiary mints their entitled reserve.
108
+ uint256[] memory reserveTokenIds = store.recordMintReservesFor({tierId: 1, count: 1});
109
+ assertEq(reserveTokenIds.length, 1, "reserve beneficiary should get 1 token");
110
+
111
+ // After reserve mint, remaining supply is 0 and reserves are fulfilled.
112
+ JB721Tier memory tier = store.tierOf(address(this), 1, false);
113
+ assertEq(tier.remainingSupply, 0, "tier should be fully minted");
114
+ assertEq(store.numberOfReservesMintedFor(address(this), 1), 1, "1 reserve should be minted");
115
+ }
116
+
117
+ /// @notice Tests a larger tier: initialSupply=10, reserveFrequency=2.
118
+ /// With frequency=2, every 2 paid mints earn 1 reserve (rounded up).
119
+ /// Post-decrement analysis for the 7th mint:
120
+ /// remaining goes 4->3, nonReserveMints=7, pending=ceil(7/2)-0=4.
121
+ /// Check: 3 < 4 -> true -> reverts. Correct!
122
+ /// So mints 1-6 succeed, mint 7 reverts.
123
+ function test_largerTierReserveProtection() public {
124
+ JB721TierConfig[] memory tiers = new JB721TierConfig[](1);
125
+ tiers[0] = JB721TierConfig({
126
+ price: 0.1 ether,
127
+ initialSupply: 10,
128
+ votingUnits: 0,
129
+ reserveFrequency: 2,
130
+ reserveBeneficiary: address(0xCAFE),
131
+ encodedIPFSUri: bytes32(0),
132
+ category: 0,
133
+ discountPercent: 0,
134
+ flags: JB721TierConfigFlags({
135
+ allowOwnerMint: false,
136
+ useReserveBeneficiaryAsDefault: false,
137
+ transfersPausable: false,
138
+ useVotingUnits: false,
139
+ cantBeRemoved: false,
140
+ cantIncreaseDiscountPercent: false,
141
+ cantBuyWithCredits: false
142
+ }),
143
+ splitPercent: 0,
144
+ splits: new JBSplit[](0)
145
+ });
146
+
147
+ store.recordAddTiers(tiers);
148
+
149
+ uint16[] memory tierIds = new uint16[](1);
150
+ tierIds[0] = 1;
151
+
152
+ // Mint 6 paid NFTs. After 6 mints: remaining=4, pending=ceil(6/2)=3.
153
+ for (uint256 i; i < 6; i++) {
154
+ store.recordMint({amount: 0.1 ether, tierIds: tierIds, isOwnerMint: false});
155
+ }
156
+
157
+ JB721Tier memory tier = store.tierOf(address(this), 1, false);
158
+ assertEq(tier.remainingSupply, 4, "should have 4 remaining after 6 mints");
159
+ assertEq(store.numberOfPendingReservesFor(address(this), 1), 3, "should have 3 pending reserves");
160
+
161
+ // 7th paid mint should revert: after decrement, remaining=3, pending=ceil(7/2)=4. 3<4 -> reverts.
162
+ vm.expectRevert(
163
+ abi.encodeWithSelector(JB721TiersHookStore.JB721TiersHookStore_InsufficientSupplyRemaining.selector, 1)
164
+ );
165
+ store.recordMint({amount: 0.1 ether, tierIds: tierIds, isOwnerMint: false});
166
+ }
167
+
168
+ /// @notice Verifies that when reserves are minted between paid mints, paid mints can continue.
169
+ /// initialSupply=4, reserveFrequency=1.
170
+ function test_paidMintsResumeAfterReservesMinted() public {
171
+ JB721TierConfig[] memory tiers = new JB721TierConfig[](1);
172
+ tiers[0] = JB721TierConfig({
173
+ price: 1 ether,
174
+ initialSupply: 4,
175
+ votingUnits: 0,
176
+ reserveFrequency: 1,
177
+ reserveBeneficiary: address(0xBEEF),
178
+ encodedIPFSUri: bytes32(0),
179
+ category: 0,
180
+ discountPercent: 0,
181
+ flags: JB721TierConfigFlags({
182
+ allowOwnerMint: false,
183
+ useReserveBeneficiaryAsDefault: false,
184
+ transfersPausable: false,
185
+ useVotingUnits: false,
186
+ cantBeRemoved: false,
187
+ cantIncreaseDiscountPercent: false,
188
+ cantBuyWithCredits: false
189
+ }),
190
+ splitPercent: 0,
191
+ splits: new JBSplit[](0)
192
+ });
193
+
194
+ store.recordAddTiers(tiers);
195
+
196
+ uint16[] memory tierIds = new uint16[](1);
197
+ tierIds[0] = 1;
198
+
199
+ // Paid mint 1: remaining 4->3, nonReserveMints=1, pending=ceil(1/1)=1. Check: 3<1? No. OK.
200
+ store.recordMint({amount: 1 ether, tierIds: tierIds, isOwnerMint: false});
201
+
202
+ // Paid mint 2: remaining 3->2, nonReserveMints=2, pending=ceil(2/1)=2. Check: 2<2? No. OK.
203
+ store.recordMint({amount: 1 ether, tierIds: tierIds, isOwnerMint: false});
204
+
205
+ // Paid mint 3: remaining 2->1, nonReserveMints=3, pending=ceil(3/1)=3. Check: 1<3? Yes! Revert.
206
+ vm.expectRevert(
207
+ abi.encodeWithSelector(JB721TiersHookStore.JB721TiersHookStore_InsufficientSupplyRemaining.selector, 1)
208
+ );
209
+ store.recordMint({amount: 1 ether, tierIds: tierIds, isOwnerMint: false});
210
+
211
+ // Mint 1 reserve — frees up a slot. Now reservesMinted=1.
212
+ store.recordMintReservesFor({tierId: 1, count: 1});
213
+
214
+ // State: remaining=1, reservesMinted=1, nonReserveMints=2.
215
+ // Paid mint attempt: remaining 1->0, nonReserveMints=3, pending=ceil(3/1)-1=2. Check: 0<2? Yes! Revert.
216
+ vm.expectRevert(
217
+ abi.encodeWithSelector(JB721TiersHookStore.JB721TiersHookStore_InsufficientSupplyRemaining.selector, 1)
218
+ );
219
+ store.recordMint({amount: 1 ether, tierIds: tierIds, isOwnerMint: false});
220
+
221
+ // Mint remaining reserve.
222
+ store.recordMintReservesFor({tierId: 1, count: 1});
223
+
224
+ // Tier fully minted — 0 remaining.
225
+ JB721Tier memory tier = store.tierOf(address(this), 1, false);
226
+ assertEq(tier.remainingSupply, 0, "tier should be fully minted");
227
+ }
228
+
229
+ /// @notice Without reserves, all NFTs in a tier should be mintable (no off-by-one).
230
+ function test_noReservesFullSupplyMintable() public {
231
+ JB721TierConfig[] memory tiers = new JB721TierConfig[](1);
232
+ tiers[0] = JB721TierConfig({
233
+ price: 0.1 ether,
234
+ initialSupply: 5,
235
+ votingUnits: 0,
236
+ reserveFrequency: 0,
237
+ reserveBeneficiary: address(0),
238
+ encodedIPFSUri: bytes32(0),
239
+ category: 0,
240
+ discountPercent: 0,
241
+ flags: JB721TierConfigFlags({
242
+ allowOwnerMint: false,
243
+ useReserveBeneficiaryAsDefault: false,
244
+ transfersPausable: false,
245
+ useVotingUnits: false,
246
+ cantBeRemoved: false,
247
+ cantIncreaseDiscountPercent: false,
248
+ cantBuyWithCredits: false
249
+ }),
250
+ splitPercent: 0,
251
+ splits: new JBSplit[](0)
252
+ });
253
+
254
+ store.recordAddTiers(tiers);
255
+
256
+ uint16[] memory tierIds = new uint16[](1);
257
+ tierIds[0] = 1;
258
+
259
+ // Mint all 5 — should succeed since no reserves to protect.
260
+ for (uint256 i; i < 5; i++) {
261
+ store.recordMint({amount: 0.1 ether, tierIds: tierIds, isOwnerMint: false});
262
+ }
263
+
264
+ JB721Tier memory tier = store.tierOf(address(this), 1, false);
265
+ assertEq(tier.remainingSupply, 0, "fully minted");
266
+
267
+ // 6th mint should revert (supply exhausted).
268
+ vm.expectRevert(
269
+ abi.encodeWithSelector(JB721TiersHookStore.JB721TiersHookStore_InsufficientSupplyRemaining.selector, 1)
270
+ );
271
+ store.recordMint({amount: 0.1 ether, tierIds: tierIds, isOwnerMint: false});
272
+ }
273
+ }
@@ -181,15 +181,15 @@ contract Test_Getters_Constructor_Unit is UnitTestSetup {
181
181
  address(hook),
182
182
  i + 1,
183
183
  JBStored721Tier({
184
- price: uint104((i + 1) * 10),
185
- remainingSupply: uint32(100 - (i + 1)),
186
- initialSupply: uint32(100),
187
- reserveFrequency: uint16(0),
188
- category: uint24(100),
189
- discountPercent: uint8(0),
190
- packedBools: hook.test_store().ForTest_packBools(false, false, false, false, false, false),
191
- splitPercent: 0
192
- })
184
+ price: uint104((i + 1) * 10),
185
+ remainingSupply: uint32(100 - (i + 1)),
186
+ initialSupply: uint32(100),
187
+ reserveFrequency: uint16(0),
188
+ category: uint24(100),
189
+ discountPercent: uint8(0),
190
+ packedBools: hook.test_store().ForTest_packBools(false, false, false, false, false, false),
191
+ splitPercent: 0
192
+ })
193
193
  );
194
194
  }
195
195
 
@@ -235,18 +235,18 @@ contract Test_Getters_Constructor_Unit is UnitTestSetup {
235
235
  address(hook),
236
236
  i + 1,
237
237
  JBStored721Tier({
238
- price: uint104((i + 1) * 10),
239
- // forge-lint: disable-next-line(unsafe-typecast)
240
- remainingSupply: uint32(initialSupply - totalMinted),
241
- // forge-lint: disable-next-line(unsafe-typecast)
242
- initialSupply: uint32(initialSupply),
243
- // forge-lint: disable-next-line(unsafe-typecast)
244
- reserveFrequency: uint16(reserveFrequency),
245
- category: uint24(100),
246
- discountPercent: uint8(0),
247
- packedBools: hook.test_store().ForTest_packBools(false, false, false, false, false, false),
248
- splitPercent: 0
249
- })
238
+ price: uint104((i + 1) * 10),
239
+ // forge-lint: disable-next-line(unsafe-typecast)
240
+ remainingSupply: uint32(initialSupply - totalMinted),
241
+ // forge-lint: disable-next-line(unsafe-typecast)
242
+ initialSupply: uint32(initialSupply),
243
+ // forge-lint: disable-next-line(unsafe-typecast)
244
+ reserveFrequency: uint16(reserveFrequency),
245
+ category: uint24(100),
246
+ discountPercent: uint8(0),
247
+ packedBools: hook.test_store().ForTest_packBools(false, false, false, false, false, false),
248
+ splitPercent: 0
249
+ })
250
250
  );
251
251
  // Manually set the number of reserve mints for each tier.
252
252
  hook.test_store().ForTest_setReservesMintedFor(address(hook), i + 1, reservedMinted);
@@ -280,15 +280,15 @@ contract Test_Getters_Constructor_Unit is UnitTestSetup {
280
280
  address(hook),
281
281
  1,
282
282
  JBStored721Tier({
283
- price: uint104(10),
284
- remainingSupply: uint32(10),
285
- initialSupply: uint32(20),
286
- reserveFrequency: uint16(100),
287
- category: uint24(100),
288
- discountPercent: uint8(0),
289
- packedBools: hook.test_store().ForTest_packBools(false, false, true, false, false, false),
290
- splitPercent: 0
291
- })
283
+ price: uint104(10),
284
+ remainingSupply: uint32(10),
285
+ initialSupply: uint32(20),
286
+ reserveFrequency: uint16(100),
287
+ category: uint24(100),
288
+ discountPercent: uint8(0),
289
+ packedBools: hook.test_store().ForTest_packBools(false, false, true, false, false, false),
290
+ splitPercent: 0
291
+ })
292
292
  );
293
293
  // Clear the voting units mapping for tier 1 (ForTest_setTier only overwrites the packed struct).
294
294
  hook.test_store().ForTest_setTierVotingUnits(address(hook), 1, 0);
@@ -438,18 +438,18 @@ contract Test_Getters_Constructor_Unit is UnitTestSetup {
438
438
  address(hook),
439
439
  i,
440
440
  JBStored721Tier({
441
- // forge-lint: disable-next-line(unsafe-typecast)
442
- price: uint104(i * 10),
443
- // forge-lint: disable-next-line(unsafe-typecast)
444
- remainingSupply: uint32(10 * i - 5 * i),
445
- // forge-lint: disable-next-line(unsafe-typecast)
446
- initialSupply: uint32(10 * i),
447
- reserveFrequency: uint16(0),
448
- category: uint24(100),
449
- discountPercent: uint8(0),
450
- packedBools: hook.test_store().ForTest_packBools(false, false, false, false, false, false),
451
- splitPercent: 0
452
- })
441
+ // forge-lint: disable-next-line(unsafe-typecast)
442
+ price: uint104(i * 10),
443
+ // forge-lint: disable-next-line(unsafe-typecast)
444
+ remainingSupply: uint32(10 * i - 5 * i),
445
+ // forge-lint: disable-next-line(unsafe-typecast)
446
+ initialSupply: uint32(10 * i),
447
+ reserveFrequency: uint16(0),
448
+ category: uint24(100),
449
+ discountPercent: uint8(0),
450
+ packedBools: hook.test_store().ForTest_packBools(false, false, false, false, false, false),
451
+ splitPercent: 0
452
+ })
453
453
  );
454
454
  // Calculate the theoretical weight for the current tier. 10 the price multiplier.
455
455
  theoreticalWeight += (10 * i - 5 * i) * i * 10;
@@ -27,18 +27,18 @@ contract Test_mintFor_mintReservesFor_Unit is UnitTestSetup {
27
27
  address(hook),
28
28
  i + 1,
29
29
  JBStored721Tier({
30
- price: uint104((i + 1) * 10),
31
- // forge-lint: disable-next-line(unsafe-typecast)
32
- remainingSupply: uint32(initialSupply - totalMinted),
33
- // forge-lint: disable-next-line(unsafe-typecast)
34
- initialSupply: uint32(initialSupply),
35
- // forge-lint: disable-next-line(unsafe-typecast)
36
- reserveFrequency: uint16(reserveFrequency),
37
- category: uint24(100),
38
- discountPercent: uint8(0),
39
- packedBools: hook.test_store().ForTest_packBools(false, false, true, false, false, false),
40
- splitPercent: 0
41
- })
30
+ price: uint104((i + 1) * 10),
31
+ // forge-lint: disable-next-line(unsafe-typecast)
32
+ remainingSupply: uint32(initialSupply - totalMinted),
33
+ // forge-lint: disable-next-line(unsafe-typecast)
34
+ initialSupply: uint32(initialSupply),
35
+ // forge-lint: disable-next-line(unsafe-typecast)
36
+ reserveFrequency: uint16(reserveFrequency),
37
+ category: uint24(100),
38
+ discountPercent: uint8(0),
39
+ packedBools: hook.test_store().ForTest_packBools(false, false, true, false, false, false),
40
+ splitPercent: 0
41
+ })
42
42
  );
43
43
  hook.test_store().ForTest_setReservesMintedFor(address(hook), i + 1, reservedMinted);
44
44
  }
@@ -77,18 +77,18 @@ contract Test_mintFor_mintReservesFor_Unit is UnitTestSetup {
77
77
  address(hook),
78
78
  1,
79
79
  JBStored721Tier({
80
- price: uint104(10),
81
- // forge-lint: disable-next-line(unsafe-typecast)
82
- remainingSupply: uint32(initialSupply),
83
- // forge-lint: disable-next-line(unsafe-typecast)
84
- initialSupply: uint32(initialSupply),
85
- // forge-lint: disable-next-line(unsafe-typecast)
86
- reserveFrequency: uint16(reserveFrequency),
87
- category: uint24(100),
88
- discountPercent: uint8(0),
89
- packedBools: hook.test_store().ForTest_packBools(true, false, true, false, false, false),
90
- splitPercent: 0
91
- })
80
+ price: uint104(10),
81
+ // forge-lint: disable-next-line(unsafe-typecast)
82
+ remainingSupply: uint32(initialSupply),
83
+ // forge-lint: disable-next-line(unsafe-typecast)
84
+ initialSupply: uint32(initialSupply),
85
+ // forge-lint: disable-next-line(unsafe-typecast)
86
+ reserveFrequency: uint16(reserveFrequency),
87
+ category: uint24(100),
88
+ discountPercent: uint8(0),
89
+ packedBools: hook.test_store().ForTest_packBools(true, false, true, false, false, false),
90
+ splitPercent: 0
91
+ })
92
92
  );
93
93
 
94
94
  // Mint the initial tiers.
@@ -184,18 +184,18 @@ contract Test_mintFor_mintReservesFor_Unit is UnitTestSetup {
184
184
  address(hook),
185
185
  i + 1,
186
186
  JBStored721Tier({
187
- price: uint104((i + 1) * 10),
188
- // forge-lint: disable-next-line(unsafe-typecast)
189
- remainingSupply: uint32(initialSupply - totalMinted),
190
- // forge-lint: disable-next-line(unsafe-typecast)
191
- initialSupply: uint32(initialSupply),
192
- // forge-lint: disable-next-line(unsafe-typecast)
193
- reserveFrequency: uint16(reserveFrequency),
194
- category: uint24(100),
195
- discountPercent: uint8(0),
196
- packedBools: hook.test_store().ForTest_packBools(false, false, true, false, false, false),
197
- splitPercent: 0
198
- })
187
+ price: uint104((i + 1) * 10),
188
+ // forge-lint: disable-next-line(unsafe-typecast)
189
+ remainingSupply: uint32(initialSupply - totalMinted),
190
+ // forge-lint: disable-next-line(unsafe-typecast)
191
+ initialSupply: uint32(initialSupply),
192
+ // forge-lint: disable-next-line(unsafe-typecast)
193
+ reserveFrequency: uint16(reserveFrequency),
194
+ category: uint24(100),
195
+ discountPercent: uint8(0),
196
+ packedBools: hook.test_store().ForTest_packBools(false, false, true, false, false, false),
197
+ splitPercent: 0
198
+ })
199
199
  );
200
200
 
201
201
  // Set the number of reserve NFTs already minted for the tier.
@@ -286,18 +286,18 @@ contract Test_mintFor_mintReservesFor_Unit is UnitTestSetup {
286
286
  address(hook),
287
287
  i + 1,
288
288
  JBStored721Tier({
289
- price: uint104((i + 1) * 10),
290
- // forge-lint: disable-next-line(unsafe-typecast)
291
- remainingSupply: uint32(initialSupply - totalMinted),
292
- // forge-lint: disable-next-line(unsafe-typecast)
293
- initialSupply: uint32(initialSupply),
294
- // forge-lint: disable-next-line(unsafe-typecast)
295
- reserveFrequency: uint16(reserveFrequency),
296
- category: uint24(100),
297
- discountPercent: uint8(0),
298
- packedBools: hook.test_store().ForTest_packBools(false, false, true, false, false, false),
299
- splitPercent: 0
300
- })
289
+ price: uint104((i + 1) * 10),
290
+ // forge-lint: disable-next-line(unsafe-typecast)
291
+ remainingSupply: uint32(initialSupply - totalMinted),
292
+ // forge-lint: disable-next-line(unsafe-typecast)
293
+ initialSupply: uint32(initialSupply),
294
+ // forge-lint: disable-next-line(unsafe-typecast)
295
+ reserveFrequency: uint16(reserveFrequency),
296
+ category: uint24(100),
297
+ discountPercent: uint8(0),
298
+ packedBools: hook.test_store().ForTest_packBools(false, false, true, false, false, false),
299
+ splitPercent: 0
300
+ })
301
301
  );
302
302
  hook.test_store().ForTest_setReservesMintedFor(address(hook), i + 1, reservedMinted);
303
303
  }
@@ -327,18 +327,18 @@ contract Test_mintFor_mintReservesFor_Unit is UnitTestSetup {
327
327
  address(hook),
328
328
  i + 1,
329
329
  JBStored721Tier({
330
- price: uint104((i + 1) * 10),
331
- // forge-lint: disable-next-line(unsafe-typecast)
332
- remainingSupply: uint32(initialSupply - totalMinted),
333
- // forge-lint: disable-next-line(unsafe-typecast)
334
- initialSupply: uint32(initialSupply),
335
- // forge-lint: disable-next-line(unsafe-typecast)
336
- reserveFrequency: uint16(reserveFrequency),
337
- category: uint24(100),
338
- discountPercent: uint8(0),
339
- packedBools: hook.test_store().ForTest_packBools(false, false, true, false, false, false),
340
- splitPercent: 0
341
- })
330
+ price: uint104((i + 1) * 10),
331
+ // forge-lint: disable-next-line(unsafe-typecast)
332
+ remainingSupply: uint32(initialSupply - totalMinted),
333
+ // forge-lint: disable-next-line(unsafe-typecast)
334
+ initialSupply: uint32(initialSupply),
335
+ // forge-lint: disable-next-line(unsafe-typecast)
336
+ reserveFrequency: uint16(reserveFrequency),
337
+ category: uint24(100),
338
+ discountPercent: uint8(0),
339
+ packedBools: hook.test_store().ForTest_packBools(false, false, true, false, false, false),
340
+ splitPercent: 0
341
+ })
342
342
  );
343
343
  hook.test_store().ForTest_setReservesMintedFor(address(hook), i + 1, reservedMinted);
344
344
  }
@@ -19,18 +19,18 @@ contract Test_cashOut_Unit is UnitTestSetup {
19
19
  address(hook),
20
20
  i,
21
21
  JBStored721Tier({
22
- // forge-lint: disable-next-line(unsafe-typecast)
23
- price: uint104(i * 10),
24
- // forge-lint: disable-next-line(unsafe-typecast)
25
- remainingSupply: uint32(10 * i - 5 * i),
26
- // forge-lint: disable-next-line(unsafe-typecast)
27
- initialSupply: uint32(10 * i),
28
- reserveFrequency: uint16(0),
29
- category: uint24(100),
30
- discountPercent: uint8(0),
31
- packedBools: hook.test_store().ForTest_packBools(false, false, false, false, false, false),
32
- splitPercent: 0
33
- })
22
+ // forge-lint: disable-next-line(unsafe-typecast)
23
+ price: uint104(i * 10),
24
+ // forge-lint: disable-next-line(unsafe-typecast)
25
+ remainingSupply: uint32(10 * i - 5 * i),
26
+ // forge-lint: disable-next-line(unsafe-typecast)
27
+ initialSupply: uint32(10 * i),
28
+ reserveFrequency: uint16(0),
29
+ category: uint24(100),
30
+ discountPercent: uint8(0),
31
+ packedBools: hook.test_store().ForTest_packBools(false, false, false, false, false, false),
32
+ splitPercent: 0
33
+ })
34
34
  );
35
35
  totalWeight += (10 * i - 5 * i) * i * 10;
36
36
  }
@@ -94,18 +94,18 @@ contract Test_cashOut_Unit is UnitTestSetup {
94
94
  address(hook),
95
95
  i,
96
96
  JBStored721Tier({
97
- // forge-lint: disable-next-line(unsafe-typecast)
98
- price: uint104(i * 10),
99
- // forge-lint: disable-next-line(unsafe-typecast)
100
- remainingSupply: uint32(10 * i - 5 * i),
101
- // forge-lint: disable-next-line(unsafe-typecast)
102
- initialSupply: uint32(10 * i),
103
- reserveFrequency: uint16(0),
104
- category: uint24(100),
105
- discountPercent: uint8(0),
106
- packedBools: hook.test_store().ForTest_packBools(false, false, false, false, false, false),
107
- splitPercent: 0
108
- })
97
+ // forge-lint: disable-next-line(unsafe-typecast)
98
+ price: uint104(i * 10),
99
+ // forge-lint: disable-next-line(unsafe-typecast)
100
+ remainingSupply: uint32(10 * i - 5 * i),
101
+ // forge-lint: disable-next-line(unsafe-typecast)
102
+ initialSupply: uint32(10 * i),
103
+ reserveFrequency: uint16(0),
104
+ category: uint24(100),
105
+ discountPercent: uint8(0),
106
+ packedBools: hook.test_store().ForTest_packBools(false, false, false, false, false, false),
107
+ splitPercent: 0
108
+ })
109
109
  );
110
110
  totalWeight += (10 * i - 5 * i) * i * 10;
111
111
  }
@@ -155,18 +155,18 @@ contract Test_cashOut_Unit is UnitTestSetup {
155
155
  address(hook),
156
156
  i,
157
157
  JBStored721Tier({
158
- // forge-lint: disable-next-line(unsafe-typecast)
159
- price: uint104(i * 10),
160
- // forge-lint: disable-next-line(unsafe-typecast)
161
- remainingSupply: uint32(10 * i - 5 * i),
162
- // forge-lint: disable-next-line(unsafe-typecast)
163
- initialSupply: uint32(10 * i),
164
- reserveFrequency: uint16(0),
165
- category: uint24(100),
166
- discountPercent: uint8(0),
167
- packedBools: hook.test_store().ForTest_packBools(false, false, false, false, false, false),
168
- splitPercent: 0
169
- })
158
+ // forge-lint: disable-next-line(unsafe-typecast)
159
+ price: uint104(i * 10),
160
+ // forge-lint: disable-next-line(unsafe-typecast)
161
+ remainingSupply: uint32(10 * i - 5 * i),
162
+ // forge-lint: disable-next-line(unsafe-typecast)
163
+ initialSupply: uint32(10 * i),
164
+ reserveFrequency: uint16(0),
165
+ category: uint24(100),
166
+ discountPercent: uint8(0),
167
+ packedBools: hook.test_store().ForTest_packBools(false, false, false, false, false, false),
168
+ splitPercent: 0
169
+ })
170
170
  );
171
171
  totalWeight += (10 * i - 5 * i) * i * 10;
172
172
  }