@zoralabs/comments-contracts 0.0.1 → 0.0.2
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/.turbo/turbo-build.log +49 -31
- package/README.md +10 -39
- package/abis/AddDelegateCommenterRole.json +9 -0
- package/abis/CallerAndCommenter.json +62 -0
- package/abis/CallerAndCommenterImpl.json +1218 -0
- package/abis/CallerAndCommenterMintAndCommentTest.json +771 -0
- package/abis/CallerAndCommenterSwapAndCommentTest.json +844 -0
- package/abis/CallerAndCommenterTestBase.json +577 -0
- package/abis/CommentsImpl.json +189 -59
- package/abis/CommentsImplConstants.json +106 -0
- package/abis/CommentsPermitTest.json +26 -6
- package/abis/CommentsTest.json +58 -10
- package/abis/Comments_mintAndCommentTest.json +11 -4
- package/abis/Comments_smartWallet.json +711 -0
- package/abis/DeployCallerAndCommenterImpl.json +9 -0
- package/abis/DeployImpl.json +0 -13
- package/abis/DeployNonDeterministic.json +0 -13
- package/abis/DeployScript.json +0 -13
- package/abis/EIP712Upgradeable.json +74 -0
- package/abis/EIP712UpgradeableWithChainId.json +49 -0
- package/abis/ERC20.json +310 -0
- package/abis/GenerateDeterministicParams.json +0 -13
- package/abis/ICallerAndCommenter.json +797 -0
- package/abis/IComments.json +629 -9
- package/abis/IERC20.json +39 -42
- package/abis/IERC20Metadata.json +224 -0
- package/abis/{CommentsDeployerBase.json → IMultiOwnable.json} +8 -2
- package/abis/IProtocolRewards.json +19 -0
- package/abis/ISecondarySwap.json +45 -0
- package/abis/IZoraCreator1155.json +51 -0
- package/abis/IZoraTimedSaleStrategy.json +91 -0
- package/abis/Mock1155.json +75 -1
- package/abis/Mock1155NoCreatorRewardRecipient.json +605 -0
- package/abis/Mock1155NoOwner.json +566 -0
- package/abis/{MockMinter.json → MockDelegateCommenter.json} +12 -2
- package/abis/MockERC20z.json +315 -0
- package/abis/MockMultiOwnable.json +212 -0
- package/abis/MockSecondarySwap.json +95 -0
- package/abis/MockZoraTimedSale.json +139 -0
- package/abis/Ownable2StepUpgradeable.json +138 -0
- package/abis/UnorderedNoncesUpgradeable.json +4 -4
- package/addresses/1.json +9 -0
- package/addresses/10.json +9 -0
- package/addresses/11155111.json +9 -0
- package/addresses/11155420.json +9 -0
- package/addresses/42161.json +9 -0
- package/addresses/7777777.json +9 -0
- package/addresses/81457.json +9 -0
- package/addresses/8453.json +9 -0
- package/addresses/84532.json +9 -0
- package/addresses/999999999.json +7 -2
- package/deterministicConfig/callerAndCommenter.json +8 -0
- package/deterministicConfig/comments.json +2 -2
- package/dist/index.cjs +724 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +723 -35
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/wagmiGenerated.d.ts +1102 -57
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/package/types.ts +4 -1
- package/package/wagmiGenerated.ts +728 -32
- package/package.json +12 -11
- package/script/AddDelegateCommenterRole.s.sol +24 -0
- package/script/CommentsDeployerBase.sol +102 -19
- package/script/Deploy.s.sol +2 -44
- package/script/DeployCallerAndCommenterImpl.s.sol +29 -0
- package/script/DeployImpl.s.sol +1 -0
- package/script/DeployNonDeterministic.s.sol +22 -13
- package/script/GenerateDeterministicParams.s.sol +32 -4
- package/scripts/generateCommentsTestData.ts +170 -79
- package/src/CommentsImpl.sol +267 -134
- package/src/CommentsImplConstants.sol +44 -0
- package/src/interfaces/ICallerAndCommenter.sol +215 -0
- package/src/interfaces/IComments.sol +189 -42
- package/src/interfaces/IMultiOwnable.sol +10 -0
- package/src/interfaces/ISecondarySwap.sol +40 -0
- package/src/interfaces/IZoraCreator1155.sol +6 -1
- package/src/interfaces/IZoraCreator1155TypesV1.sol +46 -0
- package/src/interfaces/IZoraTimedSaleStrategy.sol +25 -0
- package/src/proxy/CallerAndCommenter.sol +43 -0
- package/src/utils/CallerAndCommenterImpl.sol +376 -0
- package/src/utils/EIP712UpgradeableWithChainId.sol +12 -23
- package/src/version/ContractVersionBase.sol +1 -1
- package/test/CallerAndCommenterTestBase.sol +77 -0
- package/test/CallerAndCommenter_mintAndComment.t copy.sol +214 -0
- package/test/CallerAndCommenter_swapAndComment.t.sol +523 -0
- package/test/Comments.t.sol +166 -29
- package/test/CommentsTestBase.sol +12 -20
- package/test/Comments_delegateComment.t.sol +129 -0
- package/test/Comments_permit.t.sol +131 -44
- package/test/Comments_smartWallet.t.sol +152 -0
- package/test/mocks/Mock1155.sol +12 -1
- package/test/mocks/Mock1155NoCreatorRewardRecipient.sol +65 -0
- package/test/mocks/Mock1155NoOwner.sol +53 -0
- package/test/mocks/MockDelegateCommenter.sol +36 -0
- package/test/mocks/MockIZoraCreator1155.sol +16 -0
- package/test/mocks/MockSecondarySwap.sol +30 -0
- package/test/mocks/MockZoraTimedSale.sol +38 -0
- package/wagmi.config.ts +3 -1
- package/abis/ProxyDeployerScript.json +0 -15
- package/scripts/backfillComments.ts +0 -176
- package/scripts/queries.ts +0 -73
- package/scripts/queryAndSaveComments.ts +0 -48
- package/scripts/queryQuantityOfComments.ts +0 -53
- package/scripts/writeComments.ts +0 -198
- package/src/deployments/CommentsDeployment.sol +0 -14
- package/test/Comments_mintAndComment.t.sol +0 -101
- package/test/mocks/MockMinter.sol +0 -29
|
@@ -11,10 +11,11 @@ import {IProtocolRewards} from "@zoralabs/protocol-rewards/src/interfaces/IProto
|
|
|
11
11
|
import {ProtocolRewards} from "./mocks/ProtocolRewards.sol";
|
|
12
12
|
import {CommentsTestBase} from "./CommentsTestBase.sol";
|
|
13
13
|
import {UnorderedNoncesUpgradeable} from "@zoralabs/shared-contracts/utils/UnorderedNoncesUpgradeable.sol";
|
|
14
|
+
import {MockMultiOwnable} from "./Comments_smartWallet.t.sol";
|
|
14
15
|
|
|
15
16
|
contract CommentsPermitTest is CommentsTestBase {
|
|
16
17
|
function testPermitComment() public {
|
|
17
|
-
IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment"
|
|
18
|
+
IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment");
|
|
18
19
|
bytes memory signature = _signPermitComment(permitComment, collectorWithTokenPrivateKey);
|
|
19
20
|
|
|
20
21
|
IComments.CommentIdentifier memory expectedCommentIdentifier = _expectedCommentIdentifier(
|
|
@@ -27,7 +28,7 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
27
28
|
|
|
28
29
|
// any account can execute the permit comment on behalf of the collectorWithToken, but they must have enough eth to do so.
|
|
29
30
|
address executor = makeAddr("executor");
|
|
30
|
-
vm.deal(executor,
|
|
31
|
+
vm.deal(executor, SPARKS_VALUE);
|
|
31
32
|
|
|
32
33
|
vm.expectEmit(true, true, true, true);
|
|
33
34
|
emit IComments.Commented(
|
|
@@ -35,7 +36,7 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
35
36
|
expectedCommentIdentifier,
|
|
36
37
|
bytes32(0),
|
|
37
38
|
permitComment.replyTo,
|
|
38
|
-
|
|
39
|
+
1,
|
|
39
40
|
permitComment.text,
|
|
40
41
|
block.timestamp,
|
|
41
42
|
permitComment.referrer
|
|
@@ -47,7 +48,7 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
function testPermitComment_NonceUsedTwice() public {
|
|
50
|
-
IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment"
|
|
51
|
+
IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment");
|
|
51
52
|
bytes memory signature = _signPermitComment(permitComment, collectorWithTokenPrivateKey);
|
|
52
53
|
|
|
53
54
|
_setupTokenAndSparks(permitComment);
|
|
@@ -62,7 +63,7 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
function testPermitComment_DeadlineExpired() public {
|
|
65
|
-
IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment"
|
|
66
|
+
IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment");
|
|
66
67
|
bytes memory signature = _signPermitComment(permitComment, collectorWithTokenPrivateKey);
|
|
67
68
|
|
|
68
69
|
_setupTokenAndSparks(permitComment);
|
|
@@ -71,7 +72,7 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
71
72
|
vm.warp(permitComment.deadline + 1);
|
|
72
73
|
|
|
73
74
|
address executor = makeAddr("executor");
|
|
74
|
-
vm.deal(executor,
|
|
75
|
+
vm.deal(executor, SPARKS_VALUE);
|
|
75
76
|
vm.expectRevert(abi.encodeWithSelector(IComments.ERC2612ExpiredSignature.selector, permitComment.deadline));
|
|
76
77
|
_executePermitComment(executor, permitComment, signature);
|
|
77
78
|
}
|
|
@@ -81,7 +82,7 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
81
82
|
uint256 wrongSignerPrivateKey;
|
|
82
83
|
(wrongSigner, wrongSignerPrivateKey) = makeAddrAndKey("wrongSigner");
|
|
83
84
|
|
|
84
|
-
IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment"
|
|
85
|
+
IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment");
|
|
85
86
|
bytes memory wrongSignature = _signPermitComment(permitComment, wrongSignerPrivateKey);
|
|
86
87
|
|
|
87
88
|
_setupTokenAndSparks(permitComment);
|
|
@@ -90,26 +91,101 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
90
91
|
_executePermitComment(collectorWithToken, permitComment, wrongSignature);
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
function
|
|
94
|
-
IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment"
|
|
94
|
+
function testPermitComment_ZeroSparks_Collector() public {
|
|
95
|
+
IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment");
|
|
95
96
|
bytes memory signature = _signPermitComment(permitComment, collectorWithTokenPrivateKey);
|
|
96
97
|
|
|
97
98
|
_setupTokenAndSparks(permitComment);
|
|
98
99
|
|
|
99
100
|
vm.expectRevert(IComments.MustSendAtLeastOneSpark.selector);
|
|
100
|
-
|
|
101
|
+
vm.prank(collectorWithToken);
|
|
102
|
+
comments.permitComment{value: 0}(permitComment, signature);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function testPermitComment_ZeroSparks_Creator() public {
|
|
106
|
+
IComments.PermitComment memory permitComment = _createPermitComment(tokenAdmin, "test comment");
|
|
107
|
+
bytes memory signature = _signPermitComment(permitComment, tokenAdminPrivateKey);
|
|
108
|
+
|
|
109
|
+
_setupTokenAndSparks(permitComment);
|
|
110
|
+
|
|
111
|
+
bytes32 expectedNonce = comments.nextNonce();
|
|
112
|
+
|
|
113
|
+
// any account can execute the permit comment on behalf of the tokenAdmin,
|
|
114
|
+
// it should be executed with 0 sparks
|
|
115
|
+
vm.prank(makeAddr("random account"));
|
|
116
|
+
comments.permitComment{value: 0}(permitComment, signature);
|
|
117
|
+
|
|
118
|
+
IComments.CommentIdentifier memory expectedCommentIdentifier = IComments.CommentIdentifier({
|
|
119
|
+
commenter: tokenAdmin,
|
|
120
|
+
contractAddress: address(mock1155),
|
|
121
|
+
tokenId: tokenId1,
|
|
122
|
+
nonce: expectedNonce
|
|
123
|
+
});
|
|
124
|
+
_assertCommentExists(expectedCommentIdentifier);
|
|
101
125
|
}
|
|
102
126
|
|
|
103
127
|
function testPermitComment_Not1155Holder() public {
|
|
104
|
-
IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment"
|
|
128
|
+
IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "test comment");
|
|
105
129
|
bytes memory signature = _signPermitComment(permitComment, collectorWithTokenPrivateKey);
|
|
106
130
|
|
|
107
131
|
address executor = makeAddr("executor");
|
|
108
|
-
vm.deal(executor,
|
|
132
|
+
vm.deal(executor, SPARKS_VALUE);
|
|
109
133
|
vm.expectRevert(IComments.NotTokenHolderOrAdmin.selector);
|
|
110
134
|
_executePermitComment(executor, permitComment, signature);
|
|
111
135
|
}
|
|
112
136
|
|
|
137
|
+
function testPermitComment_SmartWalletOwner() public {
|
|
138
|
+
// Test scenario:
|
|
139
|
+
// We want to enable a smart wallet owner to comment when the smart wallet owns the token.
|
|
140
|
+
// - The smart wallet owns the 1155 token
|
|
141
|
+
// - privy account is an owner of the smart wallet
|
|
142
|
+
// - privy account is the one that signs the message
|
|
143
|
+
// - The comment is attributed to privy account (the smart wallet owner)
|
|
144
|
+
// We create a permit where:
|
|
145
|
+
// - commenter is privy account (smart wallet owner)
|
|
146
|
+
// - commenterSmartWallet is the smart wallet address
|
|
147
|
+
// - Privy account signs the message
|
|
148
|
+
// This should be a valid scenario, allowing a smart wallet owner to comment using a token owned by the smart wallet.
|
|
149
|
+
(address privyAccount, uint256 privyPrivateKey) = makeAddrAndKey("privy");
|
|
150
|
+
|
|
151
|
+
address smartWallet = address(new MockMultiOwnable(privyAccount));
|
|
152
|
+
|
|
153
|
+
mock1155.mint(smartWallet, tokenId1, 1, "");
|
|
154
|
+
|
|
155
|
+
IComments.PermitComment memory permitComment = IComments.PermitComment({
|
|
156
|
+
// comment will be attributed to the smart wallet - it should be the one that
|
|
157
|
+
// has the signature checked against it.
|
|
158
|
+
commenter: privyAccount,
|
|
159
|
+
contractAddress: address(mock1155),
|
|
160
|
+
tokenId: tokenId1,
|
|
161
|
+
replyTo: IComments.CommentIdentifier({commenter: address(0), contractAddress: address(0), tokenId: 0, nonce: bytes32(0)}),
|
|
162
|
+
text: "smart wallet comment",
|
|
163
|
+
deadline: uint48(block.timestamp + 1000),
|
|
164
|
+
nonce: bytes32(0),
|
|
165
|
+
referrer: address(0),
|
|
166
|
+
sourceChainId: uint32(100),
|
|
167
|
+
destinationChainId: uint32(block.chainid),
|
|
168
|
+
// collectorWithToken is the smart wallet owner - this is the account that actually owns the 1155 token.
|
|
169
|
+
commenterSmartWallet: smartWallet
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// sign the permit - but we have the another account (privy) sign for the smart wallet, since it is also an owner
|
|
173
|
+
bytes memory signature = _signPermitComment(permitComment, privyPrivateKey);
|
|
174
|
+
|
|
175
|
+
IComments.CommentIdentifier memory expectedCommentIdentifier = _expectedCommentIdentifier(
|
|
176
|
+
permitComment.contractAddress,
|
|
177
|
+
permitComment.tokenId,
|
|
178
|
+
// privy account is the one that signs the message, but the smart wallet is the one that is commenting
|
|
179
|
+
privyAccount
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
address executor = makeAddr("executor");
|
|
183
|
+
vm.deal(executor, SPARKS_VALUE);
|
|
184
|
+
_executePermitComment(executor, permitComment, signature);
|
|
185
|
+
|
|
186
|
+
_assertCommentExists(expectedCommentIdentifier);
|
|
187
|
+
}
|
|
188
|
+
|
|
113
189
|
function testPermitSparkCommentSparksComment() public {
|
|
114
190
|
IComments.PermitSparkComment memory permitSparkComment = _postCommentAndCreatePermitSparkComment(sparker, 3);
|
|
115
191
|
bytes memory signature = _signPermitSparkComment(permitSparkComment, sparkerPrivateKey);
|
|
@@ -119,16 +195,21 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
119
195
|
address executor = makeAddr("executor");
|
|
120
196
|
vm.deal(executor, permitSparkComment.sparksQuantity * SPARKS_VALUE);
|
|
121
197
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
uint256 beforeSparksCount = comments.commentSparksQuantity(commentId);
|
|
198
|
+
uint256 beforeSparksCount = comments.commentSparksQuantity(permitSparkComment.comment);
|
|
125
199
|
|
|
126
200
|
vm.expectEmit(true, true, true, true);
|
|
127
|
-
emit IComments.SparkedComment(
|
|
201
|
+
emit IComments.SparkedComment(
|
|
202
|
+
comments.hashCommentIdentifier(permitSparkComment.comment),
|
|
203
|
+
permitSparkComment.comment,
|
|
204
|
+
permitSparkComment.sparksQuantity,
|
|
205
|
+
sparker,
|
|
206
|
+
block.timestamp,
|
|
207
|
+
permitSparkComment.referrer
|
|
208
|
+
);
|
|
128
209
|
|
|
129
210
|
_executePermitSparkComment(executor, permitSparkComment, signature);
|
|
130
211
|
|
|
131
|
-
uint256 afterSparksCount = comments.commentSparksQuantity(
|
|
212
|
+
uint256 afterSparksCount = comments.commentSparksQuantity(permitSparkComment.comment);
|
|
132
213
|
assertEq(afterSparksCount, beforeSparksCount + permitSparkComment.sparksQuantity);
|
|
133
214
|
}
|
|
134
215
|
|
|
@@ -204,10 +285,10 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
204
285
|
}
|
|
205
286
|
|
|
206
287
|
function testPermitCommentCrossChain() public {
|
|
207
|
-
|
|
208
|
-
|
|
288
|
+
uint32 sourceChainId = 1; // Ethereum mainnet
|
|
289
|
+
uint32 destinationChainId = uint32(block.chainid);
|
|
209
290
|
|
|
210
|
-
IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "cross-chain comment"
|
|
291
|
+
IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "cross-chain comment");
|
|
211
292
|
permitComment.sourceChainId = sourceChainId;
|
|
212
293
|
permitComment.destinationChainId = destinationChainId;
|
|
213
294
|
|
|
@@ -222,7 +303,7 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
222
303
|
_setupTokenAndSparks(permitComment);
|
|
223
304
|
|
|
224
305
|
address executor = makeAddr("executor");
|
|
225
|
-
vm.deal(executor,
|
|
306
|
+
vm.deal(executor, SPARKS_VALUE);
|
|
226
307
|
|
|
227
308
|
vm.expectEmit(true, true, true, true);
|
|
228
309
|
emit IComments.Commented(
|
|
@@ -230,7 +311,7 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
230
311
|
expectedCommentIdentifier,
|
|
231
312
|
bytes32(0),
|
|
232
313
|
permitComment.replyTo,
|
|
233
|
-
|
|
314
|
+
1,
|
|
234
315
|
permitComment.text,
|
|
235
316
|
block.timestamp,
|
|
236
317
|
permitComment.referrer
|
|
@@ -242,10 +323,10 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
242
323
|
}
|
|
243
324
|
|
|
244
325
|
function testPermitCommentCrossChainInvalidDestination() public {
|
|
245
|
-
|
|
246
|
-
|
|
326
|
+
uint32 sourceChainId = 1; // Ethereum mainnet
|
|
327
|
+
uint32 invalidDestinationChainId = 42; // Some other chain ID
|
|
247
328
|
|
|
248
|
-
IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "invalid cross-chain comment"
|
|
329
|
+
IComments.PermitComment memory permitComment = _createPermitComment(collectorWithToken, "invalid cross-chain comment");
|
|
249
330
|
permitComment.sourceChainId = sourceChainId;
|
|
250
331
|
permitComment.destinationChainId = invalidDestinationChainId;
|
|
251
332
|
|
|
@@ -254,15 +335,15 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
254
335
|
_setupTokenAndSparks(permitComment);
|
|
255
336
|
|
|
256
337
|
address executor = makeAddr("executor");
|
|
257
|
-
vm.deal(executor,
|
|
338
|
+
vm.deal(executor, SPARKS_VALUE);
|
|
258
339
|
|
|
259
340
|
vm.expectRevert(abi.encodeWithSelector(IComments.IncorrectDestinationChain.selector, invalidDestinationChainId));
|
|
260
341
|
_executePermitComment(executor, permitComment, signature);
|
|
261
342
|
}
|
|
262
343
|
|
|
263
344
|
function testPermitSparkCommentCrossChain() public {
|
|
264
|
-
|
|
265
|
-
|
|
345
|
+
uint32 sourceChainId = 1; // Ethereum mainnet
|
|
346
|
+
uint32 destinationChainId = uint32(block.chainid);
|
|
266
347
|
|
|
267
348
|
IComments.PermitSparkComment memory permitSparkComment = _postCommentAndCreatePermitSparkComment(sparker, 3);
|
|
268
349
|
permitSparkComment.sourceChainId = sourceChainId;
|
|
@@ -275,22 +356,28 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
275
356
|
address executor = makeAddr("executor");
|
|
276
357
|
vm.deal(executor, permitSparkComment.sparksQuantity * SPARKS_VALUE);
|
|
277
358
|
|
|
278
|
-
|
|
359
|
+
uint256 beforeSparksCount = comments.commentSparksQuantity(permitSparkComment.comment);
|
|
279
360
|
|
|
280
|
-
|
|
361
|
+
bytes32 commentId = comments.hashCommentIdentifier(permitSparkComment.comment);
|
|
281
362
|
|
|
282
363
|
vm.expectEmit(true, true, true, true);
|
|
283
|
-
emit IComments.SparkedComment(
|
|
284
|
-
|
|
364
|
+
emit IComments.SparkedComment(
|
|
365
|
+
commentId,
|
|
366
|
+
permitSparkComment.comment,
|
|
367
|
+
permitSparkComment.sparksQuantity,
|
|
368
|
+
sparker,
|
|
369
|
+
block.timestamp,
|
|
370
|
+
permitSparkComment.referrer
|
|
371
|
+
);
|
|
285
372
|
_executePermitSparkComment(executor, permitSparkComment, signature);
|
|
286
373
|
|
|
287
|
-
uint256 afterSparksCount = comments.commentSparksQuantity(
|
|
374
|
+
uint256 afterSparksCount = comments.commentSparksQuantity(permitSparkComment.comment);
|
|
288
375
|
assertEq(afterSparksCount, beforeSparksCount + permitSparkComment.sparksQuantity);
|
|
289
376
|
}
|
|
290
377
|
|
|
291
378
|
function testPermitSparkCommentCrossChainInvalidDestination() public {
|
|
292
|
-
|
|
293
|
-
|
|
379
|
+
uint32 sourceChainId = 1; // Ethereum mainnet
|
|
380
|
+
uint32 invalidDestinationChainId = 42; // Some other chain ID
|
|
294
381
|
|
|
295
382
|
IComments.PermitSparkComment memory permitSparkComment = _postCommentAndCreatePermitSparkComment(sparker, 3);
|
|
296
383
|
permitSparkComment.sourceChainId = sourceChainId;
|
|
@@ -312,7 +399,7 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
312
399
|
address commenter = makeAddr("commenter_b");
|
|
313
400
|
IComments.CommentIdentifier memory commentIdentifier = _mockComment(commenter, emptyReplyTo);
|
|
314
401
|
|
|
315
|
-
return _createPermitSparkComment(commentIdentifier, _sparker, sparksQuantity, block.chainid, block.chainid);
|
|
402
|
+
return _createPermitSparkComment(commentIdentifier, _sparker, sparksQuantity, uint32(block.chainid), uint32(block.chainid));
|
|
316
403
|
}
|
|
317
404
|
|
|
318
405
|
// Helper functions
|
|
@@ -320,8 +407,8 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
320
407
|
IComments.CommentIdentifier memory commentIdentifier,
|
|
321
408
|
address _sparker,
|
|
322
409
|
uint64 sparksQuantity,
|
|
323
|
-
|
|
324
|
-
|
|
410
|
+
uint32 sourceChainId,
|
|
411
|
+
uint32 destinationChainId
|
|
325
412
|
) internal returns (IComments.PermitSparkComment memory) {
|
|
326
413
|
return
|
|
327
414
|
IComments.PermitSparkComment({
|
|
@@ -353,7 +440,7 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
353
440
|
}
|
|
354
441
|
|
|
355
442
|
// Helper functions
|
|
356
|
-
function _createPermitComment(address commenter, string memory text
|
|
443
|
+
function _createPermitComment(address commenter, string memory text) internal returns (IComments.PermitComment memory) {
|
|
357
444
|
return
|
|
358
445
|
IComments.PermitComment({
|
|
359
446
|
contractAddress: address(mock1155),
|
|
@@ -361,23 +448,23 @@ contract CommentsPermitTest is CommentsTestBase {
|
|
|
361
448
|
commenter: commenter,
|
|
362
449
|
replyTo: emptyCommentIdentifier,
|
|
363
450
|
text: text,
|
|
364
|
-
sparksQuantity: sparksQuantity,
|
|
365
451
|
deadline: block.timestamp + 100,
|
|
366
452
|
nonce: bytes32("1"),
|
|
367
453
|
referrer: makeAddr("referrer"),
|
|
368
|
-
sourceChainId: block.chainid,
|
|
369
|
-
destinationChainId: block.chainid
|
|
454
|
+
sourceChainId: uint32(block.chainid),
|
|
455
|
+
destinationChainId: uint32(block.chainid),
|
|
456
|
+
commenterSmartWallet: address(0)
|
|
370
457
|
});
|
|
371
458
|
}
|
|
372
459
|
|
|
373
460
|
function _setupTokenAndSparks(IComments.PermitComment memory permitComment) internal {
|
|
374
461
|
mock1155.mint(permitComment.commenter, permitComment.tokenId, 1, "");
|
|
375
|
-
vm.deal(permitComment.commenter,
|
|
462
|
+
vm.deal(permitComment.commenter, SPARKS_VALUE);
|
|
376
463
|
}
|
|
377
464
|
|
|
378
465
|
function _executePermitComment(address executor, IComments.PermitComment memory permitComment, bytes memory signature) internal {
|
|
379
466
|
vm.prank(executor);
|
|
380
|
-
comments.permitComment{value:
|
|
467
|
+
comments.permitComment{value: SPARKS_VALUE}(permitComment, signature);
|
|
381
468
|
}
|
|
382
469
|
|
|
383
470
|
function _assertCommentExists(IComments.CommentIdentifier memory commentIdentifier) internal view {
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
import {CommentsTestBase} from "./CommentsTestBase.sol";
|
|
5
|
+
import {IMultiOwnable} from "../src/interfaces/IMultiOwnable.sol";
|
|
6
|
+
import {IComments} from "../src/interfaces/IComments.sol";
|
|
7
|
+
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
|
8
|
+
import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
|
|
9
|
+
|
|
10
|
+
contract MockMultiOwnable is IMultiOwnable, ERC1155Holder {
|
|
11
|
+
bytes4 internal constant MAGIC_VALUE = bytes4(keccak256("isValidSignature(bytes32,bytes)"));
|
|
12
|
+
mapping(address => bool) public isOwner;
|
|
13
|
+
|
|
14
|
+
constructor(address _owner) {
|
|
15
|
+
isOwner[_owner] = true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function addOwner(address _owner) external {
|
|
19
|
+
isOwner[_owner] = true;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isValidSignature(bytes32 _messageHash, bytes memory _signature) public view returns (bytes4 magicValue) {
|
|
23
|
+
address signatory = ECDSA.recover(_messageHash, _signature);
|
|
24
|
+
|
|
25
|
+
if (isOwner[signatory]) {
|
|
26
|
+
return MAGIC_VALUE;
|
|
27
|
+
} else {
|
|
28
|
+
return bytes4(0);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isOwnerAddress(address account) external view returns (bool) {
|
|
33
|
+
return isOwner[account];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
contract Comments_smartWallet is CommentsTestBase {
|
|
38
|
+
function test_commentWithSmartWalletOwner_whenHolder() public {
|
|
39
|
+
address smartWallet = address(new MockMultiOwnable(address(collectorWithoutToken)));
|
|
40
|
+
|
|
41
|
+
mock1155.mint(smartWallet, tokenId1, 1, "");
|
|
42
|
+
|
|
43
|
+
IComments.CommentIdentifier memory expectedCommentIdentifier = _expectedCommentIdentifier(address(mock1155), tokenId1, collectorWithoutToken);
|
|
44
|
+
|
|
45
|
+
vm.expectEmit(true, true, true, true);
|
|
46
|
+
emit IComments.Commented(
|
|
47
|
+
comments.hashCommentIdentifier(expectedCommentIdentifier),
|
|
48
|
+
expectedCommentIdentifier,
|
|
49
|
+
0,
|
|
50
|
+
emptyCommentIdentifier,
|
|
51
|
+
1,
|
|
52
|
+
"test comment",
|
|
53
|
+
block.timestamp,
|
|
54
|
+
address(0)
|
|
55
|
+
);
|
|
56
|
+
vm.prank(collectorWithoutToken);
|
|
57
|
+
vm.deal(collectorWithoutToken, SPARKS_VALUE);
|
|
58
|
+
comments.comment{value: SPARKS_VALUE}({
|
|
59
|
+
commenter: collectorWithoutToken,
|
|
60
|
+
contractAddress: address(mock1155),
|
|
61
|
+
tokenId: tokenId1,
|
|
62
|
+
text: "test comment",
|
|
63
|
+
replyTo: emptyCommentIdentifier,
|
|
64
|
+
commenterSmartWallet: smartWallet,
|
|
65
|
+
referrer: address(0)
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function test_commentWithSmartWalletOwner_whenCreator() public {
|
|
70
|
+
address smartWallet = address(new MockMultiOwnable(address(collectorWithoutToken)));
|
|
71
|
+
|
|
72
|
+
uint256 tokenId = 10;
|
|
73
|
+
mock1155.createToken(tokenId, address(smartWallet));
|
|
74
|
+
|
|
75
|
+
IComments.CommentIdentifier memory expectedCommentIdentifier = _expectedCommentIdentifier(address(mock1155), tokenId, collectorWithoutToken);
|
|
76
|
+
|
|
77
|
+
vm.prank(collectorWithoutToken);
|
|
78
|
+
comments.comment({
|
|
79
|
+
commenter: collectorWithoutToken,
|
|
80
|
+
contractAddress: address(mock1155),
|
|
81
|
+
tokenId: tokenId,
|
|
82
|
+
text: "test comment",
|
|
83
|
+
replyTo: emptyCommentIdentifier,
|
|
84
|
+
commenterSmartWallet: smartWallet,
|
|
85
|
+
referrer: address(0)
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// check that comment was created
|
|
89
|
+
(, bool exists) = comments.hashAndCheckCommentExists(expectedCommentIdentifier);
|
|
90
|
+
assertTrue(exists);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function test_commentWithSmartWalletOwner_revertsWhenNotHolder() public {
|
|
94
|
+
address smartWallet = address(new MockMultiOwnable(address(collectorWithoutToken)));
|
|
95
|
+
|
|
96
|
+
IComments.CommentIdentifier memory emptyReplyTo;
|
|
97
|
+
|
|
98
|
+
vm.expectRevert(abi.encodeWithSelector(IComments.NotTokenHolderOrAdmin.selector));
|
|
99
|
+
vm.prank(collectorWithoutToken);
|
|
100
|
+
vm.deal(collectorWithoutToken, SPARKS_VALUE);
|
|
101
|
+
comments.comment{value: SPARKS_VALUE}({
|
|
102
|
+
commenter: collectorWithoutToken,
|
|
103
|
+
contractAddress: address(mock1155),
|
|
104
|
+
tokenId: tokenId1,
|
|
105
|
+
text: "test comment",
|
|
106
|
+
replyTo: emptyReplyTo,
|
|
107
|
+
commenterSmartWallet: smartWallet,
|
|
108
|
+
referrer: address(0)
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function test_commentWithSmartWalletOwner_revertsWhenNotOwner() public {
|
|
113
|
+
address smartWallet = address(new MockMultiOwnable(address(makeAddr("notOwner"))));
|
|
114
|
+
|
|
115
|
+
mock1155.mint(smartWallet, tokenId1, 1, "");
|
|
116
|
+
|
|
117
|
+
IComments.CommentIdentifier memory emptyReplyTo;
|
|
118
|
+
|
|
119
|
+
vm.expectRevert(IComments.NotSmartWalletOwner.selector);
|
|
120
|
+
vm.prank(collectorWithoutToken);
|
|
121
|
+
vm.deal(collectorWithoutToken, SPARKS_VALUE);
|
|
122
|
+
comments.comment{value: SPARKS_VALUE}({
|
|
123
|
+
commenter: collectorWithoutToken,
|
|
124
|
+
contractAddress: address(mock1155),
|
|
125
|
+
tokenId: tokenId1,
|
|
126
|
+
text: "test comment",
|
|
127
|
+
replyTo: emptyReplyTo,
|
|
128
|
+
commenterSmartWallet: smartWallet,
|
|
129
|
+
referrer: address(0)
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function test_commentWithSmartWalletOwner_revertsWhenNotSmartWallet() public {
|
|
134
|
+
address smartWallet = makeAddr("smartWallet");
|
|
135
|
+
|
|
136
|
+
mock1155.mint(smartWallet, tokenId1, 1, "");
|
|
137
|
+
|
|
138
|
+
IComments.CommentIdentifier memory emptyReplyTo;
|
|
139
|
+
|
|
140
|
+
vm.expectRevert(IComments.NotSmartWallet.selector);
|
|
141
|
+
vm.prank(collectorWithoutToken);
|
|
142
|
+
comments.comment({
|
|
143
|
+
commenter: collectorWithoutToken,
|
|
144
|
+
contractAddress: address(mock1155),
|
|
145
|
+
tokenId: tokenId1,
|
|
146
|
+
text: "test comment",
|
|
147
|
+
replyTo: emptyReplyTo,
|
|
148
|
+
commenterSmartWallet: smartWallet,
|
|
149
|
+
referrer: address(0)
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
package/test/mocks/Mock1155.sol
CHANGED
|
@@ -8,6 +8,9 @@ contract Mock1155 is ERC1155, IZoraCreator1155 {
|
|
|
8
8
|
/// @notice This user role allows for any action to be performed
|
|
9
9
|
uint256 public constant PERMISSION_BIT_ADMIN = 2 ** 1;
|
|
10
10
|
|
|
11
|
+
/// @notice Global contract configuration
|
|
12
|
+
ContractConfig public config;
|
|
13
|
+
|
|
11
14
|
mapping(uint256 => address) public admins;
|
|
12
15
|
|
|
13
16
|
constructor() ERC1155("") {}
|
|
@@ -40,11 +43,19 @@ contract Mock1155 is ERC1155, IZoraCreator1155 {
|
|
|
40
43
|
return super.supportsInterface(interfaceId);
|
|
41
44
|
}
|
|
42
45
|
|
|
43
|
-
function mint(address to, uint256 id, uint256 amount, bytes memory data) external {
|
|
46
|
+
function mint(address to, uint256 id, uint256 amount, bytes memory data) external payable {
|
|
44
47
|
if (!_tokenExists(id)) {
|
|
45
48
|
revert("Token does not exist");
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
_mint(to, id, amount, data);
|
|
49
52
|
}
|
|
53
|
+
|
|
54
|
+
function owner() external view returns (address) {
|
|
55
|
+
return config.owner;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function burn(address from, uint256 id, uint256 amount) external {
|
|
59
|
+
_safeTransferFrom(from, address(0), id, amount, "");
|
|
60
|
+
}
|
|
50
61
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
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 "./MockIZoraCreator1155.sol";
|
|
6
|
+
|
|
7
|
+
contract Mock1155NoCreatorRewardRecipient 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
|
+
/// @notice Global contract configuration
|
|
12
|
+
ContractConfig public config;
|
|
13
|
+
|
|
14
|
+
mapping(uint256 => address) public admins;
|
|
15
|
+
|
|
16
|
+
constructor() ERC1155("") {}
|
|
17
|
+
|
|
18
|
+
function isAdminOrRole(address user, uint256 tokenId, uint256 role) external view returns (bool) {
|
|
19
|
+
if (admins[tokenId] == user && role == PERMISSION_BIT_ADMIN) {
|
|
20
|
+
return true;
|
|
21
|
+
} else {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function _tokenExists(uint256 tokenId) internal view returns (bool) {
|
|
27
|
+
return admins[tokenId] != address(0);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function createToken(uint256 tokenId, address creator) external {
|
|
31
|
+
admins[tokenId] = creator;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function supportsInterface(bytes4 interfaceId) public view override(ERC1155, IZoraCreator1155) returns (bool) {
|
|
35
|
+
return super.supportsInterface(interfaceId);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function mint(address to, uint256 id, uint256 amount, bytes memory data) external {
|
|
39
|
+
if (!_tokenExists(id)) {
|
|
40
|
+
revert("Token does not exist");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
_mint(to, id, amount, data);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function _setFundsRecipient(address payable fundsRecipient) internal {
|
|
47
|
+
config.fundsRecipient = fundsRecipient;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function setFundsRecipient(address payable fundsRecipient) external {
|
|
51
|
+
_setFundsRecipient(fundsRecipient);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function owner() external view returns (address) {
|
|
55
|
+
return config.owner;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function _setOwner(address newOwner) internal {
|
|
59
|
+
config.owner = newOwner;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function setOwner(address newOwner) external {
|
|
63
|
+
_setOwner(newOwner);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
|
|
5
|
+
import {IERC1155} from "@openzeppelin/contracts/interfaces/IERC1155.sol";
|
|
6
|
+
import {IZoraCreator1155TypesV1} from "../../src/interfaces/IZoraCreator1155TypesV1.sol";
|
|
7
|
+
|
|
8
|
+
// For testing without getCreatorRewardRecipient
|
|
9
|
+
interface IZoraCreator1155 is IERC1155, IZoraCreator1155TypesV1 {
|
|
10
|
+
function isAdminOrRole(address user, uint256 tokenId, uint256 role) external view returns (bool);
|
|
11
|
+
|
|
12
|
+
function supportsInterface(bytes4 interfaceId) external view returns (bool);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
contract Mock1155NoOwner is ERC1155, IZoraCreator1155 {
|
|
16
|
+
/// @notice This user role allows for any action to be performed
|
|
17
|
+
uint256 public constant PERMISSION_BIT_ADMIN = 2 ** 1;
|
|
18
|
+
|
|
19
|
+
/// @notice Global contract configuration
|
|
20
|
+
ContractConfig public config;
|
|
21
|
+
|
|
22
|
+
mapping(uint256 => address) public admins;
|
|
23
|
+
|
|
24
|
+
constructor() ERC1155("") {}
|
|
25
|
+
|
|
26
|
+
function isAdminOrRole(address user, uint256 tokenId, uint256 role) external view returns (bool) {
|
|
27
|
+
if (admins[tokenId] == user && role == PERMISSION_BIT_ADMIN) {
|
|
28
|
+
return true;
|
|
29
|
+
} else {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function _tokenExists(uint256 tokenId) internal view returns (bool) {
|
|
35
|
+
return admins[tokenId] != address(0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function createToken(uint256 tokenId, address creator) external {
|
|
39
|
+
admins[tokenId] = creator;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function supportsInterface(bytes4 interfaceId) public view override(ERC1155, IZoraCreator1155) returns (bool) {
|
|
43
|
+
return super.supportsInterface(interfaceId);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function mint(address to, uint256 id, uint256 amount, bytes memory data) external {
|
|
47
|
+
if (!_tokenExists(id)) {
|
|
48
|
+
revert("Token does not exist");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
_mint(to, id, amount, data);
|
|
52
|
+
}
|
|
53
|
+
}
|