@croptop/core-v6 0.0.37 → 0.0.39

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 (40) hide show
  1. package/README.md +2 -2
  2. package/foundry.toml +2 -1
  3. package/package.json +25 -13
  4. package/script/ConfigureFeeProject.s.sol +8 -5
  5. package/src/CTDeployer.sol +52 -51
  6. package/src/CTPublisher.sol +20 -5
  7. package/src/interfaces/ICTDeployer.sol +2 -2
  8. package/ADMINISTRATION.md +0 -94
  9. package/ARCHITECTURE.md +0 -96
  10. package/AUDIT_INSTRUCTIONS.md +0 -88
  11. package/RISKS.md +0 -78
  12. package/SKILLS.md +0 -46
  13. package/STYLE_GUIDE.md +0 -610
  14. package/USER_JOURNEYS.md +0 -134
  15. package/foundry.lock +0 -11
  16. package/slither-ci.config.json +0 -10
  17. package/sphinx.lock +0 -507
  18. package/test/CTDeployer.t.sol +0 -616
  19. package/test/CTProjectOwner.t.sol +0 -185
  20. package/test/CTPublisher.t.sol +0 -869
  21. package/test/ClaimCollectionOwnership.t.sol +0 -315
  22. package/test/CroptopAttacks.t.sol +0 -437
  23. package/test/Fork.t.sol +0 -227
  24. package/test/TestAuditGaps.sol +0 -696
  25. package/test/Test_MetadataGeneration.t.sol +0 -79
  26. package/test/audit/CodexNemesisCroptopPublisherBoundary.t.sol +0 -329
  27. package/test/audit/CodexNemesisCurrencyPoCs.t.sol +0 -371
  28. package/test/audit/CodexNemesisFreshRound.t.sol +0 -395
  29. package/test/audit/CodexNemesisMetadataShadow.t.sol +0 -203
  30. package/test/audit/CodexNemesisPoCs.t.sol +0 -263
  31. package/test/audit/CodexNemesisPolicyReuse.t.sol +0 -168
  32. package/test/audit/CodexNemesisUriDrift.t.sol +0 -252
  33. package/test/audit/DeployerPermissionBypass.t.sol +0 -213
  34. package/test/audit/EmptyPostFeeBypass.t.sol +0 -53
  35. package/test/audit/FeeBeneficiaryReentrancy.t.sol +0 -247
  36. package/test/audit/FeeFallbackBlackhole.t.sol +0 -263
  37. package/test/fork/PublishFork.t.sol +0 -440
  38. package/test/regression/DuplicateUriFeeEvasion.t.sol +0 -312
  39. package/test/regression/FeeEvasion.t.sol +0 -286
  40. package/test/regression/StaleTierIdMapping.t.sol +0 -218
@@ -1,218 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity 0.8.28;
3
-
4
- // forge-lint: disable-next-line(unaliased-plain-import)
5
- import "forge-std/Test.sol";
6
-
7
- import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
8
- import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
9
- import {IJBOwnable} from "@bananapus/ownable-v6/src/interfaces/IJBOwnable.sol";
10
- import {IJB721Hook} from "@bananapus/721-hook-v6/src/interfaces/IJB721Hook.sol";
11
- import {IJB721TiersHook} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHook.sol";
12
- import {IJB721TiersHookStore} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHookStore.sol";
13
- import {JB721Tier} from "@bananapus/721-hook-v6/src/structs/JB721Tier.sol";
14
- import {JB721TierFlags} from "@bananapus/721-hook-v6/src/structs/JB721TierFlags.sol";
15
- import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
16
-
17
- import {CTPublisher} from "../../src/CTPublisher.sol";
18
- import {CTAllowedPost} from "../../src/structs/CTAllowedPost.sol";
19
- import {CTPost} from "../../src/structs/CTPost.sol";
20
-
21
- /// @title L52_StaleTierIdMapping
22
- /// @notice Stale tierIdForEncodedIPFSUriOf mapping after external tier removal.
23
- /// When a tier is removed externally via adjustTiers(), the publisher's mapping still pointed
24
- /// to the removed tier ID, blocking re-creation. The fix clears the stale mapping and allows
25
- /// the post to fall through to new-tier creation.
26
- contract L52_StaleTierIdMapping is Test {
27
- CTPublisher publisher;
28
-
29
- IJBPermissions permissions = IJBPermissions(makeAddr("permissions"));
30
- IJBDirectory directory = IJBDirectory(makeAddr("directory"));
31
-
32
- address hookOwner = makeAddr("hookOwner");
33
- address hookAddr = makeAddr("hook");
34
- address hookStoreAddr = makeAddr("hookStore");
35
- address terminalAddr = makeAddr("terminal");
36
- address poster = makeAddr("poster");
37
-
38
- uint256 feeProjectId = 1;
39
- uint256 hookProjectId = 42;
40
-
41
- bytes32 constant TEST_URI = keccak256("removable-content");
42
-
43
- function setUp() public {
44
- publisher = new CTPublisher(directory, permissions, feeProjectId, address(0));
45
-
46
- // Mock hook.owner().
47
- vm.mockCall(hookAddr, abi.encodeWithSelector(IJBOwnable.owner.selector), abi.encode(hookOwner));
48
- // Mock hook.PROJECT_ID().
49
- vm.mockCall(hookAddr, abi.encodeWithSelector(IJB721Hook.PROJECT_ID.selector), abi.encode(hookProjectId));
50
- // Mock hook.STORE().
51
- vm.mockCall(hookAddr, abi.encodeWithSelector(IJB721TiersHook.STORE.selector), abi.encode(hookStoreAddr));
52
-
53
- // Mock permissions to return true by default.
54
- vm.mockCall(
55
- address(permissions), abi.encodeWithSelector(IJBPermissions.hasPermission.selector), abi.encode(true)
56
- );
57
-
58
- // Fund poster.
59
- vm.deal(poster, 100 ether);
60
- }
61
-
62
- function _configureCategory() internal {
63
- CTAllowedPost[] memory posts = new CTAllowedPost[](1);
64
- posts[0] = CTAllowedPost({
65
- hook: hookAddr,
66
- category: 5,
67
- minimumPrice: 0,
68
- minimumTotalSupply: 1,
69
- maximumTotalSupply: 100,
70
- maximumSplitPercent: 0,
71
- allowedAddresses: new address[](0)
72
- });
73
-
74
- vm.prank(hookOwner);
75
- publisher.configurePostingCriteriaFor(posts);
76
- }
77
-
78
- function _setupMintMocks(uint256 maxTierId) internal {
79
- vm.mockCall(
80
- hookStoreAddr, abi.encodeWithSelector(IJB721TiersHookStore.maxTierIdOf.selector), abi.encode(maxTierId)
81
- );
82
- vm.mockCall(hookAddr, abi.encodeWithSelector(IJB721TiersHook.adjustTiers.selector), abi.encode());
83
- vm.mockCall(hookAddr, abi.encodeWithSelector(bytes4(keccak256("METADATA_ID_TARGET()"))), abi.encode(address(0)));
84
- vm.mockCall(
85
- address(directory),
86
- abi.encodeWithSelector(IJBDirectory.primaryTerminalOf.selector),
87
- abi.encode(terminalAddr)
88
- );
89
- vm.mockCall(terminalAddr, "", abi.encode(uint256(0)));
90
- }
91
-
92
- /// @notice After a tier is removed externally, the stale mapping should be cleared
93
- /// so that the same encodedIPFSUri can be re-posted as a new tier.
94
- function test_staleMappingClearedWhenTierRemoved() public {
95
- _configureCategory();
96
-
97
- // First mint: create tier 1 for TEST_URI.
98
- _setupMintMocks(0);
99
-
100
- // Mock isTierRemoved to return false (tier exists).
101
- vm.mockCall(
102
- hookStoreAddr,
103
- abi.encodeWithSelector(IJB721TiersHookStore.isTierRemoved.selector, hookAddr, 1),
104
- abi.encode(false)
105
- );
106
-
107
- CTPost[] memory posts = new CTPost[](1);
108
- posts[0] = CTPost({
109
- encodedIPFSUri: TEST_URI,
110
- totalSupply: 10,
111
- price: 0.1 ether,
112
- category: 5,
113
- splitPercent: 0,
114
- splits: new JBSplit[](0)
115
- });
116
-
117
- vm.prank(poster);
118
- publisher.mintFrom{value: 0.2 ether}(IJB721TiersHook(hookAddr), posts, poster, poster, "", "");
119
-
120
- // Verify tier ID 1 was stored in the mapping.
121
- assertEq(
122
- publisher.tierIdForEncodedIPFSUriOf(hookAddr, TEST_URI), 1, "tier ID should be stored after first mint"
123
- );
124
-
125
- // Now simulate external tier removal: isTierRemoved returns true for tier 1.
126
- vm.mockCall(
127
- hookStoreAddr,
128
- abi.encodeWithSelector(IJB721TiersHookStore.isTierRemoved.selector, hookAddr, 1),
129
- abi.encode(true)
130
- );
131
-
132
- // Update maxTierId to 1 so new tier gets ID 2.
133
- _setupMintMocks(1);
134
-
135
- // Second mint with the same URI should succeed (creating a new tier),
136
- // because the fix detects the stale mapping and clears it.
137
- vm.prank(poster);
138
- publisher.mintFrom{value: 0.2 ether}(IJB721TiersHook(hookAddr), posts, poster, poster, "", "");
139
-
140
- // Verify the mapping now points to the new tier ID (2).
141
- assertEq(
142
- publisher.tierIdForEncodedIPFSUriOf(hookAddr, TEST_URI),
143
- 2,
144
- "tier ID should be updated to new tier after re-post"
145
- );
146
- }
147
-
148
- /// @notice When a tier is NOT removed, the mapping should be used as-is (no re-creation).
149
- function test_existingTierNotRemovedUsesMapping() public {
150
- _configureCategory();
151
-
152
- // First mint: create tier 1 for TEST_URI.
153
- _setupMintMocks(0);
154
-
155
- // Mock isTierRemoved to return false (tier exists).
156
- vm.mockCall(
157
- hookStoreAddr,
158
- abi.encodeWithSelector(IJB721TiersHookStore.isTierRemoved.selector, hookAddr, 1),
159
- abi.encode(false)
160
- );
161
-
162
- // Mock tierOf for tier 1 so the existing-tier price lookup succeeds.
163
- JB721Tier memory tier = JB721Tier({
164
- id: 1,
165
- price: 0.1 ether,
166
- remainingSupply: 9,
167
- initialSupply: 10,
168
- votingUnits: 0,
169
- reserveFrequency: 0,
170
- reserveBeneficiary: address(0),
171
- encodedIPFSUri: TEST_URI,
172
- category: 5,
173
- discountPercent: 0,
174
- flags: JB721TierFlags({
175
- allowOwnerMint: false,
176
- transfersPausable: false,
177
- cantBeRemoved: false,
178
- cantIncreaseDiscountPercent: false,
179
- cantBuyWithCredits: false
180
- }),
181
- splitPercent: 0,
182
- resolvedUri: ""
183
- });
184
- vm.mockCall(
185
- hookStoreAddr,
186
- abi.encodeWithSelector(IJB721TiersHookStore.tierOf.selector, hookAddr, 1, false),
187
- abi.encode(tier)
188
- );
189
-
190
- CTPost[] memory posts = new CTPost[](1);
191
- posts[0] = CTPost({
192
- encodedIPFSUri: TEST_URI,
193
- totalSupply: 10,
194
- price: 0.1 ether,
195
- category: 5,
196
- splitPercent: 0,
197
- splits: new JBSplit[](0)
198
- });
199
-
200
- vm.prank(poster);
201
- publisher.mintFrom{value: 0.2 ether}(IJB721TiersHook(hookAddr), posts, poster, poster, "", "");
202
-
203
- assertEq(publisher.tierIdForEncodedIPFSUriOf(hookAddr, TEST_URI), 1);
204
-
205
- // Second mint with existing tier (not removed) — should reuse tier ID 1.
206
- _setupMintMocks(1);
207
-
208
- vm.prank(poster);
209
- publisher.mintFrom{value: 0.2 ether}(IJB721TiersHook(hookAddr), posts, poster, poster, "", "");
210
-
211
- // Mapping should still point to tier 1.
212
- assertEq(
213
- publisher.tierIdForEncodedIPFSUriOf(hookAddr, TEST_URI),
214
- 1,
215
- "tier ID should remain unchanged when tier is not removed"
216
- );
217
- }
218
- }