@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.
@@ -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
- new JB721TiersHook(jbDirectory, jbPermissions, jbPrices, jbRulesets, store, jbSplits, trustedForwarder);
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
  }