@zoralabs/comments-contracts 0.0.1 → 0.0.2-COMMENTS.0

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.
Files changed (104) hide show
  1. package/.turbo/turbo-build.log +48 -30
  2. package/CHANGELOG.md +8 -0
  3. package/README.md +10 -39
  4. package/abis/AddDelegateCommenterRole.json +22 -0
  5. package/abis/CallerAndCommenter.json +62 -0
  6. package/abis/CallerAndCommenterImpl.json +1218 -0
  7. package/abis/CallerAndCommenterMintAndCommentTest.json +771 -0
  8. package/abis/CallerAndCommenterSwapAndCommentTest.json +844 -0
  9. package/abis/CallerAndCommenterTestBase.json +577 -0
  10. package/abis/CommentsImpl.json +189 -59
  11. package/abis/CommentsImplConstants.json +106 -0
  12. package/abis/CommentsPermitTest.json +26 -6
  13. package/abis/CommentsTest.json +58 -10
  14. package/abis/Comments_mintAndCommentTest.json +11 -4
  15. package/abis/Comments_smartWallet.json +711 -0
  16. package/abis/DeployCallerAndCommenterImpl.json +22 -0
  17. package/abis/EIP712Upgradeable.json +74 -0
  18. package/abis/EIP712UpgradeableWithChainId.json +49 -0
  19. package/abis/ERC20.json +310 -0
  20. package/abis/ICallerAndCommenter.json +797 -0
  21. package/abis/IComments.json +629 -9
  22. package/abis/IERC20.json +39 -42
  23. package/abis/IERC20Metadata.json +224 -0
  24. package/abis/IMultiOwnable.json +21 -0
  25. package/abis/IProtocolRewards.json +19 -0
  26. package/abis/ISecondarySwap.json +45 -0
  27. package/abis/IZoraCreator1155.json +51 -0
  28. package/abis/IZoraTimedSaleStrategy.json +91 -0
  29. package/abis/Mock1155.json +75 -1
  30. package/abis/Mock1155NoCreatorRewardRecipient.json +605 -0
  31. package/abis/Mock1155NoOwner.json +566 -0
  32. package/abis/{MockMinter.json → MockDelegateCommenter.json} +12 -2
  33. package/abis/MockERC20z.json +315 -0
  34. package/abis/MockMultiOwnable.json +212 -0
  35. package/abis/MockSecondarySwap.json +95 -0
  36. package/abis/MockZoraTimedSale.json +139 -0
  37. package/abis/Ownable2StepUpgradeable.json +138 -0
  38. package/abis/UnorderedNoncesUpgradeable.json +4 -4
  39. package/addresses/10.json +9 -0
  40. package/addresses/11155111.json +9 -0
  41. package/addresses/11155420.json +9 -0
  42. package/addresses/42161.json +9 -0
  43. package/addresses/7777777.json +9 -0
  44. package/addresses/8453.json +9 -0
  45. package/addresses/84532.json +9 -0
  46. package/addresses/999999999.json +7 -2
  47. package/deterministicConfig/callerAndCommenter.json +8 -0
  48. package/deterministicConfig/comments.json +2 -2
  49. package/dist/index.cjs +724 -35
  50. package/dist/index.cjs.map +1 -1
  51. package/dist/index.js +723 -35
  52. package/dist/index.js.map +1 -1
  53. package/dist/types.d.ts +1 -1
  54. package/dist/types.d.ts.map +1 -1
  55. package/dist/wagmiGenerated.d.ts +1102 -57
  56. package/dist/wagmiGenerated.d.ts.map +1 -1
  57. package/package/types.ts +4 -1
  58. package/package/wagmiGenerated.ts +728 -32
  59. package/package.json +11 -10
  60. package/script/AddDelegateCommenterRole.s.sol +24 -0
  61. package/script/CommentsDeployerBase.sol +101 -19
  62. package/script/Deploy.s.sol +2 -44
  63. package/script/DeployCallerAndCommenterImpl.s.sol +27 -0
  64. package/script/DeployImpl.s.sol +1 -0
  65. package/script/DeployNonDeterministic.s.sol +22 -13
  66. package/script/GenerateDeterministicParams.s.sol +32 -4
  67. package/scripts/generateCommentsTestData.ts +170 -79
  68. package/src/CommentsImpl.sol +267 -134
  69. package/src/CommentsImplConstants.sol +44 -0
  70. package/src/interfaces/ICallerAndCommenter.sol +215 -0
  71. package/src/interfaces/IComments.sol +189 -42
  72. package/src/interfaces/IMultiOwnable.sol +10 -0
  73. package/src/interfaces/ISecondarySwap.sol +40 -0
  74. package/src/interfaces/IZoraCreator1155.sol +6 -1
  75. package/src/interfaces/IZoraCreator1155TypesV1.sol +46 -0
  76. package/src/interfaces/IZoraTimedSaleStrategy.sol +25 -0
  77. package/src/proxy/CallerAndCommenter.sol +43 -0
  78. package/src/utils/CallerAndCommenterImpl.sol +376 -0
  79. package/src/utils/EIP712UpgradeableWithChainId.sol +12 -23
  80. package/src/version/ContractVersionBase.sol +1 -1
  81. package/test/CallerAndCommenterTestBase.sol +77 -0
  82. package/test/CallerAndCommenter_mintAndComment.t copy.sol +214 -0
  83. package/test/CallerAndCommenter_swapAndComment.t.sol +523 -0
  84. package/test/Comments.t.sol +166 -29
  85. package/test/CommentsTestBase.sol +12 -20
  86. package/test/Comments_delegateComment.t.sol +129 -0
  87. package/test/Comments_permit.t.sol +131 -44
  88. package/test/Comments_smartWallet.t.sol +152 -0
  89. package/test/mocks/Mock1155.sol +12 -1
  90. package/test/mocks/Mock1155NoCreatorRewardRecipient.sol +65 -0
  91. package/test/mocks/Mock1155NoOwner.sol +53 -0
  92. package/test/mocks/MockDelegateCommenter.sol +36 -0
  93. package/test/mocks/MockIZoraCreator1155.sol +16 -0
  94. package/test/mocks/MockSecondarySwap.sol +30 -0
  95. package/test/mocks/MockZoraTimedSale.sol +38 -0
  96. package/wagmi.config.ts +3 -1
  97. package/scripts/backfillComments.ts +0 -176
  98. package/scripts/queries.ts +0 -73
  99. package/scripts/queryAndSaveComments.ts +0 -48
  100. package/scripts/queryQuantityOfComments.ts +0 -53
  101. package/scripts/writeComments.ts +0 -198
  102. package/src/deployments/CommentsDeployment.sol +0 -14
  103. package/test/Comments_mintAndComment.t.sol +0 -101
  104. package/test/mocks/MockMinter.sol +0 -29
@@ -3,21 +3,20 @@ pragma solidity ^0.8.20;
3
3
 
4
4
  import "forge-std/Test.sol";
5
5
 
6
- import {CommentsImpl} from "../src/CommentsImpl.sol";
7
- import {Comments} from "../src/proxy/Comments.sol";
8
6
  import {IComments} from "../src/interfaces/IComments.sol";
9
7
  import {Mock1155} from "./mocks/Mock1155.sol";
10
- import {IProtocolRewards} from "@zoralabs/protocol-rewards/src/interfaces/IProtocolRewards.sol";
11
- import {ProtocolRewards} from "./mocks/ProtocolRewards.sol";
12
- import {UnorderedNoncesUpgradeable} from "@zoralabs/shared-contracts/utils/UnorderedNoncesUpgradeable.sol";
13
8
  import {CommentsTestBase} from "./CommentsTestBase.sol";
9
+ import {Mock1155NoCreatorRewardRecipient} from "./mocks/Mock1155NoCreatorRewardRecipient.sol";
10
+ import {Mock1155NoOwner} from "./mocks/Mock1155NoOwner.sol";
11
+ import {CommentsImpl} from "../src/CommentsImpl.sol";
12
+ import {Comments} from "../src/proxy/Comments.sol";
14
13
 
15
14
  contract CommentsTest is CommentsTestBase {
16
15
  uint256 public constant ZORA_REWARD_PCT = 10;
17
16
  uint256 public constant REFERRER_REWARD_PCT = 20;
18
17
  uint256 internal constant BPS_TO_PERCENT_2_DECIMAL_PERCISION = 100;
19
18
 
20
- function _setupCommenterWithTokenAndSparks(address commenter, uint64 sparksQuantity) internal {
19
+ function _setupCommenterWithTokenAndSparks(address commenter, uint256 sparksQuantity) internal {
21
20
  vm.startPrank(commenter);
22
21
  mock1155.mint(commenter, tokenId1, 1, "");
23
22
  vm.stopPrank();
@@ -60,7 +59,7 @@ contract CommentsTest is CommentsTestBase {
60
59
  address(0)
61
60
  );
62
61
  vm.prank(collectorWithToken);
63
- comments.comment{value: SPARKS_VALUE}(collectorWithToken, contractAddress, tokenId, "test comment", replyTo, address(0));
62
+ comments.comment{value: SPARKS_VALUE}(collectorWithToken, contractAddress, tokenId, "test comment", replyTo, address(0), address(0));
64
63
 
65
64
  uint256 zoraReward = (SPARKS_VALUE * (ZORA_REWARD_PCT + REFERRER_REWARD_PCT)) / BPS_TO_PERCENT_2_DECIMAL_PERCISION;
66
65
  vm.assertEq(protocolRewards.balanceOf(collectorWithToken), 0);
@@ -102,7 +101,7 @@ contract CommentsTest is CommentsTestBase {
102
101
  // verify first comment is emitted
103
102
  emit IComments.BackfilledComment({
104
103
  commentId: comments.hashCommentIdentifier(commentIdentifiers[0]),
105
- comment: commentIdentifiers[0],
104
+ commentIdentifier: commentIdentifiers[0],
106
105
  text: texts[0],
107
106
  timestamp: timestamps[0],
108
107
  originalTransactionId: originalTransactionHashes[0]
@@ -111,7 +110,7 @@ contract CommentsTest is CommentsTestBase {
111
110
  // verify second comment is emitted
112
111
  emit IComments.BackfilledComment({
113
112
  commentId: comments.hashCommentIdentifier(commentIdentifiers[1]),
114
- comment: commentIdentifiers[1],
113
+ commentIdentifier: commentIdentifiers[1],
115
114
  text: texts[1],
116
115
  timestamp: timestamps[1],
117
116
  originalTransactionId: originalTransactionHashes[1]
@@ -221,7 +220,7 @@ contract CommentsTest is CommentsTestBase {
221
220
  comments.sparkComment{value: SPARKS_VALUE}(commentIdentifier, 1, address(0));
222
221
  }
223
222
 
224
- function testCommentSparkCommentValid(uint64 sparksQuantity) public {
223
+ function testCommentSparkCommentValid(uint256 sparksQuantity) public {
225
224
  vm.assume(sparksQuantity > 0 && sparksQuantity < 1_000_000_000_000_000);
226
225
 
227
226
  // comment
@@ -229,16 +228,23 @@ contract CommentsTest is CommentsTestBase {
229
228
  IComments.CommentIdentifier memory commentIdentifier = _mockComment(collectorWithToken, replyTo);
230
229
 
231
230
  // mint
232
- address commentor2 = makeAddr("commentor2");
231
+ address commenter2 = makeAddr("commenter2");
233
232
 
234
233
  uint256 zoraRecipientBalanceBeforeSpark = protocolRewards.balanceOf(zoraRecipient);
235
234
 
236
235
  // spark comment
237
- vm.deal(commentor2, sparksQuantity * SPARKS_VALUE);
236
+ vm.deal(commenter2, sparksQuantity * SPARKS_VALUE);
238
237
 
239
238
  vm.expectEmit(true, true, true, true);
240
- emit IComments.SparkedComment(comments.hashCommentIdentifier(commentIdentifier), commentIdentifier, sparksQuantity, commentor2, block.timestamp);
241
- vm.prank(commentor2);
239
+ emit IComments.SparkedComment(
240
+ comments.hashCommentIdentifier(commentIdentifier),
241
+ commentIdentifier,
242
+ sparksQuantity,
243
+ commenter2,
244
+ block.timestamp,
245
+ address(0)
246
+ );
247
+ vm.prank(commenter2);
242
248
  comments.sparkComment{value: sparksQuantity * SPARKS_VALUE}(commentIdentifier, sparksQuantity, address(0));
243
249
 
244
250
  uint256 zoraReward = (sparksQuantity * SPARKS_VALUE * (ZORA_REWARD_PCT + REFERRER_REWARD_PCT)) / BPS_TO_PERCENT_2_DECIMAL_PERCISION;
@@ -246,7 +252,7 @@ contract CommentsTest is CommentsTestBase {
246
252
  vm.assertEq(protocolRewards.balanceOf(collectorWithToken), (sparksQuantity * SPARKS_VALUE) - zoraReward);
247
253
  }
248
254
 
249
- function testCommentSparkCommentValidWithReferrer(uint64 sparksQuantity) public {
255
+ function testCommentSparkCommentValidWithReferrer(uint256 sparksQuantity) public {
250
256
  vm.assume(sparksQuantity > 0 && sparksQuantity < 1_000_000_000_000_000);
251
257
 
252
258
  // comment
@@ -254,18 +260,25 @@ contract CommentsTest is CommentsTestBase {
254
260
  IComments.CommentIdentifier memory commentIdentifier = _mockComment(collectorWithToken, replyTo);
255
261
 
256
262
  // mint
257
- address commentor2 = makeAddr("commentor2");
263
+ address commenter2 = makeAddr("commenter2");
258
264
 
259
265
  uint256 zoraRecipientBalanceBeforeSpark = protocolRewards.balanceOf(zoraRecipient);
260
266
 
261
267
  // spark comment
262
- vm.deal(commentor2, sparksQuantity * SPARKS_VALUE);
268
+ vm.deal(commenter2, sparksQuantity * SPARKS_VALUE);
263
269
 
264
270
  address referrer = makeAddr("referrer");
265
271
 
266
272
  vm.expectEmit(true, true, true, true);
267
- emit IComments.SparkedComment(comments.hashCommentIdentifier(commentIdentifier), commentIdentifier, sparksQuantity, commentor2, block.timestamp);
268
- vm.prank(commentor2);
273
+ emit IComments.SparkedComment(
274
+ comments.hashCommentIdentifier(commentIdentifier),
275
+ commentIdentifier,
276
+ sparksQuantity,
277
+ commenter2,
278
+ block.timestamp,
279
+ referrer
280
+ );
281
+ vm.prank(commenter2);
269
282
  comments.sparkComment{value: sparksQuantity * SPARKS_VALUE}(commentIdentifier, sparksQuantity, referrer);
270
283
 
271
284
  uint256 zoraReward = (sparksQuantity * SPARKS_VALUE * ZORA_REWARD_PCT) / BPS_TO_PERCENT_2_DECIMAL_PERCISION;
@@ -294,7 +307,7 @@ contract CommentsTest is CommentsTestBase {
294
307
  IComments.CommentIdentifier memory replyTo
295
308
  ) internal returns (IComments.CommentIdentifier memory) {
296
309
  vm.prank(commenter);
297
- return comments.comment{value: SPARKS_VALUE}(commenter, contractAddress, tokenId, content, replyTo, address(0));
310
+ return comments.comment{value: SPARKS_VALUE}(commenter, contractAddress, tokenId, content, replyTo, address(0), address(0));
298
311
  }
299
312
 
300
313
  function testHashAndCheckCommentExists() public {
@@ -318,8 +331,8 @@ contract CommentsTest is CommentsTestBase {
318
331
  }
319
332
 
320
333
  function testReplyToNonExistentComment() public {
321
- address commentor = makeAddr("commentor");
322
- _setupCommenterWithTokenAndSparks(commentor, 1);
334
+ address commenter = makeAddr("commenter");
335
+ _setupCommenterWithTokenAndSparks(commenter, 1);
323
336
 
324
337
  IComments.CommentIdentifier memory nonExistentReplyTo = IComments.CommentIdentifier({
325
338
  commenter: makeAddr("nonExistentCommenter"),
@@ -329,7 +342,7 @@ contract CommentsTest is CommentsTestBase {
329
342
  });
330
343
 
331
344
  vm.expectRevert(IComments.CommentDoesntExist.selector);
332
- postComment(commentor, address(mock1155), tokenId1, "Replying to non-existent comment", nonExistentReplyTo);
345
+ postComment(commenter, address(mock1155), tokenId1, "Replying to non-existent comment", nonExistentReplyTo);
333
346
  }
334
347
 
335
348
  function testReplyToCommentThatAddressDoesNotMatch() public {
@@ -354,7 +367,15 @@ contract CommentsTest is CommentsTestBase {
354
367
  abi.encodeWithSelector(IComments.CommentAddressOrTokenIdsDoNotMatch.selector, mismatchedAddress, tokenId1, address(mock1155), tokenId1)
355
368
  );
356
369
  vm.prank(replier);
357
- comments.comment{value: SPARKS_VALUE}(replier, mismatchedAddress, tokenId1, "Reply to original comment", originalCommentIdentifier, address(0));
370
+ comments.comment{value: SPARKS_VALUE}(
371
+ replier,
372
+ mismatchedAddress,
373
+ tokenId1,
374
+ "Reply to original comment",
375
+ originalCommentIdentifier,
376
+ address(0),
377
+ address(0)
378
+ );
358
379
 
359
380
  // mismatched tokenId
360
381
  uint256 mismatchedTokenId = 123;
@@ -369,6 +390,7 @@ contract CommentsTest is CommentsTestBase {
369
390
  mismatchedTokenId,
370
391
  "Reply to original comment",
371
392
  originalCommentIdentifier,
393
+ address(0),
372
394
  address(0)
373
395
  );
374
396
  }
@@ -412,7 +434,7 @@ contract CommentsTest is CommentsTestBase {
412
434
 
413
435
  assertEq(payable(address(comments)).balance, 0, "comments contract should have no balance");
414
436
 
415
- uint64 commenteeSparks = comments.commentSparksQuantity(comments.hashCommentIdentifier(originalCommentIdentifier));
437
+ uint256 commenteeSparks = comments.commentSparksQuantity(originalCommentIdentifier);
416
438
  assertEq(commenteeSparks, 0, "commentee sparks should be 0");
417
439
 
418
440
  assertEq(protocolRewards.balanceOf(originalCommenter), (SPARKS_VALUE * 70) / 100, "rewards mismatch");
@@ -429,7 +451,15 @@ contract CommentsTest is CommentsTestBase {
429
451
 
430
452
  vm.expectRevert(abi.encodeWithSelector(IComments.CommenterMismatch.selector, mismatchedCommenter, actualCommenter));
431
453
  vm.prank(actualCommenter);
432
- comments.comment{value: SPARKS_VALUE}(mismatchedCommenter, address(mock1155), tokenId1, "Mismatched commenter", emptyCommentIdentifier, address(0));
454
+ comments.comment{value: SPARKS_VALUE}(
455
+ mismatchedCommenter,
456
+ address(mock1155),
457
+ tokenId1,
458
+ "Mismatched commenter",
459
+ emptyCommentIdentifier,
460
+ address(0),
461
+ address(0)
462
+ );
433
463
  }
434
464
 
435
465
  function testRevertOnEmptyComment() public {
@@ -458,7 +488,7 @@ contract CommentsTest is CommentsTestBase {
458
488
  vm.deal(tokenHolder, 1 ether);
459
489
  vm.prank(tokenHolder);
460
490
  vm.expectRevert(abi.encodeWithSelector(IComments.IncorrectETHAmountForSparks.selector, 1 ether, SPARKS_VALUE));
461
- comments.comment{value: 1 ether}(tokenHolder, address(mock1155), tokenId1, "test", emptyCommentIdentifier, address(0));
491
+ comments.comment{value: 1 ether}(tokenHolder, address(mock1155), tokenId1, "test", emptyCommentIdentifier, address(0), address(0));
462
492
  }
463
493
 
464
494
  function testCommentRevertsWhenSendTooLittleValue() public {
@@ -468,7 +498,7 @@ contract CommentsTest is CommentsTestBase {
468
498
 
469
499
  vm.prank(tokenHolder);
470
500
  vm.expectRevert(abi.encodeWithSelector(IComments.MustSendAtLeastOneSpark.selector));
471
- comments.comment(tokenHolder, address(mock1155), tokenId1, "test", emptyCommentIdentifier, address(0));
501
+ comments.comment(tokenHolder, address(mock1155), tokenId1, "test", emptyCommentIdentifier, address(0), address(0));
472
502
  }
473
503
 
474
504
  function testCommentRevertsWhenSendExactValue() public {
@@ -477,6 +507,113 @@ contract CommentsTest is CommentsTestBase {
477
507
  _setupCommenterWithTokenAndSparks(tokenHolder, 1);
478
508
 
479
509
  vm.prank(tokenHolder);
480
- comments.comment{value: SPARKS_VALUE}(tokenHolder, address(mock1155), tokenId1, "test", emptyCommentIdentifier, address(0));
510
+ comments.comment{value: SPARKS_VALUE}(tokenHolder, address(mock1155), tokenId1, "test", emptyCommentIdentifier, address(0), address(0));
511
+ }
512
+
513
+ function testCommentWithMock1155NoCreatorRewardRecipient() public {
514
+ Mock1155NoCreatorRewardRecipient mock1155NoCreatorRewardRecipient = new Mock1155NoCreatorRewardRecipient();
515
+ mock1155NoCreatorRewardRecipient.createToken(tokenId1, tokenAdmin);
516
+
517
+ vm.startPrank(collectorWithToken);
518
+ mock1155NoCreatorRewardRecipient.mint(collectorWithToken, tokenId1, 1, "");
519
+ vm.stopPrank();
520
+
521
+ uint256 sparksQuantity = 1;
522
+
523
+ vm.deal(collectorWithToken, sparksQuantity * SPARKS_VALUE);
524
+
525
+ address contractAddress = address(mock1155NoCreatorRewardRecipient);
526
+ uint256 tokenId = tokenId1;
527
+
528
+ // blank replyTo
529
+ IComments.CommentIdentifier memory replyTo;
530
+
531
+ // funds recipient is 0x000...
532
+ vm.prank(collectorWithToken);
533
+ vm.expectRevert(abi.encodeWithSelector(IComments.NoFundsRecipient.selector));
534
+ comments.comment{value: sparksQuantity * SPARKS_VALUE}(collectorWithToken, contractAddress, tokenId, "test comment", replyTo, address(0), address(0));
535
+
536
+ // with funds recipient set
537
+ address newFundsRecipient = makeAddr("newFundsRecipient");
538
+ mock1155NoCreatorRewardRecipient.setFundsRecipient(payable(newFundsRecipient));
539
+ vm.deal(collectorWithToken, sparksQuantity * SPARKS_VALUE);
540
+
541
+ vm.prank(collectorWithToken);
542
+ comments.comment{value: sparksQuantity * SPARKS_VALUE}(
543
+ collectorWithToken,
544
+ contractAddress,
545
+ tokenId,
546
+ "test comment with recipient",
547
+ replyTo,
548
+ address(0),
549
+ address(0)
550
+ );
551
+
552
+ uint256 zoraReward = (sparksQuantity * SPARKS_VALUE * (ZORA_REWARD_PCT + REFERRER_REWARD_PCT)) / BPS_TO_PERCENT_2_DECIMAL_PERCISION;
553
+ uint256 recipientReward = (sparksQuantity * SPARKS_VALUE) - zoraReward;
554
+ vm.assertEq(protocolRewards.balanceOf(newFundsRecipient), recipientReward);
555
+ }
556
+
557
+ function testCommentWithMock1155NoOwner() public {
558
+ Mock1155NoOwner mock1155NoOwner = new Mock1155NoOwner();
559
+ mock1155NoOwner.createToken(tokenId1, tokenAdmin);
560
+
561
+ vm.startPrank(collectorWithToken);
562
+ mock1155NoOwner.mint(collectorWithToken, tokenId1, 1, "");
563
+ vm.stopPrank();
564
+
565
+ uint256 sparksQuantity = 1;
566
+ vm.deal(collectorWithToken, sparksQuantity * SPARKS_VALUE);
567
+
568
+ address contractAddress = address(mock1155NoOwner);
569
+ uint256 tokenId = tokenId1;
570
+
571
+ IComments.CommentIdentifier memory replyTo;
572
+
573
+ vm.prank(collectorWithToken);
574
+ vm.expectRevert(abi.encodeWithSelector(IComments.NoFundsRecipient.selector));
575
+ comments.comment{value: sparksQuantity * SPARKS_VALUE}(collectorWithToken, contractAddress, tokenId, "test comment", replyTo, address(0), address(0));
576
+ }
577
+
578
+ function testImplementation() public view {
579
+ assertEq(comments.implementation(), address(commentsImpl));
580
+ }
581
+
582
+ function testCommentsConstructorAddressZero() public {
583
+ vm.expectRevert(abi.encodeWithSelector(IComments.AddressZero.selector));
584
+ new CommentsImpl(SPARKS_VALUE, address(0), zoraRecipient);
585
+
586
+ vm.expectRevert(abi.encodeWithSelector(IComments.AddressZero.selector));
587
+ new CommentsImpl(SPARKS_VALUE, address(protocolRewards), address(0));
588
+ }
589
+
590
+ function testCommentsInitializeAddressZero() public {
591
+ CommentsImpl implTest = new CommentsImpl(SPARKS_VALUE, address(protocolRewards), zoraRecipient);
592
+ address[] memory delegateCommenters = new address[](0);
593
+
594
+ CommentsImpl commentsProxyTest = CommentsImpl(payable(address(new Comments(address(implTest)))));
595
+ vm.expectRevert(abi.encodeWithSelector(IComments.AddressZero.selector));
596
+ commentsProxyTest.initialize({defaultAdmin: address(0), backfiller: commentsBackfiller, delegateCommenters: delegateCommenters});
597
+
598
+ vm.expectRevert(abi.encodeWithSelector(IComments.AddressZero.selector));
599
+ commentsProxyTest.initialize({defaultAdmin: commentsAdmin, backfiller: address(0), delegateCommenters: new address[](0)});
600
+ }
601
+
602
+ function testGrantRoleWithBackfillRole() public {
603
+ address newBackfiller = makeAddr("newBackfiller");
604
+ bytes32 BACKFILLER_ROLE = keccak256("BACKFILLER_ROLE");
605
+ vm.prank(commentsAdmin);
606
+ comments.grantRole(BACKFILLER_ROLE, newBackfiller);
607
+ vm.assertEq(comments.hasRole(BACKFILLER_ROLE, newBackfiller), true);
608
+
609
+ vm.prank(commentsAdmin);
610
+ comments.revokeRole(BACKFILLER_ROLE, newBackfiller);
611
+ vm.assertEq(comments.hasRole(BACKFILLER_ROLE, newBackfiller), false);
612
+
613
+ address notAdmin = makeAddr("notAdmin");
614
+ bytes32 no_role;
615
+ vm.prank(notAdmin);
616
+ vm.expectRevert(abi.encodeWithSignature("AccessControlUnauthorizedAccount(address,bytes32)", notAdmin, no_role));
617
+ comments.grantRole(BACKFILLER_ROLE, newBackfiller);
481
618
  }
482
619
  }
@@ -7,11 +7,11 @@ import {CommentsImpl} from "../src/CommentsImpl.sol";
7
7
  import {Comments} from "../src/proxy/Comments.sol";
8
8
  import {IComments} from "../src/interfaces/IComments.sol";
9
9
  import {Mock1155} from "./mocks/Mock1155.sol";
10
- import {IProtocolRewards} from "@zoralabs/protocol-rewards/src/interfaces/IProtocolRewards.sol";
11
10
  import {ProtocolRewards} from "./mocks/ProtocolRewards.sol";
12
11
 
13
12
  contract CommentsTestBase is Test {
14
13
  CommentsImpl internal comments;
14
+ CommentsImpl internal commentsImpl;
15
15
  Mock1155 internal mock1155;
16
16
 
17
17
  uint256 internal constant SPARKS_VALUE = 0.000001 ether;
@@ -22,7 +22,8 @@ contract CommentsTestBase is Test {
22
22
  address internal commentsAdmin = makeAddr("commentsAdmin");
23
23
  address internal commentsBackfiller = makeAddr("commentsBackfiller");
24
24
  address internal zoraRecipient = makeAddr("zoraRecipient");
25
- address internal tokenAdmin = makeAddr("tokenCreator");
25
+ address internal tokenAdmin;
26
+ uint256 internal tokenAdminPrivateKey;
26
27
  address internal collectorWithToken;
27
28
  uint256 internal collectorWithTokenPrivateKey;
28
29
  address internal collectorWithoutToken = makeAddr("collectorWithoutToken");
@@ -34,32 +35,23 @@ contract CommentsTestBase is Test {
34
35
 
35
36
  function setUp() public {
36
37
  protocolRewards = new ProtocolRewards();
37
- CommentsImpl commentsImpl = new CommentsImpl(SPARKS_VALUE, address(protocolRewards));
38
+ commentsImpl = new CommentsImpl(SPARKS_VALUE, address(protocolRewards), zoraRecipient);
38
39
 
39
40
  // initialze empty delegateCommenters array
40
41
  address[] memory delegateCommenters = new address[](0);
41
42
 
42
43
  // intialize proxy
43
44
  comments = CommentsImpl(payable(address(new Comments(address(commentsImpl)))));
44
- comments.initialize({
45
- _zoraRecipient: zoraRecipient,
46
- defaultAdmin: commentsAdmin,
47
- backfiller: commentsBackfiller,
48
- delegateCommenters: delegateCommenters
49
- });
45
+ comments.initialize({defaultAdmin: commentsAdmin, backfiller: commentsBackfiller, delegateCommenters: delegateCommenters});
50
46
 
51
47
  mock1155 = new Mock1155();
48
+ (tokenAdmin, tokenAdminPrivateKey) = makeAddrAndKey("tokenAdmin");
52
49
 
53
50
  mock1155.createToken(tokenId1, tokenAdmin);
54
51
  mock1155.createToken(tokenId2, tokenAdmin);
55
52
 
56
53
  (collectorWithToken, collectorWithTokenPrivateKey) = makeAddrAndKey("collectorWithToken");
57
54
  (sparker, sparkerPrivateKey) = makeAddrAndKey("sparker");
58
-
59
- mock1155 = new Mock1155();
60
-
61
- mock1155.createToken(tokenId1, tokenAdmin);
62
- mock1155.createToken(tokenId2, tokenAdmin);
63
55
  }
64
56
 
65
57
  function _expectedCommentIdentifier(
@@ -71,16 +63,16 @@ contract CommentsTestBase is Test {
71
63
  }
72
64
 
73
65
  function _mockComment(
74
- address commentor,
66
+ address commenter,
75
67
  IComments.CommentIdentifier memory replyTo
76
68
  ) internal returns (IComments.CommentIdentifier memory commentIdentifier) {
77
- vm.startPrank(commentor);
78
- mock1155.mint(commentor, tokenId1, 1, "");
69
+ vm.startPrank(commenter);
70
+ mock1155.mint(commenter, tokenId1, 1, "");
79
71
  vm.stopPrank();
80
72
 
81
- vm.deal(commentor, SPARKS_VALUE);
73
+ vm.deal(commenter, SPARKS_VALUE);
82
74
 
83
- vm.prank(commentor);
84
- commentIdentifier = comments.comment{value: SPARKS_VALUE}(commentor, address(mock1155), tokenId1, "comment", replyTo, address(0));
75
+ vm.prank(commenter);
76
+ commentIdentifier = comments.comment{value: SPARKS_VALUE}(commenter, address(mock1155), tokenId1, "comment", replyTo, address(0), address(0));
85
77
  }
86
78
  }
@@ -0,0 +1,129 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.20;
3
+
4
+ import "forge-std/Test.sol";
5
+
6
+ import {CommentsImpl} from "../src/CommentsImpl.sol";
7
+ import {Comments} from "../src/proxy/Comments.sol";
8
+ import {IComments} from "../src/interfaces/IComments.sol";
9
+ import {Mock1155} from "./mocks/Mock1155.sol";
10
+ import {MockDelegateCommenter} from "./mocks/MockDelegateCommenter.sol";
11
+
12
+ contract Comments_mintAndCommentTest is Test {
13
+ Mock1155 mock1155;
14
+ CommentsImpl comments;
15
+
16
+ uint256 constant SPARKS_VALUE = 0.000001 ether;
17
+
18
+ address zoraRecipient = makeAddr("zoraRecipient");
19
+ address commentsAdmin = makeAddr("commentsAdmin");
20
+ address commenter = makeAddr("commenter");
21
+ address tokenAdmin = makeAddr("tokenAdmin");
22
+ address backfiller = makeAddr("backfiller");
23
+ address referrer = makeAddr("referrer");
24
+
25
+ uint256 internal constant ZORA_REWARD_PCT = 10;
26
+ uint256 internal constant REFERRER_REWARD_PCT = 20;
27
+ uint256 internal constant BPS_TO_PERCENT_2_DECIMAL_PERCISION = 100;
28
+
29
+ uint256 tokenId1 = 1;
30
+
31
+ address constant protocolRewards = 0x7777777F279eba3d3Ad8F4E708545291A6fDBA8B;
32
+ MockDelegateCommenter mockDelegateCommenter;
33
+
34
+ function setUp() public {
35
+ vm.createSelectFork("zora_sepolia", 14562731);
36
+
37
+ CommentsImpl commentsImpl = new CommentsImpl(SPARKS_VALUE, protocolRewards, zoraRecipient);
38
+
39
+ comments = CommentsImpl(payable(address(new Comments(address(commentsImpl)))));
40
+
41
+ mockDelegateCommenter = new MockDelegateCommenter(address(comments));
42
+
43
+ address[] memory delegateCommenters = new address[](1);
44
+ delegateCommenters[0] = address(mockDelegateCommenter);
45
+ comments.initialize({defaultAdmin: commentsAdmin, backfiller: backfiller, delegateCommenters: delegateCommenters});
46
+
47
+ mock1155 = new Mock1155();
48
+
49
+ mock1155.createToken(tokenId1, tokenAdmin);
50
+ }
51
+
52
+ function _expectedCommentIdentifier(
53
+ address _commenter,
54
+ address contractAddress,
55
+ uint256 tokenId
56
+ ) internal view returns (IComments.CommentIdentifier memory) {
57
+ return IComments.CommentIdentifier({commenter: _commenter, contractAddress: contractAddress, tokenId: tokenId, nonce: comments.nextNonce()});
58
+ }
59
+
60
+ function testCanDelegateCommentWithSparks() public {
61
+ uint256 quantityToMint = 1;
62
+ uint256 mintFee = 0.000111 ether;
63
+
64
+ address contractAddress = address(mock1155);
65
+ uint256 tokenId = tokenId1;
66
+
67
+ IComments.CommentIdentifier memory emptyReplyTo;
68
+
69
+ IComments.CommentIdentifier memory expectedCommentIdentifier = _expectedCommentIdentifier(commenter, contractAddress, tokenId);
70
+
71
+ bytes32 expectedCommentId = comments.hashCommentIdentifier(expectedCommentIdentifier);
72
+ bytes32 expectedReplyToId = bytes32(0);
73
+
74
+ vm.deal(commenter, mintFee * quantityToMint + SPARKS_VALUE);
75
+ vm.expectEmit(true, true, true, true);
76
+ emit IComments.Commented(
77
+ expectedCommentId,
78
+ _expectedCommentIdentifier(commenter, contractAddress, tokenId),
79
+ expectedReplyToId,
80
+ emptyReplyTo,
81
+ 1,
82
+ "test",
83
+ block.timestamp,
84
+ referrer
85
+ );
86
+ vm.prank(commenter);
87
+ mockDelegateCommenter.mintAndCommentWithSpark{value: SPARKS_VALUE + mintFee * quantityToMint}({
88
+ quantity: quantityToMint,
89
+ collection: address(mock1155),
90
+ tokenId: tokenId1,
91
+ comment: "test",
92
+ referrer: referrer,
93
+ sparksQuantity: 1
94
+ });
95
+
96
+ // validate that the protocol creator received rewards
97
+ uint256 zoraReward = (SPARKS_VALUE * (ZORA_REWARD_PCT)) / BPS_TO_PERCENT_2_DECIMAL_PERCISION;
98
+ uint256 referrerReward = (SPARKS_VALUE * (REFERRER_REWARD_PCT)) / BPS_TO_PERCENT_2_DECIMAL_PERCISION;
99
+ vm.assertEq(comments.protocolRewards().balanceOf(zoraRecipient), zoraReward);
100
+ vm.assertEq(comments.protocolRewards().balanceOf(referrer), referrerReward);
101
+ vm.assertEq(comments.protocolRewards().balanceOf(tokenAdmin), SPARKS_VALUE - zoraReward - referrerReward);
102
+ }
103
+
104
+ function testDelegateCommentRevertsWhenMoreThanOneSpark() public {
105
+ uint256 quantityToMint = 1;
106
+ uint256 mintFee = 0.000111 ether;
107
+
108
+ uint256 sparksQuantity = 2;
109
+ vm.deal(commenter, mintFee * quantityToMint + SPARKS_VALUE * sparksQuantity);
110
+
111
+ vm.prank(commenter);
112
+ vm.expectRevert(abi.encodeWithSelector(IComments.IncorrectETHAmountForSparks.selector, SPARKS_VALUE * sparksQuantity, SPARKS_VALUE));
113
+ mockDelegateCommenter.mintAndCommentWithSpark{value: SPARKS_VALUE * sparksQuantity + mintFee * quantityToMint}({
114
+ quantity: quantityToMint,
115
+ collection: address(mock1155),
116
+ tokenId: tokenId1,
117
+ comment: "test",
118
+ referrer: referrer,
119
+ sparksQuantity: sparksQuantity
120
+ });
121
+ }
122
+
123
+ function test_delegateComment_revertsWhenNotOwnerOrCreator() public {
124
+ address notOwner = makeAddr("notOwner");
125
+ vm.prank(notOwner);
126
+ vm.expectRevert(IComments.NotTokenHolderOrAdmin.selector);
127
+ mockDelegateCommenter.forwardComment(address(mock1155), tokenId1, "test");
128
+ }
129
+ }