@croptop/core-v6 0.0.21 → 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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Audit preparation document for experienced Solidity auditors. This repo contains the Croptop content publishing system: three contracts that allow permissioned posting of NFT content as 721 tiers to Juicebox V6 projects, with fee accounting, an allowlist system, and a data hook proxy for cross-chain cash-out interception.
4
4
 
5
- Compiler: `solc ^0.8.26`. Framework: Foundry.
5
+ Compiler: `solc 0.8.28`. Framework: Foundry.
6
6
 
7
7
  ---
8
8
 
@@ -479,7 +479,7 @@ Six Nemesis findings plus two regression-test findings. See `.audit/findings/nem
479
479
 
480
480
  ## Compiler and Version Info
481
481
 
482
- - **Solidity**: ^0.8.26
482
+ - **Solidity**: 0.8.28
483
483
  - **EVM target**: Cancun
484
484
  - **Optimizer**: 200 runs
485
485
  - **Dependencies**: OpenZeppelin 5.x, nana-core-v6, nana-721-hook-v6, nana-suckers-v6
package/CHANGE_LOG.md CHANGED
@@ -15,7 +15,7 @@ This document describes all changes between `croptop-core` (v5) and `croptop-cor
15
15
  ## 1. Breaking Changes
16
16
 
17
17
  ### Solidity Version
18
- - Compiler version bumped from `0.8.23` to `^0.8.26` across all implementation contracts (`CTDeployer`, `CTProjectOwner`, `CTPublisher`).
18
+ - Compiler version bumped from `0.8.23` to `0.8.28` across all implementation contracts (`CTDeployer`, `CTProjectOwner`, `CTPublisher`).
19
19
 
20
20
  ### Dependency Namespace Migration
21
21
  All imports updated from v5 to v6 namespaces:
@@ -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.
@@ -259,7 +263,7 @@ No field changes. Import path updated from `@bananapus/suckers-v5` to `@bananapu
259
263
  | `JB721TiersHookFlags`: 4 flags | `JB721TiersHookFlags`: 5 flags | Added `issueTokensForSplits` |
260
264
  | -- | `CTPublisher_DuplicatePost` | New error |
261
265
  | -- | `CTPublisher_SplitPercentExceedsMaximum` | New error |
262
- | Solidity `0.8.23` | Solidity `^0.8.26` | Compiler bump |
266
+ | Solidity `0.8.23` | Solidity `0.8.28` | Compiler bump |
263
267
  | `@bananapus/*-v5` | `@bananapus/*-v6` | All dependency namespaces |
264
268
 
265
269
  > **Cross-repo impact**: The `CTPost.splitPercent` and `splits` fields feed directly into `nana-721-hook-v6`'s tier splits system. `nana-suckers-v6` suckers are detected via `SUCKER_REGISTRY.isSuckerOf` for the 0% tax cashout path. `nana-permission-ids-v6` `uint64` projectId width change drove the `CTProjectOwner` cast update.
package/STYLE_GUIDE.md CHANGED
@@ -21,7 +21,7 @@ One contract/interface/struct/enum per file. Name the file after the type it con
21
21
 
22
22
  ```solidity
23
23
  // Contracts — pin to exact version
24
- pragma solidity ^0.8.26;
24
+ pragma solidity 0.8.28;
25
25
 
26
26
  // Interfaces, structs, enums — caret for forward compatibility
27
27
  pragma solidity ^0.8.0;
@@ -326,7 +326,7 @@ Standard config across all repos:
326
326
 
327
327
  ```toml
328
328
  [profile.default]
329
- solc = '0.8.26'
329
+ solc = '0.8.28'
330
330
  evm_version = 'cancun'
331
331
  optimizer_runs = 200
332
332
  libs = ["node_modules", "lib"]
package/foundry.toml CHANGED
@@ -1,5 +1,5 @@
1
1
  [profile.default]
2
- solc = '0.8.26'
2
+ solc = '0.8.28'
3
3
  evm_version = 'cancun'
4
4
  optimizer_runs = 200
5
5
  libs = ["node_modules", "lib"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@croptop/core-v6",
3
- "version": "0.0.21",
3
+ "version": "0.0.23",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -16,17 +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.20",
20
- "@bananapus/buyback-hook-v6": "^0.0.19",
21
- "@bananapus/core-v6": "^0.0.26",
22
- "@bananapus/ownable-v6": "^0.0.13",
23
- "@bananapus/permission-ids-v6": "^0.0.12",
24
- "@bananapus/router-terminal-v6": "^0.0.19",
25
- "@bananapus/suckers-v6": "^0.0.16",
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
+ "@bananapus/permission-ids-v6": "^0.0.14",
25
+ "@bananapus/router-terminal-v6": "^0.0.21",
26
+ "@bananapus/suckers-v6": "^0.0.18",
26
27
  "@openzeppelin/contracts": "^5.6.1"
27
28
  },
28
29
  "devDependencies": {
29
- "@rev-net/core-v6": "^0.0.14",
30
+ "@rev-net/core-v6": "^0.0.17",
30
31
  "@sphinx-labs/plugins": "^0.33.1"
31
32
  }
32
33
  }
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  import {Hook721Deployment, Hook721DeploymentLib} from "@bananapus/721-hook-v6/script/helpers/Hook721DeploymentLib.sol";
5
5
  import {CoreDeployment, CoreDeploymentLib} from "@bananapus/core-v6/script/helpers/CoreDeploymentLib.sol";
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  import {Hook721Deployment, Hook721DeploymentLib} from "@bananapus/721-hook-v6/script/helpers/Hook721DeploymentLib.sol";
5
5
  import {CoreDeployment, CoreDeploymentLib} from "@bananapus/core-v6/script/helpers/CoreDeploymentLib.sol";
@@ -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;
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  import {stdJson} from "forge-std/Script.sol";
5
5
  import {Vm} from "forge-std/Vm.sol";
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
5
5
  import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
@@ -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;
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
5
5
  import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  import {IJB721TiersHook} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHook.sol";
5
5
  import {IJB721TiersHookStore} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHookStore.sol";
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  // forge-lint: disable-next-line(unaliased-plain-import)
5
5
  import "forge-std/Test.sol";
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  // forge-lint: disable-next-line(unaliased-plain-import)
5
5
  import "forge-std/Test.sol";
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  // forge-lint: disable-next-line(unaliased-plain-import)
5
5
  import "forge-std/Test.sol";
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  // forge-lint: disable-next-line(unaliased-plain-import)
5
5
  import "forge-std/Test.sol";
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  // forge-lint: disable-next-line(unaliased-plain-import)
5
5
  import "forge-std/Test.sol";
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  // forge-lint: disable-next-line(unaliased-plain-import)
5
5
  import "forge-std/Test.sol";
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  // forge-lint: disable-next-line(unaliased-plain-import)
5
5
  import "forge-std/Test.sol";
@@ -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;
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  // forge-lint: disable-next-line(unaliased-plain-import)
5
5
  import "forge-std/Test.sol";
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  // forge-lint: disable-next-line(unaliased-plain-import)
5
5
  import "forge-std/Test.sol";
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
2
+ pragma solidity 0.8.28;
3
3
 
4
4
  // forge-lint: disable-next-line(unaliased-plain-import)
5
5
  import "forge-std/Test.sol";