@croptop/core-v6 0.0.38 → 0.0.40
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/README.md +2 -2
- package/foundry.toml +2 -1
- package/package.json +25 -13
- package/script/ConfigureFeeProject.s.sol +8 -5
- package/src/CTDeployer.sol +67 -58
- package/src/CTProjectOwner.sol +6 -4
- package/src/CTPublisher.sol +14 -4
- package/src/interfaces/ICTDeployer.sol +2 -2
- package/src/structs/CTProjectConfig.sol +7 -6
- package/ADMINISTRATION.md +0 -94
- package/ARCHITECTURE.md +0 -96
- package/AUDIT_INSTRUCTIONS.md +0 -88
- package/RISKS.md +0 -78
- package/SKILLS.md +0 -46
- package/STYLE_GUIDE.md +0 -610
- package/USER_JOURNEYS.md +0 -134
- package/foundry.lock +0 -11
- package/slither-ci.config.json +0 -10
- package/sphinx.lock +0 -507
- package/test/CTDeployer.t.sol +0 -616
- package/test/CTProjectOwner.t.sol +0 -185
- package/test/CTPublisher.t.sol +0 -869
- package/test/ClaimCollectionOwnership.t.sol +0 -315
- package/test/CroptopAttacks.t.sol +0 -437
- package/test/Fork.t.sol +0 -227
- package/test/TestAuditGaps.sol +0 -696
- package/test/Test_MetadataGeneration.t.sol +0 -79
- package/test/audit/CodexNemesisCroptopPublisherBoundary.t.sol +0 -329
- package/test/audit/CodexNemesisCurrencyPoCs.t.sol +0 -371
- package/test/audit/CodexNemesisFreshRound.t.sol +0 -395
- package/test/audit/CodexNemesisMetadataShadow.t.sol +0 -196
- package/test/audit/CodexNemesisPoCs.t.sol +0 -263
- package/test/audit/CodexNemesisPolicyReuse.t.sol +0 -168
- package/test/audit/CodexNemesisUriDrift.t.sol +0 -252
- package/test/audit/DeployerPermissionBypass.t.sol +0 -213
- package/test/audit/EmptyPostFeeBypass.t.sol +0 -53
- package/test/audit/FeeBeneficiaryReentrancy.t.sol +0 -247
- package/test/audit/FeeFallbackBlackhole.t.sol +0 -263
- package/test/audit/Pass12Fixes.t.sol +0 -388
- package/test/fork/PublishFork.t.sol +0 -440
- package/test/regression/DuplicateUriFeeEvasion.t.sol +0 -312
- package/test/regression/FeeEvasion.t.sol +0 -286
- package/test/regression/StaleTierIdMapping.t.sol +0 -228
|
@@ -1,228 +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
|
-
// Mock tierOf for the removed tier — the M-42 fix calls tierOf before checking isTierRemoved.
|
|
133
|
-
JB721Tier memory removedTier;
|
|
134
|
-
removedTier.id = 1;
|
|
135
|
-
removedTier.encodedIPFSUri = TEST_URI;
|
|
136
|
-
vm.mockCall(
|
|
137
|
-
hookStoreAddr,
|
|
138
|
-
abi.encodeWithSelector(IJB721TiersHookStore.tierOf.selector, hookAddr, 1, false),
|
|
139
|
-
abi.encode(removedTier)
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
// Update maxTierId to 1 so new tier gets ID 2.
|
|
143
|
-
_setupMintMocks(1);
|
|
144
|
-
|
|
145
|
-
// Second mint with the same URI should succeed (creating a new tier),
|
|
146
|
-
// because the fix detects the stale mapping and clears it.
|
|
147
|
-
vm.prank(poster);
|
|
148
|
-
publisher.mintFrom{value: 0.2 ether}(IJB721TiersHook(hookAddr), posts, poster, poster, "", "");
|
|
149
|
-
|
|
150
|
-
// Verify the mapping now points to the new tier ID (2).
|
|
151
|
-
assertEq(
|
|
152
|
-
publisher.tierIdForEncodedIPFSUriOf(hookAddr, TEST_URI),
|
|
153
|
-
2,
|
|
154
|
-
"tier ID should be updated to new tier after re-post"
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/// @notice When a tier is NOT removed, the mapping should be used as-is (no re-creation).
|
|
159
|
-
function test_existingTierNotRemovedUsesMapping() public {
|
|
160
|
-
_configureCategory();
|
|
161
|
-
|
|
162
|
-
// First mint: create tier 1 for TEST_URI.
|
|
163
|
-
_setupMintMocks(0);
|
|
164
|
-
|
|
165
|
-
// Mock isTierRemoved to return false (tier exists).
|
|
166
|
-
vm.mockCall(
|
|
167
|
-
hookStoreAddr,
|
|
168
|
-
abi.encodeWithSelector(IJB721TiersHookStore.isTierRemoved.selector, hookAddr, 1),
|
|
169
|
-
abi.encode(false)
|
|
170
|
-
);
|
|
171
|
-
|
|
172
|
-
// Mock tierOf for tier 1 so the existing-tier price lookup succeeds.
|
|
173
|
-
JB721Tier memory tier = JB721Tier({
|
|
174
|
-
id: 1,
|
|
175
|
-
price: 0.1 ether,
|
|
176
|
-
remainingSupply: 9,
|
|
177
|
-
initialSupply: 10,
|
|
178
|
-
votingUnits: 0,
|
|
179
|
-
reserveFrequency: 0,
|
|
180
|
-
reserveBeneficiary: address(0),
|
|
181
|
-
encodedIPFSUri: TEST_URI,
|
|
182
|
-
category: 5,
|
|
183
|
-
discountPercent: 0,
|
|
184
|
-
flags: JB721TierFlags({
|
|
185
|
-
allowOwnerMint: false,
|
|
186
|
-
transfersPausable: false,
|
|
187
|
-
cantBeRemoved: false,
|
|
188
|
-
cantIncreaseDiscountPercent: false,
|
|
189
|
-
cantBuyWithCredits: false
|
|
190
|
-
}),
|
|
191
|
-
splitPercent: 0,
|
|
192
|
-
resolvedUri: ""
|
|
193
|
-
});
|
|
194
|
-
vm.mockCall(
|
|
195
|
-
hookStoreAddr,
|
|
196
|
-
abi.encodeWithSelector(IJB721TiersHookStore.tierOf.selector, hookAddr, 1, false),
|
|
197
|
-
abi.encode(tier)
|
|
198
|
-
);
|
|
199
|
-
|
|
200
|
-
CTPost[] memory posts = new CTPost[](1);
|
|
201
|
-
posts[0] = CTPost({
|
|
202
|
-
encodedIPFSUri: TEST_URI,
|
|
203
|
-
totalSupply: 10,
|
|
204
|
-
price: 0.1 ether,
|
|
205
|
-
category: 5,
|
|
206
|
-
splitPercent: 0,
|
|
207
|
-
splits: new JBSplit[](0)
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
vm.prank(poster);
|
|
211
|
-
publisher.mintFrom{value: 0.2 ether}(IJB721TiersHook(hookAddr), posts, poster, poster, "", "");
|
|
212
|
-
|
|
213
|
-
assertEq(publisher.tierIdForEncodedIPFSUriOf(hookAddr, TEST_URI), 1);
|
|
214
|
-
|
|
215
|
-
// Second mint with existing tier (not removed) — should reuse tier ID 1.
|
|
216
|
-
_setupMintMocks(1);
|
|
217
|
-
|
|
218
|
-
vm.prank(poster);
|
|
219
|
-
publisher.mintFrom{value: 0.2 ether}(IJB721TiersHook(hookAddr), posts, poster, poster, "", "");
|
|
220
|
-
|
|
221
|
-
// Mapping should still point to tier 1.
|
|
222
|
-
assertEq(
|
|
223
|
-
publisher.tierIdForEncodedIPFSUriOf(hookAddr, TEST_URI),
|
|
224
|
-
1,
|
|
225
|
-
"tier ID should remain unchanged when tier is not removed"
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
}
|