@croptop/core-v6 0.0.22 → 0.0.23

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/CHANGE_LOG.md CHANGED
@@ -103,6 +103,10 @@ Posts can now include a `splitPercent` and an array of `splits` (JBSplit[]) that
103
103
 
104
104
  ## 3. Event Changes
105
105
 
106
+ Indexer note:
107
+ - event names are stable, but embedded struct payloads changed ABI shape;
108
+ - if your graph decodes `ConfigurePostingCriteria` or `Mint`, update the event-decoding schema for the new `maximumSplitPercent`, `splitPercent`, and `splits` fields.
109
+
106
110
  No event signatures were changed. Both versions emit the same two events:
107
111
  - `ConfigurePostingCriteria(address indexed hook, CTAllowedPost allowedPost, address caller)` — note that the `CTAllowedPost` struct gained a `maximumSplitPercent` field, which changes the ABI encoding of this event's data.
108
112
  - `Mint(uint256 indexed projectId, IJB721TiersHook indexed hook, address indexed nftBeneficiary, address feeBeneficiary, CTPost[] posts, uint256 postValue, uint256 txValue, address caller)` — note that the `CTPost` struct gained `splitPercent` and `splits` fields, which changes the ABI encoding of this event's data.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@croptop/core-v6",
3
- "version": "0.0.22",
3
+ "version": "0.0.23",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -16,18 +16,18 @@
16
16
  "artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'croptop-core-v5'"
17
17
  },
18
18
  "dependencies": {
19
- "@bananapus/721-hook-v6": "^0.0.21",
20
- "@bananapus/address-registry-v6": "^0.0.15",
21
- "@bananapus/buyback-hook-v6": "^0.0.19",
22
- "@bananapus/core-v6": "^0.0.27",
23
- "@bananapus/ownable-v6": "^0.0.14",
19
+ "@bananapus/721-hook-v6": "^0.0.22",
20
+ "@bananapus/address-registry-v6": "^0.0.16",
21
+ "@bananapus/buyback-hook-v6": "^0.0.22",
22
+ "@bananapus/core-v6": "^0.0.28",
23
+ "@bananapus/ownable-v6": "^0.0.15",
24
24
  "@bananapus/permission-ids-v6": "^0.0.14",
25
- "@bananapus/router-terminal-v6": "^0.0.20",
26
- "@bananapus/suckers-v6": "^0.0.16",
25
+ "@bananapus/router-terminal-v6": "^0.0.21",
26
+ "@bananapus/suckers-v6": "^0.0.18",
27
27
  "@openzeppelin/contracts": "^5.6.1"
28
28
  },
29
29
  "devDependencies": {
30
- "@rev-net/core-v6": "^0.0.14",
30
+ "@rev-net/core-v6": "^0.0.17",
31
31
  "@sphinx-labs/plugins": "^0.33.1"
32
32
  }
33
33
  }
@@ -64,9 +64,28 @@ contract DeployScript is Script, Sphinx {
64
64
  }
65
65
 
66
66
  function deploy() public sphinx {
67
- // If the fee project id is 0, then we want to deploy a new fee project.
67
+ // If the fee project id is 0, then we want to deploy a new fee project — but only if the publisher
68
+ // singleton doesn't already exist. Re-running with FEE_PROJECT_ID=0 would create a second fee project
69
+ // with different CREATE2 addresses, stranding the previous suite.
68
70
  if (FEE_PROJECT_ID == 0) {
69
- FEE_PROJECT_ID = core.projects.createFor(safeAddress());
71
+ // Check if the publisher already exists by scanning existing project IDs.
72
+ uint256 _existingCount = core.projects.count();
73
+ bool _found;
74
+ for (uint256 _candidateId = 1; _candidateId <= _existingCount; _candidateId++) {
75
+ (, bool _exists) = _isDeployed({
76
+ salt: PUBLISHER_SALT,
77
+ creationCode: type(CTPublisher).creationCode,
78
+ arguments: abi.encode(core.directory, core.permissions, _candidateId, TRUSTED_FORWARDER)
79
+ });
80
+ if (_exists) {
81
+ FEE_PROJECT_ID = _candidateId;
82
+ _found = true;
83
+ break;
84
+ }
85
+ }
86
+ if (!_found) {
87
+ FEE_PROJECT_ID = core.projects.createFor(safeAddress());
88
+ }
70
89
  }
71
90
 
72
91
  CTPublisher publisher;
@@ -225,9 +225,12 @@ contract CTDeployer is ERC2771Context, JBPermissioned, IJBRulesetDataHook, IERC7
225
225
  //*********************************************************************//
226
226
 
227
227
  /// @notice Claim ownership of the collection.
228
- /// @dev After calling this, the hook's owner becomes the project (resolved via PROJECTS.ownerOf). The project
229
- /// owner must then grant CTPublisher the ADJUST_721_TIERS permission for the project so that mintFrom() continues
230
- /// to work. Without this permission grant, all subsequent posts will revert. This cannot be done atomically here
228
+ /// @dev Two-step ownership transfer process:
229
+ /// Step 1 (this function): Transfers hook ownership to the project via `transferOwnershipToProject()`.
230
+ /// After this call, `hook.owner()` resolves dynamically through `PROJECTS.ownerOf(projectId)`.
231
+ /// Step 2 (caller must do separately): The project owner grants CTPublisher the `ADJUST_721_TIERS` permission
232
+ /// for the project so that `mintFrom()` continues to work.
233
+ /// Without the Step 2 permission grant, all subsequent posts will revert. This cannot be done atomically here
231
234
  /// because after transferring ownership to the project, this contract no longer has authority to set permissions
232
235
  /// on the project's behalf.
233
236
  /// @param hook The hook to claim ownership of.
@@ -283,7 +286,6 @@ contract CTDeployer is ERC2771Context, JBPermissioned, IJBRulesetDataHook, IERC7
283
286
  tiersConfig: JB721InitTiersConfig({
284
287
  tiers: new JB721TierConfig[](0), currency: JBCurrencyIds.ETH, decimals: 18
285
288
  }),
286
- reserveBeneficiary: address(0),
287
289
  flags: JB721TiersHookFlags({
288
290
  noNewTiersWithReserves: false,
289
291
  noNewTiersWithVotes: false,
@@ -337,9 +339,10 @@ contract CTDeployer is ERC2771Context, JBPermissioned, IJBRulesetDataHook, IERC7
337
339
  PROJECTS.transferFrom({from: address(this), to: owner, tokenId: projectId});
338
340
 
339
341
  // Set permission for the project's owner to do all the NFT things.
340
- // These permissions are granted from CTDeployer (address(this)), not from the project owner.
341
- // Transferring the project NFT does not invalidate them because the permission account is CTDeployer,
342
- // which remains the hook's owner regardless of who holds the project NFT.
342
+ // These permissions are granted from CTDeployer (address(this)) to the initial owner.
343
+ // The hook checks permissions against hook.owner(), which after claimCollectionOwnershipOf() resolves
344
+ // dynamically via PROJECTS.ownerOf(projectId). Before claiming, CTDeployer is the static hook owner,
345
+ // so these permissions allow the project owner to manage tiers through CTDeployer.
343
346
  uint8[] memory permissionIds = new uint8[](4);
344
347
  permissionIds[0] = JBPermissionIds.ADJUST_721_TIERS;
345
348
  permissionIds[1] = JBPermissionIds.SET_721_METADATA;
@@ -19,6 +19,7 @@ import {CTAllowedPost} from "../../src/structs/CTAllowedPost.sol";
19
19
  import {CTPost} from "../../src/structs/CTPost.sol";
20
20
 
21
21
  contract MockPermissions is IJBPermissions {
22
+ // forge-lint: disable-next-line(mixed-case-function)
22
23
  function WILDCARD_PROJECT_ID() external pure returns (uint256) {
23
24
  return 0;
24
25
  }
@@ -136,8 +137,11 @@ contract FeeTerminalRecorder {
136
137
  }
137
138
 
138
139
  contract ReentrantProjectTerminal {
140
+ // forge-lint: disable-next-line(screaming-snake-case-immutable)
139
141
  CTPublisher public immutable publisher;
142
+ // forge-lint: disable-next-line(screaming-snake-case-immutable)
140
143
  IJB721TiersHook public immutable hook;
144
+ // forge-lint: disable-next-line(screaming-snake-case-immutable)
141
145
  address public immutable attackerFeeBeneficiary;
142
146
  bool internal entered;
143
147
 
@@ -182,7 +186,7 @@ contract ReentrantProjectTerminal {
182
186
  receive() external payable {}
183
187
  }
184
188
 
185
- contract CodexFeeBeneficiaryReentrancyTest is Test {
189
+ contract FeeBeneficiaryReentrancyTest is Test {
186
190
  MockPermissions permissions;
187
191
  MockDirectory directory;
188
192
  MockStore store;