@zoralabs/comments-contracts 0.0.1

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 (140) hide show
  1. package/.env.example +11 -0
  2. package/.turbo/turbo-build.log +60 -0
  3. package/LICENSE +21 -0
  4. package/README.md +70 -0
  5. package/_imagine/Enjoy.sol +41 -0
  6. package/abis/AccessControlUpgradeable.json +250 -0
  7. package/abis/Address.json +29 -0
  8. package/abis/Comments.json +62 -0
  9. package/abis/CommentsDeployerBase.json +15 -0
  10. package/abis/CommentsImpl.json +1750 -0
  11. package/abis/CommentsPermitTest.json +847 -0
  12. package/abis/CommentsTest.json +986 -0
  13. package/abis/CommentsTestBase.json +577 -0
  14. package/abis/Comments_mintAndCommentTest.json +690 -0
  15. package/abis/ContextUpgradeable.json +25 -0
  16. package/abis/ContractVersionBase.json +15 -0
  17. package/abis/Create2.json +28 -0
  18. package/abis/DeployImpl.json +22 -0
  19. package/abis/DeployNonDeterministic.json +22 -0
  20. package/abis/DeployScript.json +22 -0
  21. package/abis/DeterministicDeployerAndCaller.json +315 -0
  22. package/abis/DeterministicUUPSProxyDeployer.json +167 -0
  23. package/abis/ECDSA.json +29 -0
  24. package/abis/EIP712.json +67 -0
  25. package/abis/EIP712UpgradeableWithChainId.json +25 -0
  26. package/abis/ERC1155.json +416 -0
  27. package/abis/ERC1155Holder.json +99 -0
  28. package/abis/ERC165.json +21 -0
  29. package/abis/ERC165Upgradeable.json +44 -0
  30. package/abis/ERC1967Proxy.json +67 -0
  31. package/abis/ERC1967Utils.json +85 -0
  32. package/abis/GenerateDeterministicParams.json +22 -0
  33. package/abis/IAccessControl.json +195 -0
  34. package/abis/IBeacon.json +15 -0
  35. package/abis/IComments.json +654 -0
  36. package/abis/IContractMetadata.json +28 -0
  37. package/abis/IERC1155.json +295 -0
  38. package/abis/IERC1155Errors.json +104 -0
  39. package/abis/IERC1155MetadataURI.json +314 -0
  40. package/abis/IERC1155Receiver.json +99 -0
  41. package/abis/IERC1271.json +26 -0
  42. package/abis/IERC165.json +21 -0
  43. package/abis/IERC1822Proxiable.json +15 -0
  44. package/abis/IERC20.json +224 -0
  45. package/abis/IERC20Errors.json +88 -0
  46. package/abis/IERC5267.json +51 -0
  47. package/abis/IERC721.json +287 -0
  48. package/abis/IERC721Enumerable.json +343 -0
  49. package/abis/IERC721Errors.json +105 -0
  50. package/abis/IERC721Metadata.json +332 -0
  51. package/abis/IERC721TokenReceiver.json +36 -0
  52. package/abis/IHasContractName.json +15 -0
  53. package/abis/IImmutableCreate2Factory.json +93 -0
  54. package/abis/IMulticall3.json +440 -0
  55. package/abis/IProtocolRewards.json +342 -0
  56. package/abis/ISafe.json +15 -0
  57. package/abis/ISymbol.json +15 -0
  58. package/abis/IVersionedContract.json +15 -0
  59. package/abis/IZoraCreator1155.json +343 -0
  60. package/abis/ImmutableCreate2FactoryUtils.json +15 -0
  61. package/abis/Initializable.json +25 -0
  62. package/abis/LibString.json +7 -0
  63. package/abis/Math.json +7 -0
  64. package/abis/Mock1155.json +547 -0
  65. package/abis/MockERC20.json +322 -0
  66. package/abis/MockERC721.json +350 -0
  67. package/abis/MockMinter.json +64 -0
  68. package/abis/OwnableUpgradeable.json +99 -0
  69. package/abis/ProtocolRewards.json +494 -0
  70. package/abis/Proxy.json +6 -0
  71. package/abis/ProxyDeployerScript.json +15 -0
  72. package/abis/ProxyShim.json +112 -0
  73. package/abis/Script.json +15 -0
  74. package/abis/ShortStrings.json +18 -0
  75. package/abis/StdAssertions.json +379 -0
  76. package/abis/StdInvariant.json +180 -0
  77. package/abis/Strings.json +18 -0
  78. package/abis/Test.json +570 -0
  79. package/abis/UUPSUpgradeable.json +130 -0
  80. package/abis/UnorderedNoncesUpgradeable.json +42 -0
  81. package/abis/Vm.json +8627 -0
  82. package/abis/VmSafe.json +7297 -0
  83. package/abis/stdError.json +119 -0
  84. package/abis/stdStorageSafe.json +52 -0
  85. package/addresses/999999999.json +4 -0
  86. package/deterministicConfig/comments.json +8 -0
  87. package/dist/index.cjs +935 -0
  88. package/dist/index.cjs.map +1 -0
  89. package/dist/index.d.ts +2 -0
  90. package/dist/index.d.ts.map +1 -0
  91. package/dist/index.js +908 -0
  92. package/dist/index.js.map +1 -0
  93. package/dist/types.d.ts +4 -0
  94. package/dist/types.d.ts.map +1 -0
  95. package/dist/wagmiGenerated.d.ts +1354 -0
  96. package/dist/wagmiGenerated.d.ts.map +1 -0
  97. package/foundry.toml +24 -0
  98. package/package/index.ts +4 -0
  99. package/package/types.ts +5 -0
  100. package/package/wagmiGenerated.ts +907 -0
  101. package/package.json +62 -0
  102. package/remappings.txt +8 -0
  103. package/script/CommentsDeployerBase.sol +60 -0
  104. package/script/Deploy.s.sol +66 -0
  105. package/script/DeployImpl.s.sol +26 -0
  106. package/script/DeployNonDeterministic.s.sol +43 -0
  107. package/script/GenerateDeterministicParams.s.sol +55 -0
  108. package/script/bundle-abis.ts +109 -0
  109. package/script/storage-check.sh +57 -0
  110. package/script/update-contract-version.ts +63 -0
  111. package/scripts/abis.ts +3 -0
  112. package/scripts/backfillComments.ts +176 -0
  113. package/scripts/generateCommentsTestData.ts +247 -0
  114. package/scripts/getCommentsAddresses.ts +10 -0
  115. package/scripts/queries.ts +73 -0
  116. package/scripts/queryAndSaveComments.ts +48 -0
  117. package/scripts/queryQuantityOfComments.ts +53 -0
  118. package/scripts/signDeployAndCall.ts +51 -0
  119. package/scripts/turnkey.ts +36 -0
  120. package/scripts/utils.ts +127 -0
  121. package/scripts/writeComments.ts +198 -0
  122. package/slither.config.json +7 -0
  123. package/src/CommentsImpl.sol +552 -0
  124. package/src/deployments/CommentsDeployment.sol +14 -0
  125. package/src/interfaces/IComments.sol +156 -0
  126. package/src/interfaces/IZoraCreator1155.sol +12 -0
  127. package/src/proxy/Comments.sol +43 -0
  128. package/src/utils/EIP712UpgradeableWithChainId.sol +36 -0
  129. package/src/version/ContractVersionBase.sol +14 -0
  130. package/test/Comments.t.sol +482 -0
  131. package/test/CommentsTestBase.sol +86 -0
  132. package/test/Comments_mintAndComment.t.sol +101 -0
  133. package/test/Comments_permit.t.sol +397 -0
  134. package/test/mocks/Mock1155.sol +50 -0
  135. package/test/mocks/MockMinter.sol +29 -0
  136. package/test/mocks/ProtocolRewards.sol +1497 -0
  137. package/tsconfig.build.json +10 -0
  138. package/tsconfig.json +9 -0
  139. package/tsup.config.ts +11 -0
  140. package/wagmi.config.ts +14 -0
@@ -0,0 +1,397 @@
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 {IProtocolRewards} from "@zoralabs/protocol-rewards/src/interfaces/IProtocolRewards.sol";
11
+ import {ProtocolRewards} from "./mocks/ProtocolRewards.sol";
12
+ import {CommentsTestBase} from "./CommentsTestBase.sol";
13
+ import {UnorderedNoncesUpgradeable} from "@zoralabs/shared-contracts/utils/UnorderedNoncesUpgradeable.sol";
14
+
15
+ contract CommentsPermitTest is CommentsTestBase {
16
+ function testPermitComment() public {
17
+ IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment", 3);
18
+ bytes memory signature = _signPermitComment(permitComment, collectorWithTokenPrivateKey);
19
+
20
+ IComments.CommentIdentifier memory expectedCommentIdentifier = _expectedCommentIdentifier(
21
+ permitComment.contractAddress,
22
+ permitComment.tokenId,
23
+ permitComment.commenter
24
+ );
25
+
26
+ _setupTokenAndSparks(permitComment);
27
+
28
+ // any account can execute the permit comment on behalf of the collectorWithToken, but they must have enough eth to do so.
29
+ address executor = makeAddr("executor");
30
+ vm.deal(executor, permitComment.sparksQuantity * SPARKS_VALUE);
31
+
32
+ vm.expectEmit(true, true, true, true);
33
+ emit IComments.Commented(
34
+ comments.hashCommentIdentifier(expectedCommentIdentifier),
35
+ expectedCommentIdentifier,
36
+ bytes32(0),
37
+ permitComment.replyTo,
38
+ permitComment.sparksQuantity,
39
+ permitComment.text,
40
+ block.timestamp,
41
+ permitComment.referrer
42
+ );
43
+
44
+ _executePermitComment(executor, permitComment, signature);
45
+
46
+ _assertCommentExists(expectedCommentIdentifier);
47
+ }
48
+
49
+ function testPermitComment_NonceUsedTwice() public {
50
+ IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment", 3);
51
+ bytes memory signature = _signPermitComment(permitComment, collectorWithTokenPrivateKey);
52
+
53
+ _setupTokenAndSparks(permitComment);
54
+
55
+ // First comment should succeed
56
+ vm.deal(collectorWithToken, 10 ether);
57
+ _executePermitComment(collectorWithToken, permitComment, signature);
58
+
59
+ // Second comment with same nonce should fail
60
+ vm.expectRevert(abi.encodeWithSelector(UnorderedNoncesUpgradeable.InvalidAccountNonce.selector, collectorWithToken, permitComment.nonce));
61
+ _executePermitComment(collectorWithToken, permitComment, signature);
62
+ }
63
+
64
+ function testPermitComment_DeadlineExpired() public {
65
+ IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment", 3);
66
+ bytes memory signature = _signPermitComment(permitComment, collectorWithTokenPrivateKey);
67
+
68
+ _setupTokenAndSparks(permitComment);
69
+
70
+ // Warp time to after the deadline
71
+ vm.warp(permitComment.deadline + 1);
72
+
73
+ address executor = makeAddr("executor");
74
+ vm.deal(executor, permitComment.sparksQuantity * SPARKS_VALUE);
75
+ vm.expectRevert(abi.encodeWithSelector(IComments.ERC2612ExpiredSignature.selector, permitComment.deadline));
76
+ _executePermitComment(executor, permitComment, signature);
77
+ }
78
+
79
+ function testPermitComment_CommenterDoesntMatchSigner() public {
80
+ address wrongSigner;
81
+ uint256 wrongSignerPrivateKey;
82
+ (wrongSigner, wrongSignerPrivateKey) = makeAddrAndKey("wrongSigner");
83
+
84
+ IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment", 3);
85
+ bytes memory wrongSignature = _signPermitComment(permitComment, wrongSignerPrivateKey);
86
+
87
+ _setupTokenAndSparks(permitComment);
88
+
89
+ vm.expectRevert(IComments.InvalidSignature.selector);
90
+ _executePermitComment(collectorWithToken, permitComment, wrongSignature);
91
+ }
92
+
93
+ function testPermitComment_ZeroSparks() public {
94
+ IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment", 0);
95
+ bytes memory signature = _signPermitComment(permitComment, collectorWithTokenPrivateKey);
96
+
97
+ _setupTokenAndSparks(permitComment);
98
+
99
+ vm.expectRevert(IComments.MustSendAtLeastOneSpark.selector);
100
+ _executePermitComment(collectorWithToken, permitComment, signature);
101
+ }
102
+
103
+ function testPermitComment_Not1155Holder() public {
104
+ IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment", 3);
105
+ bytes memory signature = _signPermitComment(permitComment, collectorWithTokenPrivateKey);
106
+
107
+ address executor = makeAddr("executor");
108
+ vm.deal(executor, permitComment.sparksQuantity * SPARKS_VALUE);
109
+ vm.expectRevert(IComments.NotTokenHolderOrAdmin.selector);
110
+ _executePermitComment(executor, permitComment, signature);
111
+ }
112
+
113
+ function testPermitSparkCommentSparksComment() public {
114
+ IComments.PermitSparkComment memory permitSparkComment = _postCommentAndCreatePermitSparkComment(sparker, 3);
115
+ bytes memory signature = _signPermitSparkComment(permitSparkComment, sparkerPrivateKey);
116
+
117
+ _setupSparkComment(permitSparkComment);
118
+
119
+ address executor = makeAddr("executor");
120
+ vm.deal(executor, permitSparkComment.sparksQuantity * SPARKS_VALUE);
121
+
122
+ bytes32 commentId = comments.hashCommentIdentifier(permitSparkComment.comment);
123
+
124
+ uint256 beforeSparksCount = comments.commentSparksQuantity(commentId);
125
+
126
+ vm.expectEmit(true, true, true, true);
127
+ emit IComments.SparkedComment(commentId, permitSparkComment.comment, permitSparkComment.sparksQuantity, sparker, block.timestamp);
128
+
129
+ _executePermitSparkComment(executor, permitSparkComment, signature);
130
+
131
+ uint256 afterSparksCount = comments.commentSparksQuantity(commentId);
132
+ assertEq(afterSparksCount, beforeSparksCount + permitSparkComment.sparksQuantity);
133
+ }
134
+
135
+ function testPermitSparkComment_NonceUsedTwice() public {
136
+ IComments.PermitSparkComment memory permitSparkComment = _postCommentAndCreatePermitSparkComment(sparker, 3);
137
+ bytes memory signature = _signPermitSparkComment(permitSparkComment, sparkerPrivateKey);
138
+
139
+ _setupSparkComment(permitSparkComment);
140
+
141
+ // First spark should succeed
142
+ vm.deal(sparker, 10 ether);
143
+ _executePermitSparkComment(sparker, permitSparkComment, signature);
144
+
145
+ // Second spark with same nonce should fail
146
+ vm.expectRevert(abi.encodeWithSelector(UnorderedNoncesUpgradeable.InvalidAccountNonce.selector, sparker, permitSparkComment.nonce));
147
+ _executePermitSparkComment(sparker, permitSparkComment, signature);
148
+ }
149
+
150
+ function testPermitSparkComment_DeadlineExpired() public {
151
+ IComments.PermitSparkComment memory permitSparkComment = _postCommentAndCreatePermitSparkComment(sparker, 3);
152
+ bytes memory signature = _signPermitSparkComment(permitSparkComment, sparkerPrivateKey);
153
+
154
+ _setupSparkComment(permitSparkComment);
155
+
156
+ // Warp time to after the deadline
157
+ vm.warp(permitSparkComment.deadline + 1);
158
+
159
+ address executor = makeAddr("executor");
160
+ vm.deal(executor, permitSparkComment.sparksQuantity * SPARKS_VALUE);
161
+ vm.expectRevert(abi.encodeWithSelector(IComments.ERC2612ExpiredSignature.selector, permitSparkComment.deadline));
162
+ _executePermitSparkComment(executor, permitSparkComment, signature);
163
+ }
164
+
165
+ function testPermitSparkComment_CommenterDoesntMatchSigner() public {
166
+ address wrongSigner;
167
+ uint256 wrongSignerPrivateKey;
168
+ (wrongSigner, wrongSignerPrivateKey) = makeAddrAndKey("wrongSigner");
169
+
170
+ IComments.PermitSparkComment memory permitSparkComment = _postCommentAndCreatePermitSparkComment(sparker, 3);
171
+ bytes memory wrongSignature = _signPermitSparkComment(permitSparkComment, wrongSignerPrivateKey);
172
+
173
+ _setupSparkComment(permitSparkComment);
174
+
175
+ vm.expectRevert(IComments.InvalidSignature.selector);
176
+ _executePermitSparkComment(makeAddr("executor"), permitSparkComment, wrongSignature);
177
+ }
178
+
179
+ function testPermitSparkComment_ZeroSparks() public {
180
+ IComments.PermitSparkComment memory permitSparkComment = _postCommentAndCreatePermitSparkComment(sparker, 0);
181
+ bytes memory signature = _signPermitSparkComment(permitSparkComment, sparkerPrivateKey);
182
+
183
+ _setupSparkComment(permitSparkComment);
184
+
185
+ vm.expectRevert(IComments.MustSendAtLeastOneSpark.selector);
186
+ _executePermitSparkComment(collectorWithToken, permitSparkComment, signature);
187
+ }
188
+
189
+ function testPermitSparkComment_IncorrectETHAmount() public {
190
+ IComments.PermitSparkComment memory permitSparkComment = _postCommentAndCreatePermitSparkComment(sparker, 3);
191
+ bytes memory signature = _signPermitSparkComment(permitSparkComment, sparkerPrivateKey);
192
+
193
+ _setupSparkComment(permitSparkComment);
194
+
195
+ address executor = makeAddr("executor");
196
+ uint256 incorrectValue = (permitSparkComment.sparksQuantity * SPARKS_VALUE) + 1 wei;
197
+ vm.deal(executor, incorrectValue);
198
+
199
+ vm.expectRevert(
200
+ abi.encodeWithSelector(IComments.IncorrectETHAmountForSparks.selector, incorrectValue, permitSparkComment.sparksQuantity * SPARKS_VALUE)
201
+ );
202
+ vm.prank(executor);
203
+ comments.permitSparkComment{value: incorrectValue}(permitSparkComment, signature);
204
+ }
205
+
206
+ function testPermitCommentCrossChain() public {
207
+ uint256 sourceChainId = 1; // Ethereum mainnet
208
+ uint256 destinationChainId = block.chainid;
209
+
210
+ IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "cross-chain comment", 3);
211
+ permitComment.sourceChainId = sourceChainId;
212
+ permitComment.destinationChainId = destinationChainId;
213
+
214
+ IComments.CommentIdentifier memory expectedCommentIdentifier = _expectedCommentIdentifier(
215
+ permitComment.contractAddress,
216
+ permitComment.tokenId,
217
+ permitComment.commenter
218
+ );
219
+
220
+ bytes memory signature = _signPermitComment(permitComment, collectorWithTokenPrivateKey);
221
+
222
+ _setupTokenAndSparks(permitComment);
223
+
224
+ address executor = makeAddr("executor");
225
+ vm.deal(executor, permitComment.sparksQuantity * SPARKS_VALUE);
226
+
227
+ vm.expectEmit(true, true, true, true);
228
+ emit IComments.Commented(
229
+ comments.hashCommentIdentifier(expectedCommentIdentifier),
230
+ expectedCommentIdentifier,
231
+ bytes32(0),
232
+ permitComment.replyTo,
233
+ permitComment.sparksQuantity,
234
+ permitComment.text,
235
+ block.timestamp,
236
+ permitComment.referrer
237
+ );
238
+
239
+ _executePermitComment(executor, permitComment, signature);
240
+
241
+ _assertCommentExists(expectedCommentIdentifier);
242
+ }
243
+
244
+ function testPermitCommentCrossChainInvalidDestination() public {
245
+ uint256 sourceChainId = 1; // Ethereum mainnet
246
+ uint256 invalidDestinationChainId = 42; // Some other chain ID
247
+
248
+ IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "invalid cross-chain comment", 3);
249
+ permitComment.sourceChainId = sourceChainId;
250
+ permitComment.destinationChainId = invalidDestinationChainId;
251
+
252
+ bytes memory signature = _signPermitComment(permitComment, collectorWithTokenPrivateKey);
253
+
254
+ _setupTokenAndSparks(permitComment);
255
+
256
+ address executor = makeAddr("executor");
257
+ vm.deal(executor, permitComment.sparksQuantity * SPARKS_VALUE);
258
+
259
+ vm.expectRevert(abi.encodeWithSelector(IComments.IncorrectDestinationChain.selector, invalidDestinationChainId));
260
+ _executePermitComment(executor, permitComment, signature);
261
+ }
262
+
263
+ function testPermitSparkCommentCrossChain() public {
264
+ uint256 sourceChainId = 1; // Ethereum mainnet
265
+ uint256 destinationChainId = block.chainid;
266
+
267
+ IComments.PermitSparkComment memory permitSparkComment = _postCommentAndCreatePermitSparkComment(sparker, 3);
268
+ permitSparkComment.sourceChainId = sourceChainId;
269
+ permitSparkComment.destinationChainId = destinationChainId;
270
+
271
+ bytes memory signature = _signPermitSparkComment(permitSparkComment, sparkerPrivateKey);
272
+
273
+ _setupSparkComment(permitSparkComment);
274
+
275
+ address executor = makeAddr("executor");
276
+ vm.deal(executor, permitSparkComment.sparksQuantity * SPARKS_VALUE);
277
+
278
+ bytes32 commentId = comments.hashCommentIdentifier(permitSparkComment.comment);
279
+
280
+ uint256 beforeSparksCount = comments.commentSparksQuantity(commentId);
281
+
282
+ vm.expectEmit(true, true, true, true);
283
+ emit IComments.SparkedComment(commentId, permitSparkComment.comment, permitSparkComment.sparksQuantity, sparker, block.timestamp);
284
+
285
+ _executePermitSparkComment(executor, permitSparkComment, signature);
286
+
287
+ uint256 afterSparksCount = comments.commentSparksQuantity(commentId);
288
+ assertEq(afterSparksCount, beforeSparksCount + permitSparkComment.sparksQuantity);
289
+ }
290
+
291
+ function testPermitSparkCommentCrossChainInvalidDestination() public {
292
+ uint256 sourceChainId = 1; // Ethereum mainnet
293
+ uint256 invalidDestinationChainId = 42; // Some other chain ID
294
+
295
+ IComments.PermitSparkComment memory permitSparkComment = _postCommentAndCreatePermitSparkComment(sparker, 3);
296
+ permitSparkComment.sourceChainId = sourceChainId;
297
+ permitSparkComment.destinationChainId = invalidDestinationChainId;
298
+
299
+ bytes memory signature = _signPermitSparkComment(permitSparkComment, sparkerPrivateKey);
300
+
301
+ _setupSparkComment(permitSparkComment);
302
+
303
+ address executor = makeAddr("executor");
304
+ vm.deal(executor, permitSparkComment.sparksQuantity * SPARKS_VALUE);
305
+
306
+ vm.expectRevert(abi.encodeWithSelector(IComments.IncorrectDestinationChain.selector, invalidDestinationChainId));
307
+ _executePermitSparkComment(executor, permitSparkComment, signature);
308
+ }
309
+
310
+ function _postCommentAndCreatePermitSparkComment(address _sparker, uint64 sparksQuantity) internal returns (IComments.PermitSparkComment memory) {
311
+ IComments.CommentIdentifier memory emptyReplyTo;
312
+ address commenter = makeAddr("commenter_b");
313
+ IComments.CommentIdentifier memory commentIdentifier = _mockComment(commenter, emptyReplyTo);
314
+
315
+ return _createPermitSparkComment(commentIdentifier, _sparker, sparksQuantity, block.chainid, block.chainid);
316
+ }
317
+
318
+ // Helper functions
319
+ function _createPermitSparkComment(
320
+ IComments.CommentIdentifier memory commentIdentifier,
321
+ address _sparker,
322
+ uint64 sparksQuantity,
323
+ uint256 sourceChainId,
324
+ uint256 destinationChainId
325
+ ) internal returns (IComments.PermitSparkComment memory) {
326
+ return
327
+ IComments.PermitSparkComment({
328
+ comment: commentIdentifier,
329
+ sparker: _sparker,
330
+ sparksQuantity: sparksQuantity,
331
+ deadline: block.timestamp + 100,
332
+ nonce: bytes32("1"),
333
+ referrer: makeAddr("referrer"),
334
+ sourceChainId: sourceChainId,
335
+ destinationChainId: destinationChainId
336
+ });
337
+ }
338
+
339
+ function _signPermitSparkComment(IComments.PermitSparkComment memory permitSparkComment, uint256 privateKey) internal view returns (bytes memory) {
340
+ bytes32 digest = comments.hashPermitSparkComment(permitSparkComment);
341
+ return _sign(privateKey, digest);
342
+ }
343
+
344
+ function _setupSparkComment(IComments.PermitSparkComment memory permitSparkComment) internal {
345
+ // For permitSparkComment, we don't need to mint a token
346
+ vm.deal(permitSparkComment.comment.commenter, permitSparkComment.sparksQuantity * SPARKS_VALUE);
347
+ }
348
+
349
+ function _executePermitSparkComment(address executor, IComments.PermitSparkComment memory permitSparkComment, bytes memory signature) internal {
350
+ vm.prank(executor);
351
+ vm.deal(executor, permitSparkComment.sparksQuantity * SPARKS_VALUE);
352
+ comments.permitSparkComment{value: permitSparkComment.sparksQuantity * SPARKS_VALUE}(permitSparkComment, signature);
353
+ }
354
+
355
+ // Helper functions
356
+ function _createPermitComment(address commenter, string memory text, uint64 sparksQuantity) internal returns (IComments.PermitComment memory) {
357
+ return
358
+ IComments.PermitComment({
359
+ contractAddress: address(mock1155),
360
+ tokenId: tokenId1,
361
+ commenter: commenter,
362
+ replyTo: emptyCommentIdentifier,
363
+ text: text,
364
+ sparksQuantity: sparksQuantity,
365
+ deadline: block.timestamp + 100,
366
+ nonce: bytes32("1"),
367
+ referrer: makeAddr("referrer"),
368
+ sourceChainId: block.chainid,
369
+ destinationChainId: block.chainid
370
+ });
371
+ }
372
+
373
+ function _setupTokenAndSparks(IComments.PermitComment memory permitComment) internal {
374
+ mock1155.mint(permitComment.commenter, permitComment.tokenId, 1, "");
375
+ vm.deal(permitComment.commenter, permitComment.sparksQuantity * SPARKS_VALUE);
376
+ }
377
+
378
+ function _executePermitComment(address executor, IComments.PermitComment memory permitComment, bytes memory signature) internal {
379
+ vm.prank(executor);
380
+ comments.permitComment{value: permitComment.sparksQuantity * SPARKS_VALUE}(permitComment, signature);
381
+ }
382
+
383
+ function _assertCommentExists(IComments.CommentIdentifier memory commentIdentifier) internal view {
384
+ (, bool exists) = comments.hashAndCheckCommentExists(commentIdentifier);
385
+ assertTrue(exists);
386
+ }
387
+
388
+ function _signPermitComment(IComments.PermitComment memory permitComment, uint256 privateKey) internal view returns (bytes memory signature) {
389
+ bytes32 digest = comments.hashPermitComment(permitComment);
390
+ signature = _sign(privateKey, digest);
391
+ }
392
+
393
+ function _sign(uint256 privateKey, bytes32 digest) internal pure returns (bytes memory signature) {
394
+ (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);
395
+ return abi.encodePacked(r, s, v);
396
+ }
397
+ }
@@ -0,0 +1,50 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.20;
3
+
4
+ import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
5
+ import {IZoraCreator1155} from "../../src/interfaces/IZoraCreator1155.sol";
6
+
7
+ contract Mock1155 is ERC1155, IZoraCreator1155 {
8
+ /// @notice This user role allows for any action to be performed
9
+ uint256 public constant PERMISSION_BIT_ADMIN = 2 ** 1;
10
+
11
+ mapping(uint256 => address) public admins;
12
+
13
+ constructor() ERC1155("") {}
14
+
15
+ function isAdminOrRole(address user, uint256 tokenId, uint256 role) external view returns (bool) {
16
+ if (admins[tokenId] == user && role == PERMISSION_BIT_ADMIN) {
17
+ return true;
18
+ } else {
19
+ return false;
20
+ }
21
+ }
22
+
23
+ function _tokenExists(uint256 tokenId) internal view returns (bool) {
24
+ return admins[tokenId] != address(0);
25
+ }
26
+
27
+ function getCreatorRewardRecipient(uint256 tokenId) external view returns (address) {
28
+ if (!_tokenExists(tokenId)) {
29
+ revert("Token does not exist");
30
+ }
31
+
32
+ return admins[tokenId];
33
+ }
34
+
35
+ function createToken(uint256 tokenId, address creator) external {
36
+ admins[tokenId] = creator;
37
+ }
38
+
39
+ function supportsInterface(bytes4 interfaceId) public view override(ERC1155, IZoraCreator1155) returns (bool) {
40
+ return super.supportsInterface(interfaceId);
41
+ }
42
+
43
+ function mint(address to, uint256 id, uint256 amount, bytes memory data) external {
44
+ if (!_tokenExists(id)) {
45
+ revert("Token does not exist");
46
+ }
47
+
48
+ _mint(to, id, amount, data);
49
+ }
50
+ }
@@ -0,0 +1,29 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.20;
3
+
4
+ import {Mock1155} from "./Mock1155.sol";
5
+ import {IComments} from "../../src/interfaces/IComments.sol";
6
+
7
+ contract MockMinter {
8
+ uint256 MINT_FEE = 0.00111 ether;
9
+ uint256 constant SPARKS_VALUE = 0.000001 ether;
10
+
11
+ IComments immutable comments;
12
+
13
+ constructor(IComments _comments) {
14
+ comments = _comments;
15
+ }
16
+
17
+ IComments.CommentIdentifier internal emptyCommentIdentifier;
18
+
19
+ function mintAndComment(uint256 quantity, address collection, uint256 tokenId, string calldata comment) external payable {
20
+ Mock1155(collection).mint(msg.sender, tokenId, quantity, "");
21
+
22
+ // get sparks value to send to comments contract
23
+ comments.delegateComment(msg.sender, collection, tokenId, comment, emptyCommentIdentifier);
24
+ }
25
+
26
+ function forwardComment(address collection, uint256 tokenId, string calldata comment) external {
27
+ comments.delegateComment(msg.sender, collection, tokenId, comment, emptyCommentIdentifier);
28
+ }
29
+ }