Liquidus NFT Contracts
Fully Audited: All smart contracts used by Liquidus are fully audited by reputational auditing companies.
Name | Blockchain | Contract |
---|---|---|
LIQ NFT | BNB Smart Chain | 0x81290EB62302620Ea8633967d08F25d46BCFa2F1 |
LIQ NFT | Cronos | 0xB91c9bf872D3193ebc7ecD7DE6c1aD579f16013d |
1
pragma solidity ^0.8.0;
2
3
4
/*
5
* @dev Provides information about the current execution context, including the
6
* sender of the transaction and its data. While these are generally available
7
* via msg.sender and msg.data, they should not be accessed in such a direct
8
* manner, since when dealing with meta-transactions the account sending and
9
* paying for execution may not be the actual sender (as far as an application
10
* is concerned).
11
*
12
* This contract is only required for intermediate, library-like contracts.
13
*/
14
abstract contract Context {
15
function _msgSender() internal view virtual returns (address) {
16
return msg.sender;
17
}
18
19
function _msgData() internal view virtual returns (bytes calldata) {
20
return msg.data;
21
}
22
}
23
24
/**
25
* @dev Contract module which provides a basic access control mechanism, where
26
* there is an account (an owner) that can be granted exclusive access to
27
* specific functions.
28
*
29
* By default, the owner account will be the one that deploys the contract. This
30
* can later be changed with {transferOwnership}.
31
*
32
* This module is used through inheritance. It will make available the modifier
33
* `onlyOwner`, which can be applied to your functions to restrict their use to
34
* the owner.
35
*/
36
abstract contract Ownable is Context {
37
address private _owner;
38
39
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
40
41
/**
42
* @dev Initializes the contract setting the deployer as the initial owner.
43
*/
44
constructor() {
45
_setOwner(_msgSender());
46
}
47
48
/**
49
* @dev Returns the address of the current owner.
50
*/
51
function owner() public view virtual returns (address) {
52
return _owner;
53
}
54
55
/**
56
* @dev Throws if called by any account other than the owner.
57
*/
58
modifier onlyOwner() {
59
require(owner() == _msgSender(), "Ownable: caller is not the owner");
60
_;
61
}
62
63
/**
64
* @dev Leaves the contract without owner. It will not be possible to call
65
* `onlyOwner` functions anymore. Can only be called by the current owner.
66
*
67
* NOTE: Renouncing ownership will leave the contract without an owner,
68
* thereby removing any functionality that is only available to the owner.
69
*/
70
function renounceOwnership() public virtual onlyOwner {
71
_setOwner(address(0));
72
}
73
74
/**
75
* @dev Transfers ownership of the contract to a new account (`newOwner`).
76
* Can only be called by the current owner.
77
*/
78
function transferOwnership(address newOwner) public virtual onlyOwner {
79
require(newOwner != address(0), "Ownable: new owner is the zero address");
80
_setOwner(newOwner);
81
}
82
83
function _setOwner(address newOwner) private {
84
address oldOwner = _owner;
85
_owner = newOwner;
86
emit OwnershipTransferred(oldOwner, newOwner);
87
}
88
}
89
90
/**
91
* @dev Interface of the ERC165 standard, as defined in the
92
* https://eips.ethereum.org/EIPS/eip-165[EIP].
93
*
94
* Implementers can declare support of contract interfaces, which can then be
95
* queried by others ({ERC165Checker}).
96
*
97
* For an implementation, see {ERC165}.
98
*/
99
interface IERC165 {
100
/**
101
* @dev Returns true if this contract implements the interface defined by
102
* `interfaceId`. See the corresponding
103
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
104
* to learn more about how these ids are created.
105
*
106
* This function call must use less than 30 000 gas.
107
*/
108
function supportsInterface(bytes4 interfaceId) external view returns (bool);
109
}
110
111
/**
112
* @dev Required interface of an ERC721 compliant contract.
113
*/
114
interface IERC721 is IERC165 {
115
/**
116
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
117
*/
118
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
119
120
/**
121
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
122
*/
123
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
124
125
/**
126
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
127
*/
128
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
129
130
/**
131
* @dev Returns the number of tokens in ``owner``'s account.
132
*/
133
function balanceOf(address owner) external view returns (uint256 balance);
134
135
/**
136
* @dev Returns the owner of the `tokenId` token.
137
*
138
* Requirements:
139
*
140
* - `tokenId` must exist.
141
*/
142
function ownerOf(uint256 tokenId) external view returns (address owner);
143
144
/**
145
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
146
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
147
*
148
* Requirements:
149
*
150
* - `from` cannot be the zero address.
151
* - `to` cannot be the zero address.
152
* - `tokenId` token must exist and be owned by `from`.
153
* - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
154
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
155
*
156
* Emits a {Transfer} event.
157
*/
158
function safeTransferFrom(
159
address from,
160
address to,
161
uint256 tokenId
162
) external;
163
164
/**
165
* @dev Transfers `tokenId` token from `from` to `to`.
166
*
167
* WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
168
*
169
* Requirements:
170
*
171
* - `from` cannot be the zero address.
172
* - `to` cannot be the zero address.
173
* - `tokenId` token must be owned by `from`.
174
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
175
*
176
* Emits a {Transfer} event.
177
*/
178
function transferFrom(
179
address from,
180
address to,
181
uint256 tokenId
182
) external;
183
184
/**
185
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
186
* The approval is cleared when the token is transferred.
187
*
188
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
189
*
190
* Requirements:
191
*
192
* - The caller must own the token or be an approved operator.
193
* - `tokenId` must exist.
194
*
195
* Emits an {Approval} event.
196
*/
197
function approve(address to, uint256 tokenId) external;
198
199
/**
200
* @dev Returns the account approved for `tokenId` token.
201
*
202
* Requirements:
203
*
204
* - `tokenId` must exist.
205
*/
206
function getApproved(uint256 tokenId) external view returns (address operator);
207
208
/**
209
* @dev Approve or remove `operator` as an operator for the caller.
210
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
211
*
212
* Requirements:
213
*
214
* - The `operator` cannot be the caller.
215
*
216
* Emits an {ApprovalForAll} event.
217
*/
218
function setApprovalForAll(address operator, bool _approved) external;
219
220
/**
221
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
222
*
223
* See {setApprovalForAll}
224
*/
225
function isApprovedForAll(address owner, address operator) external view returns (bool);
226
227
/**
228
* @dev Safely transfers `tokenId` token from `from` to `to`.
229
*
230
* Requirements:
231
*
232
* - `from` cannot be the zero address.
233
* - `to` cannot be the zero address.
234
* - `tokenId` token must exist and be owned by `from`.
235
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
236
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
237
*
238
* Emits a {Transfer} event.
239
*/
240
function safeTransferFrom(
241
address from,
242
address to,
243
uint256 tokenId,
244
bytes calldata data
245
) external;
246
}
247
248
/**
249
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
250
* @dev See https://eips.ethereum.org/EIPS/eip-721
251
*/
252
interface IERC721Enumerable is IERC721 {
253
/**
254
* @dev Returns the total amount of tokens stored by the contract.
255
*/
256
function totalSupply() external view returns (uint256);
257
258
/**
259
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
260
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
261
*/
262
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);
263
264
/**
265
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
266
* Use along with {totalSupply} to enumerate all tokens.
267
*/
268
function tokenByIndex(uint256 index) external view returns (uint256);
269
}
270
271
/**
272
* @dev Implementation of the {IERC165} interface.
273
*
274
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
275
* for the additional interface id that will be supported. For example:
276
*
277
* ```solidity
278
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
279
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
280
* }
281
* ```
282
*
283
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
284
*/
285
abstract contract ERC165 is IERC165 {
286
/**
287
* @dev See {IERC165-supportsInterface}.
288
*/
289
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
290
return interfaceId == type(IERC165).interfaceId;
291
}
292
}
293
294
/**
295
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
296
* @dev See https://eips.ethereum.org/EIPS/eip-721
297
*/
298
interface IERC721Metadata is IERC721 {
299
/**
300
* @dev Returns the token collection name.
301
*/
302
function name() external view returns (string memory);
303
304
/**
305
* @dev Returns the token collection symbol.
306
*/
307
function symbol() external view returns (string memory);
308
309
/**
310
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
311
*/
312
function tokenURI(uint256 tokenId) external view returns (string memory);
313
}
314
315
316
317
318
319
// File: @openzeppelin/contracts/token/ERC721/IERC721.sol
320
/**
321
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
322
* the Metadata extension, but not including the Enumerable extension, which is available separately as
323
* {ERC721Enumerable}.
324
*/
325
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
326
using Address for address;
327
using Strings for uint256;
328
329
// Token name
330
string private _name;
331
332
// Token symbol
333
string private _symbol;
334
335
// Mapping from token ID to owner address
336
mapping(uint256 => address) private _owners;
337
338
// Mapping owner address to token count
339
mapping(address => uint256) private _balances;
340
341
// Mapping from token ID to approved address
342
mapping(uint256 => address) private _tokenApprovals;
343
344
// Mapping from owner to operator approvals
345
mapping(address => mapping(address => bool)) private _operatorApprovals;
346
347
/**
348
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
349
*/
350
constructor(string memory name_, string memory symbol_) {
351
_name = name_;
352
_symbol = symbol_;
353
}
354
355
/**
356
* @dev See {IERC165-supportsInterface}.
357
*/
358
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
359
return
360
interfaceId == type(IERC721).interfaceId ||
361
interfaceId == type(IERC721Metadata).interfaceId ||
362
super.supportsInterface(interfaceId);
363
}
364
365
/**
366
* @dev See {IERC721-balanceOf}.
367
*/
368
function balanceOf(address owner) public view virtual override returns (uint256) {
369
require(owner != address(0), "ERC721: balance query for the zero address");
370
return _balances[owner];
371
}
372
373
/**
374
* @dev See {IERC721-ownerOf}.
375
*/
376
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
377
address owner = _owners[tokenId];
378
require(owner != address(0), "ERC721: owner query for nonexistent token");
379
return owner;
380
}
381
382
/**
383
* @dev See {IERC721Metadata-name}.
384
*/
385
function name() public view virtual override returns (string memory) {
386
return _name;
387
}
388
389
/**
390
* @dev See {IERC721Metadata-symbol}.
391
*/
392
function symbol() public view virtual override returns (string memory) {
393
return _symbol;
394
}
395
396
/**
397
* @dev See {IERC721Metadata-tokenURI}.
398
*/
399
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
400
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
401
402
string memory baseURI = _baseURI();
403
return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
404
}
405
406
/**
407
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
408
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
409
* by default, can be overriden in child contracts.
410
*/
411
function _baseURI() internal view virtual returns (string memory) {
412
return "";
413
}
414
415
/**
416
* @dev See {IERC721-approve}.
417
*/
418
function approve(address to, uint256 tokenId) public virtual override {
419
address owner = ERC721.ownerOf(tokenId);
420
require(to != owner, "ERC721: approval to current owner");
421
422
require(
423
_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
424
"ERC721: approve caller is not owner nor approved for all"
425
);
426
427
_approve(to, tokenId);
428
}
429
430
/**
431
* @dev See {IERC721-getApproved}.
432
*/
433
function getApproved(uint256 tokenId) public view virtual override returns (address) {
434
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
435
436
return _tokenApprovals[tokenId];
437
}
438
439
/**
440
* @dev See {IERC721-setApprovalForAll}.
441
*/
442
function setApprovalForAll(address operator, bool approved) public virtual override {
443
require(operator != _msgSender(), "ERC721: approve to caller");
444
445
_operatorApprovals[_msgSender()][operator] = approved;
446
emit ApprovalForAll(_msgSender(), operator, approved);
447
}
448
449
/**
450
* @dev See {IERC721-isApprovedForAll}.
451
*/
452
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
453
return _operatorApprovals[owner][operator];
454
}
455
456
/**
457
* @dev See {IERC721-transferFrom}.
458
*/
459
function transferFrom(
460
address from,
461
address to,
462
uint256 tokenId
463
) public virtual override {
464
//solhint-disable-next-line max-line-length
465
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
466
467
_transfer(from, to, tokenId);
468
}
469
470
/**
471
* @dev See {IERC721-safeTransferFrom}.
472
*/
473
function safeTransferFrom(
474
address from,
475
address to,
476
uint256 tokenId
477
) public virtual override {
478
safeTransferFrom(from, to, tokenId, "");
479
}
480
481
/**
482
* @dev See {IERC721-safeTransferFrom}.
483
*/
484
function safeTransferFrom(
485
address from,
486
address to,
487
uint256 tokenId,
488
bytes memory _data
489
) public virtual override {
490
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
491
_safeTransfer(from, to, tokenId, _data);
492
}
493
494
/**
495
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
496
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
497
*
498
* `_data` is additional data, it has no specified format and it is sent in call to `to`.
499
*
500
* This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
501
* implement alternative mechanisms to perform token transfer, such as signature-based.
502
*
503
* Requirements:
504
*
505
* - `from` cannot be the zero address.
506
* - `to` cannot be the zero address.
507
* - `tokenId` token must exist and be owned by `from`.
508
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
509
*
510
* Emits a {Transfer} event.
511
*/
512
function _safeTransfer(
513
address from,
514
address to,
515
uint256 tokenId,
516
bytes memory _data
517
) internal virtual {
518
_transfer(from, to, tokenId);
519
require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
520
}
521
522
/**
523
* @dev Returns whether `tokenId` exists.
524
*
525
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
526
*
527
* Tokens start existing when they are minted (`_mint`),
528
* and stop existing when they are burned (`_burn`).
529
*/
530
function _exists(uint256 tokenId) internal view virtual returns (bool) {
531
return _owners[tokenId] != address(0);
532
}
533
534
/**
535
* @dev Returns whether `spender` is allowed to manage `tokenId`.
536
*
537
* Requirements:
538
*
539
* - `tokenId` must exist.
540
*/
541
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
542
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
543
address owner = ERC721.ownerOf(tokenId);
544
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
545
}
546
547
/**
548
* @dev Safely mints `tokenId` and transfers it to `to`.
549
*
550
* Requirements:
551
*
552
* - `tokenId` must not exist.
553
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
554
*
555
* Emits a {Transfer} event.
556
*/
557
function _safeMint(address to, uint256 tokenId) internal virtual {
558
_safeMint(to, tokenId, "");
559
}
560
561
/**
562
* @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
563
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
564
*/
565
function _safeMint(
566
address to,
567
uint256 tokenId,
568
bytes memory _data
569
) internal virtual {
570
_mint(to, tokenId);
571
require(
572
_checkOnERC721Received(address(0), to, tokenId, _data),
573
"ERC721: transfer to non ERC721Receiver implementer"
574
);
575
}
576
577
/**
578
* @dev Mints `tokenId` and transfers it to `to`.
579
*
580
* WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
581
*
582
* Requirements:
583
*
584
* - `tokenId` must not exist.
585
* - `to` cannot be the zero address.
586
*
587
* Emits a {Transfer} event.
588
*/
589
function _mint(address to, uint256 tokenId) internal virtual {
590
require(to != address(0), "ERC721: mint to the zero address");
591
require(!_exists(tokenId), "ERC721: token already minted");
592
593
_beforeTokenTransfer(address(0), to, tokenId);
594
595
_balances[to] += 1;
596
_owners[tokenId] = to;
597
598
emit Transfer(address(0), to, tokenId);
599
}
600
601
/**
602
* @dev Destroys `tokenId`.
603
* The approval is cleared when the token is burned.
604
*
605
* Requirements:
606
*
607
* - `tokenId` must exist.
608
*
609
* Emits a {Transfer} event.
610
*/
611
function _burn(uint256 tokenId) internal virtual {
612
address owner = ERC721.ownerOf(tokenId);
613
614
_beforeTokenTransfer(owner, address(0), tokenId);
615
616
// Clear approvals
617
_approve(address(0), tokenId);
618
619
_balances[owner] -= 1;
620
delete _owners[tokenId];
621
622
emit Transfer(owner, address(0), tokenId);
623
}
624
625
/**
626
* @dev Transfers `tokenId` from `from` to `to`.
627
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
628
*
629
* Requirements:
630
*
631
* - `to` cannot be the zero address.
632
* - `tokenId` token must be owned by `from`.
633
*
634
* Emits a {Transfer} event.
635
*/
636
function _transfer(
637
address from,
638
address to,
639
uint256 tokenId
640
) internal virtual {
641
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
642
require(to != address(0), "ERC721: transfer to the zero address");
643
644
_beforeTokenTransfer(from, to, tokenId);
645
646
// Clear approvals from the previous owner
647
_approve(address(0), tokenId);
648
649
_balances[from] -= 1;
650
_balances[to] += 1;
651
_owners[tokenId] = to;
652
653
emit Transfer(from, to, tokenId);
654
}
655
656
/**
657
* @dev Approve `to` to operate on `tokenId`
658
*
659
* Emits a {Approval} event.
660
*/
661
function _approve(address to, uint256 tokenId) internal virtual {
662
_tokenApprovals[tokenId] = to;
663
emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
664
}
665
666
/**
667
* @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
668
* The call is not executed if the target address is not a contract.
669
*
670
* @param from address representing the previous owner of the given token ID
671
* @param to target address that will receive the tokens
672
* @param tokenId uint256 ID of the token to be transferred
673
* @param _data bytes optional data to send along with the call
674
* @return bool whether the call correctly returned the expected magic value
675
*/
676
function _checkOnERC721Received(
677
address from,
678
address to,
679
uint256 tokenId,
680
bytes memory _data
681
) private returns (bool) {
682
if (to.isContract()) {
683
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
684
return retval == IERC721Receiver(to).onERC721Received.selector;
685
} catch (bytes memory reason) {
686
if (reason.length == 0) {
687
revert("ERC721: transfer to non ERC721Receiver implementer");
688
} else {
689
assembly {
690
revert(add(32, reason), mload(reason))
691
}
692
}
693
}
694
} else {
695
return true;
696
}
697
}
698
699
/**
700
* @dev Hook that is called before any token transfer. This includes minting
701
* and burning.
702
*
703
* Calling conditions:
704
*
705
* - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
706
* transferred to `to`.
707
* - When `from` is zero, `tokenId` will be minted for `to`.
708
* - When `to` is zero, ``from``'s `tokenId` will be burned.
709
* - `from` and `to` are never both zero.
710
*
711
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
712
*/
713
function _beforeTokenTransfer(
714
address from,
715
address to,
716
uint256 tokenId
717
) internal virtual {}
718
}
719
720
// File: @openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol
721
/**
722
* @dev This implements an optional extension of {ERC721} defined in the EIP that adds
723
* enumerability of all the token ids in the contract as well as all token ids owned by each
724
* account.
725
*/
726
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
727
// Mapping from owner to list of owned token IDs
728
mapping(address => mapping(uint256 => uint256)) private _ownedTokens;
729
730
// Mapping from token ID to index of the owner tokens list
731
mapping(uint256 => uint256) private _ownedTokensIndex;
732
733
// Array with all token ids, used for enumeration
734
uint256[] private _allTokens;
735
736
// Mapping from token id to position in the allTokens array
737
mapping(uint256 => uint256) private _allTokensIndex;
738
739
/**
740
* @dev See {IERC165-supportsInterface}.
741
*/
742
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
743
return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
744
}
745
746
/**
747
* @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
748
*/
749
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
750
require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
751
return _ownedTokens[owner][index];
752
}
753
754
/**
755
* @dev See {IERC721Enumerable-totalSupply}.
756
*/
757
function totalSupply() public view virtual override returns (uint256) {
758
return _allTokens.length;
759
}
760
761
/**
762
* @dev See {IERC721Enumerable-tokenByIndex}.
763
*/
764
function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
765
require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
766
return _allTokens[index];
767
}
768
769
/**
770
* @dev Hook that is called before any token transfer. This includes minting
771
* and burning.
772
*
773
* Calling conditions:
774
*
775
* - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
776
* transferred to `to`.
777
* - When `from` is zero, `tokenId` will be minted for `to`.
778
* - When `to` is zero, ``from``'s `tokenId` will be burned.
779
* - `from` cannot be the zero address.
780
* - `to` cannot be the zero address.
781
*
782
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
783
*/
784
function _beforeTokenTransfer(
785
address from,
786
address to,
787
uint256 tokenId
788
) internal virtual override {
789
super._beforeTokenTransfer(from, to, tokenId);
790
791
if (from == address(0)) {
792
_addTokenToAllTokensEnumeration(tokenId);
793
} else if (from != to) {
794
_removeTokenFromOwnerEnumeration(from, tokenId);
795
}
796
if (to == address(0)) {
797
_removeTokenFromAllTokensEnumeration(tokenId);
798
} else if (to != from) {
799
_addTokenToOwnerEnumeration(to, tokenId);
800
}
801
}
802
803
/**
804
* @dev Private function to add a token to this extension's ownership-tracking data structures.
805
* @param to address representing the new owner of the given token ID
806
* @param tokenId uint256 ID of the token to be added to the tokens list of the given address
807
*/
808
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
809
uint256 length = ERC721.balanceOf(to);
810
_ownedTokens[to][length] = tokenId;
811
_ownedTokensIndex[tokenId] = length;
812
}
813
814
/**
815
* @dev Private function to add a token to this extension's token tracking data structures.
816
* @param tokenId uint256 ID of the token to be added to the tokens list
817
*/
818
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
819
_allTokensIndex[tokenId] = _allTokens.length;
820
_allTokens.push(tokenId);
821
}
822
823
/**
824
* @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
825
* while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
826
* gas optimizations e.g. when performing a transfer operation (avoiding double writes).
827
* This has O(1) time complexity, but alters the order of the _ownedTokens array.
828
* @param from address representing the previous owner of the given token ID
829
* @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
830
*/
831
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
832
// To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
833
// then delete the last slot (swap and pop).
834
835
uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
836
uint256 tokenIndex = _ownedTokensIndex[tokenId];
837
838
// When the token to delete is the last token, the swap operation is unnecessary
839
if (tokenIndex != lastTokenIndex) {
840
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
841
842
_ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
843
_ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
844
}
845
846
// This also deletes the contents at the last position of the array
847
delete _ownedTokensIndex[tokenId];
848
delete _ownedTokens[from][lastTokenIndex];
849
}
850
851
/**
852
* @dev Private function to remove a token from this extension's token tracking data structures.
853
* This has O(1) time complexity, but alters the order of the _allTokens array.
854
* @param tokenId uint256 ID of the token to be removed from the tokens list
855
*/
856
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
857
// To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
858
// then delete the last slot (swap and pop).
859
860
uint256 lastTokenIndex = _allTokens.length - 1;
861
uint256 tokenIndex = _allTokensIndex[tokenId];
862
863
// When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
864
// rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
865
// an 'if' statement (like in _removeTokenFromOwnerEnumeration)
866
uint256 lastTokenId = _allTokens[lastTokenIndex];
867
868
_allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
869
_allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
870
871
// This also deletes the contents at the last position of the array
872
delete _allTokensIndex[tokenId];
873
_allTokens.pop();