@zoralabs/comments-contracts 0.0.1 → 0.0.2-COMMENTS.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +48 -30
- package/CHANGELOG.md +8 -0
- package/README.md +10 -39
- package/abis/AddDelegateCommenterRole.json +22 -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 +22 -0
- package/abis/EIP712Upgradeable.json +74 -0
- package/abis/EIP712UpgradeableWithChainId.json +49 -0
- package/abis/ERC20.json +310 -0
- 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/IMultiOwnable.json +21 -0
- 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/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/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 +11 -10
- package/script/AddDelegateCommenterRole.s.sol +24 -0
- package/script/CommentsDeployerBase.sol +101 -19
- package/script/Deploy.s.sol +2 -44
- package/script/DeployCallerAndCommenterImpl.s.sol +27 -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/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
package/src/CommentsImpl.sol
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity ^0.8.23;
|
|
3
3
|
|
|
4
|
-
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
|
5
4
|
import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
|
|
6
5
|
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
7
6
|
import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
|
|
8
|
-
import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
|
|
9
7
|
import {IHasContractName} from "@zoralabs/shared-contracts/interfaces/IContractMetadata.sol";
|
|
10
8
|
import {ContractVersionBase} from "./version/ContractVersionBase.sol";
|
|
11
9
|
import {IZoraCreator1155} from "./interfaces/IZoraCreator1155.sol";
|
|
@@ -14,40 +12,46 @@ import {IProtocolRewards} from "@zoralabs/protocol-rewards/src/interfaces/IProto
|
|
|
14
12
|
import {UnorderedNoncesUpgradeable} from "@zoralabs/shared-contracts/utils/UnorderedNoncesUpgradeable.sol";
|
|
15
13
|
import {EIP712UpgradeableWithChainId} from "./utils/EIP712UpgradeableWithChainId.sol";
|
|
16
14
|
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
|
|
15
|
+
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
|
|
16
|
+
import {IMultiOwnable} from "./interfaces/IMultiOwnable.sol";
|
|
17
|
+
import {CommentsImplConstants} from "./CommentsImplConstants.sol";
|
|
17
18
|
|
|
18
19
|
/// @title CommentsImpl
|
|
19
20
|
/// @notice Contract for comments and sparking (liking with value) Zora 1155 posts.
|
|
20
21
|
/// @dev Implements comment creation, sparking, and backfilling functionality. Implementation contract
|
|
21
22
|
/// meant to be used with a UUPS upgradeable proxy contract.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
23
|
+
/// @author oveddan / IsabellaSmallcombe
|
|
24
|
+
contract CommentsImpl is
|
|
25
|
+
IComments,
|
|
26
|
+
AccessControlUpgradeable,
|
|
27
|
+
UUPSUpgradeable,
|
|
28
|
+
ContractVersionBase,
|
|
29
|
+
EIP712UpgradeableWithChainId,
|
|
30
|
+
UnorderedNoncesUpgradeable,
|
|
31
|
+
CommentsImplConstants,
|
|
32
|
+
IHasContractName
|
|
33
|
+
{
|
|
34
|
+
/// @notice keccak256(abi.encode(uint256(keccak256("comments.storage.CommentsStorage")) - 1)) & ~bytes32(uint256(0xff))
|
|
35
|
+
bytes32 private constant COMMENTS_STORAGE_LOCATION = 0x9e5d0d3a4c7e8d5b9e8f9d9d5b9e8f9d9d5b9e8f9d9d5b9e8f9d9d5b9e8f9d00;
|
|
36
|
+
/// @notice the spark value to comment
|
|
37
|
+
uint256 public immutable sparkValue;
|
|
38
|
+
/// @notice the address of the protocol rewards contract
|
|
39
|
+
IProtocolRewards public immutable protocolRewards;
|
|
40
|
+
/// @notice account that receives rewards Zora Rewards for from a portion of the sparks value
|
|
41
|
+
address immutable zoraRecipient;
|
|
35
42
|
|
|
36
43
|
/// @custom:storage-location erc7201:comments.storage.CommentsStorage
|
|
37
44
|
struct CommentsStorage {
|
|
38
45
|
mapping(bytes32 => Comment) comments;
|
|
39
|
-
//
|
|
40
|
-
address
|
|
46
|
+
// gap that held old zora recipient.
|
|
47
|
+
address __gap;
|
|
41
48
|
// Global autoincrementing nonce
|
|
42
49
|
uint256 nonce;
|
|
43
50
|
}
|
|
44
51
|
|
|
45
|
-
// keccak256(abi.encode(uint256(keccak256("comments.storage.CommentsStorage")) - 1)) & ~bytes32(uint256(0xff))
|
|
46
|
-
bytes32 private constant CommentsStorageLocation = 0x9e5d0d3a4c7e8d5b9e8f9d9d5b9e8f9d9d5b9e8f9d9d5b9e8f9d9d5b9e8f9d00;
|
|
47
|
-
|
|
48
52
|
function _getCommentsStorage() private pure returns (CommentsStorage storage $) {
|
|
49
53
|
assembly {
|
|
50
|
-
$.slot :=
|
|
54
|
+
$.slot := COMMENTS_STORAGE_LOCATION
|
|
51
55
|
}
|
|
52
56
|
}
|
|
53
57
|
|
|
@@ -55,38 +59,57 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
55
59
|
return _getCommentsStorage().comments[commentId];
|
|
56
60
|
}
|
|
57
61
|
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
/// @notice Returns the total number of sparks a given comment has received
|
|
63
|
+
/// @param commentIdentifier The identifier of the comment
|
|
64
|
+
/// @return The total number of sparks a comment has received
|
|
65
|
+
function commentSparksQuantity(CommentIdentifier memory commentIdentifier) external view returns (uint256) {
|
|
66
|
+
return comments(hashCommentIdentifier(commentIdentifier)).totalSparks;
|
|
60
67
|
}
|
|
61
68
|
|
|
69
|
+
/// @notice Returns the next nonce for comment creation
|
|
70
|
+
/// @return The next nonce
|
|
62
71
|
function nextNonce() external view returns (bytes32) {
|
|
63
72
|
return bytes32(_getCommentsStorage().nonce);
|
|
64
73
|
}
|
|
65
74
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
75
|
+
/// @notice Returns the implementation address of the contract
|
|
76
|
+
/// @return The implementation address
|
|
77
|
+
function implementation() external view returns (address) {
|
|
78
|
+
return ERC1967Utils.getImplementation();
|
|
79
|
+
}
|
|
69
80
|
|
|
70
|
-
|
|
71
|
-
|
|
81
|
+
/// @notice Contract constructor
|
|
82
|
+
/// @param _sparkValue The value of a spark
|
|
83
|
+
/// @param _protocolRewards The address of the protocol rewards contract
|
|
84
|
+
/// @param _zoraRecipient The address of the zora recipient
|
|
85
|
+
constructor(uint256 _sparkValue, address _protocolRewards, address _zoraRecipient) {
|
|
86
|
+
if (_protocolRewards == address(0) || _zoraRecipient == address(0)) {
|
|
87
|
+
revert AddressZero();
|
|
88
|
+
}
|
|
72
89
|
_disableInitializers();
|
|
73
90
|
|
|
74
91
|
sparkValue = _sparkValue;
|
|
75
92
|
protocolRewards = IProtocolRewards(_protocolRewards);
|
|
93
|
+
zoraRecipient = _zoraRecipient;
|
|
76
94
|
}
|
|
77
95
|
|
|
78
|
-
|
|
96
|
+
/// @notice Initializes the contract with default admin, backfiller, and delegate commenters
|
|
97
|
+
/// @param defaultAdmin The address of the default admin
|
|
98
|
+
/// @param backfiller The address of the backfiller
|
|
99
|
+
/// @param delegateCommenters The addresses of the delegate commenters
|
|
100
|
+
function initialize(address defaultAdmin, address backfiller, address[] calldata delegateCommenters) public initializer {
|
|
101
|
+
if (defaultAdmin == address(0) || backfiller == address(0)) {
|
|
102
|
+
revert AddressZero();
|
|
103
|
+
}
|
|
79
104
|
__AccessControl_init();
|
|
80
105
|
__UUPSUpgradeable_init();
|
|
81
106
|
__EIP712_init(DOMAIN_NAME, DOMAIN_VERSION);
|
|
82
107
|
|
|
83
|
-
_getCommentsStorage().zoraRecipient = _zoraRecipient;
|
|
84
|
-
|
|
85
108
|
_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);
|
|
86
109
|
_grantRole(BACKFILLER_ROLE, backfiller);
|
|
87
110
|
|
|
88
111
|
for (uint256 i = 0; i < delegateCommenters.length; i++) {
|
|
89
|
-
_grantRole(
|
|
112
|
+
_grantRole(DELEGATE_COMMENTER, delegateCommenters[i]);
|
|
90
113
|
}
|
|
91
114
|
}
|
|
92
115
|
|
|
@@ -124,6 +147,8 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
124
147
|
/// @param commenter The address of the commenter
|
|
125
148
|
/// @param text The text content of the comment
|
|
126
149
|
/// @param replyTo The identifier of the comment being replied to (if any)
|
|
150
|
+
/// @param commenterSmartWallet If the commenter has a smart wallet, the smart wallet, which can checked to be the owner or creator of the 1155 token
|
|
151
|
+
/// @param referrer The address of the referrer (if any)
|
|
127
152
|
/// @return commentIdentifier The identifier of the created comment, including the nonce
|
|
128
153
|
function comment(
|
|
129
154
|
address commenter,
|
|
@@ -131,31 +156,71 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
131
156
|
uint256 tokenId,
|
|
132
157
|
string calldata text,
|
|
133
158
|
CommentIdentifier calldata replyTo,
|
|
159
|
+
address commenterSmartWallet,
|
|
134
160
|
address referrer
|
|
135
161
|
) external payable returns (CommentIdentifier memory commentIdentifier) {
|
|
136
|
-
|
|
137
|
-
if (msg.value != 0) {
|
|
138
|
-
sparksQuantity = 1;
|
|
139
|
-
}
|
|
140
|
-
_validateSparksQuantityMatchesValue(sparksQuantity, msg.value);
|
|
162
|
+
uint256 sparksQuantity = _getAndValidateSingleSparkQuantityFromValue(msg.value);
|
|
141
163
|
|
|
142
164
|
commentIdentifier = _createCommentIdentifier(contractAddress, tokenId, commenter);
|
|
143
165
|
|
|
144
|
-
_comment(
|
|
166
|
+
_comment({
|
|
167
|
+
commenter: msg.sender,
|
|
168
|
+
commentIdentifier: commentIdentifier,
|
|
169
|
+
text: text,
|
|
170
|
+
sparksQuantity: sparksQuantity,
|
|
171
|
+
replyTo: replyTo,
|
|
172
|
+
commenterSmartWallet: commenterSmartWallet,
|
|
173
|
+
referrer: referrer,
|
|
174
|
+
mustSendAtLeastOneSpark: true
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// gets the sparks quantity from the value sent with the transaction,
|
|
179
|
+
// ensuring that at most 1 spark is sent.
|
|
180
|
+
function _getAndValidateSingleSparkQuantityFromValue(uint256 value) internal view returns (uint256) {
|
|
181
|
+
if (value == 0) {
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
if (value != sparkValue) {
|
|
185
|
+
revert IncorrectETHAmountForSparks(value, sparkValue);
|
|
186
|
+
}
|
|
187
|
+
return 1;
|
|
145
188
|
}
|
|
146
189
|
|
|
147
|
-
//
|
|
148
|
-
// to provide who the original
|
|
190
|
+
// Allows another contract to call this function to signify a caller commented, and is trusted
|
|
191
|
+
// to provide who the original commenter was. Allows no sparks to be sent.
|
|
192
|
+
/// @notice Allows another contract to delegate comment creation on behalf of a user
|
|
193
|
+
/// @param commenter The address of the commenter
|
|
194
|
+
/// @param contractAddress The address of the contract
|
|
195
|
+
/// @param tokenId The token ID
|
|
196
|
+
/// @param text The text content of the comment
|
|
197
|
+
/// @param replyTo The identifier of the comment being replied to (if any)
|
|
198
|
+
/// @param referrer The address of the referrer (if any)
|
|
199
|
+
/// @param commenterSmartWalletOwner If the commenter has a smart wallet, the smart wallet owner address
|
|
200
|
+
/// @return commentIdentifier The identifier of the created comment, including the nonce
|
|
149
201
|
function delegateComment(
|
|
150
202
|
address commenter,
|
|
151
203
|
address contractAddress,
|
|
152
204
|
uint256 tokenId,
|
|
153
205
|
string calldata text,
|
|
154
|
-
CommentIdentifier calldata replyTo
|
|
155
|
-
|
|
206
|
+
CommentIdentifier calldata replyTo,
|
|
207
|
+
address commenterSmartWalletOwner,
|
|
208
|
+
address referrer
|
|
209
|
+
) external payable onlyRole(DELEGATE_COMMENTER) returns (CommentIdentifier memory commentIdentifier, bytes32 commentId) {
|
|
210
|
+
uint256 sparksQuantity = _getAndValidateSingleSparkQuantityFromValue(msg.value);
|
|
211
|
+
|
|
156
212
|
commentIdentifier = _createCommentIdentifier(contractAddress, tokenId, commenter);
|
|
157
213
|
|
|
158
|
-
|
|
214
|
+
commentId = _comment({
|
|
215
|
+
commenter: commentIdentifier.commenter,
|
|
216
|
+
commentIdentifier: commentIdentifier,
|
|
217
|
+
text: text,
|
|
218
|
+
sparksQuantity: sparksQuantity,
|
|
219
|
+
replyTo: replyTo,
|
|
220
|
+
commenterSmartWallet: commenterSmartWalletOwner,
|
|
221
|
+
referrer: referrer,
|
|
222
|
+
mustSendAtLeastOneSpark: false
|
|
223
|
+
});
|
|
159
224
|
}
|
|
160
225
|
|
|
161
226
|
function _createCommentIdentifier(address contractAddress, uint256 tokenId, address commenter) private returns (CommentIdentifier memory) {
|
|
@@ -167,8 +232,9 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
167
232
|
address commenter,
|
|
168
233
|
CommentIdentifier memory commentIdentifier,
|
|
169
234
|
string memory text,
|
|
170
|
-
|
|
235
|
+
uint256 sparksQuantity,
|
|
171
236
|
CommentIdentifier memory replyTo,
|
|
237
|
+
address commenterSmartWallet,
|
|
172
238
|
address referrer,
|
|
173
239
|
bool mustSendAtLeastOneSpark
|
|
174
240
|
) internal returns (bytes32) {
|
|
@@ -176,7 +242,14 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
176
242
|
revert CommenterMismatch(commentIdentifier.commenter, commenter);
|
|
177
243
|
}
|
|
178
244
|
|
|
179
|
-
(bytes32 commentId, bytes32 replyToId) = _validateComment(
|
|
245
|
+
(bytes32 commentId, bytes32 replyToId) = _validateComment(
|
|
246
|
+
commentIdentifier,
|
|
247
|
+
replyTo,
|
|
248
|
+
text,
|
|
249
|
+
sparksQuantity,
|
|
250
|
+
commenterSmartWallet,
|
|
251
|
+
mustSendAtLeastOneSpark
|
|
252
|
+
);
|
|
180
253
|
|
|
181
254
|
_saveCommentAndTransferSparks(commentId, commentIdentifier, text, sparksQuantity, replyToId, replyTo, block.timestamp, referrer);
|
|
182
255
|
|
|
@@ -193,7 +266,8 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
193
266
|
CommentIdentifier memory commentIdentifier,
|
|
194
267
|
CommentIdentifier memory replyTo,
|
|
195
268
|
string memory text,
|
|
196
|
-
|
|
269
|
+
uint256 sparksQuantity,
|
|
270
|
+
address commenterSmartWallet,
|
|
197
271
|
bool mustSendAtLeastOneSpark
|
|
198
272
|
) internal view returns (bytes32 commentId, bytes32 replyToId) {
|
|
199
273
|
// verify that the commenter specified in the identifier is the one expected
|
|
@@ -208,20 +282,35 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
208
282
|
revert EmptyComment();
|
|
209
283
|
}
|
|
210
284
|
|
|
211
|
-
|
|
285
|
+
_validateCommenterAndSparksQuantity(commentIdentifier, sparksQuantity, mustSendAtLeastOneSpark, commenterSmartWallet);
|
|
212
286
|
}
|
|
213
287
|
|
|
214
|
-
function
|
|
288
|
+
function _validateCommenterAndSparksQuantity(
|
|
215
289
|
CommentIdentifier memory commentIdentifier,
|
|
216
|
-
|
|
217
|
-
bool mustSendAtLeastOneSpark
|
|
290
|
+
uint256 sparksQuantity,
|
|
291
|
+
bool mustSendAtLeastOneSpark,
|
|
292
|
+
address commenterSmartWallet
|
|
218
293
|
) internal view {
|
|
219
|
-
|
|
220
|
-
|
|
294
|
+
if (commenterSmartWallet != address(0)) {
|
|
295
|
+
if (commenterSmartWallet.code.length == 0) {
|
|
296
|
+
revert NotSmartWallet();
|
|
297
|
+
}
|
|
298
|
+
// check if the commenter is a smart wallet owner
|
|
299
|
+
if (!IMultiOwnable(commenterSmartWallet).isOwnerAddress(commentIdentifier.commenter)) {
|
|
300
|
+
revert NotSmartWalletOwner();
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// check that the commenter or smart wallet is a token admin - if they are, then they can comment for free
|
|
305
|
+
if (
|
|
306
|
+
_accountOrSmartWalletIsTokenAdmin(commentIdentifier.contractAddress, commentIdentifier.tokenId, commentIdentifier.commenter, commenterSmartWallet)
|
|
307
|
+
) {
|
|
221
308
|
return;
|
|
222
309
|
}
|
|
223
|
-
// if they aren't,
|
|
224
|
-
if (
|
|
310
|
+
// if they aren't, commenter or smart wallet must be a token holder, and have included at least 1 spark
|
|
311
|
+
if (
|
|
312
|
+
!_accountOrSmartWalletIsTokenHolder(commentIdentifier.contractAddress, commentIdentifier.tokenId, commentIdentifier.commenter, commenterSmartWallet)
|
|
313
|
+
) {
|
|
225
314
|
revert NotTokenHolderOrAdmin();
|
|
226
315
|
}
|
|
227
316
|
|
|
@@ -230,10 +319,6 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
230
319
|
}
|
|
231
320
|
}
|
|
232
321
|
|
|
233
|
-
bytes4 constant zoraRewardReason = bytes4(keccak256("zoraRewardForCommentDeposited()"));
|
|
234
|
-
bytes4 constant referrerRewardReason = bytes4(keccak256("referrerRewardForCommentDeposited()"));
|
|
235
|
-
bytes4 constant sparksRecipientRewardReason = bytes4(keccak256("sparksRecipientRewardForCommentDeposited()"));
|
|
236
|
-
|
|
237
322
|
function _getRewardDeposits(
|
|
238
323
|
address sparksRecipient,
|
|
239
324
|
address referrer,
|
|
@@ -244,33 +329,31 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
244
329
|
uint256[] memory amounts = new uint256[](recipientCount);
|
|
245
330
|
bytes4[] memory reasons = new bytes4[](recipientCount);
|
|
246
331
|
|
|
247
|
-
address zoraRecipient = _getCommentsStorage().zoraRecipient;
|
|
248
|
-
|
|
249
332
|
if (referrer != address(0)) {
|
|
250
333
|
uint256 zoraReward = (ZORA_REWARD_PCT * sparksValue) / BPS_TO_PERCENT_2_DECIMAL_PERCISION;
|
|
251
334
|
recipients[0] = zoraRecipient;
|
|
252
335
|
amounts[0] = zoraReward;
|
|
253
|
-
reasons[0] =
|
|
336
|
+
reasons[0] = ZORA_REWARD_REASON;
|
|
254
337
|
|
|
255
338
|
uint256 referrerReward = (REFERRER_REWARD_PCT * sparksValue) / BPS_TO_PERCENT_2_DECIMAL_PERCISION;
|
|
256
339
|
recipients[1] = referrer;
|
|
257
340
|
amounts[1] = referrerReward;
|
|
258
|
-
reasons[1] =
|
|
341
|
+
reasons[1] = REFERRER_REWARD_REASON;
|
|
259
342
|
|
|
260
343
|
uint256 sparksRecipientReward = sparksValue - zoraReward - referrerReward;
|
|
261
344
|
recipients[2] = sparksRecipient;
|
|
262
345
|
amounts[2] = sparksRecipientReward;
|
|
263
|
-
reasons[2] =
|
|
346
|
+
reasons[2] = SPARKS_RECIPIENT_REWARD_REASON;
|
|
264
347
|
} else {
|
|
265
348
|
uint256 zoraRewardNoReferrer = (ZORA_REWARD_NO_REFERRER_PCT * sparksValue) / BPS_TO_PERCENT_2_DECIMAL_PERCISION;
|
|
266
349
|
recipients[0] = zoraRecipient;
|
|
267
350
|
amounts[0] = zoraRewardNoReferrer;
|
|
268
|
-
reasons[0] =
|
|
351
|
+
reasons[0] = ZORA_REWARD_REASON;
|
|
269
352
|
|
|
270
353
|
uint256 sparkRecipientReward = sparksValue - zoraRewardNoReferrer;
|
|
271
354
|
recipients[1] = sparksRecipient;
|
|
272
355
|
amounts[1] = sparkRecipientReward;
|
|
273
|
-
reasons[1] =
|
|
356
|
+
reasons[1] = SPARKS_RECIPIENT_REWARD_REASON;
|
|
274
357
|
}
|
|
275
358
|
|
|
276
359
|
return (recipients, amounts, reasons);
|
|
@@ -281,8 +364,27 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
281
364
|
protocolRewards.depositBatch{value: sparksValue}(recipients, amounts, reasons, depositBatchComment);
|
|
282
365
|
}
|
|
283
366
|
|
|
367
|
+
function _accountOrSmartWalletIsTokenAdmin(address contractAddress, uint256 tokenId, address user, address smartWallet) internal view returns (bool) {
|
|
368
|
+
if (_isTokenAdmin(contractAddress, tokenId, user)) {
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
if (smartWallet != address(0)) {
|
|
372
|
+
return _isTokenAdmin(contractAddress, tokenId, smartWallet);
|
|
373
|
+
}
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function _accountOrSmartWalletIsTokenHolder(address contractAddress, uint256 tokenId, address user, address smartWallet) internal view returns (bool) {
|
|
378
|
+
if (_isTokenHolder(contractAddress, tokenId, user)) {
|
|
379
|
+
return true;
|
|
380
|
+
}
|
|
381
|
+
if (smartWallet != address(0)) {
|
|
382
|
+
return _isTokenHolder(contractAddress, tokenId, smartWallet);
|
|
383
|
+
}
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
|
|
284
387
|
function _isTokenAdmin(address contractAddress, uint256 tokenId, address user) internal view returns (bool) {
|
|
285
|
-
// TOOD: investigate is there a better way to know the token creator?
|
|
286
388
|
return IZoraCreator1155(contractAddress).isAdminOrRole(user, tokenId, PERMISSION_BIT_ADMIN);
|
|
287
389
|
}
|
|
288
390
|
|
|
@@ -306,7 +408,7 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
306
408
|
bytes32 commentId,
|
|
307
409
|
CommentIdentifier memory commentIdentifier,
|
|
308
410
|
string memory text,
|
|
309
|
-
|
|
411
|
+
uint256 sparksQuantity,
|
|
310
412
|
bytes32 replyToId,
|
|
311
413
|
CommentIdentifier memory replyToIdentifier,
|
|
312
414
|
uint256 timestamp,
|
|
@@ -330,7 +432,7 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
330
432
|
bytes32 commentId,
|
|
331
433
|
CommentIdentifier memory commentIdentifier,
|
|
332
434
|
string memory text,
|
|
333
|
-
|
|
435
|
+
uint256 sparksQuantity,
|
|
334
436
|
bytes32 replyToId,
|
|
335
437
|
CommentIdentifier memory replyToIdentifier,
|
|
336
438
|
uint256 timestamp,
|
|
@@ -345,11 +447,11 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
345
447
|
}
|
|
346
448
|
|
|
347
449
|
/// @notice Sparks a comment. Equivalant sparks value in eth to sparksQuantity must be sent with the transaction. Sparking a comment is
|
|
348
|
-
/// similar to liking it, except it is liked with the value of sparks attached. The spark value gets sent to the
|
|
450
|
+
/// similar to liking it, except it is liked with the value of sparks attached. The spark value gets sent to the commenter, with a fee taken out.
|
|
349
451
|
/// @param commentIdentifier The identifier of the comment to spark
|
|
350
452
|
/// @param sparksQuantity The quantity of sparks to send
|
|
351
453
|
/// @param referrer The referrer of the comment
|
|
352
|
-
function sparkComment(CommentIdentifier calldata commentIdentifier,
|
|
454
|
+
function sparkComment(CommentIdentifier calldata commentIdentifier, uint256 sparksQuantity, address referrer) public payable {
|
|
353
455
|
if (sparksQuantity == 0) {
|
|
354
456
|
revert MustSendAtLeastOneSpark();
|
|
355
457
|
}
|
|
@@ -357,13 +459,13 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
357
459
|
_sparkComment(commentIdentifier, msg.sender, sparksQuantity, referrer);
|
|
358
460
|
}
|
|
359
461
|
|
|
360
|
-
function _validateSparksQuantityMatchesValue(
|
|
462
|
+
function _validateSparksQuantityMatchesValue(uint256 sparksQuantity, uint256 value) internal view {
|
|
361
463
|
if (value != sparksQuantity * sparkValue) {
|
|
362
464
|
revert IncorrectETHAmountForSparks(value, sparksQuantity * sparkValue);
|
|
363
465
|
}
|
|
364
466
|
}
|
|
365
467
|
|
|
366
|
-
function _sparkComment(CommentIdentifier memory commentIdentifier, address sparker,
|
|
468
|
+
function _sparkComment(CommentIdentifier memory commentIdentifier, address sparker, uint256 sparksQuantity, address referrer) internal {
|
|
367
469
|
if (sparker == commentIdentifier.commenter) {
|
|
368
470
|
revert CannotSparkOwnComment();
|
|
369
471
|
}
|
|
@@ -372,20 +474,13 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
372
474
|
revert CommentDoesntExist();
|
|
373
475
|
}
|
|
374
476
|
|
|
375
|
-
comments(commentId).totalSparks +=
|
|
477
|
+
comments(commentId).totalSparks += uint256(sparksQuantity);
|
|
376
478
|
|
|
377
479
|
_transferSparksValueToRecipient(commentIdentifier.commenter, referrer, sparksQuantity * sparkValue, "Sparked Comment");
|
|
378
480
|
|
|
379
|
-
emit SparkedComment(commentId, commentIdentifier, sparksQuantity, sparker, block.timestamp);
|
|
481
|
+
emit SparkedComment(commentId, commentIdentifier, sparksQuantity, sparker, block.timestamp, referrer);
|
|
380
482
|
}
|
|
381
483
|
|
|
382
|
-
bytes32 constant PERMIT_COMMENT_DOMAIN =
|
|
383
|
-
keccak256(
|
|
384
|
-
"PermitComment(address contractAddress,uint256 tokenId,address commenter,CommentIdentifier replyTo,bytes text,uint64 sparksQuantity,uint256 deadline,bytes32 nonce,address referrer,uint256 sourceChainId,uint256 destinationChainId)CommentIdentifier(address contractAddress,uint256 tokenId,address commenter,bytes32 nonce)"
|
|
385
|
-
);
|
|
386
|
-
|
|
387
|
-
bytes32 constant COMMENT_IDENTIFIER_DOMAIN = keccak256("CommentIdentifier(address contractAddress,uint256 tokenId,address commenter,bytes32 nonce)");
|
|
388
|
-
|
|
389
484
|
function _hashCommentIdentifier(CommentIdentifier memory commentIdentifier) internal pure returns (bytes32) {
|
|
390
485
|
return
|
|
391
486
|
keccak256(
|
|
@@ -399,29 +494,28 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
399
494
|
);
|
|
400
495
|
}
|
|
401
496
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
497
|
+
/// @notice Hashes a permit comment struct for signing
|
|
498
|
+
/// @param permit The permit comment struct
|
|
499
|
+
/// @return The hash to sign
|
|
406
500
|
function hashPermitComment(PermitComment calldata permit) public view returns (bytes32) {
|
|
407
|
-
|
|
408
|
-
|
|
501
|
+
bytes32 structHash = keccak256(
|
|
502
|
+
abi.encode(
|
|
409
503
|
PERMIT_COMMENT_DOMAIN,
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
504
|
+
permit.contractAddress,
|
|
505
|
+
permit.tokenId,
|
|
506
|
+
permit.commenter,
|
|
507
|
+
_hashCommentIdentifier(permit.replyTo),
|
|
508
|
+
keccak256(bytes(permit.text)),
|
|
509
|
+
permit.deadline,
|
|
510
|
+
permit.nonce,
|
|
511
|
+
permit.commenterSmartWallet,
|
|
512
|
+
permit.referrer,
|
|
513
|
+
permit.sourceChainId,
|
|
514
|
+
permit.destinationChainId
|
|
515
|
+
)
|
|
516
|
+
);
|
|
517
|
+
|
|
518
|
+
return _hashTypedDataV4(structHash, permit.sourceChainId);
|
|
425
519
|
}
|
|
426
520
|
|
|
427
521
|
function _validatePermit(bytes32 digest, bytes32 nonce, bytes calldata signature, address signer, uint256 deadline) internal {
|
|
@@ -429,12 +523,16 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
429
523
|
revert ERC2612ExpiredSignature(deadline);
|
|
430
524
|
}
|
|
431
525
|
|
|
432
|
-
_useCheckedNonce(signer,
|
|
526
|
+
_useCheckedNonce(signer, nonce);
|
|
433
527
|
_validateSignerIsCommenter(digest, signature, signer);
|
|
434
528
|
}
|
|
435
529
|
|
|
530
|
+
/// @notice Creates a comment on behalf of another account using a signed message. Supports cross-chain permits
|
|
531
|
+
/// by specifying the source and destination chain ids. The signature must be signed by the commenter on the source chain.
|
|
532
|
+
/// @param permit The permit that was signed off-chain on the source chain
|
|
533
|
+
/// @param signature The signature of the permit comment
|
|
436
534
|
function permitComment(PermitComment calldata permit, bytes calldata signature) public payable {
|
|
437
|
-
if (permit.destinationChainId != block.chainid) {
|
|
535
|
+
if (permit.destinationChainId != uint32(block.chainid)) {
|
|
438
536
|
revert IncorrectDestinationChain(permit.destinationChainId);
|
|
439
537
|
}
|
|
440
538
|
|
|
@@ -442,45 +540,46 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
442
540
|
_validatePermit(digest, permit.nonce, signature, permit.commenter, permit.deadline);
|
|
443
541
|
|
|
444
542
|
CommentIdentifier memory commentIdentifier = _createCommentIdentifier(permit.contractAddress, permit.tokenId, permit.commenter);
|
|
445
|
-
(bytes32 commentId, bytes32 replyToId) = _validateComment(commentIdentifier, permit.replyTo, permit.text, permit.sparksQuantity, true);
|
|
446
543
|
|
|
447
|
-
|
|
448
|
-
|
|
544
|
+
uint256 sparksQuantity = _getAndValidateSingleSparkQuantityFromValue(msg.value);
|
|
545
|
+
|
|
546
|
+
(bytes32 commentId, bytes32 replyToId) = _validateComment(
|
|
449
547
|
commentIdentifier,
|
|
450
|
-
permit.text,
|
|
451
|
-
permit.sparksQuantity,
|
|
452
|
-
replyToId,
|
|
453
548
|
permit.replyTo,
|
|
454
|
-
|
|
455
|
-
|
|
549
|
+
permit.text,
|
|
550
|
+
sparksQuantity,
|
|
551
|
+
permit.commenterSmartWallet,
|
|
552
|
+
true
|
|
456
553
|
);
|
|
457
|
-
}
|
|
458
554
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
"PermitSparkComment(CommentIdentifier comment,address sparker,uint64 sparksQuantity,uint256 deadline,bytes32 nonce,address referrer,uint256 sourceChainId,uint256 destinationChainId)CommentIdentifier(address contractAddress,uint256 tokenId,address commenter,bytes32 nonce)"
|
|
462
|
-
);
|
|
555
|
+
_saveCommentAndTransferSparks(commentId, commentIdentifier, permit.text, sparksQuantity, replyToId, permit.replyTo, block.timestamp, permit.referrer);
|
|
556
|
+
}
|
|
463
557
|
|
|
558
|
+
/// @notice Hashes a permit spark comment struct for signing
|
|
559
|
+
/// @param permit The permit spark comment struct
|
|
464
560
|
function hashPermitSparkComment(PermitSparkComment calldata permit) public view returns (bytes32) {
|
|
465
|
-
|
|
466
|
-
|
|
561
|
+
bytes32 structHash = keccak256(
|
|
562
|
+
abi.encode(
|
|
467
563
|
PERMIT_SPARK_COMMENT_DOMAIN,
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
);
|
|
564
|
+
_hashCommentIdentifier(permit.comment),
|
|
565
|
+
permit.sparker,
|
|
566
|
+
permit.sparksQuantity,
|
|
567
|
+
permit.deadline,
|
|
568
|
+
permit.nonce,
|
|
569
|
+
permit.referrer,
|
|
570
|
+
permit.sourceChainId,
|
|
571
|
+
permit.destinationChainId
|
|
572
|
+
)
|
|
573
|
+
);
|
|
574
|
+
return _hashTypedDataV4(structHash, permit.sourceChainId);
|
|
480
575
|
}
|
|
481
576
|
|
|
577
|
+
/// @notice Sparks a comment on behalf of another account using a signed message. Supports cross-chain permits
|
|
578
|
+
/// by specifying the source and destination chain ids. The signature must be signed by the sparker on the source chain.
|
|
579
|
+
/// @param permit The permit spark comment struct
|
|
580
|
+
/// @param signature The signature of the permit. Must be signed by the sparker.
|
|
482
581
|
function permitSparkComment(PermitSparkComment calldata permit, bytes calldata signature) public payable {
|
|
483
|
-
if (permit.destinationChainId != block.chainid) {
|
|
582
|
+
if (permit.destinationChainId != uint32(block.chainid)) {
|
|
484
583
|
revert IncorrectDestinationChain(permit.destinationChainId);
|
|
485
584
|
}
|
|
486
585
|
|
|
@@ -530,11 +629,45 @@ contract CommentsImpl is IComments, AccessControlUpgradeable, UUPSUpgradeable, C
|
|
|
530
629
|
}
|
|
531
630
|
}
|
|
532
631
|
|
|
632
|
+
function _getFundsRecipient(address contractAddress) internal view returns (address) {
|
|
633
|
+
try IZoraCreator1155(contractAddress).config() returns (address, uint96, address payable fundsRecipient, uint96, address, uint96) {
|
|
634
|
+
if (fundsRecipient != address(0)) {
|
|
635
|
+
return fundsRecipient;
|
|
636
|
+
}
|
|
637
|
+
} catch {}
|
|
638
|
+
|
|
639
|
+
try IZoraCreator1155(contractAddress).owner() returns (address owner) {
|
|
640
|
+
if (owner != address(0)) {
|
|
641
|
+
return owner;
|
|
642
|
+
}
|
|
643
|
+
} catch {}
|
|
644
|
+
|
|
645
|
+
return address(0);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
function _tryGetCreatorRewardRecipient(CommentIdentifier memory commentIdentifier) internal view returns (address) {
|
|
649
|
+
try IZoraCreator1155(commentIdentifier.contractAddress).getCreatorRewardRecipient(commentIdentifier.tokenId) returns (address creatorRecipient) {
|
|
650
|
+
return creatorRecipient;
|
|
651
|
+
} catch {
|
|
652
|
+
return address(0);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
533
656
|
function _getCreatorRewardRecipient(CommentIdentifier memory commentIdentifier) internal view returns (address) {
|
|
534
|
-
|
|
535
|
-
|
|
657
|
+
address creatorRecipient = _tryGetCreatorRewardRecipient(commentIdentifier);
|
|
658
|
+
if (creatorRecipient != address(0)) {
|
|
659
|
+
return creatorRecipient;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
address fundsRecipient = _getFundsRecipient(commentIdentifier.contractAddress);
|
|
663
|
+
if (fundsRecipient != address(0)) {
|
|
664
|
+
return fundsRecipient;
|
|
665
|
+
}
|
|
666
|
+
revert NoFundsRecipient();
|
|
536
667
|
}
|
|
537
668
|
|
|
669
|
+
/// @notice Returns the name of the contract
|
|
670
|
+
/// @return The name of the contract
|
|
538
671
|
function contractName() public pure returns (string memory) {
|
|
539
672
|
return "Zora Comments";
|
|
540
673
|
}
|