@croptop/core-v6 0.0.41 → 0.0.43

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/README.md CHANGED
@@ -53,7 +53,7 @@ Many Croptop bugs are really deployment-shape bugs or posting-policy bugs, not g
53
53
  1. `test/CTPublisher.t.sol`
54
54
  2. `test/CTDeployer.t.sol`
55
55
  3. `test/ClaimCollectionOwnership.t.sol`
56
- 4. `test/audit/FeeFallbackBlackhole.t.sol`
56
+ 4. `test/regression/FeeFallbackBlackhole.t.sol`
57
57
  5. `test/regression/DuplicateUriFeeEvasion.t.sol`
58
58
 
59
59
  ## Integration Traps
@@ -105,7 +105,7 @@ src/
105
105
  interfaces/
106
106
  structs/
107
107
  test/
108
- publisher, deployer, fork, attack, audit, metadata, and regression coverage
108
+ publisher, deployer, fork, attack, review, metadata, and regression coverage
109
109
  script/
110
110
  Deploy.s.sol
111
111
  ConfigureFeeProject.s.sol
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@croptop/core-v6",
3
- "version": "0.0.41",
3
+ "version": "0.0.43",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,17 +29,17 @@
29
29
  "artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'croptop-core-v6'"
30
30
  },
31
31
  "dependencies": {
32
- "@bananapus/721-hook-v6": "0.0.43",
33
- "@bananapus/core-v6": "0.0.39",
34
- "@bananapus/ownable-v6": "0.0.24",
35
- "@bananapus/permission-ids-v6": "0.0.22",
36
- "@bananapus/router-terminal-v6": "0.0.36",
37
- "@bananapus/suckers-v6": "0.0.33",
32
+ "@bananapus/721-hook-v6": "^0.0.47",
33
+ "@bananapus/core-v6": "^0.0.44",
34
+ "@bananapus/ownable-v6": "^0.0.24",
35
+ "@bananapus/permission-ids-v6": "^0.0.23",
36
+ "@bananapus/router-terminal-v6": "^0.0.37",
37
+ "@bananapus/suckers-v6": "^0.0.37",
38
38
  "@openzeppelin/contracts": "5.6.1",
39
- "@rev-net/core-v6": "0.0.37"
39
+ "@rev-net/core-v6": "^0.0.45"
40
40
  },
41
41
  "devDependencies": {
42
- "@bananapus/address-registry-v6": "0.0.25",
42
+ "@bananapus/address-registry-v6": "^0.0.25",
43
43
  "@sphinx-labs/plugins": "0.33.3"
44
44
  }
45
45
  }
@@ -24,4 +24,4 @@
24
24
 
25
25
  - [`test/CTPublisher.t.sol`](../test/CTPublisher.t.sol) and [`test/Test_MetadataGeneration.t.sol`](../test/Test_MetadataGeneration.t.sol) for content and metadata behavior.
26
26
  - [`test/CTDeployer.t.sol`](../test/CTDeployer.t.sol) and [`test/Fork.t.sol`](../test/Fork.t.sol) for live deployment assumptions.
27
- - [`test/CroptopAttacks.t.sol`](../test/CroptopAttacks.t.sol) and [`test/TestAuditGaps.sol`](../test/TestAuditGaps.sol) when the issue could be in publisher or deployer behavior rather than one isolated function.
27
+ - [`test/CroptopAttacks.t.sol`](../test/CroptopAttacks.t.sol) and [`test/TestRegressionGaps.sol`](../test/TestRegressionGaps.sol) when the issue could be in publisher or deployer behavior rather than one isolated function.
@@ -355,19 +355,22 @@ contract ConfigureFeeProjectScript is Script, Sphinx {
355
355
  function deploy() public sphinx {
356
356
  FeeProjectConfig memory feeProjectConfig = getCroptopRevnetConfig();
357
357
 
358
- // Approve the basic deployer to configure the project and transfer it.
359
- core.projects.approve({to: address(revnet.basic_deployer), tokenId: FEE_PROJECT_ID});
360
-
361
- // Deploy the NANA fee project.
362
- revnet.basic_deployer
363
- .deployFor({
364
- revnetId: FEE_PROJECT_ID,
365
- configuration: feeProjectConfig.configuration,
366
- terminalConfigurations: feeProjectConfig.terminalConfigurations,
367
- suckerDeploymentConfiguration: feeProjectConfig.suckerDeploymentConfiguration,
368
- tiered721HookConfiguration: feeProjectConfig.hookConfiguration,
369
- allowedPosts: feeProjectConfig.allowedPosts
370
- });
358
+ // Only deploy if the project hasn't already been configured (restart-safe).
359
+ if (address(core.directory.controllerOf(FEE_PROJECT_ID)) == address(0)) {
360
+ // Approve the basic deployer to configure the project and transfer it.
361
+ core.projects.approve({to: address(revnet.basic_deployer), tokenId: FEE_PROJECT_ID});
362
+
363
+ // Deploy the NANA fee project.
364
+ revnet.basic_deployer
365
+ .deployFor({
366
+ revnetId: FEE_PROJECT_ID,
367
+ configuration: feeProjectConfig.configuration,
368
+ terminalConfigurations: feeProjectConfig.terminalConfigurations,
369
+ suckerDeploymentConfiguration: feeProjectConfig.suckerDeploymentConfiguration,
370
+ tiered721HookConfiguration: feeProjectConfig.hookConfiguration,
371
+ allowedPosts: feeProjectConfig.allowedPosts
372
+ });
373
+ }
371
374
  }
372
375
 
373
376
  function _isDeployed(
@@ -120,7 +120,8 @@ contract CTDeployer is ERC2771Context, JBPermissioned, IJBRulesetDataHook, IERC7
120
120
 
121
121
  /// @notice Claim ownership of the collection.
122
122
  /// @dev Two-step ownership transfer process:
123
- /// Step 1 (this function): Transfers hook ownership to the project via `transferOwnershipToProject()`.
123
+ /// Step 1 (this function): Revokes the deployer-scoped permissions granted at launch, then transfers hook
124
+ /// ownership to the project via `transferOwnershipToProject()`.
124
125
  /// After this call, `hook.owner()` resolves dynamically through `PROJECTS.ownerOf(projectId)`.
125
126
  /// Step 2 (caller must do separately): The project owner grants CTPublisher the `ADJUST_721_TIERS` permission
126
127
  /// for the project so that `mintFrom()` continues to work.
@@ -132,11 +133,29 @@ contract CTDeployer is ERC2771Context, JBPermissioned, IJBRulesetDataHook, IERC7
132
133
  // Get the project ID of the hook.
133
134
  uint256 projectId = hook.PROJECT_ID();
134
135
 
136
+ // Keep a reference to the caller.
137
+ address caller = _msgSender();
138
+
135
139
  // Make sure the caller is the owner of the project.
136
- if (PROJECTS.ownerOf(projectId) != _msgSender()) {
137
- revert CTDeployer_NotOwnerOfProject({projectId: projectId, hook: address(hook), caller: _msgSender()});
140
+ if (PROJECTS.ownerOf(projectId) != caller) {
141
+ revert CTDeployer_NotOwnerOfProject({projectId: projectId, hook: address(hook), caller: caller});
138
142
  }
139
143
 
144
+ // Revoke the deployer-scoped permissions that were granted to the caller during deployment.
145
+ // These permissions (ADJUST_721_TIERS, SET_721_METADATA, MINT_721, SET_721_DISCOUNT_PERCENT) allowed the
146
+ // project owner to manage the hook while the deployer owned it. After transferring hook ownership to the
147
+ // project, these deployer-scoped grants are no longer needed and should be cleaned up to prevent stale
148
+ // permission leakage.
149
+ PERMISSIONS.setPermissionsFor({
150
+ account: address(this),
151
+ permissionsData: JBPermissionsData({
152
+ operator: caller,
153
+ // forge-lint: disable-next-line(unsafe-typecast)
154
+ projectId: uint64(projectId),
155
+ permissionIds: new uint8[](0)
156
+ })
157
+ });
158
+
140
159
  // Transfer the hook's ownership to the project.
141
160
  JBOwnable(address(hook)).transferOwnershipToProject(projectId);
142
161
  }
@@ -171,7 +190,6 @@ contract CTDeployer is ERC2771Context, JBPermissioned, IJBRulesetDataHook, IERC7
171
190
  projectId = PROJECTS.createFor(address(this));
172
191
 
173
192
  // Deploy a blank project.
174
- // slither-disable-next-line reentrancy-benign
175
193
  hook = DEPLOYER.deployHookFor({
176
194
  projectId: projectId,
177
195
  deployTiersHookConfig: JBDeploy721TiersHookConfig({
@@ -200,7 +218,6 @@ contract CTDeployer is ERC2771Context, JBPermissioned, IJBRulesetDataHook, IERC7
200
218
  rulesetConfigurations[0].metadata.useDataHookForCashOut = true;
201
219
 
202
220
  // Launch the rulesets for the reserved project.
203
- // slither-disable-next-line unused-return
204
221
  controller.launchRulesetsFor({
205
222
  projectId: projectId,
206
223
  projectUri: projectConfig.projectUri,
@@ -214,7 +231,7 @@ contract CTDeployer is ERC2771Context, JBPermissioned, IJBRulesetDataHook, IERC7
214
231
 
215
232
  // Configure allowed posts.
216
233
  if (projectConfig.allowedPosts.length > 0) {
217
- _configurePostingCriteriaFor(address(hook), projectConfig.allowedPosts);
234
+ _configurePostingCriteriaFor({hook: address(hook), allowedPosts: projectConfig.allowedPosts});
218
235
  }
219
236
 
220
237
  // Deploy the suckers (if applicable).
@@ -226,7 +243,6 @@ contract CTDeployer is ERC2771Context, JBPermissioned, IJBRulesetDataHook, IERC7
226
243
 
227
244
  // Successful deployments are discoverable from the registry, and failures are reported without reverting
228
245
  // the project launch.
229
- // slither-disable-next-line unused-return
230
246
  try SUCKER_REGISTRY.deploySuckersFor({
231
247
  projectId: projectId,
232
248
  salt: suckerSalt,
@@ -237,7 +253,6 @@ contract CTDeployer is ERC2771Context, JBPermissioned, IJBRulesetDataHook, IERC7
237
253
  // no-op
238
254
  }
239
255
  catch (bytes memory reason) {
240
- // slither-disable-next-line reentrancy-events
241
256
  emit CTDeployer_SuckerDeploymentFailed({projectId: projectId, salt: suckerSalt, reason: reason});
242
257
  }
243
258
  }
@@ -283,7 +298,6 @@ contract CTDeployer is ERC2771Context, JBPermissioned, IJBRulesetDataHook, IERC7
283
298
 
284
299
  // Deploy the suckers. The sucker registry performs its own permission check against this forwarding helper,
285
300
  // so an unapproved CTDeployer fails at the downstream registry boundary without an extra preflight read here.
286
- // slither-disable-next-line unused-return
287
301
  suckers = SUCKER_REGISTRY.deploySuckersFor({
288
302
  projectId: projectId,
289
303
  salt: keccak256(abi.encode(suckerDeploymentConfiguration.salt, _msgSender())),
@@ -334,7 +348,6 @@ contract CTDeployer is ERC2771Context, JBPermissioned, IJBRulesetDataHook, IERC7
334
348
  hookSpecifications
335
349
  );
336
350
  }
337
- // slither-disable-next-line unused-return
338
351
  return hook.beforeCashOutRecordedWith(context);
339
352
  }
340
353
 
@@ -358,7 +371,6 @@ contract CTDeployer is ERC2771Context, JBPermissioned, IJBRulesetDataHook, IERC7
358
371
  return (context.weight, hookSpecifications);
359
372
  }
360
373
 
361
- // slither-disable-next-line unused-return
362
374
  return hook.beforePayRecordedWith(context);
363
375
  }
364
376
 
@@ -32,19 +32,20 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
32
32
  //*********************************************************************//
33
33
 
34
34
  error CTPublisher_DuplicatePost(bytes32 encodedIPFSUri);
35
- error CTPublisher_EmptyEncodedIPFSUri();
35
+ error CTPublisher_EmptyEncodedIPFSUri(uint256 postIndex);
36
36
  error CTPublisher_InsufficientEthSent(uint256 expected, uint256 sent);
37
37
  error CTPublisher_MaxTotalSupplyLessThanMin(uint256 min, uint256 max);
38
38
  error CTPublisher_NotInAllowList(address addr, address[] allowedAddresses);
39
39
  error CTPublisher_PriceTooSmall(uint256 price, uint256 minimumPrice);
40
- error CTPublisher_DuplicatePayMetadata();
40
+ error CTPublisher_DuplicatePayMetadata(bytes4 payMetadataId);
41
41
  error CTPublisher_FeePaymentFailed(uint256 feeAmount);
42
42
  error CTPublisher_SplitPercentExceedsMaximum(uint256 splitPercent, uint256 maximumSplitPercent);
43
43
  error CTPublisher_TotalSupplyTooBig(uint256 totalSupply, uint256 maximumTotalSupply);
44
44
  error CTPublisher_TotalSupplyTooSmall(uint256 totalSupply, uint256 minimumTotalSupply);
45
- error CTPublisher_NoPosts();
46
- error CTPublisher_UnauthorizedToPostInCategory();
47
- error CTPublisher_ZeroTotalSupply();
45
+ error CTPublisher_NoPosts(address caller);
46
+ error CTPublisher_InvalidFeeBeneficiary();
47
+ error CTPublisher_UnauthorizedToPostInCategory(address hook, uint24 category);
48
+ error CTPublisher_ZeroTotalSupply(address hook, uint24 category);
48
49
 
49
50
  //*********************************************************************//
50
51
  // ------------------------- public constants ------------------------ //
@@ -133,7 +134,6 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
133
134
  emit ConfigurePostingCriteria({hook: allowedPost.hook, allowedPost: allowedPost, caller: _msgSender()});
134
135
 
135
136
  // Enforce permissions.
136
- // slither-disable-next-line reentrancy-events,calls-loop
137
137
  _requirePermissionFrom({
138
138
  account: JBOwnable(allowedPost.hook).owner(),
139
139
  projectId: IJB721TiersHook(allowedPost.hook).PROJECT_ID(),
@@ -142,14 +142,14 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
142
142
 
143
143
  // Make sure there is a minimum supply.
144
144
  if (allowedPost.minimumTotalSupply == 0) {
145
- revert CTPublisher_ZeroTotalSupply();
145
+ revert CTPublisher_ZeroTotalSupply({hook: allowedPost.hook, category: allowedPost.category});
146
146
  }
147
147
 
148
148
  // Make sure the minimum supply does not surpass the maximum supply.
149
149
  if (allowedPost.minimumTotalSupply > allowedPost.maximumTotalSupply) {
150
- revert CTPublisher_MaxTotalSupplyLessThanMin(
151
- allowedPost.minimumTotalSupply, allowedPost.maximumTotalSupply
152
- );
150
+ revert CTPublisher_MaxTotalSupplyLessThanMin({
151
+ min: allowedPost.minimumTotalSupply, max: allowedPost.maximumTotalSupply
152
+ });
153
153
  }
154
154
 
155
155
  uint256 packed;
@@ -190,21 +190,22 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
190
190
  /// @param additionalPayMetadata Metadata bytes that should be included in the pay function's metadata. This
191
191
  /// prepends the
192
192
  /// payload needed for NFT creation.
193
- /// @param feeMetadata The metadata to send alongside the fee payment.
194
193
  function mintFrom(
195
194
  IJB721TiersHook hook,
196
195
  CTPost[] calldata posts,
197
196
  address nftBeneficiary,
198
197
  address feeBeneficiary,
199
- bytes calldata additionalPayMetadata,
200
- bytes calldata feeMetadata
198
+ bytes calldata additionalPayMetadata
201
199
  )
202
200
  external
203
201
  payable
204
202
  override
205
203
  {
206
204
  // Reject empty posts to prevent fee-free metadata shadowing.
207
- if (posts.length == 0) revert CTPublisher_NoPosts();
205
+ if (posts.length == 0) revert CTPublisher_NoPosts(_msgSender());
206
+
207
+ // Reject address(0) as fee beneficiary to prevent burning fee project tokens.
208
+ if (feeBeneficiary == address(0)) revert CTPublisher_InvalidFeeBeneficiary();
208
209
 
209
210
  // Keep a reference to the amount being paid, which is msg.value minus the fee.
210
211
  uint256 payValue = msg.value;
@@ -218,7 +219,7 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
218
219
  {
219
220
  // Setup the posts.
220
221
  (JB721TierConfig[] memory tiersToAdd, uint256[] memory tierIdsToMint, uint256 totalPrice) =
221
- _setupPosts(hook, posts);
222
+ _setupPosts({hook: hook, posts: posts});
222
223
 
223
224
  if (projectId != FEE_PROJECT_ID) {
224
225
  // Keep a reference to the fee that will be paid.
@@ -229,7 +230,7 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
229
230
 
230
231
  // Make sure enough ETH was sent to cover the fee.
231
232
  if (payValue < fee) {
232
- revert CTPublisher_InsufficientEthSent(totalPrice + fee, msg.value);
233
+ revert CTPublisher_InsufficientEthSent({expected: totalPrice + fee, sent: msg.value});
233
234
  }
234
235
 
235
236
  payValue -= fee;
@@ -237,11 +238,10 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
237
238
 
238
239
  // Make sure the amount sent to this function is at least the specified price of the tier plus the fee.
239
240
  if (totalPrice > payValue) {
240
- revert CTPublisher_InsufficientEthSent(totalPrice, msg.value);
241
+ revert CTPublisher_InsufficientEthSent({expected: totalPrice, sent: msg.value});
241
242
  }
242
243
 
243
244
  // Add the new tiers.
244
- // slither-disable-next-line reentrancy-events
245
245
  hook.adjustTiers({tiersToAdd: tiersToAdd, tierIdsToRemove: new uint256[](0)});
246
246
 
247
247
  // Keep a reference to the metadata ID target.
@@ -251,9 +251,8 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
251
251
  // tier selection, allowing the caller to mint arbitrary tiers.
252
252
  {
253
253
  bytes4 payId = JBMetadataResolver.getId({purpose: "pay", target: metadataIdTarget});
254
- // slither-disable-next-line unused-return
255
254
  (bool exists,) = JBMetadataResolver.getDataFor({id: payId, metadata: additionalPayMetadata});
256
- if (exists) revert CTPublisher_DuplicatePayMetadata();
255
+ if (exists) revert CTPublisher_DuplicatePayMetadata(payId);
257
256
  }
258
257
 
259
258
  // Create the metadata for the payment to specify the tier IDs that should be minted. We create manually the
@@ -290,7 +289,6 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
290
289
  DIRECTORY.primaryTerminalOf({projectId: projectId, token: JBConstants.NATIVE_TOKEN});
291
290
 
292
291
  // Make the payment.
293
- // slither-disable-next-line unused-return
294
292
  projectTerminal.pay{value: payValue}({
295
293
  projectId: projectId,
296
294
  token: JBConstants.NATIVE_TOKEN,
@@ -314,7 +312,6 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
314
312
 
315
313
  // Make the fee payment. If the fee sink is unavailable, refund the fee to the caller
316
314
  // rather than trapping or silently redirecting protocol funds.
317
- // slither-disable-next-line unused-return
318
315
  try feeTerminal.pay{value: payValue}({
319
316
  projectId: FEE_PROJECT_ID,
320
317
  amount: payValue,
@@ -322,10 +319,9 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
322
319
  beneficiary: feeBeneficiary,
323
320
  minReturnedTokens: 0,
324
321
  memo: "",
325
- metadata: feeMetadata
322
+ metadata: ""
326
323
  }) {}
327
324
  catch {
328
- // slither-disable-next-line low-level-calls
329
325
  (bool success,) = _msgSender().call{value: payValue}("");
330
326
  if (!success) revert CTPublisher_FeePaymentFailed(payValue);
331
327
  }
@@ -365,7 +361,6 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
365
361
 
366
362
  // If there's a tier ID stored, resolve it.
367
363
  if (tierId != 0) {
368
- // slither-disable-next-line calls-loop
369
364
  tiers[i] = IJB721TiersHook(hook).STORE().tierOf({hook: hook, id: tierId, includeResolvedUri: false});
370
365
  }
371
366
 
@@ -465,13 +460,13 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
465
460
  // Make sure the post includes an encodedIPFSUri.
466
461
  // forge-lint: disable-next-line(unsafe-typecast)
467
462
  if (post.encodedIPFSUri == bytes32("")) {
468
- revert CTPublisher_EmptyEncodedIPFSUri();
463
+ revert CTPublisher_EmptyEncodedIPFSUri({postIndex: i});
469
464
  }
470
465
 
471
466
  // Check for duplicate encodedIPFSUri within the same batch to prevent fee evasion.
472
467
  for (uint256 j; j < i;) {
473
468
  if (posts[j].encodedIPFSUri == post.encodedIPFSUri) {
474
- revert CTPublisher_DuplicatePost(post.encodedIPFSUri);
469
+ revert CTPublisher_DuplicatePost({encodedIPFSUri: post.encodedIPFSUri});
475
470
  }
476
471
  unchecked {
477
472
  ++j;
@@ -488,10 +483,8 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
488
483
  // The cache can become stale if the tier was removed (via adjustTiers) or
489
484
  // its URI was changed (via setMetadata). In either case, clear the stale
490
485
  // mapping and fall through to create a new tier.
491
- // slither-disable-next-line calls-loop
492
486
  JB721Tier memory cachedTier =
493
487
  store.tierOf({hook: address(hook), id: tierId, includeResolvedUri: false});
494
- // slither-disable-next-line calls-loop
495
488
  if (store.isTierRemoved(address(hook), tierId) || cachedTier.encodedIPFSUri != post.encodedIPFSUri)
496
489
  {
497
490
  delete tierIdForEncodedIPFSUriOf[address(hook)][post.encodedIPFSUri];
@@ -520,34 +513,40 @@ contract CTPublisher is JBPermissioned, ERC2771Context, ICTPublisher {
520
513
 
521
514
  // Make sure the category being posted to allows publishing.
522
515
  if (minimumTotalSupply == 0) {
523
- revert CTPublisher_UnauthorizedToPostInCategory();
516
+ revert CTPublisher_UnauthorizedToPostInCategory({hook: address(hook), category: post.category});
524
517
  }
525
518
 
526
519
  // Make sure the price being paid for the post is at least the allowed minimum price.
527
520
  if (post.price < minimumPrice) {
528
- revert CTPublisher_PriceTooSmall(post.price, minimumPrice);
521
+ revert CTPublisher_PriceTooSmall({price: post.price, minimumPrice: minimumPrice});
529
522
  }
530
523
 
531
524
  // Make sure the total supply being made available for the post is at least the allowed minimum
532
525
  // total supply.
533
526
  if (post.totalSupply < minimumTotalSupply) {
534
- revert CTPublisher_TotalSupplyTooSmall(post.totalSupply, minimumTotalSupply);
527
+ revert CTPublisher_TotalSupplyTooSmall({
528
+ totalSupply: post.totalSupply, minimumTotalSupply: minimumTotalSupply
529
+ });
535
530
  }
536
531
 
537
532
  // Make sure the total supply being made available for the post is at most the allowed maximum total
538
533
  // supply.
539
534
  if (post.totalSupply > maximumTotalSupply) {
540
- revert CTPublisher_TotalSupplyTooBig(post.totalSupply, maximumTotalSupply);
535
+ revert CTPublisher_TotalSupplyTooBig({
536
+ totalSupply: post.totalSupply, maximumTotalSupply: maximumTotalSupply
537
+ });
541
538
  }
542
539
 
543
540
  // Make sure the split percent is within the allowed maximum.
544
541
  if (post.splitPercent > maximumSplitPercent) {
545
- revert CTPublisher_SplitPercentExceedsMaximum(post.splitPercent, maximumSplitPercent);
542
+ revert CTPublisher_SplitPercentExceedsMaximum({
543
+ splitPercent: post.splitPercent, maximumSplitPercent: maximumSplitPercent
544
+ });
546
545
  }
547
546
 
548
547
  // Make sure the address is allowed to post.
549
548
  if (addresses.length != 0 && !_isAllowed({addrs: _msgSender(), addresses: addresses})) {
550
- revert CTPublisher_NotInAllowList(_msgSender(), addresses);
549
+ revert CTPublisher_NotInAllowList({addr: _msgSender(), allowedAddresses: addresses});
551
550
  }
552
551
  }
553
552
 
@@ -93,14 +93,12 @@ interface ICTPublisher {
93
93
  /// @param nftBeneficiary The beneficiary of the NFT mints.
94
94
  /// @param feeBeneficiary The beneficiary of the fee project's tokens.
95
95
  /// @param additionalPayMetadata Extra metadata bytes to include in the payment.
96
- /// @param feeMetadata Metadata to send alongside the fee payment.
97
96
  function mintFrom(
98
97
  IJB721TiersHook hook,
99
98
  CTPost[] calldata posts,
100
99
  address nftBeneficiary,
101
100
  address feeBeneficiary,
102
- bytes calldata additionalPayMetadata,
103
- bytes calldata feeMetadata
101
+ bytes calldata additionalPayMetadata
104
102
  )
105
103
  external
106
104
  payable;