@croptop/core-v6 0.0.20 → 0.0.21
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 +41 -27
- package/ARCHITECTURE.md +141 -28
- package/AUDIT_INSTRUCTIONS.md +118 -70
- package/CHANGE_LOG.md +14 -2
- package/README.md +45 -6
- package/RISKS.md +21 -4
- package/SKILLS.md +23 -11
- package/STYLE_GUIDE.md +1 -1
- package/USER_JOURNEYS.md +246 -132
- package/package.json +8 -8
- package/script/ConfigureFeeProject.s.sol +1 -1
- package/script/Deploy.s.sol +1 -1
- package/script/helpers/CroptopDeploymentLib.sol +1 -1
- package/src/CTDeployer.sol +14 -4
- package/src/CTProjectOwner.sol +1 -1
- package/src/CTPublisher.sol +11 -10
- package/src/interfaces/ICTDeployer.sol +2 -2
- package/src/interfaces/ICTPublisher.sol +1 -1
- package/test/CTDeployer.t.sol +15 -8
- package/test/CTProjectOwner.t.sol +1 -1
- package/test/CTPublisher.t.sol +1 -1
- package/test/ClaimCollectionOwnership.t.sol +1 -1
- package/test/CroptopAttacks.t.sol +1 -1
- package/test/TestAuditGaps.sol +16 -10
- package/test/audit/CodexFeeBeneficiaryReentrancy.t.sol +243 -0
- package/test/regression/DuplicateUriFeeEvasion.t.sol +1 -1
- package/test/regression/FeeEvasion.t.sol +1 -1
- package/test/regression/StaleTierIdMapping.t.sol +1 -1
package/SKILLS.md
CHANGED
|
@@ -10,7 +10,7 @@ Permissioned NFT publishing system that lets anyone post content as 721 tiers to
|
|
|
10
10
|
|----------|------|
|
|
11
11
|
| `CTPublisher` | Core publishing engine. Validates posts against bit-packed allowances, creates 721 tiers on hooks, mints first copies to posters, and routes fees. Inherits `JBPermissioned`, `ERC2771Context`. |
|
|
12
12
|
| `CTDeployer` | Factory that deploys a Juicebox project + 721 hook + posting criteria in one transaction. Also acts as `IJBRulesetDataHook` proxy that forwards pay/cash-out calls to the underlying hook while granting fee-free cash outs to suckers. |
|
|
13
|
-
| `CTProjectOwner` |
|
|
13
|
+
| `CTProjectOwner` | Burn-lock contract: receives the project ownership NFT and grants `CTPublisher` the `ADJUST_721_TIERS` permission permanently. Since `CTProjectOwner` has no `transferFrom`, `reconfigure`, or `withdraw` functions, ownership is effectively burned -- no one can reclaim the project NFT, change rulesets, or modify posting criteria after transfer. Use this when you want a fully autonomous project where only community posting (within pre-set criteria) is possible. If you need to retain the ability to reconfigure the project, adjust tiers, or withdraw funds, keep ownership yourself (or use a multisig) instead. Configure all desired posting criteria **before** transferring the project NFT here, as they become immutable once ownership moves. Accepts both mints and `safeTransferFrom` calls originating from the `PROJECTS` contract. |
|
|
14
14
|
|
|
15
15
|
## Key Functions
|
|
16
16
|
|
|
@@ -40,15 +40,15 @@ Permissioned NFT publishing system that lets anyone post content as 721 tiers to
|
|
|
40
40
|
|
|
41
41
|
| Function | What it does |
|
|
42
42
|
|----------|-------------|
|
|
43
|
-
| `CTDeployer.beforePayRecordedWith(context)` | Forwards pay context to the stored `dataHookOf[projectId]` (typically the 721 tiers hook). |
|
|
44
|
-
| `CTDeployer.beforeCashOutRecordedWith(context)` | Returns zero tax rate for sucker addresses (fee-free cross-chain cash outs). Otherwise forwards to the stored data hook. |
|
|
43
|
+
| `CTDeployer.beforePayRecordedWith(context)` | Forwards pay context to the stored `dataHookOf[projectId]` (typically the 721 tiers hook). Hook specifications returned include a `noop` field — the 721 hook always returns `noop: false`. |
|
|
44
|
+
| `CTDeployer.beforeCashOutRecordedWith(context)` | Returns zero tax rate for sucker addresses (fee-free cross-chain cash outs). Otherwise forwards to the stored data hook. Forwarded hook specifications preserve the inner hook's `noop` flag. |
|
|
45
45
|
| `CTDeployer.hasMintPermissionFor(projectId, ruleset, addr)` | Returns `true` if `addr` is a sucker for the project. |
|
|
46
46
|
|
|
47
47
|
### Burn-Lock Ownership
|
|
48
48
|
|
|
49
49
|
| Function | What it does |
|
|
50
50
|
|----------|-------------|
|
|
51
|
-
| `CTProjectOwner.onERC721Received(operator, from, tokenId, data)` | On receiving the project NFT, grants `CTPublisher` the `ADJUST_721_TIERS` permission for that project.
|
|
51
|
+
| `CTProjectOwner.onERC721Received(operator, from, tokenId, data)` | On receiving the project NFT, grants `CTPublisher` the `ADJUST_721_TIERS` permission for that project. Accepts both mints and transfers from `PROJECTS` (reverts if `msg.sender` is not `PROJECTS`). |
|
|
52
52
|
|
|
53
53
|
## Integration Points
|
|
54
54
|
|
|
@@ -65,10 +65,10 @@ Permissioned NFT publishing system that lets anyone post content as 721 tiers to
|
|
|
65
65
|
|
|
66
66
|
| Struct | Key Fields | Used In |
|
|
67
67
|
|--------|------------|---------|
|
|
68
|
-
| `CTAllowedPost` | `hook`, `category` (uint24), `minimumPrice` (uint104), `minimumTotalSupply` (uint32), `maximumTotalSupply` (uint32), `maximumSplitPercent` (uint32), `allowedAddresses[]` | `configurePostingCriteriaFor` |
|
|
68
|
+
| `CTAllowedPost` | `hook`, `category` (uint24), `minimumPrice` (uint104), `minimumTotalSupply` (uint32), `maximumTotalSupply` (uint32), `maximumSplitPercent` (uint32), `allowedAddresses[]` | `configurePostingCriteriaFor` -- used when calling `CTPublisher` directly on an existing hook |
|
|
69
|
+
| `CTDeployerAllowedPost` | Same fields as `CTAllowedPost` minus `hook` | `CTProjectConfig.allowedPosts` -- used during `deployProjectFor` because the hook address is not yet known; `CTDeployer._configurePostingCriteriaFor` fills in the `hook` field automatically after deploying the hook |
|
|
69
70
|
| `CTPost` | `encodedIPFSUri` (bytes32), `totalSupply` (uint32), `price` (uint104), `category` (uint24), `splitPercent` (uint32), `splits[]` (JBSplit[]) | `mintFrom` |
|
|
70
71
|
| `CTProjectConfig` | `terminalConfigurations`, `projectUri`, `allowedPosts` (CTDeployerAllowedPost[]), `contractUri`, `name`, `symbol`, `salt` | `deployProjectFor` |
|
|
71
|
-
| `CTDeployerAllowedPost` | Same as `CTAllowedPost` minus `hook` (inferred during deployment) | `CTProjectConfig.allowedPosts` |
|
|
72
72
|
| `CTSuckerDeploymentConfig` | `deployerConfigurations` (JBSuckerDeployerConfig[]), `salt` | `deployProjectFor`, `deploySuckersFor` |
|
|
73
73
|
|
|
74
74
|
## Events
|
|
@@ -92,6 +92,7 @@ Permissioned NFT publishing system that lets anyone post content as 721 tiers to
|
|
|
92
92
|
| `CTPublisher_TotalSupplyTooBig` | Post `totalSupply > maximumTotalSupply` (when max > 0) |
|
|
93
93
|
| `CTPublisher_UnauthorizedToPostInCategory` | Category unconfigured (`minSupply == 0`) |
|
|
94
94
|
| `CTPublisher_ZeroTotalSupply` | `configurePostingCriteriaFor` with `minimumTotalSupply == 0` |
|
|
95
|
+
| `CTPublisher_DuplicatePost(bytes32 encodedIPFSUri)` | Same `encodedIPFSUri` appears more than once within the same `mintFrom` batch |
|
|
95
96
|
| `CTDeployer_NotOwnerOfProject` | `claimCollectionOwnershipOf` called by non-owner |
|
|
96
97
|
|
|
97
98
|
## Constants
|
|
@@ -103,12 +104,23 @@ Permissioned NFT publishing system that lets anyone post content as 721 tiers to
|
|
|
103
104
|
|
|
104
105
|
## Storage
|
|
105
106
|
|
|
106
|
-
|
|
107
|
-
|
|
107
|
+
### CTPublisher
|
|
108
|
+
|
|
109
|
+
| Variable | Type | Purpose |
|
|
110
|
+
|----------|------|---------|
|
|
108
111
|
| `tierIdForEncodedIPFSUriOf` | `hook => encodedIPFSUri => uint256` | Maps IPFS URI to existing tier ID (prevents duplicates) |
|
|
109
112
|
| `_packedAllowanceFor` | `hook => category => uint256` | Bit-packed allowance: price (0-103), minSupply (104-135), maxSupply (136-167), maxSplitPercent (168-199) |
|
|
110
113
|
| `_allowedAddresses` | `hook => category => address[]` | Per-category address allowlist |
|
|
111
|
-
|
|
114
|
+
|
|
115
|
+
### CTDeployer
|
|
116
|
+
|
|
117
|
+
| Variable | Type | Purpose |
|
|
118
|
+
|----------|------|---------|
|
|
119
|
+
| `PROJECTS` | `IJBProjects` (immutable) | ERC-721 contract for Juicebox project ownership |
|
|
120
|
+
| `DEPLOYER` | `IJB721TiersHookDeployer` (immutable) | Factory for deploying 721 tiers hooks |
|
|
121
|
+
| `PUBLISHER` | `ICTPublisher` (immutable) | CTPublisher instance used for posting |
|
|
122
|
+
| `SUCKER_REGISTRY` | `IJBSuckerRegistry` (immutable) | Registry for cross-chain sucker deployment and lookup |
|
|
123
|
+
| `dataHookOf` | `projectId => IJBRulesetDataHook` | Stores original data hook per project (CTDeployer proxy pattern) |
|
|
112
124
|
|
|
113
125
|
## Gotchas
|
|
114
126
|
|
|
@@ -119,12 +131,12 @@ Permissioned NFT publishing system that lets anyone post content as 721 tiers to
|
|
|
119
131
|
5. **Tier reuse by IPFS URI.** If an encoded IPFS URI was already minted on the hook, the existing tier ID is reused instead of creating a new tier. The poster still gets a mint of the existing tier. The fee is calculated from the actual tier price stored on-chain (not from `post.price`), preventing fee evasion (H-19 fix).
|
|
120
132
|
6. **Stale tier mapping cleanup.** If a tier was removed externally via `adjustTiers()`, the `tierIdForEncodedIPFSUriOf` mapping is automatically cleared when the same IPFS URI is posted again, allowing a new tier to be created (L-52 fix).
|
|
121
133
|
7. **Array resizing via assembly.** `_setupPosts` resizes `tiersToAdd` via inline assembly when some posts reuse existing tiers. The `tierIdsToMint` array is NOT resized and may contain zeros for pre-existing tiers.
|
|
122
|
-
8. **CTProjectOwner only accepts
|
|
134
|
+
8. **CTProjectOwner only accepts from PROJECTS contract.** `onERC721Received` reverts if `msg.sender != address(PROJECTS)`. It does NOT check the `from` address, so both mints and transfers through `PROJECTS.safeTransferFrom` are accepted.
|
|
123
135
|
9. **CTDeployer rejects direct transfers.** `CTDeployer.onERC721Received` reverts if `from != address(0)`. It only accepts mints from `PROJECTS`.
|
|
124
136
|
10. **Temporary ownership during deployment.** `CTDeployer` owns the project NFT temporarily during `deployProjectFor` (to configure permissions and hooks), then transfers it to the specified `owner`. If the transfer reverts, the entire deployment fails.
|
|
125
137
|
11. **Data hook proxy pattern.** `CTDeployer` wraps itself as the data hook, forwarding to `dataHookOf[projectId]`. This is needed to intercept cash-out calls and grant fee-free cash outs to suckers. Both `useDataHookForPay` and `useDataHookForCashOut` are enabled (M-37 fix).
|
|
126
138
|
12. **Sucker registry trust.** `CTDeployer.beforeCashOutRecordedWith` trusts `SUCKER_REGISTRY.isSuckerOf` to determine fee exemption. If the registry is compromised, any address could cash out without tax.
|
|
127
|
-
13. **Allowlist uses linear scan.** `_isAllowed()` iterates the full allowlist array. Acceptable for <100 addresses; gas cost scales linearly with list size.
|
|
139
|
+
13. **Allowlist uses linear scan.** `_isAllowed()` iterates the full allowlist array. Acceptable for <100 addresses; gas cost scales linearly with list size. This also affects `mintFrom` with large post batches: each post in the batch triggers a separate allowlist scan, so gas scales as `O(posts * allowlistSize)`. Keep batches under ~20 posts with allowlists under ~50 addresses to stay within block gas limits.
|
|
128
140
|
14. **Referral ID in metadata.** `FEE_PROJECT_ID` is stored in the first 32 bytes of mint metadata (via assembly `mstore`), allowing the fee terminal to track referrals.
|
|
129
141
|
15. **Deterministic deployment.** Hook salt is `keccak256(abi.encode(projectConfig.salt, msg.sender))` and sucker salt is `keccak256(abi.encode(suckerConfig.salt, msg.sender))`. Different callers with the same salt get different addresses.
|
|
130
142
|
16. **Default project weight.** `CTDeployer` deploys projects with `weight = 1_000_000 * 10^18`, ETH currency, and `maxCashOutTaxRate`. These defaults are hardcoded.
|
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.26;
|
|
25
25
|
|
|
26
26
|
// Interfaces, structs, enums — caret for forward compatibility
|
|
27
27
|
pragma solidity ^0.8.0;
|