@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.
- package/.env.example +11 -0
- package/.turbo/turbo-build.log +60 -0
- package/LICENSE +21 -0
- package/README.md +70 -0
- package/_imagine/Enjoy.sol +41 -0
- package/abis/AccessControlUpgradeable.json +250 -0
- package/abis/Address.json +29 -0
- package/abis/Comments.json +62 -0
- package/abis/CommentsDeployerBase.json +15 -0
- package/abis/CommentsImpl.json +1750 -0
- package/abis/CommentsPermitTest.json +847 -0
- package/abis/CommentsTest.json +986 -0
- package/abis/CommentsTestBase.json +577 -0
- package/abis/Comments_mintAndCommentTest.json +690 -0
- package/abis/ContextUpgradeable.json +25 -0
- package/abis/ContractVersionBase.json +15 -0
- package/abis/Create2.json +28 -0
- package/abis/DeployImpl.json +22 -0
- package/abis/DeployNonDeterministic.json +22 -0
- package/abis/DeployScript.json +22 -0
- package/abis/DeterministicDeployerAndCaller.json +315 -0
- package/abis/DeterministicUUPSProxyDeployer.json +167 -0
- package/abis/ECDSA.json +29 -0
- package/abis/EIP712.json +67 -0
- package/abis/EIP712UpgradeableWithChainId.json +25 -0
- package/abis/ERC1155.json +416 -0
- package/abis/ERC1155Holder.json +99 -0
- package/abis/ERC165.json +21 -0
- package/abis/ERC165Upgradeable.json +44 -0
- package/abis/ERC1967Proxy.json +67 -0
- package/abis/ERC1967Utils.json +85 -0
- package/abis/GenerateDeterministicParams.json +22 -0
- package/abis/IAccessControl.json +195 -0
- package/abis/IBeacon.json +15 -0
- package/abis/IComments.json +654 -0
- package/abis/IContractMetadata.json +28 -0
- package/abis/IERC1155.json +295 -0
- package/abis/IERC1155Errors.json +104 -0
- package/abis/IERC1155MetadataURI.json +314 -0
- package/abis/IERC1155Receiver.json +99 -0
- package/abis/IERC1271.json +26 -0
- package/abis/IERC165.json +21 -0
- package/abis/IERC1822Proxiable.json +15 -0
- package/abis/IERC20.json +224 -0
- package/abis/IERC20Errors.json +88 -0
- package/abis/IERC5267.json +51 -0
- package/abis/IERC721.json +287 -0
- package/abis/IERC721Enumerable.json +343 -0
- package/abis/IERC721Errors.json +105 -0
- package/abis/IERC721Metadata.json +332 -0
- package/abis/IERC721TokenReceiver.json +36 -0
- package/abis/IHasContractName.json +15 -0
- package/abis/IImmutableCreate2Factory.json +93 -0
- package/abis/IMulticall3.json +440 -0
- package/abis/IProtocolRewards.json +342 -0
- package/abis/ISafe.json +15 -0
- package/abis/ISymbol.json +15 -0
- package/abis/IVersionedContract.json +15 -0
- package/abis/IZoraCreator1155.json +343 -0
- package/abis/ImmutableCreate2FactoryUtils.json +15 -0
- package/abis/Initializable.json +25 -0
- package/abis/LibString.json +7 -0
- package/abis/Math.json +7 -0
- package/abis/Mock1155.json +547 -0
- package/abis/MockERC20.json +322 -0
- package/abis/MockERC721.json +350 -0
- package/abis/MockMinter.json +64 -0
- package/abis/OwnableUpgradeable.json +99 -0
- package/abis/ProtocolRewards.json +494 -0
- package/abis/Proxy.json +6 -0
- package/abis/ProxyDeployerScript.json +15 -0
- package/abis/ProxyShim.json +112 -0
- package/abis/Script.json +15 -0
- package/abis/ShortStrings.json +18 -0
- package/abis/StdAssertions.json +379 -0
- package/abis/StdInvariant.json +180 -0
- package/abis/Strings.json +18 -0
- package/abis/Test.json +570 -0
- package/abis/UUPSUpgradeable.json +130 -0
- package/abis/UnorderedNoncesUpgradeable.json +42 -0
- package/abis/Vm.json +8627 -0
- package/abis/VmSafe.json +7297 -0
- package/abis/stdError.json +119 -0
- package/abis/stdStorageSafe.json +52 -0
- package/addresses/999999999.json +4 -0
- package/deterministicConfig/comments.json +8 -0
- package/dist/index.cjs +935 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +908 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/wagmiGenerated.d.ts +1354 -0
- package/dist/wagmiGenerated.d.ts.map +1 -0
- package/foundry.toml +24 -0
- package/package/index.ts +4 -0
- package/package/types.ts +5 -0
- package/package/wagmiGenerated.ts +907 -0
- package/package.json +62 -0
- package/remappings.txt +8 -0
- package/script/CommentsDeployerBase.sol +60 -0
- package/script/Deploy.s.sol +66 -0
- package/script/DeployImpl.s.sol +26 -0
- package/script/DeployNonDeterministic.s.sol +43 -0
- package/script/GenerateDeterministicParams.s.sol +55 -0
- package/script/bundle-abis.ts +109 -0
- package/script/storage-check.sh +57 -0
- package/script/update-contract-version.ts +63 -0
- package/scripts/abis.ts +3 -0
- package/scripts/backfillComments.ts +176 -0
- package/scripts/generateCommentsTestData.ts +247 -0
- package/scripts/getCommentsAddresses.ts +10 -0
- package/scripts/queries.ts +73 -0
- package/scripts/queryAndSaveComments.ts +48 -0
- package/scripts/queryQuantityOfComments.ts +53 -0
- package/scripts/signDeployAndCall.ts +51 -0
- package/scripts/turnkey.ts +36 -0
- package/scripts/utils.ts +127 -0
- package/scripts/writeComments.ts +198 -0
- package/slither.config.json +7 -0
- package/src/CommentsImpl.sol +552 -0
- package/src/deployments/CommentsDeployment.sol +14 -0
- package/src/interfaces/IComments.sol +156 -0
- package/src/interfaces/IZoraCreator1155.sol +12 -0
- package/src/proxy/Comments.sol +43 -0
- package/src/utils/EIP712UpgradeableWithChainId.sol +36 -0
- package/src/version/ContractVersionBase.sol +14 -0
- package/test/Comments.t.sol +482 -0
- package/test/CommentsTestBase.sol +86 -0
- package/test/Comments_mintAndComment.t.sol +101 -0
- package/test/Comments_permit.t.sol +397 -0
- package/test/mocks/Mock1155.sol +50 -0
- package/test/mocks/MockMinter.sol +29 -0
- package/test/mocks/ProtocolRewards.sol +1497 -0
- package/tsconfig.build.json +10 -0
- package/tsconfig.json +9 -0
- package/tsup.config.ts +11 -0
- package/wagmi.config.ts +14 -0
|
@@ -0,0 +1,482 @@
|
|
|
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 {UnorderedNoncesUpgradeable} from "@zoralabs/shared-contracts/utils/UnorderedNoncesUpgradeable.sol";
|
|
13
|
+
import {CommentsTestBase} from "./CommentsTestBase.sol";
|
|
14
|
+
|
|
15
|
+
contract CommentsTest is CommentsTestBase {
|
|
16
|
+
uint256 public constant ZORA_REWARD_PCT = 10;
|
|
17
|
+
uint256 public constant REFERRER_REWARD_PCT = 20;
|
|
18
|
+
uint256 internal constant BPS_TO_PERCENT_2_DECIMAL_PERCISION = 100;
|
|
19
|
+
|
|
20
|
+
function _setupCommenterWithTokenAndSparks(address commenter, uint64 sparksQuantity) internal {
|
|
21
|
+
vm.startPrank(commenter);
|
|
22
|
+
mock1155.mint(commenter, tokenId1, 1, "");
|
|
23
|
+
vm.stopPrank();
|
|
24
|
+
vm.deal(commenter, sparksQuantity * SPARKS_VALUE);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function _createCommentIdentifier(address commenter, bytes32 nonce) internal view returns (IComments.CommentIdentifier memory) {
|
|
28
|
+
return IComments.CommentIdentifier({commenter: commenter, contractAddress: address(mock1155), tokenId: tokenId1, nonce: nonce});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function testCommentContractName() public view {
|
|
32
|
+
assertEq(comments.contractName(), "Zora Comments");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function testCommentWhenCollectorHasTokenShouldEmitCommented() public {
|
|
36
|
+
vm.startPrank(collectorWithToken);
|
|
37
|
+
mock1155.mint(collectorWithToken, tokenId1, 1, "");
|
|
38
|
+
vm.stopPrank();
|
|
39
|
+
|
|
40
|
+
vm.deal(collectorWithToken, SPARKS_VALUE);
|
|
41
|
+
|
|
42
|
+
address contractAddress = address(mock1155);
|
|
43
|
+
uint256 tokenId = tokenId1;
|
|
44
|
+
address commenter = collectorWithToken;
|
|
45
|
+
|
|
46
|
+
IComments.CommentIdentifier memory expectedCommentIdentifier = _expectedCommentIdentifier(contractAddress, tokenId, commenter);
|
|
47
|
+
|
|
48
|
+
// blank replyTo
|
|
49
|
+
IComments.CommentIdentifier memory replyTo;
|
|
50
|
+
|
|
51
|
+
vm.expectEmit(true, true, true, true);
|
|
52
|
+
emit IComments.Commented(
|
|
53
|
+
comments.hashCommentIdentifier(expectedCommentIdentifier),
|
|
54
|
+
expectedCommentIdentifier,
|
|
55
|
+
0,
|
|
56
|
+
replyTo,
|
|
57
|
+
1,
|
|
58
|
+
"test comment",
|
|
59
|
+
block.timestamp,
|
|
60
|
+
address(0)
|
|
61
|
+
);
|
|
62
|
+
vm.prank(collectorWithToken);
|
|
63
|
+
comments.comment{value: SPARKS_VALUE}(collectorWithToken, contractAddress, tokenId, "test comment", replyTo, address(0));
|
|
64
|
+
|
|
65
|
+
uint256 zoraReward = (SPARKS_VALUE * (ZORA_REWARD_PCT + REFERRER_REWARD_PCT)) / BPS_TO_PERCENT_2_DECIMAL_PERCISION;
|
|
66
|
+
vm.assertEq(protocolRewards.balanceOf(collectorWithToken), 0);
|
|
67
|
+
vm.assertEq(protocolRewards.balanceOf(zoraRecipient), zoraReward);
|
|
68
|
+
vm.assertEq(protocolRewards.balanceOf(tokenAdmin), SPARKS_VALUE - zoraReward);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function testCommentBackfillBatchAddCommentShouldEmitCommented() public {
|
|
72
|
+
IComments.CommentIdentifier[] memory commentIdentifiers = new IComments.CommentIdentifier[](2);
|
|
73
|
+
|
|
74
|
+
commentIdentifiers[0] = IComments.CommentIdentifier({
|
|
75
|
+
commenter: makeAddr("commenter1"),
|
|
76
|
+
contractAddress: address(mock1155),
|
|
77
|
+
tokenId: tokenId1,
|
|
78
|
+
nonce: 0
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
commentIdentifiers[1] = IComments.CommentIdentifier({
|
|
82
|
+
commenter: makeAddr("commenter2"),
|
|
83
|
+
contractAddress: address(mock1155),
|
|
84
|
+
tokenId: tokenId2,
|
|
85
|
+
nonce: bytes32("1")
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
string[] memory texts = new string[](2);
|
|
89
|
+
texts[0] = "test comment 1";
|
|
90
|
+
texts[1] = "test comment 2";
|
|
91
|
+
|
|
92
|
+
uint256[] memory timestamps = new uint256[](2);
|
|
93
|
+
|
|
94
|
+
timestamps[0] = block.timestamp;
|
|
95
|
+
timestamps[1] = block.timestamp + 100;
|
|
96
|
+
|
|
97
|
+
bytes32[] memory originalTransactionHashes = new bytes32[](2);
|
|
98
|
+
originalTransactionHashes[0] = bytes32("1");
|
|
99
|
+
originalTransactionHashes[1] = bytes32("2");
|
|
100
|
+
|
|
101
|
+
vm.expectEmit(true, true, true, true);
|
|
102
|
+
// verify first comment is emitted
|
|
103
|
+
emit IComments.BackfilledComment({
|
|
104
|
+
commentId: comments.hashCommentIdentifier(commentIdentifiers[0]),
|
|
105
|
+
comment: commentIdentifiers[0],
|
|
106
|
+
text: texts[0],
|
|
107
|
+
timestamp: timestamps[0],
|
|
108
|
+
originalTransactionId: originalTransactionHashes[0]
|
|
109
|
+
});
|
|
110
|
+
vm.expectEmit(true, true, true, true);
|
|
111
|
+
// verify second comment is emitted
|
|
112
|
+
emit IComments.BackfilledComment({
|
|
113
|
+
commentId: comments.hashCommentIdentifier(commentIdentifiers[1]),
|
|
114
|
+
comment: commentIdentifiers[1],
|
|
115
|
+
text: texts[1],
|
|
116
|
+
timestamp: timestamps[1],
|
|
117
|
+
originalTransactionId: originalTransactionHashes[1]
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
vm.prank(commentsBackfiller);
|
|
121
|
+
comments.backfillBatchAddComment(commentIdentifiers, texts, timestamps, originalTransactionHashes);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function testCommentBackfillBatchAddCommentShouldRevertIfDuplicate() public {
|
|
125
|
+
IComments.CommentIdentifier[] memory commentIdentifiers = new IComments.CommentIdentifier[](2);
|
|
126
|
+
|
|
127
|
+
commentIdentifiers[0] = IComments.CommentIdentifier({
|
|
128
|
+
commenter: makeAddr("commenter1"),
|
|
129
|
+
contractAddress: address(mock1155),
|
|
130
|
+
tokenId: tokenId1,
|
|
131
|
+
nonce: 0
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
commentIdentifiers[1] = IComments.CommentIdentifier({
|
|
135
|
+
commenter: makeAddr("commenter2"),
|
|
136
|
+
contractAddress: address(mock1155),
|
|
137
|
+
tokenId: tokenId2,
|
|
138
|
+
nonce: keccak256("1")
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
string[] memory texts = new string[](2);
|
|
142
|
+
texts[0] = "test comment 1";
|
|
143
|
+
texts[1] = "test comment 2";
|
|
144
|
+
|
|
145
|
+
uint256[] memory timestamps = new uint256[](2);
|
|
146
|
+
|
|
147
|
+
timestamps[0] = block.timestamp;
|
|
148
|
+
timestamps[1] = block.timestamp + 100;
|
|
149
|
+
|
|
150
|
+
bytes32[] memory originalTransactionHashes = new bytes32[](2);
|
|
151
|
+
originalTransactionHashes[0] = bytes32("1");
|
|
152
|
+
originalTransactionHashes[1] = bytes32("2");
|
|
153
|
+
|
|
154
|
+
vm.prank(commentsBackfiller);
|
|
155
|
+
comments.backfillBatchAddComment(commentIdentifiers, texts, timestamps, originalTransactionHashes);
|
|
156
|
+
|
|
157
|
+
// ensure that when backfilling a duplicate, it reverts
|
|
158
|
+
vm.expectRevert(abi.encodeWithSelector(IComments.DuplicateComment.selector, comments.hashCommentIdentifier(commentIdentifiers[0])));
|
|
159
|
+
vm.prank(commentsBackfiller);
|
|
160
|
+
comments.backfillBatchAddComment(commentIdentifiers, texts, timestamps, originalTransactionHashes);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function testCommentBackfillBatchAddCommentShouldRevertIfArrayLengthMismatch() public {
|
|
164
|
+
IComments.CommentIdentifier[] memory commentIdentifiers = new IComments.CommentIdentifier[](2);
|
|
165
|
+
commentIdentifiers[1] = commentIdentifiers[0];
|
|
166
|
+
|
|
167
|
+
string[] memory texts = new string[](2);
|
|
168
|
+
|
|
169
|
+
uint256[] memory timestamps = new uint256[](1); // Mismatched length
|
|
170
|
+
|
|
171
|
+
bytes32[] memory originalTransactionHashes = new bytes32[](2);
|
|
172
|
+
|
|
173
|
+
vm.expectRevert(IComments.ArrayLengthMismatch.selector);
|
|
174
|
+
vm.prank(commentsBackfiller);
|
|
175
|
+
comments.backfillBatchAddComment(commentIdentifiers, texts, timestamps, originalTransactionHashes);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function testCommentSparkCommentWithZeroSparks() public {
|
|
179
|
+
IComments.CommentIdentifier memory commentIdentifier = IComments.CommentIdentifier({
|
|
180
|
+
commenter: collectorWithToken,
|
|
181
|
+
contractAddress: address(mock1155),
|
|
182
|
+
tokenId: tokenId1,
|
|
183
|
+
nonce: bytes32(0)
|
|
184
|
+
});
|
|
185
|
+
vm.expectRevert(abi.encodeWithSignature("MustSendAtLeastOneSpark()"));
|
|
186
|
+
comments.sparkComment(commentIdentifier, 0, address(0));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function testCommentSparkCommentWithInvalidAmount() public {
|
|
190
|
+
IComments.CommentIdentifier memory commentIdentifier = IComments.CommentIdentifier({
|
|
191
|
+
commenter: collectorWithToken,
|
|
192
|
+
contractAddress: address(mock1155),
|
|
193
|
+
tokenId: tokenId1,
|
|
194
|
+
nonce: bytes32(0)
|
|
195
|
+
});
|
|
196
|
+
vm.expectRevert(abi.encodeWithSelector(IComments.IncorrectETHAmountForSparks.selector, 0, SPARKS_VALUE));
|
|
197
|
+
comments.sparkComment{value: 0}(commentIdentifier, 1, address(0));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function testCommentSparkCommentOwnComment() public {
|
|
201
|
+
// comment
|
|
202
|
+
IComments.CommentIdentifier memory replyTo;
|
|
203
|
+
IComments.CommentIdentifier memory commentIdentifier = _mockComment(collectorWithToken, replyTo);
|
|
204
|
+
|
|
205
|
+
// spark own comment
|
|
206
|
+
vm.deal(collectorWithToken, SPARKS_VALUE);
|
|
207
|
+
|
|
208
|
+
vm.expectRevert(abi.encodeWithSignature("CannotSparkOwnComment()"));
|
|
209
|
+
vm.prank(collectorWithToken);
|
|
210
|
+
comments.sparkComment{value: SPARKS_VALUE}(commentIdentifier, 1, address(0));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function testCommentSparkCommentDoesNotExist() public {
|
|
214
|
+
IComments.CommentIdentifier memory commentIdentifier = IComments.CommentIdentifier({
|
|
215
|
+
commenter: collectorWithToken,
|
|
216
|
+
contractAddress: address(mock1155),
|
|
217
|
+
tokenId: tokenId1,
|
|
218
|
+
nonce: keccak256("123456")
|
|
219
|
+
});
|
|
220
|
+
vm.expectRevert(abi.encodeWithSignature("CommentDoesntExist()"));
|
|
221
|
+
comments.sparkComment{value: SPARKS_VALUE}(commentIdentifier, 1, address(0));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function testCommentSparkCommentValid(uint64 sparksQuantity) public {
|
|
225
|
+
vm.assume(sparksQuantity > 0 && sparksQuantity < 1_000_000_000_000_000);
|
|
226
|
+
|
|
227
|
+
// comment
|
|
228
|
+
IComments.CommentIdentifier memory replyTo;
|
|
229
|
+
IComments.CommentIdentifier memory commentIdentifier = _mockComment(collectorWithToken, replyTo);
|
|
230
|
+
|
|
231
|
+
// mint
|
|
232
|
+
address commentor2 = makeAddr("commentor2");
|
|
233
|
+
|
|
234
|
+
uint256 zoraRecipientBalanceBeforeSpark = protocolRewards.balanceOf(zoraRecipient);
|
|
235
|
+
|
|
236
|
+
// spark comment
|
|
237
|
+
vm.deal(commentor2, sparksQuantity * SPARKS_VALUE);
|
|
238
|
+
|
|
239
|
+
vm.expectEmit(true, true, true, true);
|
|
240
|
+
emit IComments.SparkedComment(comments.hashCommentIdentifier(commentIdentifier), commentIdentifier, sparksQuantity, commentor2, block.timestamp);
|
|
241
|
+
vm.prank(commentor2);
|
|
242
|
+
comments.sparkComment{value: sparksQuantity * SPARKS_VALUE}(commentIdentifier, sparksQuantity, address(0));
|
|
243
|
+
|
|
244
|
+
uint256 zoraReward = (sparksQuantity * SPARKS_VALUE * (ZORA_REWARD_PCT + REFERRER_REWARD_PCT)) / BPS_TO_PERCENT_2_DECIMAL_PERCISION;
|
|
245
|
+
vm.assertEq(protocolRewards.balanceOf(zoraRecipient) - zoraRecipientBalanceBeforeSpark, zoraReward);
|
|
246
|
+
vm.assertEq(protocolRewards.balanceOf(collectorWithToken), (sparksQuantity * SPARKS_VALUE) - zoraReward);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function testCommentSparkCommentValidWithReferrer(uint64 sparksQuantity) public {
|
|
250
|
+
vm.assume(sparksQuantity > 0 && sparksQuantity < 1_000_000_000_000_000);
|
|
251
|
+
|
|
252
|
+
// comment
|
|
253
|
+
IComments.CommentIdentifier memory replyTo;
|
|
254
|
+
IComments.CommentIdentifier memory commentIdentifier = _mockComment(collectorWithToken, replyTo);
|
|
255
|
+
|
|
256
|
+
// mint
|
|
257
|
+
address commentor2 = makeAddr("commentor2");
|
|
258
|
+
|
|
259
|
+
uint256 zoraRecipientBalanceBeforeSpark = protocolRewards.balanceOf(zoraRecipient);
|
|
260
|
+
|
|
261
|
+
// spark comment
|
|
262
|
+
vm.deal(commentor2, sparksQuantity * SPARKS_VALUE);
|
|
263
|
+
|
|
264
|
+
address referrer = makeAddr("referrer");
|
|
265
|
+
|
|
266
|
+
vm.expectEmit(true, true, true, true);
|
|
267
|
+
emit IComments.SparkedComment(comments.hashCommentIdentifier(commentIdentifier), commentIdentifier, sparksQuantity, commentor2, block.timestamp);
|
|
268
|
+
vm.prank(commentor2);
|
|
269
|
+
comments.sparkComment{value: sparksQuantity * SPARKS_VALUE}(commentIdentifier, sparksQuantity, referrer);
|
|
270
|
+
|
|
271
|
+
uint256 zoraReward = (sparksQuantity * SPARKS_VALUE * ZORA_REWARD_PCT) / BPS_TO_PERCENT_2_DECIMAL_PERCISION;
|
|
272
|
+
uint256 referrerReward = (sparksQuantity * SPARKS_VALUE * REFERRER_REWARD_PCT) / BPS_TO_PERCENT_2_DECIMAL_PERCISION;
|
|
273
|
+
vm.assertEq(protocolRewards.balanceOf(zoraRecipient) - zoraRecipientBalanceBeforeSpark, zoraReward);
|
|
274
|
+
vm.assertEq(protocolRewards.balanceOf(referrer), referrerReward);
|
|
275
|
+
vm.assertEq(protocolRewards.balanceOf(collectorWithToken), (sparksQuantity * SPARKS_VALUE) - zoraReward - referrerReward);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function testCommentHashAndValidateCommentExists() public {
|
|
279
|
+
IComments.CommentIdentifier memory commentIdentifier = IComments.CommentIdentifier({
|
|
280
|
+
commenter: collectorWithToken,
|
|
281
|
+
contractAddress: address(mock1155),
|
|
282
|
+
tokenId: tokenId1,
|
|
283
|
+
nonce: keccak256("123456")
|
|
284
|
+
});
|
|
285
|
+
vm.expectRevert(abi.encodeWithSignature("CommentDoesntExist()"));
|
|
286
|
+
comments.hashAndValidateCommentExists(commentIdentifier);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function postComment(
|
|
290
|
+
address commenter,
|
|
291
|
+
address contractAddress,
|
|
292
|
+
uint256 tokenId,
|
|
293
|
+
string memory content,
|
|
294
|
+
IComments.CommentIdentifier memory replyTo
|
|
295
|
+
) internal returns (IComments.CommentIdentifier memory) {
|
|
296
|
+
vm.prank(commenter);
|
|
297
|
+
return comments.comment{value: SPARKS_VALUE}(commenter, contractAddress, tokenId, content, replyTo, address(0));
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function testHashAndCheckCommentExists() public {
|
|
301
|
+
address commenter = collectorWithToken;
|
|
302
|
+
address contractAddress = address(mock1155);
|
|
303
|
+
uint256 tokenId = tokenId1;
|
|
304
|
+
|
|
305
|
+
// Check that the comment doesn't exist initially
|
|
306
|
+
(bytes32 commentId, bool exists) = comments.hashAndCheckCommentExists(_expectedCommentIdentifier(contractAddress, tokenId, commenter));
|
|
307
|
+
assertFalse(exists);
|
|
308
|
+
|
|
309
|
+
// Setup and post comment
|
|
310
|
+
_setupCommenterWithTokenAndSparks(commenter, 1);
|
|
311
|
+
IComments.CommentIdentifier memory postedCommentIdentifier = postComment(commenter, contractAddress, tokenId, "test comment", emptyCommentIdentifier);
|
|
312
|
+
|
|
313
|
+
// Check that the comment now exists
|
|
314
|
+
(bytes32 newCommentId, bool newExists) = comments.hashAndCheckCommentExists(postedCommentIdentifier);
|
|
315
|
+
assertTrue(newExists);
|
|
316
|
+
assertEq(commentId, newCommentId);
|
|
317
|
+
assertEq(comments.hashCommentIdentifier(postedCommentIdentifier), newCommentId);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function testReplyToNonExistentComment() public {
|
|
321
|
+
address commentor = makeAddr("commentor");
|
|
322
|
+
_setupCommenterWithTokenAndSparks(commentor, 1);
|
|
323
|
+
|
|
324
|
+
IComments.CommentIdentifier memory nonExistentReplyTo = IComments.CommentIdentifier({
|
|
325
|
+
commenter: makeAddr("nonExistentCommenter"),
|
|
326
|
+
contractAddress: address(mock1155),
|
|
327
|
+
tokenId: tokenId1,
|
|
328
|
+
nonce: keccak256("nonExistentNonce")
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
vm.expectRevert(IComments.CommentDoesntExist.selector);
|
|
332
|
+
postComment(commentor, address(mock1155), tokenId1, "Replying to non-existent comment", nonExistentReplyTo);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function testReplyToCommentThatAddressDoesNotMatch() public {
|
|
336
|
+
address originalCommenter = makeAddr("originalCommenter");
|
|
337
|
+
address replier = makeAddr("replier");
|
|
338
|
+
|
|
339
|
+
_setupCommenterWithTokenAndSparks(originalCommenter, 1);
|
|
340
|
+
_setupCommenterWithTokenAndSparks(replier, 1);
|
|
341
|
+
|
|
342
|
+
IComments.CommentIdentifier memory originalCommentIdentifier = postComment(
|
|
343
|
+
originalCommenter,
|
|
344
|
+
address(mock1155),
|
|
345
|
+
tokenId1,
|
|
346
|
+
"Original comment",
|
|
347
|
+
emptyCommentIdentifier
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
// mismatched address
|
|
351
|
+
address mismatchedAddress = makeAddr("xyz");
|
|
352
|
+
|
|
353
|
+
vm.expectRevert(
|
|
354
|
+
abi.encodeWithSelector(IComments.CommentAddressOrTokenIdsDoNotMatch.selector, mismatchedAddress, tokenId1, address(mock1155), tokenId1)
|
|
355
|
+
);
|
|
356
|
+
vm.prank(replier);
|
|
357
|
+
comments.comment{value: SPARKS_VALUE}(replier, mismatchedAddress, tokenId1, "Reply to original comment", originalCommentIdentifier, address(0));
|
|
358
|
+
|
|
359
|
+
// mismatched tokenId
|
|
360
|
+
uint256 mismatchedTokenId = 123;
|
|
361
|
+
|
|
362
|
+
vm.expectRevert(
|
|
363
|
+
abi.encodeWithSelector(IComments.CommentAddressOrTokenIdsDoNotMatch.selector, address(mock1155), mismatchedTokenId, address(mock1155), tokenId1)
|
|
364
|
+
);
|
|
365
|
+
vm.prank(replier);
|
|
366
|
+
comments.comment{value: SPARKS_VALUE}(
|
|
367
|
+
replier,
|
|
368
|
+
address(mock1155),
|
|
369
|
+
mismatchedTokenId,
|
|
370
|
+
"Reply to original comment",
|
|
371
|
+
originalCommentIdentifier,
|
|
372
|
+
address(0)
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function testReplyToExistingComment() public {
|
|
377
|
+
address originalCommenter = makeAddr("originalCommenter");
|
|
378
|
+
address replier = makeAddr("replier");
|
|
379
|
+
|
|
380
|
+
_setupCommenterWithTokenAndSparks(originalCommenter, 1);
|
|
381
|
+
_setupCommenterWithTokenAndSparks(replier, 1);
|
|
382
|
+
|
|
383
|
+
IComments.CommentIdentifier memory originalCommentIdentifier = postComment(
|
|
384
|
+
originalCommenter,
|
|
385
|
+
address(mock1155),
|
|
386
|
+
tokenId1,
|
|
387
|
+
"Original comment",
|
|
388
|
+
emptyCommentIdentifier
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
IComments.CommentIdentifier memory expectedReplyCommentIdentifier = _expectedCommentIdentifier(address(mock1155), tokenId1, replier);
|
|
392
|
+
|
|
393
|
+
vm.expectEmit(true, true, true, true);
|
|
394
|
+
emit IComments.Commented(
|
|
395
|
+
comments.hashCommentIdentifier(expectedReplyCommentIdentifier),
|
|
396
|
+
expectedReplyCommentIdentifier,
|
|
397
|
+
comments.hashCommentIdentifier(originalCommentIdentifier),
|
|
398
|
+
originalCommentIdentifier,
|
|
399
|
+
1,
|
|
400
|
+
"Reply to original comment",
|
|
401
|
+
block.timestamp,
|
|
402
|
+
address(0)
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
IComments.CommentIdentifier memory replyCommentIdentifier = postComment(
|
|
406
|
+
replier,
|
|
407
|
+
address(mock1155),
|
|
408
|
+
tokenId1,
|
|
409
|
+
"Reply to original comment",
|
|
410
|
+
originalCommentIdentifier
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
assertEq(payable(address(comments)).balance, 0, "comments contract should have no balance");
|
|
414
|
+
|
|
415
|
+
uint64 commenteeSparks = comments.commentSparksQuantity(comments.hashCommentIdentifier(originalCommentIdentifier));
|
|
416
|
+
assertEq(commenteeSparks, 0, "commentee sparks should be 0");
|
|
417
|
+
|
|
418
|
+
assertEq(protocolRewards.balanceOf(originalCommenter), (SPARKS_VALUE * 70) / 100, "rewards mismatch");
|
|
419
|
+
|
|
420
|
+
(, bool exists) = comments.hashAndCheckCommentExists(replyCommentIdentifier);
|
|
421
|
+
assertTrue(exists);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function testCommentMismatchedCommenter() public {
|
|
425
|
+
address actualCommenter = makeAddr("actualCommenter");
|
|
426
|
+
address mismatchedCommenter = makeAddr("mismatchedCommenter");
|
|
427
|
+
|
|
428
|
+
_setupCommenterWithTokenAndSparks(actualCommenter, 1);
|
|
429
|
+
|
|
430
|
+
vm.expectRevert(abi.encodeWithSelector(IComments.CommenterMismatch.selector, mismatchedCommenter, actualCommenter));
|
|
431
|
+
vm.prank(actualCommenter);
|
|
432
|
+
comments.comment{value: SPARKS_VALUE}(mismatchedCommenter, address(mock1155), tokenId1, "Mismatched commenter", emptyCommentIdentifier, address(0));
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function testRevertOnEmptyComment() public {
|
|
436
|
+
address commenter = makeAddr("commenter");
|
|
437
|
+
_setupCommenterWithTokenAndSparks(commenter, 1);
|
|
438
|
+
|
|
439
|
+
vm.expectRevert(IComments.EmptyComment.selector);
|
|
440
|
+
postComment(commenter, address(mock1155), tokenId1, "", emptyCommentIdentifier);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function testRevertOnNotTokenHolderOrAdmin() public {
|
|
444
|
+
address nonHolder = makeAddr("nonHolder");
|
|
445
|
+
|
|
446
|
+
// We don't set up the commenter with a token, so they're neither a holder nor an admin
|
|
447
|
+
vm.deal(nonHolder, SPARKS_VALUE);
|
|
448
|
+
|
|
449
|
+
vm.expectRevert(IComments.NotTokenHolderOrAdmin.selector);
|
|
450
|
+
postComment(nonHolder, address(mock1155), tokenId1, "Attempting to comment without holding token", emptyCommentIdentifier);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function testCommentRevertsWhenSendTooMuchValue() public {
|
|
454
|
+
address tokenHolder = makeAddr("tokenHolder");
|
|
455
|
+
|
|
456
|
+
_setupCommenterWithTokenAndSparks(tokenHolder, 1);
|
|
457
|
+
|
|
458
|
+
vm.deal(tokenHolder, 1 ether);
|
|
459
|
+
vm.prank(tokenHolder);
|
|
460
|
+
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));
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function testCommentRevertsWhenSendTooLittleValue() public {
|
|
465
|
+
address tokenHolder = makeAddr("tokenHolder");
|
|
466
|
+
|
|
467
|
+
_setupCommenterWithTokenAndSparks(tokenHolder, 1);
|
|
468
|
+
|
|
469
|
+
vm.prank(tokenHolder);
|
|
470
|
+
vm.expectRevert(abi.encodeWithSelector(IComments.MustSendAtLeastOneSpark.selector));
|
|
471
|
+
comments.comment(tokenHolder, address(mock1155), tokenId1, "test", emptyCommentIdentifier, address(0));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function testCommentRevertsWhenSendExactValue() public {
|
|
475
|
+
address tokenHolder = makeAddr("tokenHolder");
|
|
476
|
+
|
|
477
|
+
_setupCommenterWithTokenAndSparks(tokenHolder, 1);
|
|
478
|
+
|
|
479
|
+
vm.prank(tokenHolder);
|
|
480
|
+
comments.comment{value: SPARKS_VALUE}(tokenHolder, address(mock1155), tokenId1, "test", emptyCommentIdentifier, address(0));
|
|
481
|
+
}
|
|
482
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
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
|
+
|
|
13
|
+
contract CommentsTestBase is Test {
|
|
14
|
+
CommentsImpl internal comments;
|
|
15
|
+
Mock1155 internal mock1155;
|
|
16
|
+
|
|
17
|
+
uint256 internal constant SPARKS_VALUE = 0.000001 ether;
|
|
18
|
+
|
|
19
|
+
IComments.CommentIdentifier internal emptyCommentIdentifier;
|
|
20
|
+
ProtocolRewards internal protocolRewards;
|
|
21
|
+
|
|
22
|
+
address internal commentsAdmin = makeAddr("commentsAdmin");
|
|
23
|
+
address internal commentsBackfiller = makeAddr("commentsBackfiller");
|
|
24
|
+
address internal zoraRecipient = makeAddr("zoraRecipient");
|
|
25
|
+
address internal tokenAdmin = makeAddr("tokenCreator");
|
|
26
|
+
address internal collectorWithToken;
|
|
27
|
+
uint256 internal collectorWithTokenPrivateKey;
|
|
28
|
+
address internal collectorWithoutToken = makeAddr("collectorWithoutToken");
|
|
29
|
+
address internal sparker;
|
|
30
|
+
uint256 internal sparkerPrivateKey;
|
|
31
|
+
|
|
32
|
+
uint256 internal tokenId1 = 1;
|
|
33
|
+
uint256 internal tokenId2 = 2;
|
|
34
|
+
|
|
35
|
+
function setUp() public {
|
|
36
|
+
protocolRewards = new ProtocolRewards();
|
|
37
|
+
CommentsImpl commentsImpl = new CommentsImpl(SPARKS_VALUE, address(protocolRewards));
|
|
38
|
+
|
|
39
|
+
// initialze empty delegateCommenters array
|
|
40
|
+
address[] memory delegateCommenters = new address[](0);
|
|
41
|
+
|
|
42
|
+
// intialize proxy
|
|
43
|
+
comments = CommentsImpl(payable(address(new Comments(address(commentsImpl)))));
|
|
44
|
+
comments.initialize({
|
|
45
|
+
_zoraRecipient: zoraRecipient,
|
|
46
|
+
defaultAdmin: commentsAdmin,
|
|
47
|
+
backfiller: commentsBackfiller,
|
|
48
|
+
delegateCommenters: delegateCommenters
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
mock1155 = new Mock1155();
|
|
52
|
+
|
|
53
|
+
mock1155.createToken(tokenId1, tokenAdmin);
|
|
54
|
+
mock1155.createToken(tokenId2, tokenAdmin);
|
|
55
|
+
|
|
56
|
+
(collectorWithToken, collectorWithTokenPrivateKey) = makeAddrAndKey("collectorWithToken");
|
|
57
|
+
(sparker, sparkerPrivateKey) = makeAddrAndKey("sparker");
|
|
58
|
+
|
|
59
|
+
mock1155 = new Mock1155();
|
|
60
|
+
|
|
61
|
+
mock1155.createToken(tokenId1, tokenAdmin);
|
|
62
|
+
mock1155.createToken(tokenId2, tokenAdmin);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function _expectedCommentIdentifier(
|
|
66
|
+
address contractAddress,
|
|
67
|
+
uint256 tokenId,
|
|
68
|
+
address commenter
|
|
69
|
+
) internal view returns (IComments.CommentIdentifier memory) {
|
|
70
|
+
return IComments.CommentIdentifier({commenter: commenter, contractAddress: contractAddress, tokenId: tokenId, nonce: comments.nextNonce()});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function _mockComment(
|
|
74
|
+
address commentor,
|
|
75
|
+
IComments.CommentIdentifier memory replyTo
|
|
76
|
+
) internal returns (IComments.CommentIdentifier memory commentIdentifier) {
|
|
77
|
+
vm.startPrank(commentor);
|
|
78
|
+
mock1155.mint(commentor, tokenId1, 1, "");
|
|
79
|
+
vm.stopPrank();
|
|
80
|
+
|
|
81
|
+
vm.deal(commentor, SPARKS_VALUE);
|
|
82
|
+
|
|
83
|
+
vm.prank(commentor);
|
|
84
|
+
commentIdentifier = comments.comment{value: SPARKS_VALUE}(commentor, address(mock1155), tokenId1, "comment", replyTo, address(0));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
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 {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
|
|
12
|
+
import {MockMinter} from "./mocks/MockMinter.sol";
|
|
13
|
+
|
|
14
|
+
contract Comments_mintAndCommentTest is Test {
|
|
15
|
+
Mock1155 mock1155;
|
|
16
|
+
CommentsImpl comments;
|
|
17
|
+
|
|
18
|
+
uint256 constant SPARKS_VALUE = 0.000001 ether;
|
|
19
|
+
|
|
20
|
+
address zoraRecipient = makeAddr("zoraRecipient");
|
|
21
|
+
address commentsAdmin = makeAddr("commentsAdmin");
|
|
22
|
+
address commentor = makeAddr("commentor");
|
|
23
|
+
address tokenAdmin = makeAddr("tokenAdmin");
|
|
24
|
+
|
|
25
|
+
uint256 tokenId1 = 1;
|
|
26
|
+
|
|
27
|
+
address constant protocolRewards = 0x7777777F279eba3d3Ad8F4E708545291A6fDBA8B;
|
|
28
|
+
MockMinter mockMinter;
|
|
29
|
+
|
|
30
|
+
function setUp() public {
|
|
31
|
+
vm.createSelectFork("zora_sepolia", 14562731);
|
|
32
|
+
|
|
33
|
+
CommentsImpl commentsImpl = new CommentsImpl(SPARKS_VALUE, protocolRewards);
|
|
34
|
+
|
|
35
|
+
comments = CommentsImpl(payable(address(new Comments(address(commentsImpl)))));
|
|
36
|
+
|
|
37
|
+
// create mock minter, which will mint and comment on the comments contract.
|
|
38
|
+
// mock minter will be granted permission to do a delegateComment on the comments contract
|
|
39
|
+
mockMinter = new MockMinter(IComments(address(comments)));
|
|
40
|
+
address[] memory delegateCommenters = new address[](1);
|
|
41
|
+
delegateCommenters[0] = address(mockMinter);
|
|
42
|
+
|
|
43
|
+
comments.initialize({_zoraRecipient: zoraRecipient, defaultAdmin: commentsAdmin, backfiller: address(0), delegateCommenters: delegateCommenters});
|
|
44
|
+
|
|
45
|
+
mock1155 = new Mock1155();
|
|
46
|
+
|
|
47
|
+
mock1155.createToken(tokenId1, tokenAdmin);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function _expectedCommentIdentifier(
|
|
51
|
+
address commenter,
|
|
52
|
+
address contractAddress,
|
|
53
|
+
uint256 tokenId
|
|
54
|
+
) internal view returns (IComments.CommentIdentifier memory) {
|
|
55
|
+
return IComments.CommentIdentifier({commenter: commenter, contractAddress: contractAddress, tokenId: tokenId, nonce: comments.nextNonce()});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function testCanMintAndCommentWithNoSparks() public {
|
|
59
|
+
uint256 quantityToMint = 1;
|
|
60
|
+
uint256 mintFee = 0.000111 ether;
|
|
61
|
+
|
|
62
|
+
address commenter = commentor;
|
|
63
|
+
address contractAddress = address(mock1155);
|
|
64
|
+
uint256 tokenId = tokenId1;
|
|
65
|
+
|
|
66
|
+
IComments.CommentIdentifier memory emptyReplyTo;
|
|
67
|
+
|
|
68
|
+
IComments.CommentIdentifier memory expectedCommentIdentifier = _expectedCommentIdentifier(commenter, contractAddress, tokenId);
|
|
69
|
+
|
|
70
|
+
bytes32 expectedCommentId = comments.hashCommentIdentifier(expectedCommentIdentifier);
|
|
71
|
+
bytes32 expectedReplyToId = bytes32(0);
|
|
72
|
+
|
|
73
|
+
uint64 sparksQuantity = 0;
|
|
74
|
+
|
|
75
|
+
vm.deal(commentor, mintFee * quantityToMint);
|
|
76
|
+
vm.expectEmit(true, true, true, true);
|
|
77
|
+
emit IComments.Commented(
|
|
78
|
+
expectedCommentId,
|
|
79
|
+
_expectedCommentIdentifier(commenter, contractAddress, tokenId),
|
|
80
|
+
expectedReplyToId,
|
|
81
|
+
emptyReplyTo,
|
|
82
|
+
sparksQuantity,
|
|
83
|
+
"test",
|
|
84
|
+
block.timestamp,
|
|
85
|
+
address(0)
|
|
86
|
+
);
|
|
87
|
+
vm.prank(commentor);
|
|
88
|
+
mockMinter.mintAndComment(quantityToMint, address(mock1155), tokenId1, "test");
|
|
89
|
+
|
|
90
|
+
// validate that the comment was created
|
|
91
|
+
(, bool exists) = comments.hashAndCheckCommentExists(expectedCommentIdentifier);
|
|
92
|
+
assertEq(exists, true);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function test_delegateComment_revertsWhenNotOwnerOrCreator() public {
|
|
96
|
+
address notOwner = makeAddr("notOwner");
|
|
97
|
+
vm.prank(notOwner);
|
|
98
|
+
vm.expectRevert(IComments.NotTokenHolderOrAdmin.selector);
|
|
99
|
+
mockMinter.forwardComment(address(mock1155), tokenId1, "test");
|
|
100
|
+
}
|
|
101
|
+
}
|