@croptop/core-v6 0.0.32 → 0.0.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ADMINISTRATION.md +65 -145
- package/ARCHITECTURE.md +68 -43
- package/AUDIT_INSTRUCTIONS.md +54 -62
- package/README.md +47 -6
- package/RISKS.md +2 -0
- package/SKILLS.md +7 -2
- package/USER_JOURNEYS.md +86 -35
- package/foundry.toml +2 -0
- package/package.json +31 -31
- package/references/operations.md +2 -2
- package/references/runtime.md +3 -3
- package/src/CTDeployer.sol +116 -126
- package/src/CTPublisher.sol +134 -138
- package/src/interfaces/ICTPublisher.sol +1 -2
- package/src/structs/CTAllowedPost.sol +0 -1
- package/src/structs/CTDeployerAllowedPost.sol +0 -1
- package/src/structs/CTPost.sol +0 -2
- package/src/structs/CTProjectConfig.sol +0 -1
- package/src/structs/CTSuckerDeploymentConfig.sol +0 -1
- package/test/CTDeployer.t.sol +5 -4
- package/test/Fork.t.sol +6 -3
- package/test/TestAuditGaps.sol +9 -8
- package/test/audit/CodexNemesisPoCs.t.sol +263 -0
- package/test/fork/PublishFork.t.sol +6 -3
|
@@ -0,0 +1,263 @@
|
|
|
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 {IJB721TiersHook} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHook.sol";
|
|
8
|
+
import {IJB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHookDeployer.sol";
|
|
9
|
+
import {JBDeploy721TiersHookConfig} from "@bananapus/721-hook-v6/src/structs/JBDeploy721TiersHookConfig.sol";
|
|
10
|
+
import {JB721TierConfig} from "@bananapus/721-hook-v6/src/structs/JB721TierConfig.sol";
|
|
11
|
+
import {JBPermissioned} from "@bananapus/core-v6/src/abstract/JBPermissioned.sol";
|
|
12
|
+
import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
13
|
+
import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
|
|
14
|
+
import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
|
|
15
|
+
import {IJBProjects} from "@bananapus/core-v6/src/interfaces/IJBProjects.sol";
|
|
16
|
+
import {JBPermissions} from "@bananapus/core-v6/src/JBPermissions.sol";
|
|
17
|
+
import {JBRulesetConfig} from "@bananapus/core-v6/src/structs/JBRulesetConfig.sol";
|
|
18
|
+
import {JBTerminalConfig} from "@bananapus/core-v6/src/structs/JBTerminalConfig.sol";
|
|
19
|
+
import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
|
|
20
|
+
import {IJBSuckerRegistry} from "@bananapus/suckers-v6/src/interfaces/IJBSuckerRegistry.sol";
|
|
21
|
+
import {JBSuckerRegistry} from "@bananapus/suckers-v6/src/JBSuckerRegistry.sol";
|
|
22
|
+
import {JBSuckerDeployerConfig} from "@bananapus/suckers-v6/src/structs/JBSuckerDeployerConfig.sol";
|
|
23
|
+
|
|
24
|
+
import {CTDeployer} from "../../src/CTDeployer.sol";
|
|
25
|
+
import {CTPublisher} from "../../src/CTPublisher.sol";
|
|
26
|
+
import {ICTPublisher} from "../../src/interfaces/ICTPublisher.sol";
|
|
27
|
+
import {CTDeployerAllowedPost} from "../../src/structs/CTDeployerAllowedPost.sol";
|
|
28
|
+
import {CTProjectConfig} from "../../src/structs/CTProjectConfig.sol";
|
|
29
|
+
import {CTSuckerDeploymentConfig} from "../../src/structs/CTSuckerDeploymentConfig.sol";
|
|
30
|
+
|
|
31
|
+
contract NemesisMockProjects {
|
|
32
|
+
uint256 public countValue;
|
|
33
|
+
mapping(uint256 => address) internal _ownerOf;
|
|
34
|
+
|
|
35
|
+
function setCount(uint256 count_) external {
|
|
36
|
+
countValue = count_;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function setOwner(uint256 projectId, address owner_) external {
|
|
40
|
+
_ownerOf[projectId] = owner_;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function count() external view returns (uint256) {
|
|
44
|
+
return countValue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function ownerOf(uint256 projectId) external view returns (address) {
|
|
48
|
+
return _ownerOf[projectId];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function transferFrom(address from, address to, uint256 tokenId) external {
|
|
52
|
+
require(_ownerOf[tokenId] == from, "wrong from");
|
|
53
|
+
_ownerOf[tokenId] = to;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
contract NemesisMockController {
|
|
58
|
+
NemesisMockProjects public immutable PROJECTS;
|
|
59
|
+
uint256 public immutable nextProjectId;
|
|
60
|
+
|
|
61
|
+
constructor(NemesisMockProjects projects_, uint256 nextProjectId_) {
|
|
62
|
+
PROJECTS = projects_;
|
|
63
|
+
nextProjectId = nextProjectId_;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function launchProjectFor(
|
|
67
|
+
address owner,
|
|
68
|
+
string calldata,
|
|
69
|
+
JBRulesetConfig[] calldata,
|
|
70
|
+
JBTerminalConfig[] calldata,
|
|
71
|
+
string calldata
|
|
72
|
+
)
|
|
73
|
+
external
|
|
74
|
+
returns (uint256)
|
|
75
|
+
{
|
|
76
|
+
PROJECTS.setOwner(nextProjectId, owner);
|
|
77
|
+
return nextProjectId;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
contract NemesisPermissionedHook is JBPermissioned {
|
|
82
|
+
address public immutable ownerAccount;
|
|
83
|
+
uint256 public immutable projectId;
|
|
84
|
+
bool public adjusted;
|
|
85
|
+
|
|
86
|
+
constructor(IJBPermissions permissions, address ownerAccount_, uint256 projectId_) JBPermissioned(permissions) {
|
|
87
|
+
ownerAccount = ownerAccount_;
|
|
88
|
+
projectId = projectId_;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// forge-lint: disable-next-line(mixed-case-function)
|
|
92
|
+
function PROJECT_ID() external view returns (uint256) {
|
|
93
|
+
return projectId;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function owner() external view returns (address) {
|
|
97
|
+
return ownerAccount;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function adjustTiers(JB721TierConfig[] calldata, uint256[] calldata) external {
|
|
101
|
+
_requirePermissionFrom(ownerAccount, projectId, JBPermissionIds.ADJUST_721_TIERS);
|
|
102
|
+
adjusted = true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
contract NemesisMockHookDeployer {
|
|
107
|
+
IJB721TiersHook public hook;
|
|
108
|
+
|
|
109
|
+
function setHook(IJB721TiersHook hook_) external {
|
|
110
|
+
hook = hook_;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function deployHookFor(
|
|
114
|
+
uint256,
|
|
115
|
+
JBDeploy721TiersHookConfig calldata,
|
|
116
|
+
bytes32
|
|
117
|
+
)
|
|
118
|
+
external
|
|
119
|
+
view
|
|
120
|
+
returns (IJB721TiersHook)
|
|
121
|
+
{
|
|
122
|
+
return hook;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
contract NemesisNoopSuckerRegistry {
|
|
127
|
+
function isSuckerOf(uint256, address) external pure returns (bool) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function deploySuckersFor(
|
|
132
|
+
uint256,
|
|
133
|
+
bytes32,
|
|
134
|
+
JBSuckerDeployerConfig[] calldata
|
|
135
|
+
)
|
|
136
|
+
external
|
|
137
|
+
pure
|
|
138
|
+
returns (address[] memory suckers)
|
|
139
|
+
{
|
|
140
|
+
return suckers;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
contract NemesisMockDirectory {
|
|
145
|
+
IJBProjects public immutable PROJECTS;
|
|
146
|
+
|
|
147
|
+
constructor(IJBProjects projects_) {
|
|
148
|
+
PROJECTS = projects_;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
contract CodexNemesisPoCs is Test {
|
|
153
|
+
JBPermissions permissions;
|
|
154
|
+
NemesisMockProjects projects;
|
|
155
|
+
NemesisMockHookDeployer hookDeployer;
|
|
156
|
+
NemesisMockController controller;
|
|
157
|
+
CTPublisher publisher;
|
|
158
|
+
CTDeployer deployer;
|
|
159
|
+
NemesisPermissionedHook hook;
|
|
160
|
+
|
|
161
|
+
address alice = makeAddr("alice");
|
|
162
|
+
address bob = makeAddr("bob");
|
|
163
|
+
|
|
164
|
+
function setUp() public {
|
|
165
|
+
permissions = new JBPermissions(address(0));
|
|
166
|
+
projects = new NemesisMockProjects();
|
|
167
|
+
projects.setCount(5);
|
|
168
|
+
|
|
169
|
+
hookDeployer = new NemesisMockHookDeployer();
|
|
170
|
+
publisher = new CTPublisher(IJBDirectory(makeAddr("directory")), permissions, 1, address(0));
|
|
171
|
+
deployer = new CTDeployer(
|
|
172
|
+
permissions,
|
|
173
|
+
IJBProjects(address(projects)),
|
|
174
|
+
IJB721TiersHookDeployer(address(hookDeployer)),
|
|
175
|
+
ICTPublisher(address(publisher)),
|
|
176
|
+
IJBSuckerRegistry(address(new NemesisNoopSuckerRegistry())),
|
|
177
|
+
address(0)
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
hook = new NemesisPermissionedHook(permissions, address(deployer), 6);
|
|
181
|
+
hookDeployer.setHook(IJB721TiersHook(address(hook)));
|
|
182
|
+
controller = new NemesisMockController(projects, 6);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function test_oldProjectOwnerRetainsHookControlAfterProjectNftTransferUntilClaim() public {
|
|
186
|
+
CTProjectConfig memory config = CTProjectConfig({
|
|
187
|
+
terminalConfigurations: new JBTerminalConfig[](0),
|
|
188
|
+
projectUri: "ipfs://project",
|
|
189
|
+
allowedPosts: new CTDeployerAllowedPost[](0),
|
|
190
|
+
contractUri: "ipfs://contract",
|
|
191
|
+
name: "Croptop",
|
|
192
|
+
symbol: "CT",
|
|
193
|
+
salt: bytes32(0)
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
CTSuckerDeploymentConfig memory suckerConfig =
|
|
197
|
+
CTSuckerDeploymentConfig({deployerConfigurations: new JBSuckerDeployerConfig[](0), salt: bytes32(0)});
|
|
198
|
+
|
|
199
|
+
deployer.deployProjectFor(alice, config, suckerConfig, IJBController(address(controller)));
|
|
200
|
+
assertEq(projects.ownerOf(6), alice, "alice should receive the project NFT");
|
|
201
|
+
|
|
202
|
+
projects.transferFrom(alice, bob, 6);
|
|
203
|
+
assertEq(projects.ownerOf(6), bob, "bob should own the project NFT after transfer");
|
|
204
|
+
|
|
205
|
+
JB721TierConfig[] memory arbitraryTiers = new JB721TierConfig[](0);
|
|
206
|
+
uint256[] memory removals = new uint256[](0);
|
|
207
|
+
|
|
208
|
+
vm.prank(alice);
|
|
209
|
+
NemesisPermissionedHook(address(hook)).adjustTiers(arbitraryTiers, removals);
|
|
210
|
+
|
|
211
|
+
assertTrue(
|
|
212
|
+
hook.adjusted(),
|
|
213
|
+
"the previous owner should still be able to mutate hook state until the new NFT owner explicitly claims"
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function test_deploySuckersHelperBreaksAfterOwnershipTransferBecauseRegistrySeesCtDeployerAsCaller() public {
|
|
218
|
+
NemesisMockDirectory directory = new NemesisMockDirectory(IJBProjects(address(projects)));
|
|
219
|
+
JBSuckerRegistry registry =
|
|
220
|
+
new JBSuckerRegistry(IJBDirectory(address(directory)), permissions, address(this), address(0));
|
|
221
|
+
|
|
222
|
+
deployer = new CTDeployer(
|
|
223
|
+
permissions,
|
|
224
|
+
IJBProjects(address(projects)),
|
|
225
|
+
IJB721TiersHookDeployer(address(hookDeployer)),
|
|
226
|
+
ICTPublisher(address(publisher)),
|
|
227
|
+
IJBSuckerRegistry(address(registry)),
|
|
228
|
+
address(0)
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
hook = new NemesisPermissionedHook(permissions, address(deployer), 6);
|
|
232
|
+
hookDeployer.setHook(IJB721TiersHook(address(hook)));
|
|
233
|
+
|
|
234
|
+
CTProjectConfig memory config = CTProjectConfig({
|
|
235
|
+
terminalConfigurations: new JBTerminalConfig[](0),
|
|
236
|
+
projectUri: "ipfs://project",
|
|
237
|
+
allowedPosts: new CTDeployerAllowedPost[](0),
|
|
238
|
+
contractUri: "ipfs://contract",
|
|
239
|
+
name: "Croptop",
|
|
240
|
+
symbol: "CT",
|
|
241
|
+
salt: bytes32(0)
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
CTSuckerDeploymentConfig memory emptySuckerConfig =
|
|
245
|
+
CTSuckerDeploymentConfig({deployerConfigurations: new JBSuckerDeployerConfig[](0), salt: bytes32(0)});
|
|
246
|
+
deployer.deployProjectFor(alice, config, emptySuckerConfig, IJBController(address(controller)));
|
|
247
|
+
|
|
248
|
+
CTSuckerDeploymentConfig memory laterSuckerConfig =
|
|
249
|
+
CTSuckerDeploymentConfig({deployerConfigurations: new JBSuckerDeployerConfig[](0), salt: bytes32("later")});
|
|
250
|
+
|
|
251
|
+
vm.prank(alice);
|
|
252
|
+
vm.expectRevert(
|
|
253
|
+
abi.encodeWithSelector(
|
|
254
|
+
JBPermissioned.JBPermissioned_Unauthorized.selector,
|
|
255
|
+
alice,
|
|
256
|
+
address(deployer),
|
|
257
|
+
6,
|
|
258
|
+
JBPermissionIds.DEPLOY_SUCKERS
|
|
259
|
+
)
|
|
260
|
+
);
|
|
261
|
+
deployer.deploySuckersFor(6, laterSuckerConfig);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
@@ -32,6 +32,7 @@ import {MockPriceFeed} from "@bananapus/core-v6/test/mock/MockPriceFeed.sol";
|
|
|
32
32
|
import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStore.sol";
|
|
33
33
|
import {JB721TiersHook} from "@bananapus/721-hook-v6/src/JB721TiersHook.sol";
|
|
34
34
|
import {JB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/JB721TiersHookDeployer.sol";
|
|
35
|
+
import {JB721CheckpointsDeployer} from "@bananapus/721-hook-v6/src/JB721CheckpointsDeployer.sol";
|
|
35
36
|
import {IJB721TiersHook} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHook.sol";
|
|
36
37
|
import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
|
|
37
38
|
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
|
@@ -276,7 +277,7 @@ contract PublishForkTest is Test, DeployPermit2 {
|
|
|
276
277
|
jbPermissions = new JBPermissions(trustedForwarder);
|
|
277
278
|
jbProjects = new JBProjects(multisig, address(0), trustedForwarder);
|
|
278
279
|
jbDirectory = new JBDirectory(jbPermissions, jbProjects, multisig);
|
|
279
|
-
JBERC20 jbErc20 = new JBERC20();
|
|
280
|
+
JBERC20 jbErc20 = new JBERC20(jbPermissions, jbProjects);
|
|
280
281
|
jbTokens = new JBTokens(jbDirectory, jbErc20);
|
|
281
282
|
jbRulesets = new JBRulesets(jbDirectory);
|
|
282
283
|
jbPrices = new JBPrices(jbDirectory, jbPermissions, jbProjects, multisig, trustedForwarder);
|
|
@@ -321,9 +322,11 @@ contract PublishForkTest is Test, DeployPermit2 {
|
|
|
321
322
|
function _deploy721Hook() internal {
|
|
322
323
|
JB721TiersHookStore store = new JB721TiersHookStore();
|
|
323
324
|
JBAddressRegistry addressRegistry = new JBAddressRegistry();
|
|
325
|
+
JB721CheckpointsDeployer checkpointsDeployer = new JB721CheckpointsDeployer();
|
|
324
326
|
|
|
325
|
-
JB721TiersHook hookImpl =
|
|
326
|
-
|
|
327
|
+
JB721TiersHook hookImpl = new JB721TiersHook(
|
|
328
|
+
jbDirectory, jbPermissions, jbPrices, jbRulesets, store, jbSplits, checkpointsDeployer, trustedForwarder
|
|
329
|
+
);
|
|
327
330
|
|
|
328
331
|
hookDeployer = new JB721TiersHookDeployer(hookImpl, store, addressRegistry, trustedForwarder);
|
|
329
332
|
}
|