@theqrl/qrl-contracts 0.1.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/interfaces/ISQRCTN1.hyp +6 -0
- package/interfaces/IZRC165.hyp +6 -0
- package/interfaces/IZRC4906.hyp +20 -0
- package/interfaces/draft-IZRC6093.hyp +161 -0
- package/package.json +26 -0
- package/token/SQRCTB1/ISQRCTB1.hyp +123 -0
- package/token/SQRCTB1/ISQRCTB1Receiver.hyp +59 -0
- package/token/SQRCTB1/SQRCTB1.hyp +389 -0
- package/token/SQRCTB1/extensions/ISQRCTB1MetadataURI.hyp +20 -0
- package/token/SQRCTB1/utils/SQRCTB1Utils.hyp +88 -0
- package/token/SQRCTF1/ISQRCTF1.hyp +79 -0
- package/token/SQRCTF1/SQRCTF1.hyp +305 -0
- package/token/SQRCTF1/extensions/ISQRCTF1Metadata.hyp +26 -0
- package/token/SQRCTN1/ISQRCTN1.hyp +135 -0
- package/token/SQRCTN1/ISQRCTN1Receiver.hyp +28 -0
- package/token/SQRCTN1/SQRCTN1.hyp +430 -0
- package/token/SQRCTN1/extensions/ISQRCTN1Metadata.hyp +27 -0
- package/token/SQRCTN1/extensions/SQRCTN1URIStorage.hyp +58 -0
- package/token/SQRCTN1/utils/SQRCTN1Utils.hyp +50 -0
- package/utils/Arrays.hyp +552 -0
- package/utils/Comparators.hyp +19 -0
- package/utils/Context.hyp +28 -0
- package/utils/Counters.hyp +43 -0
- package/utils/Panic.hyp +57 -0
- package/utils/SlotDerivation.hyp +155 -0
- package/utils/StorageSlot.hyp +143 -0
- package/utils/Strings.hyp +490 -0
- package/utils/introspection/IZRC165.hyp +25 -0
- package/utils/introspection/ZRC165.hyp +25 -0
- package/utils/math/Math.hyp +749 -0
- package/utils/math/SafeCast.hyp +1162 -0
- package/utils/math/SignedMath.hyp +68 -0
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// QRL Contracts (last updated v0.1.0) (token/SQRCTN1/SQRCTN1.hyp)
|
|
3
|
+
|
|
4
|
+
pragma hyperion >=0.0;
|
|
5
|
+
|
|
6
|
+
import {ISQRCTN1} from "./ISQRCTN1.hyp";
|
|
7
|
+
import {ISQRCTN1Metadata} from "./extensions/ISQRCTN1Metadata.hyp";
|
|
8
|
+
import {SQRCTN1Utils} from "./utils/SQRCTN1Utils.hyp";
|
|
9
|
+
import {Context} from "../../utils/Context.hyp";
|
|
10
|
+
import {Strings} from "../../utils/Strings.hyp";
|
|
11
|
+
import {IZRC165, ZRC165} from "../../utils/introspection/ZRC165.hyp";
|
|
12
|
+
import {ISQRCTN1Errors} from "../../interfaces/draft-IZRC6093.hyp";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[SQRC-TN1] Non-Fungible Token Standard, including
|
|
16
|
+
* the Metadata extension, but not including the Enumerable extension, which is available separately as
|
|
17
|
+
* {SQRCTN1Enumerable}.
|
|
18
|
+
*/
|
|
19
|
+
abstract contract SQRCTN1 is Context, ZRC165, ISQRCTN1, ISQRCTN1Metadata, ISQRCTN1Errors {
|
|
20
|
+
using Strings for uint256;
|
|
21
|
+
|
|
22
|
+
// Token name
|
|
23
|
+
string private _name;
|
|
24
|
+
|
|
25
|
+
// Token symbol
|
|
26
|
+
string private _symbol;
|
|
27
|
+
|
|
28
|
+
mapping(uint256 tokenId => address) private _owners;
|
|
29
|
+
|
|
30
|
+
mapping(address owner => uint256) private _balances;
|
|
31
|
+
|
|
32
|
+
mapping(uint256 tokenId => address) private _tokenApprovals;
|
|
33
|
+
|
|
34
|
+
mapping(address owner => mapping(address operator => bool)) private _operatorApprovals;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
|
|
38
|
+
*/
|
|
39
|
+
constructor(string memory name_, string memory symbol_) {
|
|
40
|
+
_name = name_;
|
|
41
|
+
_symbol = symbol_;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// @inheritdoc IZRC165
|
|
45
|
+
function supportsInterface(bytes4 interfaceId) public view virtual override(ZRC165, IZRC165) returns (bool) {
|
|
46
|
+
return
|
|
47
|
+
interfaceId == type(ISQRCTN1).interfaceId ||
|
|
48
|
+
interfaceId == type(ISQRCTN1Metadata).interfaceId ||
|
|
49
|
+
super.supportsInterface(interfaceId);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/// @inheritdoc ISQRCTN1
|
|
53
|
+
function balanceOf(address owner) public view virtual returns (uint256) {
|
|
54
|
+
if (owner == address(0)) {
|
|
55
|
+
revert SQRCTN1InvalidOwner(address(0));
|
|
56
|
+
}
|
|
57
|
+
return _balances[owner];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/// @inheritdoc ISQRCTN1
|
|
61
|
+
function ownerOf(uint256 tokenId) public view virtual returns (address) {
|
|
62
|
+
return _requireOwned(tokenId);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// @inheritdoc ISQRCTN1Metadata
|
|
66
|
+
function name() public view virtual returns (string memory) {
|
|
67
|
+
return _name;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// @inheritdoc ISQRCTN1Metadata
|
|
71
|
+
function symbol() public view virtual returns (string memory) {
|
|
72
|
+
return _symbol;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// @inheritdoc ISQRCTN1Metadata
|
|
76
|
+
function tokenURI(uint256 tokenId) public view virtual returns (string memory) {
|
|
77
|
+
_requireOwned(tokenId);
|
|
78
|
+
|
|
79
|
+
string memory baseURI = _baseURI();
|
|
80
|
+
return bytes(baseURI).length > 0 ? string.concat(baseURI, tokenId.toString()) : "";
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
|
|
85
|
+
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
|
|
86
|
+
* by default, can be overridden in child contracts.
|
|
87
|
+
*/
|
|
88
|
+
function _baseURI() internal view virtual returns (string memory) {
|
|
89
|
+
return "";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// @inheritdoc ISQRCTN1
|
|
93
|
+
function approve(address to, uint256 tokenId) public virtual {
|
|
94
|
+
_approve(to, tokenId, _msgSender());
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/// @inheritdoc ISQRCTN1
|
|
98
|
+
function getApproved(uint256 tokenId) public view virtual returns (address) {
|
|
99
|
+
_requireOwned(tokenId);
|
|
100
|
+
|
|
101
|
+
return _getApproved(tokenId);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/// @inheritdoc ISQRCTN1
|
|
105
|
+
function setApprovalForAll(address operator, bool approved) public virtual {
|
|
106
|
+
_setApprovalForAll(_msgSender(), operator, approved);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/// @inheritdoc ISQRCTN1
|
|
110
|
+
function isApprovedForAll(address owner, address operator) public view virtual returns (bool) {
|
|
111
|
+
return _operatorApprovals[owner][operator];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/// @inheritdoc ISQRCTN1
|
|
115
|
+
function transferFrom(address from, address to, uint256 tokenId) public virtual {
|
|
116
|
+
if (to == address(0)) {
|
|
117
|
+
revert SQRCTN1InvalidReceiver(address(0));
|
|
118
|
+
}
|
|
119
|
+
// Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists
|
|
120
|
+
// (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.
|
|
121
|
+
address previousOwner = _update(to, tokenId, _msgSender());
|
|
122
|
+
if (previousOwner != from) {
|
|
123
|
+
revert SQRCTN1IncorrectOwner(from, tokenId, previousOwner);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/// @inheritdoc ISQRCTN1
|
|
128
|
+
function safeTransferFrom(address from, address to, uint256 tokenId) public {
|
|
129
|
+
safeTransferFrom(from, to, tokenId, "");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/// @inheritdoc ISQRCTN1
|
|
133
|
+
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual {
|
|
134
|
+
transferFrom(from, to, tokenId);
|
|
135
|
+
SQRCTN1Utils.checkOnSQRCTN1Received(_msgSender(), from, to, tokenId, data);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
|
|
140
|
+
*
|
|
141
|
+
* IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the
|
|
142
|
+
* core SQRC-TN1 logic MUST be matched with the use of {_increaseBalance} to keep balances
|
|
143
|
+
* consistent with ownership. The invariant to preserve is that for any address `a` the value returned by
|
|
144
|
+
* `balanceOf(a)` must be equal to the number of tokens such that `_ownerOf(tokenId)` is `a`.
|
|
145
|
+
*/
|
|
146
|
+
function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
|
|
147
|
+
return _owners[tokenId];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted.
|
|
152
|
+
*/
|
|
153
|
+
function _getApproved(uint256 tokenId) internal view virtual returns (address) {
|
|
154
|
+
return _tokenApprovals[tokenId];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in
|
|
159
|
+
* particular (ignoring whether it is owned by `owner`).
|
|
160
|
+
*
|
|
161
|
+
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
|
|
162
|
+
* assumption.
|
|
163
|
+
*/
|
|
164
|
+
function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) {
|
|
165
|
+
return
|
|
166
|
+
spender != address(0) &&
|
|
167
|
+
(owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner.
|
|
172
|
+
* Reverts if:
|
|
173
|
+
* - `spender` does not have approval from `owner` for `tokenId`.
|
|
174
|
+
* - `spender` does not have approval to manage all of `owner`'s assets.
|
|
175
|
+
*
|
|
176
|
+
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
|
|
177
|
+
* assumption.
|
|
178
|
+
*/
|
|
179
|
+
function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual {
|
|
180
|
+
if (!_isAuthorized(owner, spender, tokenId)) {
|
|
181
|
+
if (owner == address(0)) {
|
|
182
|
+
revert SQRCTN1NonexistentToken(tokenId);
|
|
183
|
+
} else {
|
|
184
|
+
revert SQRCTN1InsufficientApproval(spender, tokenId);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override.
|
|
191
|
+
*
|
|
192
|
+
* NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that
|
|
193
|
+
* a uint256 would ever overflow from increments when these increments are bounded to uint128 values.
|
|
194
|
+
*
|
|
195
|
+
* WARNING: Increasing an account's balance using this function tends to be paired with an override of the
|
|
196
|
+
* {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership
|
|
197
|
+
* remain consistent with one another.
|
|
198
|
+
*/
|
|
199
|
+
function _increaseBalance(address account, uint128 value) internal virtual {
|
|
200
|
+
unchecked {
|
|
201
|
+
_balances[account] += value;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner
|
|
207
|
+
* (or `to`) is the zero address. Returns the owner of the `tokenId` before the update.
|
|
208
|
+
*
|
|
209
|
+
* The `auth` argument is optional. If the value passed is non 0, then this function will check that
|
|
210
|
+
* `auth` is either the owner of the token, or approved to operate on the token (by the owner).
|
|
211
|
+
*
|
|
212
|
+
* Emits a {Transfer} event.
|
|
213
|
+
*
|
|
214
|
+
* NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}.
|
|
215
|
+
*/
|
|
216
|
+
function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) {
|
|
217
|
+
address from = _ownerOf(tokenId);
|
|
218
|
+
|
|
219
|
+
// Perform (optional) operator check
|
|
220
|
+
if (auth != address(0)) {
|
|
221
|
+
_checkAuthorized(from, auth, tokenId);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Execute the update
|
|
225
|
+
if (from != address(0)) {
|
|
226
|
+
// Clear approval. No need to re-authorize or emit the Approval event
|
|
227
|
+
_approve(address(0), tokenId, address(0), false);
|
|
228
|
+
|
|
229
|
+
unchecked {
|
|
230
|
+
_balances[from] -= 1;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (to != address(0)) {
|
|
235
|
+
unchecked {
|
|
236
|
+
_balances[to] += 1;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
_owners[tokenId] = to;
|
|
241
|
+
|
|
242
|
+
emit Transfer(from, to, tokenId);
|
|
243
|
+
|
|
244
|
+
return from;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* @dev Mints `tokenId` and transfers it to `to`.
|
|
249
|
+
*
|
|
250
|
+
* WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
|
|
251
|
+
*
|
|
252
|
+
* Requirements:
|
|
253
|
+
*
|
|
254
|
+
* - `tokenId` must not exist.
|
|
255
|
+
* - `to` cannot be the zero address.
|
|
256
|
+
*
|
|
257
|
+
* Emits a {Transfer} event.
|
|
258
|
+
*/
|
|
259
|
+
function _mint(address to, uint256 tokenId) internal {
|
|
260
|
+
if (to == address(0)) {
|
|
261
|
+
revert SQRCTN1InvalidReceiver(address(0));
|
|
262
|
+
}
|
|
263
|
+
address previousOwner = _update(to, tokenId, address(0));
|
|
264
|
+
if (previousOwner != address(0)) {
|
|
265
|
+
revert SQRCTN1InvalidSender(address(0));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance.
|
|
271
|
+
*
|
|
272
|
+
* Requirements:
|
|
273
|
+
*
|
|
274
|
+
* - `tokenId` must not exist.
|
|
275
|
+
* - If `to` refers to a smart contract, it must implement {ISQRCTN1Receiver-onSQRCTN1Received}, which is called upon a safe transfer.
|
|
276
|
+
*
|
|
277
|
+
* Emits a {Transfer} event.
|
|
278
|
+
*/
|
|
279
|
+
function _safeMint(address to, uint256 tokenId) internal {
|
|
280
|
+
_safeMint(to, tokenId, "");
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* @dev Same as {xref-SQRCTN1-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
|
|
285
|
+
* forwarded in {ISQRCTN1Receiver-onSQRCTN1Received} to contract recipients.
|
|
286
|
+
*/
|
|
287
|
+
function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual {
|
|
288
|
+
_mint(to, tokenId);
|
|
289
|
+
SQRCTN1Utils.checkOnSQRCTN1Received(_msgSender(), address(0), to, tokenId, data);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @dev Destroys `tokenId`.
|
|
294
|
+
* The approval is cleared when the token is burned.
|
|
295
|
+
* This is an internal function that does not check if the sender is authorized to operate on the token.
|
|
296
|
+
*
|
|
297
|
+
* Requirements:
|
|
298
|
+
*
|
|
299
|
+
* - `tokenId` must exist.
|
|
300
|
+
*
|
|
301
|
+
* Emits a {Transfer} event.
|
|
302
|
+
*/
|
|
303
|
+
function _burn(uint256 tokenId) internal {
|
|
304
|
+
address previousOwner = _update(address(0), tokenId, address(0));
|
|
305
|
+
if (previousOwner == address(0)) {
|
|
306
|
+
revert SQRCTN1NonexistentToken(tokenId);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* @dev Transfers `tokenId` from `from` to `to`.
|
|
312
|
+
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
|
|
313
|
+
*
|
|
314
|
+
* Requirements:
|
|
315
|
+
*
|
|
316
|
+
* - `to` cannot be the zero address.
|
|
317
|
+
* - `tokenId` token must be owned by `from`.
|
|
318
|
+
*
|
|
319
|
+
* Emits a {Transfer} event.
|
|
320
|
+
*/
|
|
321
|
+
function _transfer(address from, address to, uint256 tokenId) internal {
|
|
322
|
+
if (to == address(0)) {
|
|
323
|
+
revert SQRCTN1InvalidReceiver(address(0));
|
|
324
|
+
}
|
|
325
|
+
address previousOwner = _update(to, tokenId, address(0));
|
|
326
|
+
if (previousOwner == address(0)) {
|
|
327
|
+
revert SQRCTN1NonexistentToken(tokenId);
|
|
328
|
+
} else if (previousOwner != from) {
|
|
329
|
+
revert SQRCTN1IncorrectOwner(from, tokenId, previousOwner);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients
|
|
335
|
+
* are aware of the SQRC-TN1 standard to prevent tokens from being forever locked.
|
|
336
|
+
*
|
|
337
|
+
* `data` is additional data, it has no specified format and it is sent in call to `to`.
|
|
338
|
+
*
|
|
339
|
+
* This internal function is like {safeTransferFrom} in the sense that it invokes
|
|
340
|
+
* {ISQRCTN1Receiver-onSQRCTN1Received} on the receiver, and can be used to e.g.
|
|
341
|
+
* implement alternative mechanisms to perform token transfer, such as signature-based.
|
|
342
|
+
*
|
|
343
|
+
* Requirements:
|
|
344
|
+
*
|
|
345
|
+
* - `tokenId` token must exist and be owned by `from`.
|
|
346
|
+
* - `to` cannot be the zero address.
|
|
347
|
+
* - `from` cannot be the zero address.
|
|
348
|
+
* - If `to` refers to a smart contract, it must implement {ISQRCTN1Receiver-onSQRCTN1Received}, which is called upon a safe transfer.
|
|
349
|
+
*
|
|
350
|
+
* Emits a {Transfer} event.
|
|
351
|
+
*/
|
|
352
|
+
function _safeTransfer(address from, address to, uint256 tokenId) internal {
|
|
353
|
+
_safeTransfer(from, to, tokenId, "");
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* @dev Same as {xref-SQRCTN1-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is
|
|
358
|
+
* forwarded in {ISQRCTN1Receiver-onSQRCTN1Received} to contract recipients.
|
|
359
|
+
*/
|
|
360
|
+
function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual {
|
|
361
|
+
_transfer(from, to, tokenId);
|
|
362
|
+
SQRCTN1Utils.checkOnSQRCTN1Received(_msgSender(), from, to, tokenId, data);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* @dev Approve `to` to operate on `tokenId`
|
|
367
|
+
*
|
|
368
|
+
* The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is
|
|
369
|
+
* either the owner of the token, or approved to operate on all tokens held by this owner.
|
|
370
|
+
*
|
|
371
|
+
* Emits an {Approval} event.
|
|
372
|
+
*
|
|
373
|
+
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
|
|
374
|
+
*/
|
|
375
|
+
function _approve(address to, uint256 tokenId, address auth) internal {
|
|
376
|
+
_approve(to, tokenId, auth, true);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not
|
|
381
|
+
* emitted in the context of transfers.
|
|
382
|
+
*/
|
|
383
|
+
function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual {
|
|
384
|
+
// Avoid reading the owner unless necessary
|
|
385
|
+
if (emitEvent || auth != address(0)) {
|
|
386
|
+
address owner = _requireOwned(tokenId);
|
|
387
|
+
|
|
388
|
+
// We do not use _isAuthorized because single-token approvals should not be able to call approve
|
|
389
|
+
if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) {
|
|
390
|
+
revert SQRCTN1InvalidApprover(auth);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (emitEvent) {
|
|
394
|
+
emit Approval(owner, to, tokenId);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
_tokenApprovals[tokenId] = to;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* @dev Approve `operator` to operate on all of `owner` tokens
|
|
403
|
+
*
|
|
404
|
+
* Requirements:
|
|
405
|
+
* - operator can't be the address zero.
|
|
406
|
+
*
|
|
407
|
+
* Emits an {ApprovalForAll} event.
|
|
408
|
+
*/
|
|
409
|
+
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
|
|
410
|
+
if (operator == address(0)) {
|
|
411
|
+
revert SQRCTN1InvalidOperator(operator);
|
|
412
|
+
}
|
|
413
|
+
_operatorApprovals[owner][operator] = approved;
|
|
414
|
+
emit ApprovalForAll(owner, operator, approved);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned).
|
|
419
|
+
* Returns the owner.
|
|
420
|
+
*
|
|
421
|
+
* Overrides to ownership logic should be done to {_ownerOf}.
|
|
422
|
+
*/
|
|
423
|
+
function _requireOwned(uint256 tokenId) internal view returns (address) {
|
|
424
|
+
address owner = _ownerOf(tokenId);
|
|
425
|
+
if (owner == address(0)) {
|
|
426
|
+
revert SQRCTN1NonexistentToken(tokenId);
|
|
427
|
+
}
|
|
428
|
+
return owner;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// QRL Contracts (last updated v0.1.0) (token/SQRCTN1/extensions/ISQRCTN1Metadata.hyp)
|
|
3
|
+
|
|
4
|
+
pragma hyperion >=0.0;
|
|
5
|
+
|
|
6
|
+
import {ISQRCTN1} from "../ISQRCTN1.hyp";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @title SQRC-TN1 Non-Fungible Token Standard, optional metadata extension
|
|
10
|
+
* @dev See https://eips.ethereum.org/EIPS/eip-721
|
|
11
|
+
*/
|
|
12
|
+
interface ISQRCTN1Metadata is ISQRCTN1 {
|
|
13
|
+
/**
|
|
14
|
+
* @dev Returns the token collection name.
|
|
15
|
+
*/
|
|
16
|
+
function name() external view returns (string memory);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @dev Returns the token collection symbol.
|
|
20
|
+
*/
|
|
21
|
+
function symbol() external view returns (string memory);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
|
|
25
|
+
*/
|
|
26
|
+
function tokenURI(uint256 tokenId) external view returns (string memory);
|
|
27
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// QRL Contracts (last updated v0.1.0) (token/SQRCTN1/extensions/SQRCTN1URIStorage.hyp)
|
|
3
|
+
|
|
4
|
+
pragma hyperion >=0.0;
|
|
5
|
+
|
|
6
|
+
import {SQRCTN1} from "../SQRCTN1.hyp";
|
|
7
|
+
import {ISQRCTN1Metadata} from "./ISQRCTN1Metadata.hyp";
|
|
8
|
+
import {Strings} from "../../../utils/Strings.hyp";
|
|
9
|
+
import {IZRC4906} from "../../../interfaces/IZRC4906.hyp";
|
|
10
|
+
import {IZRC165} from "../../../interfaces/IZRC165.hyp";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @dev SQRC-TN1 token with storage based token URI management.
|
|
14
|
+
*/
|
|
15
|
+
abstract contract SQRCTN1URIStorage is IZRC4906, SQRCTN1 {
|
|
16
|
+
using Strings for uint256;
|
|
17
|
+
|
|
18
|
+
// Interface ID as defined in ZRC-4906. This does not correspond to a traditional interface ID as ZRC-4906 only
|
|
19
|
+
// defines events and does not include any external function.
|
|
20
|
+
bytes4 private constant ZRC4906_INTERFACE_ID = bytes4(0x49064906);
|
|
21
|
+
|
|
22
|
+
// Optional mapping for token URIs
|
|
23
|
+
mapping(uint256 tokenId => string) private _tokenURIs;
|
|
24
|
+
|
|
25
|
+
/// @inheritdoc IZRC165
|
|
26
|
+
function supportsInterface(bytes4 interfaceId) public view virtual override(SQRCTN1, IZRC165) returns (bool) {
|
|
27
|
+
return interfaceId == ZRC4906_INTERFACE_ID || super.supportsInterface(interfaceId);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// @inheritdoc ISQRCTN1Metadata
|
|
31
|
+
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
|
|
32
|
+
_requireOwned(tokenId);
|
|
33
|
+
|
|
34
|
+
string memory _tokenURI = _tokenURIs[tokenId];
|
|
35
|
+
string memory base = _baseURI();
|
|
36
|
+
|
|
37
|
+
// If there is no base URI, return the token URI.
|
|
38
|
+
if (bytes(base).length == 0) {
|
|
39
|
+
return _tokenURI;
|
|
40
|
+
}
|
|
41
|
+
// If both are set, concatenate the baseURI and tokenURI (via string.concat).
|
|
42
|
+
if (bytes(_tokenURI).length > 0) {
|
|
43
|
+
return string.concat(base, _tokenURI);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return super.tokenURI(tokenId);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
|
|
51
|
+
*
|
|
52
|
+
* Emits {IZRC4906-MetadataUpdate}.
|
|
53
|
+
*/
|
|
54
|
+
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
|
|
55
|
+
_tokenURIs[tokenId] = _tokenURI;
|
|
56
|
+
emit MetadataUpdate(tokenId);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// QRL Contracts (last updated v0.1.0) (token/SQRCTN1/utils/SQRCTN1Utils.hyp)
|
|
3
|
+
|
|
4
|
+
pragma hyperion >=0.0;
|
|
5
|
+
|
|
6
|
+
import {ISQRCTN1Receiver} from "../ISQRCTN1Receiver.hyp";
|
|
7
|
+
import {ISQRCTN1Errors} from "../../../interfaces/draft-IZRC6093.hyp";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @dev Library that provide common SQRC-TN1 utility functions.
|
|
11
|
+
*
|
|
12
|
+
* See https://eips.ethereum.org/EIPS/eip-721[SQRC-TN1].
|
|
13
|
+
*
|
|
14
|
+
* _Available since v5.1._
|
|
15
|
+
*/
|
|
16
|
+
library SQRCTN1Utils {
|
|
17
|
+
/**
|
|
18
|
+
* @dev Performs an acceptance check for the provided `operator` by calling {ISQRCTN1Receiver-onSQRCTN1Received}
|
|
19
|
+
* on the `to` address. The `operator` is generally the address that initiated the token transfer (i.e. `msg.sender`).
|
|
20
|
+
*
|
|
21
|
+
* The acceptance call is not executed and treated as a no-op if the target address doesn't contain code (i.e. an EOA).
|
|
22
|
+
* Otherwise, the recipient must implement {ISQRCTN1Receiver-onSQRCTN1Received} and return the acceptance magic value to accept
|
|
23
|
+
* the transfer.
|
|
24
|
+
*/
|
|
25
|
+
function checkOnSQRCTN1Received(
|
|
26
|
+
address operator,
|
|
27
|
+
address from,
|
|
28
|
+
address to,
|
|
29
|
+
uint256 tokenId,
|
|
30
|
+
bytes memory data
|
|
31
|
+
) internal {
|
|
32
|
+
if (to.code.length > 0) {
|
|
33
|
+
try ISQRCTN1Receiver(to).onSQRCTN1Received(operator, from, tokenId, data) returns (bytes4 retval) {
|
|
34
|
+
if (retval != ISQRCTN1Receiver.onSQRCTN1Received.selector) {
|
|
35
|
+
// Token rejected
|
|
36
|
+
revert ISQRCTN1Errors.SQRCTN1InvalidReceiver(to);
|
|
37
|
+
}
|
|
38
|
+
} catch (bytes memory reason) {
|
|
39
|
+
if (reason.length == 0) {
|
|
40
|
+
// non-ISQRCTN1Receiver implementer
|
|
41
|
+
revert ISQRCTN1Errors.SQRCTN1InvalidReceiver(to);
|
|
42
|
+
} else {
|
|
43
|
+
assembly ("memory-safe") {
|
|
44
|
+
revert(add(32, reason), mload(reason))
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|