From 95477244ac1c3b4b7fdf5fb488cee78042774c60 Mon Sep 17 00:00:00 2001 From: Gerald Bauer Date: Tue, 20 Dec 2022 15:54:20 +0100 Subject: [PATCH] up --- ...1920cc2d9f5c10b444fd44009cd64f829e7be2.sol | 4726 +++++++++++++++++ ...1920cc2d9f5c10b444fd44009cd64f829e7be2.yml | 12 + ...0167a823c6619d430b1a96ad85b888bcf97c37.sol | 1924 +++++++ ...0167a823c6619d430b1a96ad85b888bcf97c37.yml | 12 + ...f5a35647d6f03d5d3da7b35409d65ba03af3b2.sol | 223 + ...f5a35647d6f03d5d3da7b35409d65ba03af3b2.yml | 12 + ...04a94f96d39df3b6bc0298cf068c8c82dc8d61.sol | 2810 ++++++++++ ...04a94f96d39df3b6bc0298cf068c8c82dc8d61.yml | 12 + ...581767a106ae21c074b2276d25e5c3e136a68b.sol | 4333 +++++++++++++++ ...581767a106ae21c074b2276d25e5c3e136a68b.yml | 12 + ...2bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d.sol | 1246 +++++ ...2bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d.yml | 12 + ...625ecaa75c0ea33733a05c584f4cf112c10b6b.sol | 2768 ++++++++++ ...625ecaa75c0ea33733a05c584f4cf112c10b6b.yml | 12 + ...e90596c2065befd3060767736c829c18f3474c.sol | 1085 ++++ ...e90596c2065befd3060767736c829c18f3474c.yml | 12 + ...cd862c9c687a9de49aecdc3a99b74a4fc54ab6.sol | 331 ++ ...cd862c9c687a9de49aecdc3a99b74a4fc54ab6.yml | 12 + ...a6f2207e343923ba692e5cae646fb0f566db8d.sol | 136 + ...a6f2207e343923ba692e5cae646fb0f566db8d.yml | 12 + ...eb5c179ceb640160853144cbb8df5bd24ab5cc.sol | 1070 ++++ ...eb5c179ceb640160853144cbb8df5bd24ab5cc.yml | 12 + ...40c393dc0f283f318791d746d894ddd3693572.sol | 1870 +++++++ ...40c393dc0f283f318791d746d894ddd3693572.yml | 12 + ...66d03fc1eee61a512341058e95f1a68dc3a913.sol | 2746 ++++++++++ ...66d03fc1eee61a512341058e95f1a68dc3a913.yml | 12 + ...9f0378a6f3f3361d8e962f3589ec28f4f8f159.sol | 2232 ++++++++ ...9f0378a6f3f3361d8e962f3589ec28f4f8f159.yml | 12 + ...2f3a61f002f83eba7d184c50bb2a8b359ca1ce.sol | 1652 ++++++ ...2f3a61f002f83eba7d184c50bb2a8b359ca1ce.yml | 12 + ...8474ba5a7f6abc52708f171f57fefc5cdc8c1c.sol | 2746 ++++++++++ ...8474ba5a7f6abc52708f171f57fefc5cdc8c1c.yml | 12 + ...9ce4b327a3b690abea6f78eccbfefffbea9fdf.sol | 680 +++ ...9ce4b327a3b690abea6f78eccbfefffbea9fdf.yml | 12 + ...7e3cd837ddf8e4c57f05d70ab865de6e193bbb.sol | 246 + ...7e3cd837ddf8e4c57f05d70ab865de6e193bbb.yml | 12 + ...f733ca98e0dad0386979eb96fb1722a1a05e69.sol | 3335 ++++++++++++ ...f733ca98e0dad0386979eb96fb1722a1a05e69.yml | 12 + ...2882c8b5d1bccca57c994c6af7d96355590dbd.sol | 1202 +++++ ...2882c8b5d1bccca57c994c6af7d96355590dbd.yml | 12 + ...3c078c2486b7be0f7b4dda9b14f35163b949e0.sol | 1152 ++++ ...3c078c2486b7be0f7b4dda9b14f35163b949e0.yml | 12 + ...a5520b798c5f67ca1b0657b932656df02595ad.sol | 2752 ++++++++++ ...a5520b798c5f67ca1b0657b932656df02595ad.yml | 12 + ...b91d537c3aa5a3fa87275fbd2e4feaaed69bd0.sol | 2455 +++++++++ ...b91d537c3aa5a3fa87275fbd2e4feaaed69bd0.yml | 12 + ...7468ead8cf26c752c676e43c814fee9c8cf402.sol | 1630 ++++++ ...7468ead8cf26c752c676e43c814fee9c8cf402.yml | 12 + ...a4644e818c2843ba0aabea93af6c80b5984114.sol | 1132 ++++ ...a4644e818c2843ba0aabea93af6c80b5984114.yml | 12 + .../sandbox/{download.rb => download_abis.rb} | 2 +- ethabi/sandbox/download_code.rb | 96 + etherscan-lite/lib/etherscan-lite/contract.rb | 16 +- 53 files changed, 46894 insertions(+), 2 deletions(-) create mode 100644 ethabi/code/0x031920cc2d9f5c10b444fd44009cd64f829e7be2.sol create mode 100644 ethabi/code/0x031920cc2d9f5c10b444fd44009cd64f829e7be2.yml create mode 100644 ethabi/code/0x0d0167a823c6619d430b1a96ad85b888bcf97c37.sol create mode 100644 ethabi/code/0x0d0167a823c6619d430b1a96ad85b888bcf97c37.yml create mode 100644 ethabi/code/0x16f5a35647d6f03d5d3da7b35409d65ba03af3b2.sol create mode 100644 ethabi/code/0x16f5a35647d6f03d5d3da7b35409d65ba03af3b2.yml create mode 100644 ethabi/code/0x2204a94f96d39df3b6bc0298cf068c8c82dc8d61.sol create mode 100644 ethabi/code/0x2204a94f96d39df3b6bc0298cf068c8c82dc8d61.yml create mode 100644 ethabi/code/0x23581767a106ae21c074b2276d25e5c3e136a68b.sol create mode 100644 ethabi/code/0x23581767a106ae21c074b2276d25e5c3e136a68b.yml create mode 100644 ethabi/code/0x282bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d.sol create mode 100644 ethabi/code/0x282bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d.yml create mode 100644 ethabi/code/0x34625ecaa75c0ea33733a05c584f4cf112c10b6b.sol create mode 100644 ethabi/code/0x34625ecaa75c0ea33733a05c584f4cf112c10b6b.yml create mode 100644 ethabi/code/0x58e90596c2065befd3060767736c829c18f3474c.sol create mode 100644 ethabi/code/0x58e90596c2065befd3060767736c829c18f3474c.yml create mode 100644 ethabi/code/0x60cd862c9c687a9de49aecdc3a99b74a4fc54ab6.sol create mode 100644 ethabi/code/0x60cd862c9c687a9de49aecdc3a99b74a4fc54ab6.yml create mode 100644 ethabi/code/0x6ba6f2207e343923ba692e5cae646fb0f566db8d.sol create mode 100644 ethabi/code/0x6ba6f2207e343923ba692e5cae646fb0f566db8d.yml create mode 100644 ethabi/code/0x71eb5c179ceb640160853144cbb8df5bd24ab5cc.sol create mode 100644 ethabi/code/0x71eb5c179ceb640160853144cbb8df5bd24ab5cc.yml create mode 100644 ethabi/code/0x7c40c393dc0f283f318791d746d894ddd3693572.sol create mode 100644 ethabi/code/0x7c40c393dc0f283f318791d746d894ddd3693572.yml create mode 100644 ethabi/code/0x9b66d03fc1eee61a512341058e95f1a68dc3a913.sol create mode 100644 ethabi/code/0x9b66d03fc1eee61a512341058e95f1a68dc3a913.yml create mode 100644 ethabi/code/0xa19f0378a6f3f3361d8e962f3589ec28f4f8f159.sol create mode 100644 ethabi/code/0xa19f0378a6f3f3361d8e962f3589ec28f4f8f159.yml create mode 100644 ethabi/code/0xa82f3a61f002f83eba7d184c50bb2a8b359ca1ce.sol create mode 100644 ethabi/code/0xa82f3a61f002f83eba7d184c50bb2a8b359ca1ce.yml create mode 100644 ethabi/code/0xad8474ba5a7f6abc52708f171f57fefc5cdc8c1c.sol create mode 100644 ethabi/code/0xad8474ba5a7f6abc52708f171f57fefc5cdc8c1c.yml create mode 100644 ethabi/code/0xaf9ce4b327a3b690abea6f78eccbfefffbea9fdf.sol create mode 100644 ethabi/code/0xaf9ce4b327a3b690abea6f78eccbfefffbea9fdf.yml create mode 100644 ethabi/code/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb.sol create mode 100644 ethabi/code/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb.yml create mode 100644 ethabi/code/0xc3f733ca98e0dad0386979eb96fb1722a1a05e69.sol create mode 100644 ethabi/code/0xc3f733ca98e0dad0386979eb96fb1722a1a05e69.yml create mode 100644 ethabi/code/0xd12882c8b5d1bccca57c994c6af7d96355590dbd.sol create mode 100644 ethabi/code/0xd12882c8b5d1bccca57c994c6af7d96355590dbd.yml create mode 100644 ethabi/code/0xd33c078c2486b7be0f7b4dda9b14f35163b949e0.sol create mode 100644 ethabi/code/0xd33c078c2486b7be0f7b4dda9b14f35163b949e0.yml create mode 100644 ethabi/code/0xe5a5520b798c5f67ca1b0657b932656df02595ad.sol create mode 100644 ethabi/code/0xe5a5520b798c5f67ca1b0657b932656df02595ad.yml create mode 100644 ethabi/code/0xe9b91d537c3aa5a3fa87275fbd2e4feaaed69bd0.sol create mode 100644 ethabi/code/0xe9b91d537c3aa5a3fa87275fbd2e4feaaed69bd0.yml create mode 100644 ethabi/code/0xf07468ead8cf26c752c676e43c814fee9c8cf402.sol create mode 100644 ethabi/code/0xf07468ead8cf26c752c676e43c814fee9c8cf402.yml create mode 100644 ethabi/code/0xf4a4644e818c2843ba0aabea93af6c80b5984114.sol create mode 100644 ethabi/code/0xf4a4644e818c2843ba0aabea93af6c80b5984114.yml rename ethabi/sandbox/{download.rb => download_abis.rb} (91%) create mode 100644 ethabi/sandbox/download_code.rb diff --git a/ethabi/code/0x031920cc2d9f5c10b444fd44009cd64f829e7be2.sol b/ethabi/code/0x031920cc2d9f5c10b444fd44009cd64f829e7be2.sol new file mode 100644 index 0000000..f94c523 --- /dev/null +++ b/ethabi/code/0x031920cc2d9f5c10b444fd44009cd64f829e7be2.sol @@ -0,0 +1,4726 @@ +/////////////////////////////////////////// +// File: contracts/CryptoZunks.sol + +//SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; +import "@openzeppelin/contracts/utils/structs/EnumerableMap.sol"; + +import "hardhat/console.sol"; + +contract CryptoZunks is + Ownable, + ERC721Enumerable, + ERC721Burnable, + ReentrancyGuard +{ + using Strings for uint256; + + enum Slot { + accessories, + beard, + ear, + eyes, + hat, + lips, + neck, + smoke + } + + mapping(string => bool) public unavailableZunks; + mapping(uint256 => string) public serialIdToZunk; + mapping(string => bool) public existingZunks; + + mapping(uint256 => uint256[]) public femaleProbabilities; + mapping(uint256 => uint256[]) public maleProbabilities; + + string NO_OPTIONS = "no options"; + uint256 NO_REROLL_OPTIONS = 99999; + + uint256[8] femaleSlotProbabilities = [ + 2608, + 0, + 3959, + 8614, + 10000, + 6625, + 1950, + 2080 + ]; + uint256[8] maleSlotProbabilities = [ + 2608, + 7187, + 3959, + 6923, + 10000, + 2437, + 1825, + 3225 + ]; + uint256[] genderProbabilities = [5000, 5000]; + uint256[] skinProbabilities = [14, 36, 2454, 2454, 2454, 2456, 132]; + + struct Attributes { + uint256 accessories; + uint256 beard; + uint256 ear; + uint256 eyes; + uint256 hat; + uint256 lips; + uint256 neck; + uint256 smoke; + } + + struct AttributesAsString { + string accessories; + string beard; + string ear; + string eyes; + string hat; + string lips; + string neck; + string smoke; + } + + struct SerialIdAndTokenRepresentation { + uint256 serialId; + string tokenRepresentation; + } + + constructor() ERC721("CryptoZunks", "ZUNK") { + femaleProbabilities[uint256(Slot.accessories)] = [1913, 5812, 1155, 1119]; + femaleProbabilities[uint256(Slot.beard)] = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ]; + femaleProbabilities[uint256(Slot.ear)] = [10000]; + femaleProbabilities[uint256(Slot.eyes)] = [ + 402, + 752, + 974, + 706, + 540, + 537, + 412, + 648, + 496, + 752, + 804, + 959, + 741, + 496, + 467, + 315 + ]; + femaleProbabilities[uint256(Slot.hat)] = [ + 237, + 0, + 378, + 332, + 347, + 0, + 146, + 237, + 409, + 404, + 0, + 227, + 436, + 378, + 0, + 0, + 414, + 227, + 434, + 424, + 434, + 175, + 0, + 242, + 139, + 244, + 229, + 0, + 378, + 0, + 388, + 370, + 381, + 228, + 229, + 141, + 228, + 0, + 370, + 441, + 350 + ]; + femaleProbabilities[uint256(Slot.lips)] = [ + 1567, + 1768, + 1664, + 1768, + 1664, + 1567 + ]; + femaleProbabilities[uint256(Slot.neck)] = [2778, 3756, 3467]; + femaleProbabilities[uint256(Slot.smoke)] = [5571, 1014, 1838, 1577]; + + maleProbabilities[uint256(Slot.accessories)] = [1913, 5812, 1155, 1119]; + maleProbabilities[uint256(Slot.beard)] = [ + 417, + 805, + 779, + 742, + 842, + 751, + 816, + 822, + 864, + 834, + 825, + 1502 + ]; + maleProbabilities[uint256(Slot.ear)] = [10000]; + maleProbabilities[uint256(Slot.eyes)] = [ + 527, + 987, + 566, + 926, + 708, + 704, + 540, + 850, + 0, + 987, + 527, + 0, + 972, + 566, + 612, + 527 + ]; + maleProbabilities[uint256(Slot.hat)] = [ + 505, + 75, + 0, + 0, + 369, + 433, + 155, + 242, + 434, + 0, + 512, + 317, + 463, + 0, + 692, + 442, + 440, + 483, + 463, + 451, + 231, + 0, + 517, + 0, + 0, + 0, + 346, + 281, + 231, + 512, + 0, + 0, + 0, + 486, + 0, + 0, + 196, + 251, + 0, + 470, + 0 + ]; + maleProbabilities[uint256(Slot.lips)] = [0, 1351, 2261, 2261, 0, 4125]; + maleProbabilities[uint256(Slot.neck)] = [2600, 2600, 4800]; + maleProbabilities[uint256(Slot.smoke)] = [5571, 1014, 1838, 1577]; + } + + bool public hasDevSingleMinted = false; + bool public isMintAndRerollEnabled = false; + uint256 private MAX_SUPPLY = 10000; + uint256 private currentIndex = 10000; + + uint256 public freeMintsFromPoolRedeemed = 0; + uint256 public freeMintsAllocatedByDevsCap = 300; + mapping(address => uint256) freeMintsAllocatedByDevs; + mapping(address => bool) public hasRedeemedFreeMintFromPool; + + event Zunk( + address indexed user, + uint256 serialId, + string tokenRepresentation, + bool isReroll + ); + + function _numMintedSoFar() internal view returns (uint256) { + return currentIndex - 10000; + } + + function freeMintOne() public payable nonReentrant { + require(userHasFreeMint(msg.sender), "You have no free mints available (pool has ran out)."); + if (freeMintsAllocatedByDevs[msg.sender] > 0) { + freeMintsAllocatedByDevs[msg.sender]--; + } else { + freeMintsFromPoolRedeemed++; + hasRedeemedFreeMintFromPool[msg.sender] = true; + } + _mintNoCostChecks(1); + } + + function mintOne() public payable nonReentrant { + _mint(1); + } + + function mintTwo() public payable nonReentrant { + _mint(2); + } + + function mintThree() public payable nonReentrant { + _mint(3); + } + + function mintFour() public payable nonReentrant { + _mint(4); + } + + function mintFive() public payable nonReentrant { + _mint(5); + } + + function mintSix() public payable nonReentrant { + _mint(6); + } + + function mintSeven() public payable nonReentrant { + _mint(7); + } + + function mintEight() public payable nonReentrant { + _mint(8); + } + + function mintNine() public payable nonReentrant { + _mint(9); + } + + function mintTen() public payable nonReentrant { + _mint(10); + } + + // internal minting function + function _mint(uint256 _numToMint) internal { + uint256 _numMinted = _numMintedSoFar(); + require( + _numMinted + _numToMint <= MAX_SUPPLY, + "There aren't this many zunks left." + ); + uint256 costForMint = getCostForMints(_numToMint); + require(msg.value >= costForMint, "Need to send more ETH."); + if (msg.value > costForMint) { + payable(msg.sender).transfer(msg.value - costForMint); + } + _mintNoCostChecks(_numToMint); + } + + function _mintNoCostChecks(uint256 _numToMint) internal { + require(isMintAndRerollEnabled, "Minting is not enabled."); + _mintNoChecks(_numToMint); + } + + function _mintNoChecks(uint256 _numToMint) internal { + uint256 newSerialId = currentIndex; + for (uint256 i = 0; i < _numToMint; i++) { + _safeMint(msg.sender, newSerialId); + + string memory generatedZunk = generateZunk(newSerialId); + if (isInvalidZunk(generatedZunk) || unableToRerollZunk(generatedZunk)) { + generatedZunk = generateZunk(newSerialId); + } + require( + !(isInvalidZunk(generatedZunk) || unableToRerollZunk(generatedZunk)), + "Unable to mint, please try again." + ); + serialIdToZunk[newSerialId] = generatedZunk; + existingZunks[generatedZunk] = true; + emit Zunk(msg.sender, newSerialId, generatedZunk, false); + newSerialId++; + } + currentIndex = newSerialId; + } + + function validateSlotToRerollValid( + uint256 slotToReroll, + Attributes memory attributes + ) internal pure { + uint256[] memory validSlots = getValidSlotsForReroll(attributes); + bool slotToRerollValid = false; + + for (uint256 i = 0; i < validSlots.length; i++) { + if (slotToReroll == validSlots[i]) { + slotToRerollValid = true; + break; + } + } + + require(slotToRerollValid, "slotToReroll is not valid for zunk"); + } + + function rerollZunk(uint256 serialId, uint256 slotToReroll) public payable { + require(isMintAndRerollEnabled, "Reroll is not enabled"); + require(msg.sender == ownerOf(serialId), "Only owner can reroll."); + require(slotToReroll != uint256(Slot.ear), "Cant reroll earring"); + uint256 costForReroll = getCostForRerollAttribute(); + require(msg.value >= costForReroll, "Need to send more ETH for reroll."); + if (msg.value > costForReroll) { + payable(msg.sender).transfer(msg.value - costForReroll); + } + + string memory zunk = serialIdToZunk[serialId]; + string memory zunkSkinAsString = substring(zunk, 0, 2); + string memory zunkGenderAsString = substring(zunk, 2, 4); + Attributes memory attributes = createAttributesFromZunk(zunk); + + validateSlotToRerollValid(slotToReroll, attributes); + + uint256 zunkGender = convertToUint(zunkGenderAsString); + uint256 zunkSkin = convertToUint(zunkSkinAsString); + bool isFemale = isZunkFemale(zunkGender); + + string memory rerolledZunk = _rerollZunk( + isFemale, + serialId, + zunkSkin, + zunkGender, + attributes, + slotToReroll, + zunk + ); + + require( + !isInvalidZunk(rerolledZunk), + "Could not reroll into a valid zunk, please try again." + ); + + serialIdToZunk[serialId] = rerolledZunk; + existingZunks[rerolledZunk] = true; + existingZunks[zunk] = false; + emit Zunk(msg.sender, serialId, rerolledZunk, true); + } + + function createAttributesFromZunk(string memory zunk) + internal + pure + returns (Attributes memory) + { + string memory attributes1 = substring(zunk, 4, 6); + string memory attributes2 = substring(zunk, 6, 8); + string memory attributes3 = substring(zunk, 8, 10); + string memory attributes4 = substring(zunk, 10, 12); + string memory attributes5 = substring(zunk, 12, 14); + string memory attributes6 = substring(zunk, 14, 16); + string memory attributes7 = substring(zunk, 16, 18); + string memory attributes8 = substring(zunk, 18, 20); + return + Attributes( + convertToUint(attributes1), + convertToUint(attributes2), + convertToUint(attributes3), + convertToUint(attributes4), + convertToUint(attributes5), + convertToUint(attributes6), + convertToUint(attributes7), + convertToUint(attributes8) + ); + } + + function _rerollZunk( + bool isFemale, + uint256 serialId, + uint256 zunkSkin, + uint256 zunkGender, + Attributes memory attributes, + uint256 slotToReroll, + string memory zunk + ) internal view returns (string memory) { + return + _rerollZunk( + isFemale, + serialId, + zunkSkin, + zunkGender, + attributes, + slotToReroll, + zunk, + true + ); + } + + function _rerollZunk( + bool isFemale, + uint256 serialId, + uint256 zunkSkin, + uint256 zunkGender, + Attributes memory attributes, + uint256 slotToReroll, + string memory zunk, + bool throwIfUnableToReroll + ) internal view returns (string memory) { + uint256 rerolledAttribute; + Attributes memory rerolledAttributes = Attributes( + attributes.accessories, + attributes.beard, + attributes.ear, + attributes.eyes, + attributes.hat, + attributes.lips, + attributes.neck, + attributes.smoke + ); + + if (slotToReroll == uint256(Slot.accessories)) { + rerolledAttribute = rerollZunkSlot( + isFemale, + serialId, + Slot.accessories, + attributes.accessories, + zunk, + throwIfUnableToReroll + ); + if (rerolledAttribute == NO_REROLL_OPTIONS) { + return NO_OPTIONS; + } + rerolledAttributes.accessories = rerolledAttribute; + } else if (slotToReroll == uint256(Slot.beard)) { + rerolledAttribute = rerollZunkSlot( + isFemale, + serialId, + Slot.beard, + attributes.beard, + zunk, + throwIfUnableToReroll + ); + if (rerolledAttribute == NO_REROLL_OPTIONS) { + return NO_OPTIONS; + } + rerolledAttributes.beard = rerolledAttribute; + } else if (slotToReroll == uint256(Slot.ear)) { + rerolledAttribute = rerollZunkSlot( + isFemale, + serialId, + Slot.ear, + attributes.ear, + zunk, + throwIfUnableToReroll + ); + if (rerolledAttribute == NO_REROLL_OPTIONS) { + return NO_OPTIONS; + } + rerolledAttributes.ear = rerolledAttribute; + } else if (slotToReroll == uint256(Slot.eyes)) { + rerolledAttribute = rerollZunkSlot( + isFemale, + serialId, + Slot.eyes, + attributes.eyes, + zunk, + throwIfUnableToReroll + ); + if (rerolledAttribute == NO_REROLL_OPTIONS) { + return NO_OPTIONS; + } + rerolledAttributes.eyes = rerolledAttribute; + } else if (slotToReroll == uint256(Slot.hat)) { + rerolledAttribute = rerollZunkSlot( + isFemale, + serialId, + Slot.hat, + attributes.hat, + zunk, + throwIfUnableToReroll + ); + if (rerolledAttribute == NO_REROLL_OPTIONS) { + return NO_OPTIONS; + } + rerolledAttributes.hat = rerolledAttribute; + } else if (slotToReroll == uint256(Slot.lips)) { + rerolledAttribute = rerollZunkSlot( + isFemale, + serialId, + Slot.lips, + attributes.lips, + zunk, + throwIfUnableToReroll + ); + if (rerolledAttribute == NO_REROLL_OPTIONS) { + return NO_OPTIONS; + } + rerolledAttributes.lips = rerolledAttribute; + } else if (slotToReroll == uint256(Slot.neck)) { + rerolledAttribute = rerollZunkSlot( + isFemale, + serialId, + Slot.neck, + attributes.neck, + zunk, + throwIfUnableToReroll + ); + if (rerolledAttribute == NO_REROLL_OPTIONS) { + return NO_OPTIONS; + } + rerolledAttributes.neck = rerolledAttribute; + } else { + rerolledAttribute = rerollZunkSlot( + isFemale, + serialId, + Slot.smoke, + attributes.smoke, + zunk, + throwIfUnableToReroll + ); + if (rerolledAttribute == NO_REROLL_OPTIONS) { + return NO_OPTIONS; + } + rerolledAttributes.smoke = rerolledAttribute; + } + + return + createZunkStringRepresentation(zunkSkin, zunkGender, rerolledAttributes); + } + + function rerollZunkSlot( + bool isFemale, + uint256 serialId, + Slot slot, + uint256 attribute, + string memory zunk, + bool throwIfUnableToReroll + ) internal view returns (uint256) { + uint256 slotAsUint = uint256(slot); + uint256[] storage attributeProbabilities = getAttributeProbabilities( + isFemale, + slotAsUint + ); + uint256 probabilitiesLength = attributeProbabilities.length; + + string[] memory rerollCandidates = getRerollCandidates( + slot, + zunk, + probabilitiesLength + ); + + uint256[] memory adjustedProbabilities = getAdjustedProbabilities( + isFemale, + slot, + attribute, + probabilitiesLength, + rerollCandidates + ); + + bool atLeastOneValidAttribute = false; + for (uint256 i = 0; i < probabilitiesLength; i++) { + if (adjustedProbabilities[i] > 0) { + atLeastOneValidAttribute = true; + break; + } + } + + if (!atLeastOneValidAttribute) { + if (throwIfUnableToReroll) { + require(atLeastOneValidAttribute, "Unable to mint. Please try again."); + } else { + return NO_REROLL_OPTIONS; + } + } + + return + pickRandomFromMemory( + adjustedProbabilities, + serialId, + uint256(slot), + attribute + ); + } + + function getAdjustedProbabilities( + bool isFemale, + Slot slot, + uint256 attribute, + uint256 probabilitiesLength, + string[] memory rerollCandidates + ) internal view returns (uint256[] memory) { + bool[] memory validAttribute = new bool[](probabilitiesLength); + uint256 slotAsUint = uint256(slot); + uint256[] storage attributeProbabilities = getAttributeProbabilities( + isFemale, + slotAsUint + ); + + uint256[] memory adjustedProbabilities = new uint256[](probabilitiesLength); + uint256 invalidProbabilitiesToDistribute = 0; + for (uint256 i = 0; i < probabilitiesLength; i++) { + string memory rerollCandidate = rerollCandidates[i]; + // can't give any attribute already off limits, if it makes a zunk/punk, or their current attribute + if ( + attributeProbabilities[i] == 0 || + isInvalidZunk(rerollCandidate) || + i == attribute + ) { + invalidProbabilitiesToDistribute += attributeProbabilities[i]; + } else { + validAttribute[i] = true; + } + } + + for (uint256 i = 0; i < probabilitiesLength; i++) { + if (validAttribute[i]) { + // the math here is to calculate how much of the invalidProbabilitiesToDistribute to + // give to each validProbability. If we are removing 2000 from the pool and giving + // 1000 its share, the additional probability for 1000 is 1000/8000 * 2000 + adjustedProbabilities[i] = + ((attributeProbabilities[i] * invalidProbabilitiesToDistribute) / + (10000 - invalidProbabilitiesToDistribute)) + + attributeProbabilities[i]; + } else { + adjustedProbabilities[i] = 0; + } + } + return adjustedProbabilities; + } + + function getRerollCandidates( + Slot slot, + string memory zunk, + uint256 probabilitiesLength + ) internal pure returns (string[] memory) { + string memory firstHalf = substring(zunk, 0, 4 + uint256(slot) * 2); + string memory secondHalf = substring(zunk, 6 + uint256(slot) * 2, 20); + string[] memory candidates = new string[](probabilitiesLength); + + for (uint256 i = 0; i < probabilitiesLength; i++) { + candidates[i] = string( + abi.encodePacked(firstHalf, convertToString(i), secondHalf) + ); + } + + return candidates; + } + + function getValidSlotsForReroll(Attributes memory attributes) + internal + pure + returns (uint256[] memory) + { + bool[] memory validSlots = new bool[](8); + uint256 numValidSlots = 0; + + if (attributes.accessories != 99) { + validSlots[uint256(Slot.accessories)] = true; + numValidSlots++; + } + if (attributes.beard != 99) { + validSlots[uint256(Slot.beard)] = true; + numValidSlots++; + } + if (attributes.eyes != 99) { + validSlots[uint256(Slot.eyes)] = true; + numValidSlots++; + } + if (attributes.hat != 99) { + validSlots[uint256(Slot.hat)] = true; + numValidSlots++; + } + if (attributes.lips != 99) { + validSlots[uint256(Slot.lips)] = true; + numValidSlots++; + } + if (attributes.neck != 99) { + validSlots[uint256(Slot.neck)] = true; + numValidSlots++; + } + if (attributes.smoke != 99) { + validSlots[uint256(Slot.smoke)] = true; + numValidSlots++; + } + + uint256[] memory valid = new uint256[](numValidSlots); + uint256 counter = 0; + for (uint256 i = 0; i < validSlots.length; i++) { + if (validSlots[i]) { + valid[counter] = i; + counter++; + } + } + return valid; + } + + function generateZunk(uint256 serialId) + internal + view + returns (string memory) + { + // these seed numbers are arbitrary, matches prospectiveSlot and mappingLength used elsewhere + uint256 zunkSkin = pickRandomFromStorage(skinProbabilities, serialId, 0, 7); + uint256 zunkGender = pickRandomFromStorage( + genderProbabilities, + serialId, + 1, + 2 + ); + + bool isFemale = isZunkFemale(zunkGender); + + Attributes memory attributes = getAttributes(isFemale, serialId); + string memory generatedZunk = createZunkStringRepresentation( + zunkSkin, + zunkGender, + attributes + ); + + if (isInvalidZunk(generatedZunk) || unableToRerollZunk(generatedZunk)) { + uint256[] memory validSlots = getValidSlotsForReroll(attributes); + uint256 randomSlotIndex = getRandomNumber( + zunkGender, + zunkSkin, + serialId + ) % validSlots.length; + + generatedZunk = _rerollZunk( + isFemale, + serialId, + zunkSkin, + zunkGender, + attributes, + validSlots[randomSlotIndex], + generatedZunk, + false + ); + } + return generatedZunk; + } + + function convertSlotsToString(Attributes memory attributes) + internal + pure + returns (AttributesAsString memory) + { + return + AttributesAsString( + convertToString(attributes.accessories), + convertToString(attributes.beard), + convertToString(attributes.ear), + convertToString(attributes.eyes), + convertToString(attributes.hat), + convertToString(attributes.lips), + convertToString(attributes.neck), + convertToString(attributes.smoke) + ); + } + + function getAttributes(bool isFemale, uint256 serialId) + internal + view + returns (Attributes memory) + { + return + Attributes( + maybeGetAttribute(isFemale, Slot.accessories, serialId), + maybeGetAttribute(isFemale, Slot.beard, serialId), + maybeGetAttribute(isFemale, Slot.ear, serialId), + maybeGetAttribute(isFemale, Slot.eyes, serialId), + maybeGetAttribute(isFemale, Slot.hat, serialId), + maybeGetAttribute(isFemale, Slot.lips, serialId), + maybeGetAttribute(isFemale, Slot.neck, serialId), + maybeGetAttribute(isFemale, Slot.smoke, serialId) + ); + } + + function maybeGetAttribute( + bool isFemale, + Slot slot, + uint256 serialId + ) internal view returns (uint256) { + uint256 slotAsUint = uint256(slot); + uint256[] storage attributeProbabilities = getAttributeProbabilities( + isFemale, + slotAsUint + ); + uint256 length = attributeProbabilities.length; + bool isSelected = isSlotSelected( + slot, + isFemale, + serialId, + slotAsUint, + length + ); + + if (!isSelected) { + return 99; + } else { + uint256 attribute = pickRandomFromStorage( + attributeProbabilities, + serialId, + slotAsUint, + length + ); + return attribute; + } + } + + // prospective slots are 0-7 + function isSlotSelected( + Slot prospectiveSlot, + bool isFemale, + uint256 seed1, + uint256 seed2, + uint256 seed3 + ) internal view returns (bool) { + uint256 randomNumber = getRandomNumber(seed1, seed2, seed3); + if (isFemale) { + return femaleSlotProbabilities[uint256(prospectiveSlot)] >= randomNumber; + } else { + return maleSlotProbabilities[uint256(prospectiveSlot)] >= randomNumber; + } + } + + function pickRandomFromStorage( + uint256[] storage attributeProbabilities, + uint256 seed1, + uint256 seed2, + uint256 seed3 + ) internal view returns (uint256) { + // mix up ordering of seed to generate diff random number from the random number in isSlotSelected + uint256 randomNumber = getRandomNumber(seed3, seed2, seed1); + uint256 sum = 0; + for (uint256 i = 0; i < attributeProbabilities.length; i++) { + sum += attributeProbabilities[i]; + if (sum >= randomNumber) { + return i; + } + } + // return the last one + return attributeProbabilities.length - 1; + } + + function pickRandomFromMemory( + uint256[] memory attributeProbabilities, + uint256 seed1, + uint256 seed2, + uint256 seed3 + ) internal view returns (uint256) { + // mix up ordering of seed to generate diff random number from the random number in isSlotSelected + uint256 randomNumber = getRandomNumber(seed3, seed2, seed1); + uint256 sum = 0; + for (uint256 i = 0; i < attributeProbabilities.length; i++) { + sum += attributeProbabilities[i]; + if (sum >= randomNumber) { + return i; + } + } + // return the last one + return attributeProbabilities.length - 1; + } + + function getRandomNumber( + uint256 seed1, + uint256 seed2, + uint256 seed3 + ) internal view returns (uint256) { + uint256 randomNum = uint256( + keccak256( + abi.encode( + msg.sender, + tx.gasprice, + block.number, + block.timestamp, + blockhash(block.number - 1), + seed1, + seed2, + seed3 + ) + ) + ); + + // never return 0, edge cases where first probability of accessory + // could be 0 while rerolling + return (randomNum % 10000) + 1; + } + + function createZunkStringRepresentation( + uint256 zunkSkin, + uint256 zunkGender, + Attributes memory attribues + ) internal pure returns (string memory) { + AttributesAsString memory slotsAsString = convertSlotsToString(attribues); + return + appendAttributes( + convertToString(zunkSkin), + convertToString(zunkGender), + slotsAsString + ); + } + + function appendAttributes( + string memory zunkSkin, + string memory zunkGender, + AttributesAsString memory attributes + ) internal pure returns (string memory) { + bytes memory firstHalf = abi.encodePacked( + zunkSkin, + zunkGender, + attributes.accessories, + attributes.beard, + attributes.ear + ); + bytes memory secondHalf = abi.encodePacked( + attributes.eyes, + attributes.hat, + attributes.lips, + attributes.neck, + attributes.smoke + ); + return string(abi.encodePacked(firstHalf, secondHalf)); + } + + function isInvalidZunk(string memory zunk) internal view returns (bool) { + return unavailableZunks[zunk] || existingZunks[zunk]; + } + + function getAttributeProbabilities(bool isFemale, uint256 slotAsUint) + internal + view + returns (uint256[] storage) + { + uint256[] storage attributeProbabilities = femaleProbabilities[slotAsUint]; + if (!isFemale) { + attributeProbabilities = maleProbabilities[slotAsUint]; + } + return attributeProbabilities; + } + + function convertToString(uint256 num) internal pure returns (string memory) { + if (num == 0) { + return "00"; + } else if (num == 1) { + return "01"; + } else if (num == 2) { + return "02"; + } else if (num == 3) { + return "03"; + } else if (num == 4) { + return "04"; + } else if (num == 5) { + return "05"; + } else if (num == 6) { + return "06"; + } else if (num == 7) { + return "07"; + } else if (num == 8) { + return "08"; + } else if (num == 9) { + return "09"; + } + + return Strings.toString(num); + } + + function substring( + string memory str, + uint256 startIndex, + uint256 endIndex + ) internal pure returns (string memory) { + bytes memory strBytes = bytes(str); + bytes memory result = new bytes(endIndex - startIndex); + for (uint256 i = startIndex; i < endIndex; i++) { + result[i - startIndex] = strBytes[i]; + } + return string(result); + } + + // s will always be len 2 + function convertToUint(string memory s) internal pure returns (uint256) { + string memory tensDigit = substring(s, 0, 1); + string memory onesDigit = substring(s, 1, 2); + return stringToUint(tensDigit) * 10 + stringToUint(onesDigit); + } + + function stringToUint(string memory s) internal pure returns (uint256) { + //bytes32 sHash = keccak256(abi.encodePacked(s)); + if (compareStrings(s, "0")) { + return 0; + } else if (compareStrings(s, "1")) { + return 1; + } else if (compareStrings(s, "2")) { + return 2; + } else if (compareStrings(s, "3")) { + return 3; + } else if (compareStrings(s, "4")) { + return 4; + } else if (compareStrings(s, "5")) { + return 5; + } else if (compareStrings(s, "6")) { + return 6; + } else if (compareStrings(s, "7")) { + return 7; + } else if (compareStrings(s, "8")) { + return 8; + } else { + return 9; + } + } + + function unableToRerollZunk(string memory zunk) internal view returns (bool) { + return compareStrings(zunk, NO_OPTIONS); + } + + function compareStrings(string memory s1, string memory s2) + internal + pure + returns (bool) + { + return keccak256(bytes(s1)) == keccak256(bytes(s2)); + } + + function isZunkFemale(uint256 zunkGender) internal pure returns (bool) { + return zunkGender == 0; + } + + function getOwnerZunks(address _owner) + external + view + returns (SerialIdAndTokenRepresentation[] memory) + { + uint256 numSerialIds = balanceOf(_owner); + if (numSerialIds == 0) { + return new SerialIdAndTokenRepresentation[](0); + } else { + SerialIdAndTokenRepresentation[] + memory result = new SerialIdAndTokenRepresentation[](numSerialIds); + for (uint256 i = 0; i < numSerialIds; i++) { + uint256 serialId = tokenOfOwnerByIndex(_owner, i); + string memory zunk = serialIdToZunk[serialId]; + result[i] = SerialIdAndTokenRepresentation(serialId, zunk); + } + return result; + } + } + + function getSerialIdTokenRepresentations(uint256[] memory serialIds) + external + view + returns (string[] memory) + { + string[] memory tokenRepresentations = new string[](serialIds.length); + for (uint256 i = 0; i < serialIds.length; i++) { + tokenRepresentations[i] = serialIdToZunk[serialIds[i]]; + } + return tokenRepresentations; + } + + // This does not factor free mints into account + function getCostForMints(uint256 _numToMint) public pure returns (uint256) { + uint256 _cost; + uint256 _index; + for (_index; _index < _numToMint; _index++) { + _cost += 0.05 ether; + } + return _cost; + } + + function getCostForRerollAttribute() public pure returns (uint256) { + return 0.02 ether; + } + + function hasFreeMintsInPoolRemaining() internal view returns (bool) { + return 200 - freeMintsFromPoolRedeemed > 0; + } + + function userHasFreeMint(address userAddress) public view returns (bool) { + if (freeMintsAllocatedByDevs[userAddress] > 0) { + return true; + } + if ( + !hasRedeemedFreeMintFromPool[userAddress] && hasFreeMintsInPoolRemaining() + ) { + // Free mints from pool are only accessible for those who have never free minted from the pool before. + return true; + } + return false; + } + + function enableMintAndReroll() public onlyOwner { + isMintAndRerollEnabled = true; + } + + function disableMintAndReroll() public onlyOwner { + isMintAndRerollEnabled = false; + } + + function devSingleMint() public onlyOwner { + require(!hasDevSingleMinted, "Can only dev single mint once"); + _mintNoChecks(1); + hasDevSingleMinted = true; + } + + function seedPunks(string[] memory punks) public onlyOwner { + for (uint256 i = 0; i < punks.length; i++) { + unavailableZunks[punks[i]] = true; + } + } + + function addFreeMintsAllocatedByDevs( + address[] memory addresses, + uint256[] memory numOfFreeMints + ) public onlyOwner { + require( + addresses.length == numOfFreeMints.length, + "tokenOwners does not match numOfFreeRolls length" + ); + uint256 freeMintsFromThisSeed = 0; + for (uint256 i = 0; i < addresses.length; i++) { + freeMintsAllocatedByDevs[addresses[i]] = + freeMintsAllocatedByDevs[addresses[i]] + + numOfFreeMints[i]; + freeMintsFromThisSeed += numOfFreeMints[i]; + } + require( + freeMintsFromThisSeed < freeMintsAllocatedByDevsCap, + "too many freemints allocated by devs" + ); + } + + // // metadata URI + string private _baseTokenURI; + + function _baseURI() internal view virtual override returns (string memory) { + return _baseTokenURI; + } + + function tokenURI(uint256 _serialId) + public + view + override + returns (string memory) + { + string memory base = _baseURI(); + string memory _tokenURI = Strings.toString(_serialId); + + // If there is no base URI, return the token URI. + if (bytes(base).length == 0) { + return _tokenURI; + } + + return string(abi.encodePacked(base, _tokenURI)); + } + + function setBaseURI(string calldata baseURI) external onlyOwner { + _baseTokenURI = baseURI; + } + + function withdrawMoney() public payable onlyOwner { + (bool success, ) = msg.sender.call{value: address(this).balance}(""); + require(success, "Transfer failed."); + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 serialId + ) internal virtual override(ERC721, ERC721Enumerable) { + super._beforeTokenTransfer(from, to, serialId); + } + + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(ERC721, ERC721Enumerable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/access/Ownable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor() { + _setOwner(_msgSender()); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _setOwner(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _setOwner(newOwner); + } + + function _setOwner(address newOwner) private { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/security/ReentrancyGuard.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor() { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and make it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/ERC721.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./IERC721.sol"; +import "./IERC721Receiver.sol"; +import "./extensions/IERC721Metadata.sol"; +import "../../utils/Address.sol"; +import "../../utils/Context.sol"; +import "../../utils/Strings.sol"; +import "../../utils/introspection/ERC165.sol"; + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including + * the Metadata extension, but not including the Enumerable extension, which is available separately as + * {ERC721Enumerable}. + */ +contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { + using Address for address; + using Strings for uint256; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to owner address + mapping(uint256 => address) private _owners; + + // Mapping owner address to token count + mapping(address => uint256) private _balances; + + // Mapping from token ID to approved address + mapping(uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view virtual override returns (uint256) { + require(owner != address(0), "ERC721: balance query for the zero address"); + return _balances[owner]; + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view virtual override returns (address) { + address owner = _owners[tokenId]; + require(owner != address(0), "ERC721: owner query for nonexistent token"); + return owner; + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, can be overriden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ""; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public virtual override { + address owner = ERC721.ownerOf(tokenId); + require(to != owner, "ERC721: approval to current owner"); + + require( + _msgSender() == owner || isApprovedForAll(owner, _msgSender()), + "ERC721: approve caller is not owner nor approved for all" + ); + + _approve(to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view virtual override returns (address) { + require(_exists(tokenId), "ERC721: approved query for nonexistent token"); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + require(operator != _msgSender(), "ERC721: approve to caller"); + + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + + _transfer(from, to, tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + safeTransferFrom(from, to, tokenId, ""); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) public virtual override { + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + _safeTransfer(from, to, tokenId, _data); + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * `_data` is additional data, it has no specified format and it is sent in call to `to`. + * + * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. + * implement alternative mechanisms to perform token transfer, such as signature-based. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeTransfer( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) internal virtual { + _transfer(from, to, tokenId); + require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + * and stop existing when they are burned (`_burn`). + */ + function _exists(uint256 tokenId) internal view virtual returns (bool) { + return _owners[tokenId] != address(0); + } + + /** + * @dev Returns whether `spender` is allowed to manage `tokenId`. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { + require(_exists(tokenId), "ERC721: operator query for nonexistent token"); + address owner = ERC721.ownerOf(tokenId); + return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); + } + + /** + * @dev Safely mints `tokenId` and transfers it to `to`. + * + * Requirements: + * + * - `tokenId` must not exist. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeMint(address to, uint256 tokenId) internal virtual { + _safeMint(to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeMint( + address to, + uint256 tokenId, + bytes memory _data + ) internal virtual { + _mint(to, tokenId); + require( + _checkOnERC721Received(address(0), to, tokenId, _data), + "ERC721: transfer to non ERC721Receiver implementer" + ); + } + + /** + * @dev Mints `tokenId` and transfers it to `to`. + * + * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * Emits a {Transfer} event. + */ + function _mint(address to, uint256 tokenId) internal virtual { + require(to != address(0), "ERC721: mint to the zero address"); + require(!_exists(tokenId), "ERC721: token already minted"); + + _beforeTokenTransfer(address(0), to, tokenId); + + _balances[to] += 1; + _owners[tokenId] = to; + + emit Transfer(address(0), to, tokenId); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId) internal virtual { + address owner = ERC721.ownerOf(tokenId); + + _beforeTokenTransfer(owner, address(0), tokenId); + + // Clear approvals + _approve(address(0), tokenId); + + _balances[owner] -= 1; + delete _owners[tokenId]; + + emit Transfer(owner, address(0), tokenId); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer( + address from, + address to, + uint256 tokenId + ) internal virtual { + require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); + require(to != address(0), "ERC721: transfer to the zero address"); + + _beforeTokenTransfer(from, to, tokenId); + + // Clear approvals from the previous owner + _approve(address(0), tokenId); + + _balances[from] -= 1; + _balances[to] += 1; + _owners[tokenId] = to; + + emit Transfer(from, to, tokenId); + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * Emits a {Approval} event. + */ + function _approve(address to, uint256 tokenId) internal virtual { + _tokenApprovals[tokenId] = to; + emit Approval(ERC721.ownerOf(tokenId), to, tokenId); + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * The call is not executed if the target address is not a contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) private returns (bool) { + if (to.isContract()) { + try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { + return retval == IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert("ERC721: transfer to non ERC721Receiver implementer"); + } else { + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } else { + return true; + } + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, ``from``'s `tokenId` will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId + ) internal virtual {} +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "../../../utils/Context.sol"; + +/** + * @title ERC721 Burnable Token + * @dev ERC721 Token that can be irreversibly burned (destroyed). + */ +abstract contract ERC721Burnable is Context, ERC721 { + /** + * @dev Burns `tokenId`. See {ERC721-_burn}. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(uint256 tokenId) public virtual { + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721Burnable: caller is not owner nor approved"); + _burn(tokenId); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "./IERC721Enumerable.sol"; + +/** + * @dev This implements an optional extension of {ERC721} defined in the EIP that adds + * enumerability of all the token ids in the contract as well as all token ids owned by each + * account. + */ +abstract contract ERC721Enumerable is ERC721, IERC721Enumerable { + // Mapping from owner to list of owned token IDs + mapping(address => mapping(uint256 => uint256)) private _ownedTokens; + + // Mapping from token ID to index of the owner tokens list + mapping(uint256 => uint256) private _ownedTokensIndex; + + // Array with all token ids, used for enumeration + uint256[] private _allTokens; + + // Mapping from token id to position in the allTokens array + mapping(uint256 => uint256) private _allTokensIndex; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { + return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { + require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); + return _ownedTokens[owner][index]; + } + + /** + * @dev See {IERC721Enumerable-totalSupply}. + */ + function totalSupply() public view virtual override returns (uint256) { + return _allTokens.length; + } + + /** + * @dev See {IERC721Enumerable-tokenByIndex}. + */ + function tokenByIndex(uint256 index) public view virtual override returns (uint256) { + require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds"); + return _allTokens[index]; + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, ``from``'s `tokenId` will be burned. + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId + ) internal virtual override { + super._beforeTokenTransfer(from, to, tokenId); + + if (from == address(0)) { + _addTokenToAllTokensEnumeration(tokenId); + } else if (from != to) { + _removeTokenFromOwnerEnumeration(from, tokenId); + } + if (to == address(0)) { + _removeTokenFromAllTokensEnumeration(tokenId); + } else if (to != from) { + _addTokenToOwnerEnumeration(to, tokenId); + } + } + + /** + * @dev Private function to add a token to this extension's ownership-tracking data structures. + * @param to address representing the new owner of the given token ID + * @param tokenId uint256 ID of the token to be added to the tokens list of the given address + */ + function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { + uint256 length = ERC721.balanceOf(to); + _ownedTokens[to][length] = tokenId; + _ownedTokensIndex[tokenId] = length; + } + + /** + * @dev Private function to add a token to this extension's token tracking data structures. + * @param tokenId uint256 ID of the token to be added to the tokens list + */ + function _addTokenToAllTokensEnumeration(uint256 tokenId) private { + _allTokensIndex[tokenId] = _allTokens.length; + _allTokens.push(tokenId); + } + + /** + * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that + * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for + * gas optimizations e.g. when performing a transfer operation (avoiding double writes). + * This has O(1) time complexity, but alters the order of the _ownedTokens array. + * @param from address representing the previous owner of the given token ID + * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address + */ + function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { + // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and + // then delete the last slot (swap and pop). + + uint256 lastTokenIndex = ERC721.balanceOf(from) - 1; + uint256 tokenIndex = _ownedTokensIndex[tokenId]; + + // When the token to delete is the last token, the swap operation is unnecessary + if (tokenIndex != lastTokenIndex) { + uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; + + _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token + _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index + } + + // This also deletes the contents at the last position of the array + delete _ownedTokensIndex[tokenId]; + delete _ownedTokens[from][lastTokenIndex]; + } + + /** + * @dev Private function to remove a token from this extension's token tracking data structures. + * This has O(1) time complexity, but alters the order of the _allTokens array. + * @param tokenId uint256 ID of the token to be removed from the tokens list + */ + function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { + // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and + // then delete the last slot (swap and pop). + + uint256 lastTokenIndex = _allTokens.length - 1; + uint256 tokenIndex = _allTokensIndex[tokenId]; + + // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so + // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding + // an 'if' statement (like in _removeTokenFromOwnerEnumeration) + uint256 lastTokenId = _allTokens[lastTokenIndex]; + + _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token + _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index + + // This also deletes the contents at the last position of the array + delete _allTokensIndex[tokenId]; + _allTokens.pop(); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Strings.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + // Inspired by OraclizeAPI's implementation - MIT licence + // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol + + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + while (value != 0) { + digits -= 1; + buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); + value /= 10; + } + return string(buffer); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + if (value == 0) { + return "0x00"; + } + uint256 temp = value; + uint256 length = 0; + while (temp != 0) { + length++; + temp >>= 8; + } + return toHexString(value, length); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _HEX_SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/structs/EnumerableMap.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./EnumerableSet.sol"; + +/** + * @dev Library for managing an enumerable variant of Solidity's + * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] + * type. + * + * Maps have the following properties: + * + * - Entries are added, removed, and checked for existence in constant time + * (O(1)). + * - Entries are enumerated in O(n). No guarantees are made on the ordering. + * + * ``` + * contract Example { + * // Add the library methods + * using EnumerableMap for EnumerableMap.UintToAddressMap; + * + * // Declare a set state variable + * EnumerableMap.UintToAddressMap private myMap; + * } + * ``` + * + * As of v3.0.0, only maps of type `uint256 -> address` (`UintToAddressMap`) are + * supported. + */ +library EnumerableMap { + using EnumerableSet for EnumerableSet.Bytes32Set; + + // To implement this library for multiple types with as little code + // repetition as possible, we write it in terms of a generic Map type with + // bytes32 keys and values. + // The Map implementation uses private functions, and user-facing + // implementations (such as Uint256ToAddressMap) are just wrappers around + // the underlying Map. + // This means that we can only create new EnumerableMaps for types that fit + // in bytes32. + + struct Map { + // Storage of keys + EnumerableSet.Bytes32Set _keys; + mapping(bytes32 => bytes32) _values; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function _set( + Map storage map, + bytes32 key, + bytes32 value + ) private returns (bool) { + map._values[key] = value; + return map._keys.add(key); + } + + /** + * @dev Removes a key-value pair from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function _remove(Map storage map, bytes32 key) private returns (bool) { + delete map._values[key]; + return map._keys.remove(key); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function _contains(Map storage map, bytes32 key) private view returns (bool) { + return map._keys.contains(key); + } + + /** + * @dev Returns the number of key-value pairs in the map. O(1). + */ + function _length(Map storage map) private view returns (uint256) { + return map._keys.length(); + } + + /** + * @dev Returns the key-value pair stored at position `index` in the map. O(1). + * + * Note that there are no guarantees on the ordering of entries inside the + * array, and it may change when more entries are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function _at(Map storage map, uint256 index) private view returns (bytes32, bytes32) { + bytes32 key = map._keys.at(index); + return (key, map._values[key]); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function _tryGet(Map storage map, bytes32 key) private view returns (bool, bytes32) { + bytes32 value = map._values[key]; + if (value == bytes32(0)) { + return (_contains(map, key), bytes32(0)); + } else { + return (true, value); + } + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function _get(Map storage map, bytes32 key) private view returns (bytes32) { + bytes32 value = map._values[key]; + require(value != 0 || _contains(map, key), "EnumerableMap: nonexistent key"); + return value; + } + + /** + * @dev Same as {_get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {_tryGet}. + */ + function _get( + Map storage map, + bytes32 key, + string memory errorMessage + ) private view returns (bytes32) { + bytes32 value = map._values[key]; + require(value != 0 || _contains(map, key), errorMessage); + return value; + } + + // UintToAddressMap + + struct UintToAddressMap { + Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set( + UintToAddressMap storage map, + uint256 key, + address value + ) internal returns (bool) { + return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value)))); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { + return _remove(map._inner, bytes32(key)); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { + return _contains(map._inner, bytes32(key)); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(UintToAddressMap storage map) internal view returns (uint256) { + return _length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the set. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { + (bytes32 key, bytes32 value) = _at(map._inner, index); + return (uint256(key), address(uint160(uint256(value)))); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + * + * _Available since v3.4._ + */ + function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) { + (bool success, bytes32 value) = _tryGet(map._inner, bytes32(key)); + return (success, address(uint160(uint256(value)))); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { + return address(uint160(uint256(_get(map._inner, bytes32(key))))); + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get( + UintToAddressMap storage map, + uint256 key, + string memory errorMessage + ) internal view returns (address) { + return address(uint160(uint256(_get(map._inner, bytes32(key), errorMessage)))); + } +} + + +/////////////////////////////////////////// +// File: hardhat/console.sol + +// SPDX-License-Identifier: MIT +pragma solidity >= 0.4.22 <0.9.0; + +library console { + address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); + + function _sendLogPayload(bytes memory payload) private view { + uint256 payloadLength = payload.length; + address consoleAddress = CONSOLE_ADDRESS; + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function log() internal view { + _sendLogPayload(abi.encodeWithSignature("log()")); + } + + function logInt(int p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int)", p0)); + } + + function logUint(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function logString(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function logBool(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function logAddress(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function logBytes(bytes memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); + } + + function logBytes1(bytes1 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); + } + + function logBytes2(bytes2 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); + } + + function logBytes3(bytes3 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); + } + + function logBytes4(bytes4 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); + } + + function logBytes5(bytes5 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); + } + + function logBytes6(bytes6 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); + } + + function logBytes7(bytes7 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); + } + + function logBytes8(bytes8 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); + } + + function logBytes9(bytes9 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); + } + + function logBytes10(bytes10 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); + } + + function logBytes11(bytes11 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); + } + + function logBytes12(bytes12 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); + } + + function logBytes13(bytes13 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); + } + + function logBytes14(bytes14 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); + } + + function logBytes15(bytes15 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); + } + + function logBytes16(bytes16 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); + } + + function logBytes17(bytes17 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); + } + + function logBytes18(bytes18 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); + } + + function logBytes19(bytes19 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); + } + + function logBytes20(bytes20 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); + } + + function logBytes21(bytes21 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); + } + + function logBytes22(bytes22 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); + } + + function logBytes23(bytes23 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); + } + + function logBytes24(bytes24 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); + } + + function logBytes25(bytes25 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); + } + + function logBytes26(bytes26 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); + } + + function logBytes27(bytes27 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); + } + + function logBytes28(bytes28 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); + } + + function logBytes29(bytes29 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); + } + + function logBytes30(bytes30 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); + } + + function logBytes31(bytes31 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); + } + + function logBytes32(bytes32 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); + } + + function log(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function log(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function log(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function log(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function log(uint p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1)); + } + + function log(uint p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1)); + } + + function log(uint p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1)); + } + + function log(uint p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1)); + } + + function log(string memory p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1)); + } + + function log(string memory p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } + + function log(string memory p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); + } + + function log(string memory p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); + } + + function log(bool p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1)); + } + + function log(bool p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); + } + + function log(bool p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); + } + + function log(bool p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); + } + + function log(address p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1)); + } + + function log(address p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); + } + + function log(address p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); + } + + function log(address p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); + } + + function log(uint p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2)); + } + + function log(uint p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2)); + } + + function log(uint p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2)); + } + + function log(uint p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2)); + } + + function log(uint p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2)); + } + + function log(uint p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2)); + } + + function log(uint p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2)); + } + + function log(uint p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2)); + } + + function log(uint p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2)); + } + + function log(uint p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2)); + } + + function log(uint p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2)); + } + + function log(uint p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); + } + + function log(string memory p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2)); + } + + function log(string memory p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); + } + + function log(string memory p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); + } + + function log(string memory p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); + } + + function log(bool p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2)); + } + + function log(bool p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2)); + } + + function log(bool p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2)); + } + + function log(bool p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); + } + + function log(bool p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2)); + } + + function log(bool p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); + } + + function log(bool p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); + } + + function log(bool p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); + } + + function log(bool p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2)); + } + + function log(bool p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); + } + + function log(bool p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); + } + + function log(bool p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); + } + + function log(address p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2)); + } + + function log(address p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2)); + } + + function log(address p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2)); + } + + function log(address p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2)); + } + + function log(address p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2)); + } + + function log(address p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); + } + + function log(address p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); + } + + function log(address p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); + } + + function log(address p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2)); + } + + function log(address p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); + } + + function log(address p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); + } + + function log(address p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); + } + + function log(address p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2)); + } + + function log(address p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); + } + + function log(address p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); + } + + function log(address p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); + } + + function log(uint p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); + } + +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/IERC721.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external; +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. + */ + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + assembly { + size := extcodesize(account) + } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + (bool success, bytes memory returndata) = target.call{value: value}(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) private pure returns (bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/introspection/ERC165.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/introspection/IERC165.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Enumerable is IERC721 { + /** + * @dev Returns the total amount of tokens stored by the contract. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns a token ID owned by `owner` at a given `index` of its token list. + * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); + + /** + * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. + * Use along with {totalSupply} to enumerate all tokens. + */ + function tokenByIndex(uint256 index) external view returns (uint256); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/structs/EnumerableSet.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Library for managing + * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive + * types. + * + * Sets have the following properties: + * + * - Elements are added, removed, and checked for existence in constant time + * (O(1)). + * - Elements are enumerated in O(n). No guarantees are made on the ordering. + * + * ``` + * contract Example { + * // Add the library methods + * using EnumerableSet for EnumerableSet.AddressSet; + * + * // Declare a set state variable + * EnumerableSet.AddressSet private mySet; + * } + * ``` + * + * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) + * and `uint256` (`UintSet`) are supported. + */ +library EnumerableSet { + // To implement this library for multiple types with as little code + // repetition as possible, we write it in terms of a generic Set type with + // bytes32 values. + // The Set implementation uses private functions, and user-facing + // implementations (such as AddressSet) are just wrappers around the + // underlying Set. + // This means that we can only create new EnumerableSets for types that fit + // in bytes32. + + struct Set { + // Storage of set values + bytes32[] _values; + // Position of the value in the `values` array, plus 1 because index 0 + // means a value is not in the set. + mapping(bytes32 => uint256) _indexes; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function _add(Set storage set, bytes32 value) private returns (bool) { + if (!_contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + set._indexes[value] = set._values.length; + return true; + } else { + return false; + } + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function _remove(Set storage set, bytes32 value) private returns (bool) { + // We read and store the value's index to prevent multiple reads from the same storage slot + uint256 valueIndex = set._indexes[value]; + + if (valueIndex != 0) { + // Equivalent to contains(set, value) + // To delete an element from the _values array in O(1), we swap the element to delete with the last one in + // the array, and then remove the last element (sometimes called as 'swap and pop'). + // This modifies the order of the array, as noted in {at}. + + uint256 toDeleteIndex = valueIndex - 1; + uint256 lastIndex = set._values.length - 1; + + if (lastIndex != toDeleteIndex) { + bytes32 lastvalue = set._values[lastIndex]; + + // Move the last value to the index where the value to delete is + set._values[toDeleteIndex] = lastvalue; + // Update the index for the moved value + set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex + } + + // Delete the slot where the moved value was stored + set._values.pop(); + + // Delete the index for the deleted slot + delete set._indexes[value]; + + return true; + } else { + return false; + } + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function _contains(Set storage set, bytes32 value) private view returns (bool) { + return set._indexes[value] != 0; + } + + /** + * @dev Returns the number of values on the set. O(1). + */ + function _length(Set storage set) private view returns (uint256) { + return set._values.length; + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function _at(Set storage set, uint256 index) private view returns (bytes32) { + return set._values[index]; + } + + // Bytes32Set + + struct Bytes32Set { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _add(set._inner, value); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _remove(set._inner, value); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { + return _contains(set._inner, value); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(Bytes32Set storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { + return _at(set._inner, index); + } + + // AddressSet + + struct AddressSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(AddressSet storage set, address value) internal returns (bool) { + return _add(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(AddressSet storage set, address value) internal returns (bool) { + return _remove(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(AddressSet storage set, address value) internal view returns (bool) { + return _contains(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(AddressSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(AddressSet storage set, uint256 index) internal view returns (address) { + return address(uint160(uint256(_at(set._inner, index)))); + } + + // UintSet + + struct UintSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(UintSet storage set, uint256 value) internal returns (bool) { + return _add(set._inner, bytes32(value)); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(UintSet storage set, uint256 value) internal returns (bool) { + return _remove(set._inner, bytes32(value)); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(UintSet storage set, uint256 value) internal view returns (bool) { + return _contains(set._inner, bytes32(value)); + } + + /** + * @dev Returns the number of values on the set. O(1). + */ + function length(UintSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintSet storage set, uint256 index) internal view returns (uint256) { + return uint256(_at(set._inner, index)); + } +} + + diff --git a/ethabi/code/0x031920cc2d9f5c10b444fd44009cd64f829e7be2.yml b/ethabi/code/0x031920cc2d9f5c10b444fd44009cd64f829e7be2.yml new file mode 100644 index 0000000..30e05b6 --- /dev/null +++ b/ethabi/code/0x031920cc2d9f5c10b444fd44009cd64f829e7be2.yml @@ -0,0 +1,12 @@ +--- +ContractName: CryptoZunks +CompilerVersion: v0.8.4+commit.c7e474f2 +OptimizationUsed: '1' +Runs: '500' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: '' +Proxy: '0' +Implementation: '' +SwarmSource: '' diff --git a/ethabi/code/0x0d0167a823c6619d430b1a96ad85b888bcf97c37.sol b/ethabi/code/0x0d0167a823c6619d430b1a96ad85b888bcf97c37.sol new file mode 100644 index 0000000..f0444ea --- /dev/null +++ b/ethabi/code/0x0d0167a823c6619d430b1a96ad85b888bcf97c37.sol @@ -0,0 +1,1924 @@ +/////////////////////////////////////////// +// File: @openzeppelin/contracts/access/Ownable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor() { + _setOwner(_msgSender()); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _setOwner(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _setOwner(newOwner); + } + + function _setOwner(address newOwner) private { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/security/ReentrancyGuard.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor() { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and make it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/ERC721.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./IERC721.sol"; +import "./IERC721Receiver.sol"; +import "./extensions/IERC721Metadata.sol"; +import "../../utils/Address.sol"; +import "../../utils/Context.sol"; +import "../../utils/Strings.sol"; +import "../../utils/introspection/ERC165.sol"; + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including + * the Metadata extension, but not including the Enumerable extension, which is available separately as + * {ERC721Enumerable}. + */ +contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { + using Address for address; + using Strings for uint256; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to owner address + mapping(uint256 => address) private _owners; + + // Mapping owner address to token count + mapping(address => uint256) private _balances; + + // Mapping from token ID to approved address + mapping(uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view virtual override returns (uint256) { + require(owner != address(0), "ERC721: balance query for the zero address"); + return _balances[owner]; + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view virtual override returns (address) { + address owner = _owners[tokenId]; + require(owner != address(0), "ERC721: owner query for nonexistent token"); + return owner; + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, can be overriden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ""; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public virtual override { + address owner = ERC721.ownerOf(tokenId); + require(to != owner, "ERC721: approval to current owner"); + + require( + _msgSender() == owner || isApprovedForAll(owner, _msgSender()), + "ERC721: approve caller is not owner nor approved for all" + ); + + _approve(to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view virtual override returns (address) { + require(_exists(tokenId), "ERC721: approved query for nonexistent token"); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + require(operator != _msgSender(), "ERC721: approve to caller"); + + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + + _transfer(from, to, tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + safeTransferFrom(from, to, tokenId, ""); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) public virtual override { + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + _safeTransfer(from, to, tokenId, _data); + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * `_data` is additional data, it has no specified format and it is sent in call to `to`. + * + * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. + * implement alternative mechanisms to perform token transfer, such as signature-based. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeTransfer( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) internal virtual { + _transfer(from, to, tokenId); + require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + * and stop existing when they are burned (`_burn`). + */ + function _exists(uint256 tokenId) internal view virtual returns (bool) { + return _owners[tokenId] != address(0); + } + + /** + * @dev Returns whether `spender` is allowed to manage `tokenId`. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { + require(_exists(tokenId), "ERC721: operator query for nonexistent token"); + address owner = ERC721.ownerOf(tokenId); + return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); + } + + /** + * @dev Safely mints `tokenId` and transfers it to `to`. + * + * Requirements: + * + * - `tokenId` must not exist. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeMint(address to, uint256 tokenId) internal virtual { + _safeMint(to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeMint( + address to, + uint256 tokenId, + bytes memory _data + ) internal virtual { + _mint(to, tokenId); + require( + _checkOnERC721Received(address(0), to, tokenId, _data), + "ERC721: transfer to non ERC721Receiver implementer" + ); + } + + /** + * @dev Mints `tokenId` and transfers it to `to`. + * + * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * Emits a {Transfer} event. + */ + function _mint(address to, uint256 tokenId) internal virtual { + require(to != address(0), "ERC721: mint to the zero address"); + require(!_exists(tokenId), "ERC721: token already minted"); + + _beforeTokenTransfer(address(0), to, tokenId); + + _balances[to] += 1; + _owners[tokenId] = to; + + emit Transfer(address(0), to, tokenId); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId) internal virtual { + address owner = ERC721.ownerOf(tokenId); + + _beforeTokenTransfer(owner, address(0), tokenId); + + // Clear approvals + _approve(address(0), tokenId); + + _balances[owner] -= 1; + delete _owners[tokenId]; + + emit Transfer(owner, address(0), tokenId); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer( + address from, + address to, + uint256 tokenId + ) internal virtual { + require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); + require(to != address(0), "ERC721: transfer to the zero address"); + + _beforeTokenTransfer(from, to, tokenId); + + // Clear approvals from the previous owner + _approve(address(0), tokenId); + + _balances[from] -= 1; + _balances[to] += 1; + _owners[tokenId] = to; + + emit Transfer(from, to, tokenId); + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * Emits a {Approval} event. + */ + function _approve(address to, uint256 tokenId) internal virtual { + _tokenApprovals[tokenId] = to; + emit Approval(ERC721.ownerOf(tokenId), to, tokenId); + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * The call is not executed if the target address is not a contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) private returns (bool) { + if (to.isContract()) { + try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { + return retval == IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert("ERC721: transfer to non ERC721Receiver implementer"); + } else { + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } else { + return true; + } + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, ``from``'s `tokenId` will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId + ) internal virtual {} +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/IERC721.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external; +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. + */ + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "./IERC721Enumerable.sol"; + +/** + * @dev This implements an optional extension of {ERC721} defined in the EIP that adds + * enumerability of all the token ids in the contract as well as all token ids owned by each + * account. + */ +abstract contract ERC721Enumerable is ERC721, IERC721Enumerable { + // Mapping from owner to list of owned token IDs + mapping(address => mapping(uint256 => uint256)) private _ownedTokens; + + // Mapping from token ID to index of the owner tokens list + mapping(uint256 => uint256) private _ownedTokensIndex; + + // Array with all token ids, used for enumeration + uint256[] private _allTokens; + + // Mapping from token id to position in the allTokens array + mapping(uint256 => uint256) private _allTokensIndex; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { + return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { + require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); + return _ownedTokens[owner][index]; + } + + /** + * @dev See {IERC721Enumerable-totalSupply}. + */ + function totalSupply() public view virtual override returns (uint256) { + return _allTokens.length; + } + + /** + * @dev See {IERC721Enumerable-tokenByIndex}. + */ + function tokenByIndex(uint256 index) public view virtual override returns (uint256) { + require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds"); + return _allTokens[index]; + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, ``from``'s `tokenId` will be burned. + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId + ) internal virtual override { + super._beforeTokenTransfer(from, to, tokenId); + + if (from == address(0)) { + _addTokenToAllTokensEnumeration(tokenId); + } else if (from != to) { + _removeTokenFromOwnerEnumeration(from, tokenId); + } + if (to == address(0)) { + _removeTokenFromAllTokensEnumeration(tokenId); + } else if (to != from) { + _addTokenToOwnerEnumeration(to, tokenId); + } + } + + /** + * @dev Private function to add a token to this extension's ownership-tracking data structures. + * @param to address representing the new owner of the given token ID + * @param tokenId uint256 ID of the token to be added to the tokens list of the given address + */ + function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { + uint256 length = ERC721.balanceOf(to); + _ownedTokens[to][length] = tokenId; + _ownedTokensIndex[tokenId] = length; + } + + /** + * @dev Private function to add a token to this extension's token tracking data structures. + * @param tokenId uint256 ID of the token to be added to the tokens list + */ + function _addTokenToAllTokensEnumeration(uint256 tokenId) private { + _allTokensIndex[tokenId] = _allTokens.length; + _allTokens.push(tokenId); + } + + /** + * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that + * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for + * gas optimizations e.g. when performing a transfer operation (avoiding double writes). + * This has O(1) time complexity, but alters the order of the _ownedTokens array. + * @param from address representing the previous owner of the given token ID + * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address + */ + function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { + // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and + // then delete the last slot (swap and pop). + + uint256 lastTokenIndex = ERC721.balanceOf(from) - 1; + uint256 tokenIndex = _ownedTokensIndex[tokenId]; + + // When the token to delete is the last token, the swap operation is unnecessary + if (tokenIndex != lastTokenIndex) { + uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; + + _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token + _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index + } + + // This also deletes the contents at the last position of the array + delete _ownedTokensIndex[tokenId]; + delete _ownedTokens[from][lastTokenIndex]; + } + + /** + * @dev Private function to remove a token from this extension's token tracking data structures. + * This has O(1) time complexity, but alters the order of the _allTokens array. + * @param tokenId uint256 ID of the token to be removed from the tokens list + */ + function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { + // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and + // then delete the last slot (swap and pop). + + uint256 lastTokenIndex = _allTokens.length - 1; + uint256 tokenIndex = _allTokensIndex[tokenId]; + + // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so + // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding + // an 'if' statement (like in _removeTokenFromOwnerEnumeration) + uint256 lastTokenId = _allTokens[lastTokenIndex]; + + _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token + _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index + + // This also deletes the contents at the last position of the array + delete _allTokensIndex[tokenId]; + _allTokens.pop(); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Enumerable is IERC721 { + /** + * @dev Returns the total amount of tokens stored by the contract. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns a token ID owned by `owner` at a given `index` of its token list. + * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); + + /** + * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. + * Use along with {totalSupply} to enumerate all tokens. + */ + function tokenByIndex(uint256 index) external view returns (uint256); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + assembly { + size := extcodesize(account) + } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + (bool success, bytes memory returndata) = target.call{value: value}(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) private pure returns (bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Strings.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + // Inspired by OraclizeAPI's implementation - MIT licence + // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol + + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + while (value != 0) { + digits -= 1; + buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); + value /= 10; + } + return string(buffer); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + if (value == 0) { + return "0x00"; + } + uint256 temp = value; + uint256 length = 0; + while (temp != 0) { + length++; + temp >>= 8; + } + return toHexString(value, length); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _HEX_SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/introspection/ERC165.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/introspection/IERC165.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +// CAUTION +// This version of SafeMath should only be used with Solidity 0.8 or later, +// because it relies on the compiler's built in overflow checks. + +/** + * @dev Wrappers over Solidity's arithmetic operations. + * + * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler + * now has built in overflow checking. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b > a) return (false, 0); + return (true, a - b); + } + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a / b); + } + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a % b); + } + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + return a + b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + return a * b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub( + uint256 a, + uint256 b, + string memory errorMessage + ) internal pure returns (uint256) { + unchecked { + require(b <= a, errorMessage); + return a - b; + } + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div( + uint256 a, + uint256 b, + string memory errorMessage + ) internal pure returns (uint256) { + unchecked { + require(b > 0, errorMessage); + return a / b; + } + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod( + uint256 a, + uint256 b, + string memory errorMessage + ) internal pure returns (uint256) { + unchecked { + require(b > 0, errorMessage); + return a % b; + } + } +} + + +/////////////////////////////////////////// +// File: contracts/ExpansionPunks.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; +import "@openzeppelin/contracts/utils/math/SafeMath.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; +import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; + +// *********************************:::::::::::::::::::::::::::::::::...............:::::::::::::::::**********************::::::::::: +// *********************************:::::::::::::::::::::::::::::::::...............:::::::::::::::::**********************::::::::::: +// *********************************:::::::::::::::::::::::::::::::::............::::::::::::::::::::**********************::::::::::: +// ******************************::::::::::::::::::::::::::::::::.::...........:::::::::::::::::**********************:::::::::::..... +// *****************************::::::::::::::::::::::::::::::::::::...........:::::::::::::::::**********************:::::::::::::::: +// ***************************:::::::::::::::::::::::::::::::::............::.:::::::::::::::::**********************::::::::::::..... +// ***************************:::::::::::::::::::::::::::::::::...........:::::::::::::::::**********************:::::::::::.::....... +// ***************************::::::::::::::::::::::::::::.................::::::::::::::::**********************:::::::::::.:........ +// **********************:::::::::::::::::::::::::::F$$$$$$$$$I......:::::I$$$$$$$$$I::***********************:*:::::::::::........... +// *********************::::::::::::::::::::::::::::IMMMMNNMMM$......::.::$MMNNNNMMM$::*********************:*:::::::::::::......:.::: +// *****************:***::::::::::::::::::::::::::::$MMMNNNNNM$:::::::::::$MMNNNNNMM$**********************::::::::::::.::.......::::: +// ****************:::::::::::::::::::::::::::*MMMMMMMMNNNNNNMMMMMMMMMMMMMMMNNNNNNMMMMMMMMF***************:::::::::::...........:::::: +// ****************:::::::::::::::::::::::::::*MMMMMMMMNNNNNNMMMMMMNMMMMMMMMNNNNNNNMMMMMMMF***************:::::::::::...........:::::: +// ***************::::::::::::::::::::::::::::*MNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMF**********:::::::::::::.........::::::::::: +// ***********::::::::::::::::::::::::::::::::*MNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMF**********:::::::::::...........::::::::::: +// ***********::::::::::::::::::::::::::::::::*MNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMNMF**********:::::::::::...........::::::::::: +// **********:::::::::::::::::::::::::::::::..*MNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMF*****:::::::::::...........:::::::::::::::: +// ******::::::::::::::::::::::::::::::::.....*MNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMF*****:::::::::::..........::::::::::::::::: +// ******::::::::::::::::::::::::::::::::::::.*MMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMF*****:::::::::::......::::::::::::::::::::: +// *****:::::::::::*$$$$F::::::::::::..:.I$$$$MMMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMM$$$$I::::::..:.......F$$$$*:::::::::::***** +// ::::::::::::::::FMMMMI:::::::::::.....$MMMMNMMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMNNMMMM$::::::.::.......VMMMMF:::::::::::***** +// ::::::::::::::::FMMMM$****************$MMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMM$****************$MMMNF::::::::::****** +// ::::::::::::::::FMMMMMMMMMMMMMNMMMNMMMMNMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMNNNNNNNNNMMMMMMMMMMF:::::*********** +// ::::::::::::::::FMMMMMMMMMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMF:::::*********** +// ::::::::::::::::*****FMMMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMIFFFF*:::::*********** +// :::::::::::::::::::::*MMMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMM*:::::**************** +// :::::::::::::::::::::*$MMMMMMMMMMMMMMMMMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMM$*:::::**************** +// ::::::::::::::::::::::::::::::::::::::$MMNNNNNNNNNNNN - EXPANSION PUNKS - NNNNNNNNNNNNNNNMMM$:::::::::::***:*::::****************** +// :::::::::::::::::::::............::::.$MMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN$:.::.::::::::::::**:****************** +// :::::::::::::::::::::............::::.$N A community-led expansion to the CryptoPunks M$:::::::::::::::::********************* +// :::::::::::::::::...........::::::::::$M phenomena that empowers everyone to feel M$::::::::::::::::********************** +// :::::::::::::::::...........:...::::::$M welcome, valued and represented in the M$::::::::::::::::********************** +// ::::::::::::::::...........::::::*****$M emerging metaverse. Honoring the ethos of M$:::::::::::**:************************ +// :::::::::::...............::::::*MNMMMNM the original collection's design philosophies M$:::::::::::*************************** +// :::::::::::...............::::::*MNNNNNN and trait principles, ExpansionPunks are fully M$:::::::::::*************************** +// ::::::::..............::::::::::*MMNMNNN unique and diverse additions to the Punkverse. M$*::::********************************* +// ::::::...............:::::::::::*MMMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMM$*::::********************************* +// ::::::...............:::::::::::*MMMMNNNNNNNNNNNNN MADE WITH <3 BY JP & FU NNNNNNNNNNNMN$*::::********************************* +// :::::...........::::::::::::::::*MMNMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMN$************************************** +// :::::...........::::::::::::::::*MMMMMMMMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMM$************************************** +// ............:::.::::::::::::::::*IIIII$MMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMM$************************************** +// ...........::::::::::::::::***********$MMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMM$************************************** +// ...........::::::::::::::::***********$MMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMM$************************************** +// .......:..:::::::::::::::::***********$MMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMM$************************************** +// .....:::::::::::::::::****************$MMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM$***********FF*F******************::::: +// .....:::::::::::::::::****************$MMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMM$***********FF*F******************::::: +// .....::::::::::::*:*:*****************$MMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMM$F****************************:**:::::: +// :::::::::::::::::**:******************$MMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMM$F*****FF********************:::::::::: +// :::::::::::::::::*********************$MMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMM$***************************::::::::::: +// ::::::::::::::::**********************$MMMNNNNMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMM$***********************::*:::::::::::: +// ::::::::::::*:::**********************$MMMMMNNMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMM$************************:*:::::::::::: +// :::::::::::**********************:::::*FFFFIMMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMM$IIIII**********************:::::::::::::::: +// :::::::::::**********************::::::::::*MMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMI**************************::::::::::::::::: +// :::::::::::**********************::::::::::*MMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMI**************************::::::::::::::::: +// :::::***********************:::::::::::....*MMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMM$FFFFF**********************:::::::::::::::::..... +// :::::**********************::::::::::::....*MMMNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMM$***************************:::::::::::::::::..... +// :::::**********************::::::::::::....*MNMNNNNNNNNNNNNNNNNNNNNNNNNNNNMMM$$$$$***************************:::::::::::::::::..... +// **********************:::::::::::.::.......*MNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMF***************************:::::::::::::::::::::...... +// **********************::::::::::::::.......*MNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMF***************************:::::::::::::::::::::...... +// *********************::::::::::::..........*MNNNNNNNNNNNNNNNNNNNNNNNNMM$IIIIF**************************::::::::::::::::::.......... +// *****************:::::::::::::::.......::::*MMMNNNNNNNNNNNNNNNNNNNNNNMMF***************************:::::::::::::::::::::......::::: +// *****************:::::::::::::::.......::::*MMMNNNNNNNNNNNNNNNNNNNNNNMMF**************************:::::::::::::::::::::::.....::::: +// ****************:::::::::::...........:::::*MMMNNNNNNNNNNNNNNNNNNNNNNMMF**************************:::::::::::::::::::::::....:::::: +// **************:*:::::::::::...........:::::*MMMNNNNNNNNNNNNNNNNNNNNNNMMF**********************::::::::::::::::::::::::::::::::::::: +// **************:*:::::::::::...........:::::*MMMNNNNNNNNNNNNNNNNNNNNNNMMF**********************::::::::::::::::::::::::::::::::::::: + + +contract ExpansionPunks is ERC721, ERC721Enumerable, Ownable, ReentrancyGuard { + using SafeMath for uint256; + + // ----- Token config ----- + // Total number of ExpansionPunks that can be minted + uint256 public constant maxSupply = 10000; + // Number of ExpansionPunks reserved for promotion & giveaways + uint256 public totalReserved = 100; + // IPFS hash of the 100x100 grid of the ExpansionPunks + string public EP_PROVENANCE_SHA256 = "2BAFBF1C1DEC1349579B033BAAFBFF55ABD9230EE94F6E04BEB9DE4D023333E7"; + string public EP_PROVENANCE_IPFS = "bafybeigqmo7mlti7sevdy5x33zaohvqbshrlvwavlwp3seknt5v4ar7x5q"; + + // Root of the IPFS metadata store + string public baseURI = ""; + // Current number of tokens + uint256 public numTokens = 0; + // remaining ExpansionPunks in the reserve + uint256 private _reserved; + + // ----- Sale config ----- + // Price for a single token + uint256 private _price = 0.06 ether; + // Can you mint tokens already + bool private _saleStarted; + + // ----- Owner config ----- + address public jp = 0x3Cd1676e8e0511aa96495c8eB24879d584dc3fdB; + address public fu = 0x277ad5d56cB83DBfe5926232495888ABc0710e2F; + address public dao = 0x6Df748fD1d9154FFAEa6F2F59d369cCaCc1c9F2c; + + // Mapping which token we already handed out + uint256[maxSupply] private indices; + + // Constructor. We set the symbol and name and start with sa + constructor( + ) ERC721("ExpansionPunks", "xPUNK") { + _saleStarted = false; + _reserved = totalReserved; + } + + receive() external payable {} + + // ----- Modifiers config ----- + // restrict to only allow when we have a running sale + modifier saleIsOpen() { + require(_saleStarted == true, "Sale not started yet"); + _; + } + + // restrict to onyl accept requests from one either deployer, jp or fu + modifier onlyAdmin() { + require( + _msgSender() == owner() || _msgSender() == jp || _msgSender() == fu, + "Ownable: caller is not admin" + ); + _; + } + + // ----- ERC721 functions ----- + function _baseURI() internal view override(ERC721) returns (string memory) { + return baseURI; + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId + ) internal override(ERC721, ERC721Enumerable) { + super._beforeTokenTransfer(from, to, tokenId); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721, ERC721Enumerable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } + + // ----- Getter functions ----- + function getPrice() public view returns (uint256) { + return _price; + } + + function getReservedLeft() public view returns (uint256) { + return _reserved; + } + + function getSaleStarted() public view returns (bool) { + return _saleStarted; + } + + function getBalance() public view returns (uint256) { + return address(this).balance; + } + + // ----- Setter functions ----- + // These functions allow us to change values after contract deployment + + // Way to change the baseUri, this is usefull if we ever need to switch the IPFS gateway for example + function setBaseURI(string memory _URI) external onlyOwner { + baseURI = _URI; + } + + // ----- Minting functions ----- + + /// @notice Select a random number without modulo bias using a random seed and upper bound + /// @param _entropy The seed for randomness + /// @param _upperBound The upper bound of the desired number + /// @return A random number less than the _upperBound + function uniform(uint256 _entropy, uint256 _upperBound) + internal + pure + returns (uint256) + { + require(_upperBound > 0, "UpperBound needs to be >0"); + uint256 negation = _upperBound & (~_upperBound + 1); + uint256 min = negation % _upperBound; + uint256 randomNr = _entropy; + while (true) { + if (randomNr >= min) { + break; + } + randomNr = uint256(keccak256(abi.encodePacked(randomNr))); + } + return randomNr % _upperBound; + } + + /// @notice Generates a pseudo random number based on arguments with decent entropy + /// @param max The maximum value we want to receive + /// @return _randomNumber A random number less than the max + function random(uint256 max) internal view returns (uint256 _randomNumber) { + uint256 randomness = uint256( + keccak256( + abi.encode( + msg.sender, + tx.gasprice, + block.number, + block.timestamp, + blockhash(block.number - 1), + block.difficulty + ) + ) + ); + _randomNumber = uniform(randomness, max); + return _randomNumber; + } + + /// @notice Generates a pseudo random index of our tokens that has not been used so far + /// @return A random index between 10000 and 19999 + function randomIndex() internal returns (uint256) { + // id of the gerneated token + uint256 tokenId = 0; + // number of tokens left to create + uint256 totalSize = maxSupply - numTokens; + // generate a random index + uint256 index = random(totalSize); + // if we haven't handed out a token with nr index we that now + + uint256 tokenAtPlace = indices[index]; + + // if we havent stored a replacement token... + if (tokenAtPlace == 0) { + //... we just return the current index + tokenId = index; + } else { + // else we take the replace we stored with logic below + tokenId = tokenAtPlace; + } + + // get the highest token id we havent handed out + uint256 lastTokenAvailable = indices[totalSize - 1]; + // we need to store a replacement token for the next time we roll the same index + // if the last token is still unused... + if (lastTokenAvailable == 0) { + // ... we store the last token as index + indices[index] = totalSize - 1; + } else { + // ... we store the token that was stored for the last token + indices[index] = lastTokenAvailable; + } + + // We start our tokens at 10000 + return tokenId + (10000); + } + + /// @notice Select a number of tokens and send them to a receiver + /// @param _number How many tokens to mint + /// @param _receiver Address to mint the tokens to + function _internalMint(uint256 _number, address _receiver) + internal + { + for (uint256 i; i < _number; i++) { + uint256 tokenID = randomIndex(); + numTokens = numTokens + 1; + _safeMint(_receiver, tokenID); + } + } + + /// @notice Mint a number of tokens and send them to a receiver + /// @param _number How many tokens to mint + function mint(uint256 _number) + external + payable + nonReentrant + saleIsOpen + { + uint256 supply = uint256(totalSupply()); + require( + supply + _number <= maxSupply - _reserved, + "Not enough ExpansionPunks left." + ); + require( + _number < 21, + "You cannot mint more than 20 ExpansionPunks at once!" + ); + require(_number * _price == msg.value, "Inconsistent amount sent!"); + _internalMint(_number, msg.sender); + } + + // ----- Sale functions ----- + + /// @notice Flip the sale status + function flipSaleStarted() external onlyAdmin { + _saleStarted = !_saleStarted; + } + + // ----- Helper functions ----- + /// @notice Get all token ids belonging to an address + /// @param _owner Wallet to find tokens of + /// @return Array of the owned token ids + function walletOfOwner(address _owner) + public + view + returns (uint256[] memory) + { + uint256 tokenCount = balanceOf(_owner); + + uint256[] memory tokensId = new uint256[](tokenCount); + for (uint256 i; i < tokenCount; i++) { + tokensId[i] = tokenOfOwnerByIndex(_owner, i); + } + return tokensId; + } + + /// @notice Claim a number of tokens from the reserve for free + /// @param _number How many tokens to mint + /// @param _receiver Address to mint the tokens to + function claimReserved(uint256 _number, address _receiver) + external + onlyAdmin + { + require(_number <= _reserved, "That would exceed the max reserved."); + _internalMint(_number, _receiver); + _reserved -= _number; + } + + /// @notice his will take the eth on the contract and split it based on the logif below and send it out. We funnel 1/3 for each dev and 1/3 into the ExpansionPunkDAO + function withdraw() public onlyAdmin { + uint256 _balance = address(this).balance; + uint256 _split = _balance.mul(33).div(100); + require(payable(jp).send(_split)); + require(payable(fu).send(_split)); + require(payable(dao).send(_balance.sub(_split * 2))); + } +} + + diff --git a/ethabi/code/0x0d0167a823c6619d430b1a96ad85b888bcf97c37.yml b/ethabi/code/0x0d0167a823c6619d430b1a96ad85b888bcf97c37.yml new file mode 100644 index 0000000..7f2c52f --- /dev/null +++ b/ethabi/code/0x0d0167a823c6619d430b1a96ad85b888bcf97c37.yml @@ -0,0 +1,12 @@ +--- +ContractName: ExpansionPunks +CompilerVersion: v0.8.7+commit.e28d00a7 +OptimizationUsed: '1' +Runs: '400' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: MIT +Proxy: '0' +Implementation: '' +SwarmSource: '' diff --git a/ethabi/code/0x16f5a35647d6f03d5d3da7b35409d65ba03af3b2.sol b/ethabi/code/0x16f5a35647d6f03d5d3da7b35409d65ba03af3b2.sol new file mode 100644 index 0000000..8130593 --- /dev/null +++ b/ethabi/code/0x16f5a35647d6f03d5d3da7b35409d65ba03af3b2.sol @@ -0,0 +1,223 @@ +pragma solidity 0.7.6; + +/** + * ____ _ _ ____ _ + * / ___|_ __ _ _ _ __ | |_ ___ _ __ _ _ _ __ | | _____ | _ \ __ _| |_ __ _ + * | | | '__| | | | '_ \| __/ _ \| '_ \| | | | '_ \| |/ / __| | | | |/ _` | __/ _` | + * | |___| | | |_| | |_) | || (_) | |_) | |_| | | | | <\__ \ | |_| | (_| | || (_| | + * \____|_| \__, | .__/ \__\___/| .__/ \__,_|_| |_|_|\_\___/ |____/ \__,_|\__\__,_| + * |___/|_| |_| + * + * On-chain Cryptopunk images and attributes, by Larva Labs. + * + * This contract holds the image and attribute data for the Cryptopunks on-chain. + * The Cryptopunk images are available as raw RGBA pixels, or in SVG format. + * The punk attributes are available as a comma-separated list. + * Included in the attribute list is the head type (various color male and female heads, + * plus the rare zombie, ape, and alien types). + * + * This contract was motivated by community members snowfro and 0xdeafbeef, including a proof-of-concept contract created by 0xdeafbeef. + * Without their involvement, the project would not have come to fruition. + */ +contract CryptopunksData { + + string internal constant SVG_HEADER = 'data:image/svg+xml;utf8,'; + string internal constant SVG_FOOTER = ''; + + bytes private palette; + mapping(uint8 => bytes) private assets; + mapping(uint8 => string) private assetNames; + mapping(uint64 => uint32) private composites; + mapping(uint8 => bytes) private punks; + + address payable internal deployer; + bool private contractSealed = false; + + modifier onlyDeployer() { + require(msg.sender == deployer, "Only deployer."); + _; + } + + modifier unsealed() { + require(!contractSealed, "Contract sealed."); + _; + } + + constructor() { + deployer = msg.sender; + } + + function setPalette(bytes memory _palette) external onlyDeployer unsealed { + palette = _palette; + } + + function addAsset(uint8 index, bytes memory encoding, string memory name) external onlyDeployer unsealed { + assets[index] = encoding; + assetNames[index] = name; + } + + function addComposites(uint64 key1, uint32 value1, uint64 key2, uint32 value2, uint64 key3, uint32 value3, uint64 key4, uint32 value4) external onlyDeployer unsealed { + composites[key1] = value1; + composites[key2] = value2; + composites[key3] = value3; + composites[key4] = value4; + } + + function addPunks(uint8 index, bytes memory _punks) external onlyDeployer unsealed { + punks[index] = _punks; + } + + function sealContract() external onlyDeployer unsealed { + contractSealed = true; + } + + /** + * The Cryptopunk image for the given index. + * The image is represented in a row-major byte array where each set of 4 bytes is a pixel in RGBA format. + * @param index the punk index, 0 <= index < 10000 + */ + function punkImage(uint16 index) public view returns (bytes memory) { + require(index >= 0 && index < 10000); + bytes memory pixels = new bytes(2304); + for (uint j = 0; j < 8; j++) { + uint8 asset = uint8(punks[uint8(index / 100)][(index % 100) * 8 + j]); + if (asset > 0) { + bytes storage a = assets[asset]; + uint n = a.length / 3; + for (uint i = 0; i < n; i++) { + uint[4] memory v = [ + uint(uint8(a[i * 3]) & 0xF0) >> 4, + uint(uint8(a[i * 3]) & 0xF), + uint(uint8(a[i * 3 + 2]) & 0xF0) >> 4, + uint(uint8(a[i * 3 + 2]) & 0xF) + ]; + for (uint dx = 0; dx < 2; dx++) { + for (uint dy = 0; dy < 2; dy++) { + uint p = ((2 * v[1] + dy) * 24 + (2 * v[0] + dx)) * 4; + if (v[2] & (1 << (dx * 2 + dy)) != 0) { + bytes4 c = composite(a[i * 3 + 1], + pixels[p], + pixels[p + 1], + pixels[p + 2], + pixels[p + 3] + ); + pixels[p] = c[0]; + pixels[p+1] = c[1]; + pixels[p+2] = c[2]; + pixels[p+3] = c[3]; + } else if (v[3] & (1 << (dx * 2 + dy)) != 0) { + pixels[p] = 0; + pixels[p+1] = 0; + pixels[p+2] = 0; + pixels[p+3] = 0xFF; + } + } + } + } + } + } + return pixels; + } + + /** + * The Cryptopunk image for the given index, in SVG format. + * In the SVG, each "pixel" is represented as a 1x1 rectangle. + * @param index the punk index, 0 <= index < 10000 + */ + function punkImageSvg(uint16 index) external view returns (string memory svg) { + bytes memory pixels = punkImage(index); + svg = string(abi.encodePacked(SVG_HEADER)); + bytes memory buffer = new bytes(8); + for (uint y = 0; y < 24; y++) { + for (uint x = 0; x < 24; x++) { + uint p = (y * 24 + x) * 4; + if (uint8(pixels[p + 3]) > 0) { + for (uint i = 0; i < 4; i++) { + uint8 value = uint8(pixels[p + i]); + buffer[i * 2 + 1] = _HEX_SYMBOLS[value & 0xf]; + value >>= 4; + buffer[i * 2] = _HEX_SYMBOLS[value & 0xf]; + } + svg = string(abi.encodePacked(svg, + '')); + } + } + } + svg = string(abi.encodePacked(svg, SVG_FOOTER)); + } + + /** + * The Cryptopunk attributes for the given index. + * The attributes are a comma-separated list in UTF-8 string format. + * The first entry listed is not technically an attribute, but the "head type" of the Cryptopunk. + * @param index the punk index, 0 <= index < 10000 + */ + function punkAttributes(uint16 index) external view returns (string memory text) { + require(index >= 0 && index < 10000); + uint8 cell = uint8(index / 100); + uint offset = (index % 100) * 8; + for (uint j = 0; j < 8; j++) { + uint8 asset = uint8(punks[cell][offset + j]); + if (asset > 0) { + if (j > 0) { + text = string(abi.encodePacked(text, ", ", assetNames[asset])); + } else { + text = assetNames[asset]; + } + } else { + break; + } + } + } + + function composite(byte index, byte yr, byte yg, byte yb, byte ya) internal view returns (bytes4 rgba) { + uint x = uint(uint8(index)) * 4; + uint8 xAlpha = uint8(palette[x + 3]); + if (xAlpha == 0xFF) { + rgba = bytes4(uint32( + (uint(uint8(palette[x])) << 24) | + (uint(uint8(palette[x+1])) << 16) | + (uint(uint8(palette[x+2])) << 8) | + xAlpha + )); + } else { + uint64 key = + (uint64(uint8(palette[x])) << 56) | + (uint64(uint8(palette[x + 1])) << 48) | + (uint64(uint8(palette[x + 2])) << 40) | + (uint64(xAlpha) << 32) | + (uint64(uint8(yr)) << 24) | + (uint64(uint8(yg)) << 16) | + (uint64(uint8(yb)) << 8) | + (uint64(uint8(ya))); + rgba = bytes4(composites[key]); + } + } + + //// String stuff from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Strings.sol + + bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; + + function toString(uint256 value) internal pure returns (string memory) { + // Inspired by OraclizeAPI's implementation - MIT licence + // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol + + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + while (value != 0) { + digits -= 1; + buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); + value /= 10; + } + return string(buffer); + } + +} \ No newline at end of file diff --git a/ethabi/code/0x16f5a35647d6f03d5d3da7b35409d65ba03af3b2.yml b/ethabi/code/0x16f5a35647d6f03d5d3da7b35409d65ba03af3b2.yml new file mode 100644 index 0000000..7f6423a --- /dev/null +++ b/ethabi/code/0x16f5a35647d6f03d5d3da7b35409d65ba03af3b2.yml @@ -0,0 +1,12 @@ +--- +ContractName: CryptopunksData +CompilerVersion: v0.7.6+commit.7338295f +OptimizationUsed: '0' +Runs: '200' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: None +Proxy: '0' +Implementation: '' +SwarmSource: ipfs://b5cb11115801def41650f7bf1e201c6d351bae4bbea91fcfec5f6b5be6c6f5b3 diff --git a/ethabi/code/0x2204a94f96d39df3b6bc0298cf068c8c82dc8d61.sol b/ethabi/code/0x2204a94f96d39df3b6bc0298cf068c8c82dc8d61.sol new file mode 100644 index 0000000..377c3e1 --- /dev/null +++ b/ethabi/code/0x2204a94f96d39df3b6bc0298cf068c8c82dc8d61.sol @@ -0,0 +1,2810 @@ +/////////////////////////////////////////// +// File: /app/contracts/Indelible.sol + + + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.4; + + import "erc721a/contracts/ERC721A.sol"; + import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; + import "@openzeppelin/contracts/access/Ownable.sol"; + import "@openzeppelin/contracts/utils/Base64.sol"; + import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; + import "@openzeppelin/contracts/utils/Address.sol"; + import "./SSTORE2.sol"; + import "./DynamicBuffer.sol"; + import "./HelperLib.sol"; + + contract Indelible is ERC721A, ReentrancyGuard, Ownable { + using HelperLib for uint; + using DynamicBuffer for bytes; + + struct LinkedTraitDTO { + uint[] traitA; + uint[] traitB; + } + + struct TraitDTO { + string name; + string mimetype; + bytes data; + bool hide; + bool useExistingData; + uint existingDataIndex; + } + + struct Trait { + string name; + string mimetype; + bool hide; + } + + struct ContractData { + string name; + string description; + string image; + string banner; + string website; + uint royalties; + string royaltiesRecipient; + } + + struct WithdrawRecipient { + string name; + string imageUrl; + address recipientAddress; + uint percentage; + } + + mapping(uint => address[]) internal _traitDataPointers; + mapping(uint => mapping(uint => Trait)) internal _traitDetails; + mapping(uint => bool) internal _renderTokenOffChain; + mapping(uint => mapping(uint => uint[])) internal _linkedTraits; + + uint[15] private PRIME_NUMBERS; + uint private constant DEVELOPER_FEE = 250; // of 10,000 = 2.5% + uint private constant NUM_LAYERS = 7; + uint private constant MAX_BATCH_MINT = 20; + uint[][NUM_LAYERS] private TIERS; + string[] private LAYER_NAMES = [unicode"headwear&1/1s", unicode"eyes", unicode"mouth", unicode"accessories", unicode"wearables", unicode"fur", unicode"background"]; + bool private shouldWrapSVG = true; + string private backgroundColor = "transparent"; + uint private randomSeedData; + + WithdrawRecipient[1] public withdrawRecipients; + bool public isContractSealed; + uint public constant maxSupply = 1500; + uint public maxPerAddress = 8; + uint public publicMintPrice = 0.020 ether; + string public baseURI = ""; + bool public isPublicMintActive; + bytes32 private merkleRoot = 0; + uint public allowListPrice = 0.005 ether; + uint public maxPerAllowList = 2; + bool public isAllowListActive; + + ContractData public contractData = ContractData(unicode"Aloha Chi-Chi Onchain", unicode"A fully onchain generative pixel art collection of 1500 Chi-Chis that live Aloha.", "https://indeliblelabs-prod.s3.us-east-2.amazonaws.com/profile/842deb38-7014-4780-bccd-a4f61a76c72e", "https://indeliblelabs-prod.s3.us-east-2.amazonaws.com/banner/842deb38-7014-4780-bccd-a4f61a76c72e", "https://alohachichinft.com/", 500, "0x29323644B5540D20e834578943A2Bd91027699B1"); + + constructor() ERC721A(unicode"Aloha Chi-Chi Onchain", unicode"ACCO") { + TIERS[0] = [1,1,1,1,1,1,10,17,18,28,34,38,46,54,63,63,65,69,76,81,82,89,91,113,132,133,192]; +TIERS[1] = [0,13,18,43,62,85,88,110,111,121,189,193,231,236]; +TIERS[2] = [0,15,37,38,55,169,190,284,293,419]; +TIERS[3] = [0,3,4,9,99,147,187,254,318,479]; +TIERS[4] = [0,36,52,61,71,108,158,205,228,253,328]; +TIERS[5] = [0,5,22,27,64,147,167,172,219,289,388]; +TIERS[6] = [0,7,34,90,90,142,150,183,257,260,287]; + withdrawRecipients[0] = WithdrawRecipient(unicode"The American Society for the Prevention of Cruelty to Animals (ASPCA)",unicode"https://static.tgbwidget.com/organization_logo%2F8dc93941-eaf6-421d-b4c3-cdae8df95ec9.jpg", 0x8F7E43CE815B2c2a4542adC97Ac0A11207009453, 1000); + PRIME_NUMBERS = [ + 896353651830364561540707634717046743479841853086536248690737, + 881620940286709375756927686087073151589884188606081093706959, + 239439210107002209100408342483681304951633794994177274881807, + 281985178301575220656442477929008459267923613534257332455929, + 320078828389115961650782679700072873328499789823998523466099, + 404644724038849848148120945109420144471824163937039418139293, + 263743197985470588204349265269345001644610514897601719492623, + 774988306700992475970790762502873362986676222144851638448617, + 222880340296779472696004625829965490706697301235372335793669, + 455255148896994205943326626951197024927648464365329800703251, + 752418160701043808365139710144653623245409393563454484133021, + 308043264033071943254647080990150144301849302687707544552767, + 874778160644048956810394214801467472093537087897851981604983, + 192516593828483755313857340433869706973450072701701194101197, + 809964495083245361527940381794788695820367981156436813625509 + ]; + randomSeedData = uint( + keccak256( + abi.encodePacked( + tx.gasprice, + block.number, + block.timestamp, + block.difficulty, + blockhash(block.number - 1), + msg.sender + ) + ) + ); + } + + modifier whenMintActive() { + require(isMintActive(), "Minting is not active"); + _; + } + + modifier whenUnsealed() { + require(!isContractSealed, "Contract is sealed"); + _; + } + + receive() external payable { + require(isPublicMintActive, "Public minting is not active"); + handleMint(msg.value / publicMintPrice, msg.sender); + } + + function rarityGen(uint randinput, uint rarityTier) + internal + view + returns (uint) + { + uint currentLowerBound = 0; + for (uint i = 0; i < TIERS[rarityTier].length; i++) { + uint thisPercentage = TIERS[rarityTier][i]; + if ( + randinput >= currentLowerBound && + randinput < currentLowerBound + thisPercentage + ) return i; + currentLowerBound = currentLowerBound + thisPercentage; + } + + revert(); + } + + function entropyForExtraData() internal view returns (uint24) { + uint randomNumber = uint( + keccak256( + abi.encodePacked( + tx.gasprice, + block.number, + block.timestamp, + block.difficulty, + blockhash(block.number - 1), + msg.sender + ) + ) + ); + return uint24(randomNumber); + } + + function stringCompare(string memory a, string memory b) internal pure returns (bool) { + return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b)); + } + + function tokensAreDuplicates(uint tokenIdA, uint tokenIdB) public view returns (bool) { + return stringCompare( + tokenIdToHash(tokenIdA), + tokenIdToHash(tokenIdB) + ); + } + + function reRollDuplicate( + uint tokenIdA, + uint tokenIdB + ) public whenUnsealed { + require(tokensAreDuplicates(tokenIdA, tokenIdB), "All tokens must be duplicates"); + + uint largerTokenId = tokenIdA > tokenIdB ? tokenIdA : tokenIdB; + + if (msg.sender != owner()) { + require(msg.sender == ownerOf(largerTokenId), "Only the token owner or contract owner can re-roll"); + } + + _initializeOwnershipAt(largerTokenId); + if (_exists(largerTokenId + 1)) { + _initializeOwnershipAt(largerTokenId + 1); + } + + _setExtraDataAt(largerTokenId, entropyForExtraData()); + } + + function _extraData( + address from, + address to, + uint24 previousExtraData + ) internal view virtual override returns (uint24) { + return from == address(0) ? 0 : previousExtraData; + } + + function getTokenSeed(uint tokenId) internal view returns (uint24) { + return _ownershipOf(tokenId).extraData; + } + + function tokenIdToHash( + uint tokenId + ) public view returns (string memory) { + require(_exists(tokenId), "Invalid token"); + // This will generate a NUM_LAYERS * 3 character string. + bytes memory hashBytes = DynamicBuffer.allocate(NUM_LAYERS * 4); + + uint[] memory hash = new uint[](NUM_LAYERS); + bool[] memory modifiedLayers = new bool[](NUM_LAYERS); + uint traitSeed = randomSeedData % maxSupply; + + for (uint i = 0; i < NUM_LAYERS; i++) { + uint traitIndex = hash[i]; + if (modifiedLayers[i] == false) { + uint tokenExtraData = getTokenSeed(tokenId); + uint traitRangePosition; + if (tokenExtraData == 0) { + traitRangePosition = ((tokenId + i + traitSeed) * PRIME_NUMBERS[i]) % maxSupply; + } else { + traitRangePosition = uint( + keccak256( + abi.encodePacked( + tokenExtraData, + tokenId, + tokenId + i + ) + ) + ) % maxSupply; + } + + traitIndex = rarityGen(traitRangePosition, i); + hash[i] = traitIndex; + } + + if (_linkedTraits[i][traitIndex].length > 0) { + hash[_linkedTraits[i][traitIndex][0]] = _linkedTraits[i][traitIndex][1]; + modifiedLayers[_linkedTraits[i][traitIndex][0]] = true; + } + } + + for (uint i = 0; i < hash.length; i++) { + if (hash[i] < 10) { + hashBytes.appendSafe("00"); + } else if (hash[i] < 100) { + hashBytes.appendSafe("0"); + } + if (hash[i] > 999) { + hashBytes.appendSafe("999"); + } else { + hashBytes.appendSafe(bytes(_toString(hash[i]))); + } + } + + return string(hashBytes); + } + + function handleMint(uint256 count, address recipient) internal whenMintActive returns (uint256) { + uint256 totalMinted = _totalMinted(); + require(count > 0, "Invalid token count"); + require(totalMinted + count <= maxSupply, "All tokens are gone"); + + if (isPublicMintActive) { + if (msg.sender != owner()) { + require(_numberMinted(msg.sender) + count <= maxPerAddress, "Exceeded max mints allowed"); + require(count * publicMintPrice == msg.value, "Incorrect amount of ether sent"); + } + require(msg.sender == tx.origin, "EOAs only"); + } + + uint256 batchCount = count / MAX_BATCH_MINT; + uint256 remainder = count % MAX_BATCH_MINT; + + for (uint256 i = 0; i < batchCount; i++) { + _mint(recipient, MAX_BATCH_MINT); + } + + if (remainder > 0) { + _mint(recipient, remainder); + } + + return totalMinted; + } + + function mint(uint256 count, bytes32[] calldata merkleProof) + external + payable + nonReentrant + whenMintActive + returns (uint) + { + if (!isPublicMintActive && msg.sender != owner()) { + require(onAllowList(msg.sender, merkleProof), "Not on allow list"); + require(_numberMinted(msg.sender) + count <= maxPerAllowList, "Exceeded max mints allowed"); + require(count * allowListPrice == msg.value, "Incorrect amount of ether sent"); + } + return handleMint(count, msg.sender); + } + + function airdrop(uint256 count, address recipient) + external + payable + nonReentrant + whenMintActive + returns (uint) + { + require(isPublicMintActive || msg.sender == owner(), "Public minting is not active"); + return handleMint(count, recipient); + } + + function isMintActive() public view returns (bool) { + return _totalMinted() < maxSupply && (isPublicMintActive || isAllowListActive || msg.sender == owner()); + } + + function hashToSVG(string memory _hash) + public + view + returns (string memory) + { + uint thisTraitIndex; + + bytes memory svgBytes = DynamicBuffer.allocate(1024 * 128); + svgBytes.appendSafe('' + ) + ); + + return string( + abi.encodePacked( + "data:image/svg+xml;base64,", + Base64.encode(svgBytes) + ) + ); + } + + function hashToMetadata(string memory _hash) + public + view + returns (string memory) + { + bytes memory metadataBytes = DynamicBuffer.allocate(1024 * 128); + metadataBytes.appendSafe("["); + bool afterFirstTrait; + + for (uint i = 0; i < NUM_LAYERS; i++) { + uint thisTraitIndex = HelperLib.parseInt( + HelperLib._substring(_hash, (i * 3), (i * 3) + 3) + ); + if (_traitDetails[i][thisTraitIndex].hide == false) { + if (afterFirstTrait) { + metadataBytes.appendSafe(","); + } + metadataBytes.appendSafe( + abi.encodePacked( + '{"trait_type":"', + LAYER_NAMES[i], + '","value":"', + _traitDetails[i][thisTraitIndex].name, + '"}' + ) + ); + if (afterFirstTrait == false) { + afterFirstTrait = true; + } + } + + if (i == NUM_LAYERS - 1) { + metadataBytes.appendSafe("]"); + } + } + + return string(metadataBytes); + } + + function onAllowList(address addr, bytes32[] calldata merkleProof) public view returns (bool) { + return MerkleProof.verify(merkleProof, merkleRoot, keccak256(abi.encodePacked(addr))); + } + + function tokenURI(uint tokenId) + public + view + override + returns (string memory) + { + require(_exists(tokenId), "Invalid token"); + require(_traitDataPointers[0].length > 0, "Traits have not been added"); + + string memory tokenHash = tokenIdToHash(tokenId); + + bytes memory jsonBytes = DynamicBuffer.allocate(1024 * 128); + jsonBytes.appendSafe(unicode"{\"name\":\"Aloha Chi-Chi Onchain #"); + + jsonBytes.appendSafe( + abi.encodePacked( + _toString(tokenId), + "\",\"description\":\"", + contractData.description, + "\"," + ) + ); + + if (bytes(baseURI).length > 0 && _renderTokenOffChain[tokenId]) { + jsonBytes.appendSafe( + abi.encodePacked( + '"image":"', + baseURI, + _toString(tokenId), + "?dna=", + tokenHash, + '&network=mainnet",' + ) + ); + } else { + string memory svgCode = ""; + if (shouldWrapSVG) { + string memory svgString = hashToSVG(tokenHash); + svgCode = string( + abi.encodePacked( + "data:image/svg+xml;base64,", + Base64.encode( + abi.encodePacked( + '' + ) + ) + ) + ); + jsonBytes.appendSafe( + abi.encodePacked( + '"svg_image_data":"', + svgString, + '",' + ) + ); + } else { + svgCode = hashToSVG(tokenHash); + } + + jsonBytes.appendSafe( + abi.encodePacked( + '"image_data":"', + svgCode, + '",' + ) + ); + } + + jsonBytes.appendSafe( + abi.encodePacked( + '"attributes":', + hashToMetadata(tokenHash), + "}" + ) + ); + + return string( + abi.encodePacked( + "data:application/json;base64,", + Base64.encode(jsonBytes) + ) + ); + } + + function contractURI() + public + view + returns (string memory) + { + return string( + abi.encodePacked( + "data:application/json;base64,", + Base64.encode( + abi.encodePacked( + '{"name":"', + contractData.name, + '","description":"', + contractData.description, + '","image":"', + contractData.image, + '","banner":"', + contractData.banner, + '","external_link":"', + contractData.website, + '","seller_fee_basis_points":', + _toString(contractData.royalties), + ',"fee_recipient":"', + contractData.royaltiesRecipient, + '"}' + ) + ) + ) + ); + } + + function tokenIdToSVG(uint tokenId) + public + view + returns (string memory) + { + return hashToSVG(tokenIdToHash(tokenId)); + } + + function traitDetails(uint layerIndex, uint traitIndex) + public + view + returns (Trait memory) + { + return _traitDetails[layerIndex][traitIndex]; + } + + function traitData(uint layerIndex, uint traitIndex) + public + view + returns (string memory) + { + return string(SSTORE2.read(_traitDataPointers[layerIndex][traitIndex])); + } + + function getLinkedTraits(uint layerIndex, uint traitIndex) + public + view + returns (uint[] memory) + { + return _linkedTraits[layerIndex][traitIndex]; + } + + function addLayer(uint layerIndex, TraitDTO[] memory traits) + public + onlyOwner + whenUnsealed + { + require(TIERS[layerIndex].length == traits.length, "Traits size does not match tiers for this index"); + address[] memory dataPointers = new address[](traits.length); + for (uint i = 0; i < traits.length; i++) { + if (traits[i].useExistingData) { + dataPointers[i] = dataPointers[traits[i].existingDataIndex]; + } else { + dataPointers[i] = SSTORE2.write(traits[i].data); + } + _traitDetails[layerIndex][i] = Trait(traits[i].name, traits[i].mimetype, traits[i].hide); + } + _traitDataPointers[layerIndex] = dataPointers; + return; + } + + function addTrait(uint layerIndex, uint traitIndex, TraitDTO memory trait) + public + onlyOwner + whenUnsealed + { + _traitDetails[layerIndex][traitIndex] = Trait(trait.name, trait.mimetype, trait.hide); + address[] memory dataPointers = _traitDataPointers[layerIndex]; + if (trait.useExistingData) { + dataPointers[traitIndex] = dataPointers[trait.existingDataIndex]; + } else { + dataPointers[traitIndex] = SSTORE2.write(trait.data); + } + _traitDataPointers[layerIndex] = dataPointers; + return; + } + + function setLinkedTraits(LinkedTraitDTO[] memory linkedTraits) + public + onlyOwner + whenUnsealed + { + for (uint i = 0; i < linkedTraits.length; i++) { + _linkedTraits[linkedTraits[i].traitA[0]][linkedTraits[i].traitA[1]] = [linkedTraits[i].traitB[0],linkedTraits[i].traitB[1]]; + } + } + + function setContractData(ContractData memory data) external onlyOwner whenUnsealed { + contractData = data; + } + + function setMaxPerAddress(uint max) external onlyOwner { + maxPerAddress = max; + } + + function setBaseURI(string memory uri) external onlyOwner { + baseURI = uri; + } + + function setBackgroundColor(string memory color) external onlyOwner whenUnsealed { + backgroundColor = color; + } + + function setRenderOfTokenId(uint tokenId, bool renderOffChain) external { + require(msg.sender == ownerOf(tokenId), "Only the token owner can set the render method"); + _renderTokenOffChain[tokenId] = renderOffChain; + } + + function setMerkleRoot(bytes32 newMerkleRoot) external onlyOwner { + merkleRoot = newMerkleRoot; + } + + function setMaxPerAllowList(uint max) external onlyOwner { + maxPerAllowList = max; + } + + function setAllowListPrice(uint price) external onlyOwner { + allowListPrice = price; + } + + function toggleAllowListMint() external onlyOwner { + isAllowListActive = !isAllowListActive; + } + + function toggleWrapSVG() external onlyOwner { + shouldWrapSVG = !shouldWrapSVG; + } + + function togglePublicMint() external onlyOwner { + isPublicMintActive = !isPublicMintActive; + } + + function sealContract() external whenUnsealed onlyOwner { + isContractSealed = true; + } + + function withdraw() external onlyOwner nonReentrant { + uint balance = address(this).balance; + uint amount = (balance * (10000 - DEVELOPER_FEE)) / 10000; + uint distAmount = 0; + uint totalDistributionPercentage = 0; + + address payable receiver = payable(owner()); + address payable dev = payable(0xEA208Da933C43857683C04BC76e3FD331D7bfdf7); + Address.sendValue(dev, balance - amount); + + if (withdrawRecipients.length > 0) { + for (uint i = 0; i < withdrawRecipients.length; i++) { + totalDistributionPercentage = totalDistributionPercentage + withdrawRecipients[i].percentage; + address payable currRecepient = payable(withdrawRecipients[i].recipientAddress); + distAmount = (amount * (10000 - withdrawRecipients[i].percentage)) / 10000; + + Address.sendValue(currRecepient, amount - distAmount); + } + } + balance = address(this).balance; + Address.sendValue(receiver, balance); + } + } + + +/////////////////////////////////////////// +// File: /app/contracts/DynamicBuffer.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) + +pragma solidity >=0.8.0; + +/// @title DynamicBuffer +/// @author David Huber (@cxkoda) and Simon Fremaux (@dievardump). See also +/// https://raw.githubusercontent.com/dievardump/solidity-dynamic-buffer +/// @notice This library is used to allocate a big amount of container memory +// which will be subsequently filled without needing to reallocate +/// memory. +/// @dev First, allocate memory. +/// Then use `buffer.appendUnchecked(theBytes)` or `appendSafe()` if +/// bounds checking is required. +library DynamicBuffer { + /// @notice Allocates container space for the DynamicBuffer + /// @param capacity The intended max amount of bytes in the buffer + /// @return buffer The memory location of the buffer + /// @dev Allocates `capacity + 0x60` bytes of space + /// The buffer array starts at the first container data position, + /// (i.e. `buffer = container + 0x20`) + function allocate(uint256 capacity) + internal + pure + returns (bytes memory buffer) + { + assembly { + // Get next-free memory address + let container := mload(0x40) + + // Allocate memory by setting a new next-free address + { + // Add 2 x 32 bytes in size for the two length fields + // Add 32 bytes safety space for 32B chunked copy + let size := add(capacity, 0x60) + let newNextFree := add(container, size) + mstore(0x40, newNextFree) + } + + // Set the correct container length + { + let length := add(capacity, 0x40) + mstore(container, length) + } + + // The buffer starts at idx 1 in the container (0 is length) + buffer := add(container, 0x20) + + // Init content with length 0 + mstore(buffer, 0) + } + + return buffer; + } + + /// @notice Appends data to buffer, and update buffer length + /// @param buffer the buffer to append the data to + /// @param data the data to append + /// @dev Does not perform out-of-bound checks (container capacity) + /// for efficiency. + function appendUnchecked(bytes memory buffer, bytes memory data) + internal + pure + { + assembly { + let length := mload(data) + for { + data := add(data, 0x20) + let dataEnd := add(data, length) + let copyTo := add(buffer, add(mload(buffer), 0x20)) + } lt(data, dataEnd) { + data := add(data, 0x20) + copyTo := add(copyTo, 0x20) + } { + // Copy 32B chunks from data to buffer. + // This may read over data array boundaries and copy invalid + // bytes, which doesn't matter in the end since we will + // later set the correct buffer length, and have allocated an + // additional word to avoid buffer overflow. + mstore(copyTo, mload(data)) + } + + // Update buffer length + mstore(buffer, add(mload(buffer), length)) + } + } + + /// @notice Appends data to buffer, and update buffer length + /// @param buffer the buffer to append the data to + /// @param data the data to append + /// @dev Performs out-of-bound checks and calls `appendUnchecked`. + function appendSafe(bytes memory buffer, bytes memory data) internal pure { + uint256 capacity; + uint256 length; + assembly { + capacity := sub(mload(sub(buffer, 0x20)), 0x40) + length := mload(buffer) + } + + require( + length + data.length <= capacity, + "DynamicBuffer: Appending out of bounds." + ); + appendUnchecked(buffer, data); + } +} + +/////////////////////////////////////////// +// File: /app/contracts/HelperLib.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.14; + +library HelperLib { + function parseInt(string memory _a) + internal + pure + returns (uint8 _parsedInt) + { + bytes memory bresult = bytes(_a); + uint8 mint = 0; + for (uint8 i = 0; i < bresult.length; i++) { + if ( + (uint8(uint8(bresult[i])) >= 48) && + (uint8(uint8(bresult[i])) <= 57) + ) { + mint *= 10; + mint += uint8(bresult[i]) - 48; + } + } + return mint; + } + + function _substring( + string memory str, + uint256 startIndex, + uint256 endIndex + ) internal pure returns (string memory) { + bytes memory strBytes = bytes(str); + bytes memory result = new bytes(endIndex - startIndex); + for (uint256 i = startIndex; i < endIndex; i++) { + result[i - startIndex] = strBytes[i]; + } + return string(result); + } +} + +/////////////////////////////////////////// +// File: /app/contracts/SSTORE2.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./utils/Bytecode.sol"; + +/** + @title A key-value storage with auto-generated keys for storing chunks of data with a lower write & read cost. + @author Agustin Aguilar + + Readme: https://github.com/0xsequence/sstore2#readme +*/ +library SSTORE2 { + error WriteError(); + + /** + @notice Stores `_data` and returns `pointer` as key for later retrieval + @dev The pointer is a contract address with `_data` as code + @param _data to be written + @return pointer Pointer to the written `_data` + */ + function write(bytes memory _data) internal returns (address pointer) { + // Append 00 to _data so contract can't be called + // Build init code + bytes memory code = Bytecode.creationCodeFor( + abi.encodePacked( + hex'00', + _data + ) + ); + + // Deploy contract using create + assembly { pointer := create(0, add(code, 32), mload(code)) } + + // Address MUST be non-zero + if (pointer == address(0)) revert WriteError(); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @return data read from `_pointer` contract + */ + function read(address _pointer) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, 1, type(uint256).max); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @param _start number of bytes to skip + @return data read from `_pointer` contract + */ + function read(address _pointer, uint256 _start) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, _start + 1, type(uint256).max); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @param _start number of bytes to skip + @param _end index before which to end extraction + @return data read from `_pointer` contract + */ + function read(address _pointer, uint256 _start, uint256 _end) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, _start + 1, _end + 1); + } +} + +/////////////////////////////////////////// +// File: /app/contracts/utils/Bytecode.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + + +library Bytecode { + error InvalidCodeAtRange(uint256 _size, uint256 _start, uint256 _end); + + /** + @notice Generate a creation code that results on a contract with `_code` as bytecode + @param _code The returning value of the resulting `creationCode` + @return creationCode (constructor) for new contract + */ + function creationCodeFor(bytes memory _code) internal pure returns (bytes memory) { + /* + 0x00 0x63 0x63XXXXXX PUSH4 _code.length size + 0x01 0x80 0x80 DUP1 size size + 0x02 0x60 0x600e PUSH1 14 14 size size + 0x03 0x60 0x6000 PUSH1 00 0 14 size size + 0x04 0x39 0x39 CODECOPY size + 0x05 0x60 0x6000 PUSH1 00 0 size + 0x06 0xf3 0xf3 RETURN + + */ + + return abi.encodePacked( + hex"63", + uint32(_code.length), + hex"80_60_0E_60_00_39_60_00_F3", + _code + ); + } + + /** + @notice Returns the size of the code on a given address + @param _addr Address that may or may not contain code + @return size of the code on the given `_addr` + */ + function codeSize(address _addr) internal view returns (uint256 size) { + assembly { size := extcodesize(_addr) } + } + + /** + @notice Returns the code of a given address + @dev It will fail if `_end < _start` + @param _addr Address that may or may not contain code + @param _start number of bytes of code to skip on read + @param _end index before which to end extraction + @return oCode read from `_addr` deployed bytecode + + Forked from: https://gist.github.com/KardanovIR/fe98661df9338c842b4a30306d507fbd + */ + function codeAt(address _addr, uint256 _start, uint256 _end) internal view returns (bytes memory oCode) { + uint256 csize = codeSize(_addr); + if (csize == 0) return bytes(""); + + if (_start > csize) return bytes(""); + if (_end < _start) revert InvalidCodeAtRange(csize, _start, _end); + + unchecked { + uint256 reqSize = _end - _start; + uint256 maxSize = csize - _start; + + uint256 size = maxSize < reqSize ? maxSize : reqSize; + + assembly { + // allocate output byte array - this could also be done without assembly + // by using o_code = new bytes(size) + oCode := mload(0x40) + // new "memory end" including padding + mstore(0x40, add(oCode, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + // store length in memory + mstore(oCode, size) + // actually retrieve the code, this needs assembly + extcodecopy(_addr, add(oCode, 0x20), _start, size) + } + } + } +} + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/access/Ownable.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor() { + _transferOwnership(_msgSender()); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/security/ReentrancyGuard.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor() { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and making it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) + +pragma solidity ^0.8.1; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + * + * [IMPORTANT] + * ==== + * You shouldn't rely on `isContract` to protect against flash loan attacks! + * + * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets + * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract + * constructor. + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize/address.code.length, which returns 0 + // for contracts in construction, since the code is only stored at the end + // of the constructor execution. + + return account.code.length > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Base64.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (utils/Base64.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides a set of functions to operate with Base64 strings. + * + * _Available since v4.5._ + */ +library Base64 { + /** + * @dev Base64 Encoding/Decoding Table + */ + string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** + * @dev Converts a `bytes` to its Bytes64 `string` representation. + */ + function encode(bytes memory data) internal pure returns (string memory) { + /** + * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence + * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol + */ + if (data.length == 0) return ""; + + // Loads the table into memory + string memory table = _TABLE; + + // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter + // and split into 4 numbers of 6 bits. + // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up + // - `data.length + 2` -> Round up + // - `/ 3` -> Number of 3-bytes chunks + // - `4 *` -> 4 characters for each chunk + string memory result = new string(4 * ((data.length + 2) / 3)); + + assembly { + // Prepare the lookup table (skip the first "length" byte) + let tablePtr := add(table, 1) + + // Prepare result pointer, jump over length + let resultPtr := add(result, 32) + + // Run over the input, 3 bytes at a time + for { + let dataPtr := data + let endPtr := add(data, mload(data)) + } lt(dataPtr, endPtr) { + + } { + // Advance 3 bytes + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + + // To write each character, shift the 3 bytes (18 bits) chunk + // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) + // and apply logical AND with 0x3F which is the number of + // the previous character in the ASCII table prior to the Base64 Table + // The result is then added to the table to get the character to write, + // and finally write it in the result pointer but with a left shift + // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits + + mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + } + + // When data `bytes` is not exactly 3 bytes long + // it is padded with `=` characters at the end + switch mod(mload(data), 3) + case 1 { + mstore8(sub(resultPtr, 1), 0x3d) + mstore8(sub(resultPtr, 2), 0x3d) + } + case 2 { + mstore8(sub(resultPtr, 1), 0x3d) + } + } + + return result; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/cryptography/MerkleProof.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (utils/cryptography/MerkleProof.sol) + +pragma solidity ^0.8.0; + +/** + * @dev These functions deal with verification of Merkle Trees proofs. + * + * The proofs can be generated using the JavaScript library + * https://github.com/miguelmota/merkletreejs[merkletreejs]. + * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled. + * + * See `test/utils/cryptography/MerkleProof.test.js` for some examples. + * + * WARNING: You should avoid using leaf values that are 64 bytes long prior to + * hashing, or use a hash function other than keccak256 for hashing leaves. + * This is because the concatenation of a sorted pair of internal nodes in + * the merkle tree could be reinterpreted as a leaf value. + */ +library MerkleProof { + /** + * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree + * defined by `root`. For this, a `proof` must be provided, containing + * sibling hashes on the branch from the leaf to the root of the tree. Each + * pair of leaves and each pair of pre-images are assumed to be sorted. + */ + function verify( + bytes32[] memory proof, + bytes32 root, + bytes32 leaf + ) internal pure returns (bool) { + return processProof(proof, leaf) == root; + } + + /** + * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up + * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt + * hash matches the root of the tree. When processing the proof, the pairs + * of leafs & pre-images are assumed to be sorted. + * + * _Available since v4.4._ + */ + function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + bytes32 proofElement = proof[i]; + if (computedHash <= proofElement) { + // Hash(current computed hash + current element of the proof) + computedHash = _efficientHash(computedHash, proofElement); + } else { + // Hash(current element of the proof + current computed hash) + computedHash = _efficientHash(proofElement, computedHash); + } + } + return computedHash; + } + + function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { + assembly { + mstore(0x00, a) + mstore(0x20, b) + value := keccak256(0x00, 0x40) + } + } +} + + +/////////////////////////////////////////// +// File: erc721a/contracts/ERC721A.sol + +// SPDX-License-Identifier: MIT +// ERC721A Contracts v4.1.0 +// Creator: Chiru Labs + +pragma solidity ^0.8.4; + +import './IERC721A.sol'; + +/** + * @dev ERC721 token receiver interface. + */ +interface ERC721A__IERC721Receiver { + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, + * including the Metadata extension. Built to optimize for lower gas during batch mints. + * + * Assumes serials are sequentially minted starting at `_startTokenId()` + * (defaults to 0, e.g. 0, 1, 2, 3..). + * + * Assumes that an owner cannot have more than 2**64 - 1 (max value of uint64) of supply. + * + * Assumes that the maximum token id cannot exceed 2**256 - 1 (max value of uint256). + */ +contract ERC721A is IERC721A { + // Mask of an entry in packed address data. + uint256 private constant BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1; + + // The bit position of `numberMinted` in packed address data. + uint256 private constant BITPOS_NUMBER_MINTED = 64; + + // The bit position of `numberBurned` in packed address data. + uint256 private constant BITPOS_NUMBER_BURNED = 128; + + // The bit position of `aux` in packed address data. + uint256 private constant BITPOS_AUX = 192; + + // Mask of all 256 bits in packed address data except the 64 bits for `aux`. + uint256 private constant BITMASK_AUX_COMPLEMENT = (1 << 192) - 1; + + // The bit position of `startTimestamp` in packed ownership. + uint256 private constant BITPOS_START_TIMESTAMP = 160; + + // The bit mask of the `burned` bit in packed ownership. + uint256 private constant BITMASK_BURNED = 1 << 224; + + // The bit position of the `nextInitialized` bit in packed ownership. + uint256 private constant BITPOS_NEXT_INITIALIZED = 225; + + // The bit mask of the `nextInitialized` bit in packed ownership. + uint256 private constant BITMASK_NEXT_INITIALIZED = 1 << 225; + + // The bit position of `extraData` in packed ownership. + uint256 private constant BITPOS_EXTRA_DATA = 232; + + // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`. + uint256 private constant BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1; + + // The mask of the lower 160 bits for addresses. + uint256 private constant BITMASK_ADDRESS = (1 << 160) - 1; + + // The maximum `quantity` that can be minted with `_mintERC2309`. + // This limit is to prevent overflows on the address data entries. + // For a limit of 5000, a total of 3.689e15 calls to `_mintERC2309` + // is required to cause an overflow, which is unrealistic. + uint256 private constant MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000; + + // The tokenId of the next token to be minted. + uint256 private _currentIndex; + + // The number of tokens burned. + uint256 private _burnCounter; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to ownership details + // An empty struct value does not necessarily mean the token is unowned. + // See `_packedOwnershipOf` implementation for details. + // + // Bits Layout: + // - [0..159] `addr` + // - [160..223] `startTimestamp` + // - [224] `burned` + // - [225] `nextInitialized` + // - [232..255] `extraData` + mapping(uint256 => uint256) private _packedOwnerships; + + // Mapping owner address to address data. + // + // Bits Layout: + // - [0..63] `balance` + // - [64..127] `numberMinted` + // - [128..191] `numberBurned` + // - [192..255] `aux` + mapping(address => uint256) private _packedAddressData; + + // Mapping from token ID to approved address. + mapping(uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + _currentIndex = _startTokenId(); + } + + /** + * @dev Returns the starting token ID. + * To change the starting token ID, please override this function. + */ + function _startTokenId() internal view virtual returns (uint256) { + return 0; + } + + /** + * @dev Returns the next token ID to be minted. + */ + function _nextTokenId() internal view returns (uint256) { + return _currentIndex; + } + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see `_totalMinted`. + */ + function totalSupply() public view override returns (uint256) { + // Counter underflow is impossible as _burnCounter cannot be incremented + // more than `_currentIndex - _startTokenId()` times. + unchecked { + return _currentIndex - _burnCounter - _startTokenId(); + } + } + + /** + * @dev Returns the total amount of tokens minted in the contract. + */ + function _totalMinted() internal view returns (uint256) { + // Counter underflow is impossible as _currentIndex does not decrement, + // and it is initialized to `_startTokenId()` + unchecked { + return _currentIndex - _startTokenId(); + } + } + + /** + * @dev Returns the total number of tokens burned. + */ + function _totalBurned() internal view returns (uint256) { + return _burnCounter; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + // The interface IDs are constants representing the first 4 bytes of the XOR of + // all function selectors in the interface. See: https://eips.ethereum.org/EIPS/eip-165 + // e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)` + return + interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165. + interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721. + interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata. + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view override returns (uint256) { + if (owner == address(0)) revert BalanceQueryForZeroAddress(); + return _packedAddressData[owner] & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the number of tokens minted by `owner`. + */ + function _numberMinted(address owner) internal view returns (uint256) { + return (_packedAddressData[owner] >> BITPOS_NUMBER_MINTED) & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the number of tokens burned by or on behalf of `owner`. + */ + function _numberBurned(address owner) internal view returns (uint256) { + return (_packedAddressData[owner] >> BITPOS_NUMBER_BURNED) & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). + */ + function _getAux(address owner) internal view returns (uint64) { + return uint64(_packedAddressData[owner] >> BITPOS_AUX); + } + + /** + * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). + * If there are multiple variables, please pack them into a uint64. + */ + function _setAux(address owner, uint64 aux) internal { + uint256 packed = _packedAddressData[owner]; + uint256 auxCasted; + // Cast `aux` with assembly to avoid redundant masking. + assembly { + auxCasted := aux + } + packed = (packed & BITMASK_AUX_COMPLEMENT) | (auxCasted << BITPOS_AUX); + _packedAddressData[owner] = packed; + } + + /** + * Returns the packed ownership data of `tokenId`. + */ + function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) { + uint256 curr = tokenId; + + unchecked { + if (_startTokenId() <= curr) + if (curr < _currentIndex) { + uint256 packed = _packedOwnerships[curr]; + // If not burned. + if (packed & BITMASK_BURNED == 0) { + // Invariant: + // There will always be an ownership that has an address and is not burned + // before an ownership that does not have an address and is not burned. + // Hence, curr will not underflow. + // + // We can directly compare the packed value. + // If the address is zero, packed is zero. + while (packed == 0) { + packed = _packedOwnerships[--curr]; + } + return packed; + } + } + } + revert OwnerQueryForNonexistentToken(); + } + + /** + * Returns the unpacked `TokenOwnership` struct from `packed`. + */ + function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) { + ownership.addr = address(uint160(packed)); + ownership.startTimestamp = uint64(packed >> BITPOS_START_TIMESTAMP); + ownership.burned = packed & BITMASK_BURNED != 0; + ownership.extraData = uint24(packed >> BITPOS_EXTRA_DATA); + } + + /** + * Returns the unpacked `TokenOwnership` struct at `index`. + */ + function _ownershipAt(uint256 index) internal view returns (TokenOwnership memory) { + return _unpackedOwnership(_packedOwnerships[index]); + } + + /** + * @dev Initializes the ownership slot minted at `index` for efficiency purposes. + */ + function _initializeOwnershipAt(uint256 index) internal { + if (_packedOwnerships[index] == 0) { + _packedOwnerships[index] = _packedOwnershipOf(index); + } + } + + /** + * Gas spent here starts off proportional to the maximum mint batch size. + * It gradually moves to O(1) as tokens get transferred around in the collection over time. + */ + function _ownershipOf(uint256 tokenId) internal view returns (TokenOwnership memory) { + return _unpackedOwnership(_packedOwnershipOf(tokenId)); + } + + /** + * @dev Packs ownership data into a single uint256. + */ + function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) { + assembly { + // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. + owner := and(owner, BITMASK_ADDRESS) + // `owner | (block.timestamp << BITPOS_START_TIMESTAMP) | flags`. + result := or(owner, or(shl(BITPOS_START_TIMESTAMP, timestamp()), flags)) + } + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view override returns (address) { + return address(uint160(_packedOwnershipOf(tokenId))); + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + if (!_exists(tokenId)) revert URIQueryForNonexistentToken(); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : ''; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, it can be overridden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ''; + } + + /** + * @dev Returns the `nextInitialized` flag set if `quantity` equals 1. + */ + function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) { + // For branchless setting of the `nextInitialized` flag. + assembly { + // `(quantity == 1) << BITPOS_NEXT_INITIALIZED`. + result := shl(BITPOS_NEXT_INITIALIZED, eq(quantity, 1)) + } + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public override { + address owner = ownerOf(tokenId); + + if (_msgSenderERC721A() != owner) + if (!isApprovedForAll(owner, _msgSenderERC721A())) { + revert ApprovalCallerNotOwnerNorApproved(); + } + + _tokenApprovals[tokenId] = to; + emit Approval(owner, to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view override returns (address) { + if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken(); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + if (operator == _msgSenderERC721A()) revert ApproveToCaller(); + + _operatorApprovals[_msgSenderERC721A()][operator] = approved; + emit ApprovalForAll(_msgSenderERC721A(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + safeTransferFrom(from, to, tokenId, ''); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) public virtual override { + transferFrom(from, to, tokenId); + if (to.code.length != 0) + if (!_checkContractOnERC721Received(from, to, tokenId, _data)) { + revert TransferToNonERC721ReceiverImplementer(); + } + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + */ + function _exists(uint256 tokenId) internal view returns (bool) { + return + _startTokenId() <= tokenId && + tokenId < _currentIndex && // If within bounds, + _packedOwnerships[tokenId] & BITMASK_BURNED == 0; // and not burned. + } + + /** + * @dev Equivalent to `_safeMint(to, quantity, '')`. + */ + function _safeMint(address to, uint256 quantity) internal { + _safeMint(to, quantity, ''); + } + + /** + * @dev Safely mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called for each safe transfer. + * - `quantity` must be greater than 0. + * + * See {_mint}. + * + * Emits a {Transfer} event for each mint. + */ + function _safeMint( + address to, + uint256 quantity, + bytes memory _data + ) internal { + _mint(to, quantity); + + unchecked { + if (to.code.length != 0) { + uint256 end = _currentIndex; + uint256 index = end - quantity; + do { + if (!_checkContractOnERC721Received(address(0), to, index++, _data)) { + revert TransferToNonERC721ReceiverImplementer(); + } + } while (index < end); + // Reentrancy protection. + if (_currentIndex != end) revert(); + } + } + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {Transfer} event for each mint. + */ + function _mint(address to, uint256 quantity) internal { + uint256 startTokenId = _currentIndex; + if (to == address(0)) revert MintToZeroAddress(); + if (quantity == 0) revert MintZeroQuantity(); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are incredibly unrealistic. + // `balance` and `numberMinted` have a maximum limit of 2**64. + // `tokenId` has a maximum limit of 2**256. + unchecked { + // Updates: + // - `balance += quantity`. + // - `numberMinted += quantity`. + // + // We can directly add to the `balance` and `numberMinted`. + _packedAddressData[to] += quantity * ((1 << BITPOS_NUMBER_MINTED) | 1); + + // Updates: + // - `address` to the owner. + // - `startTimestamp` to the timestamp of minting. + // - `burned` to `false`. + // - `nextInitialized` to `quantity == 1`. + _packedOwnerships[startTokenId] = _packOwnershipData( + to, + _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) + ); + + uint256 tokenId = startTokenId; + uint256 end = startTokenId + quantity; + do { + emit Transfer(address(0), to, tokenId++); + } while (tokenId < end); + + _currentIndex = end; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * This function is intended for efficient minting only during contract creation. + * + * It emits only one {ConsecutiveTransfer} as defined in + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309), + * instead of a sequence of {Transfer} event(s). + * + * Calling this function outside of contract creation WILL make your contract + * non-compliant with the ERC721 standard. + * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309 + * {ConsecutiveTransfer} event is only permissible during contract creation. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {ConsecutiveTransfer} event. + */ + function _mintERC2309(address to, uint256 quantity) internal { + uint256 startTokenId = _currentIndex; + if (to == address(0)) revert MintToZeroAddress(); + if (quantity == 0) revert MintZeroQuantity(); + if (quantity > MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit(); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are unrealistic due to the above check for `quantity` to be below the limit. + unchecked { + // Updates: + // - `balance += quantity`. + // - `numberMinted += quantity`. + // + // We can directly add to the `balance` and `numberMinted`. + _packedAddressData[to] += quantity * ((1 << BITPOS_NUMBER_MINTED) | 1); + + // Updates: + // - `address` to the owner. + // - `startTimestamp` to the timestamp of minting. + // - `burned` to `false`. + // - `nextInitialized` to `quantity == 1`. + _packedOwnerships[startTokenId] = _packOwnershipData( + to, + _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) + ); + + emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to); + + _currentIndex = startTokenId + quantity; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Returns the storage slot and value for the approved address of `tokenId`. + */ + function _getApprovedAddress(uint256 tokenId) + private + view + returns (uint256 approvedAddressSlot, address approvedAddress) + { + mapping(uint256 => address) storage tokenApprovalsPtr = _tokenApprovals; + // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId]`. + assembly { + // Compute the slot. + mstore(0x00, tokenId) + mstore(0x20, tokenApprovalsPtr.slot) + approvedAddressSlot := keccak256(0x00, 0x40) + // Load the slot's value from storage. + approvedAddress := sload(approvedAddressSlot) + } + } + + /** + * @dev Returns whether the `approvedAddress` is equals to `from` or `msgSender`. + */ + function _isOwnerOrApproved( + address approvedAddress, + address from, + address msgSender + ) private pure returns (bool result) { + assembly { + // Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean. + from := and(from, BITMASK_ADDRESS) + // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean. + msgSender := and(msgSender, BITMASK_ADDRESS) + // `msgSender == from || msgSender == approvedAddress`. + result := or(eq(msgSender, from), eq(msgSender, approvedAddress)) + } + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); + + if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner(); + + (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedAddress(tokenId); + + // The nested ifs save around 20+ gas over a compound boolean condition. + if (!_isOwnerOrApproved(approvedAddress, from, _msgSenderERC721A())) + if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved(); + + if (to == address(0)) revert TransferToZeroAddress(); + + _beforeTokenTransfers(from, to, tokenId, 1); + + // Clear approvals from the previous owner. + assembly { + if approvedAddress { + // This is equivalent to `delete _tokenApprovals[tokenId]`. + sstore(approvedAddressSlot, 0) + } + } + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as tokenId would have to be 2**256. + unchecked { + // We can directly increment and decrement the balances. + --_packedAddressData[from]; // Updates: `balance -= 1`. + ++_packedAddressData[to]; // Updates: `balance += 1`. + + // Updates: + // - `address` to the next owner. + // - `startTimestamp` to the timestamp of transfering. + // - `burned` to `false`. + // - `nextInitialized` to `true`. + _packedOwnerships[tokenId] = _packOwnershipData( + to, + BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked) + ); + + // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . + if (prevOwnershipPacked & BITMASK_NEXT_INITIALIZED == 0) { + uint256 nextTokenId = tokenId + 1; + // If the next slot's address is zero and not burned (i.e. packed value is zero). + if (_packedOwnerships[nextTokenId] == 0) { + // If the next slot is within bounds. + if (nextTokenId != _currentIndex) { + // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. + _packedOwnerships[nextTokenId] = prevOwnershipPacked; + } + } + } + } + + emit Transfer(from, to, tokenId); + _afterTokenTransfers(from, to, tokenId, 1); + } + + /** + * @dev Equivalent to `_burn(tokenId, false)`. + */ + function _burn(uint256 tokenId) internal virtual { + _burn(tokenId, false); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId, bool approvalCheck) internal virtual { + uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); + + address from = address(uint160(prevOwnershipPacked)); + + (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedAddress(tokenId); + + if (approvalCheck) { + // The nested ifs save around 20+ gas over a compound boolean condition. + if (!_isOwnerOrApproved(approvedAddress, from, _msgSenderERC721A())) + if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved(); + } + + _beforeTokenTransfers(from, address(0), tokenId, 1); + + // Clear approvals from the previous owner. + assembly { + if approvedAddress { + // This is equivalent to `delete _tokenApprovals[tokenId]`. + sstore(approvedAddressSlot, 0) + } + } + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. + unchecked { + // Updates: + // - `balance -= 1`. + // - `numberBurned += 1`. + // + // We can directly decrement the balance, and increment the number burned. + // This is equivalent to `packed -= 1; packed += 1 << BITPOS_NUMBER_BURNED;`. + _packedAddressData[from] += (1 << BITPOS_NUMBER_BURNED) - 1; + + // Updates: + // - `address` to the last owner. + // - `startTimestamp` to the timestamp of burning. + // - `burned` to `true`. + // - `nextInitialized` to `true`. + _packedOwnerships[tokenId] = _packOwnershipData( + from, + (BITMASK_BURNED | BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked) + ); + + // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . + if (prevOwnershipPacked & BITMASK_NEXT_INITIALIZED == 0) { + uint256 nextTokenId = tokenId + 1; + // If the next slot's address is zero and not burned (i.e. packed value is zero). + if (_packedOwnerships[nextTokenId] == 0) { + // If the next slot is within bounds. + if (nextTokenId != _currentIndex) { + // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. + _packedOwnerships[nextTokenId] = prevOwnershipPacked; + } + } + } + } + + emit Transfer(from, address(0), tokenId); + _afterTokenTransfers(from, address(0), tokenId, 1); + + // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times. + unchecked { + _burnCounter++; + } + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkContractOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) private returns (bool) { + try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns ( + bytes4 retval + ) { + return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert TransferToNonERC721ReceiverImplementer(); + } else { + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } + + /** + * @dev Directly sets the extra data for the ownership data `index`. + */ + function _setExtraDataAt(uint256 index, uint24 extraData) internal { + uint256 packed = _packedOwnerships[index]; + if (packed == 0) revert OwnershipNotInitializedForExtraData(); + uint256 extraDataCasted; + // Cast `extraData` with assembly to avoid redundant masking. + assembly { + extraDataCasted := extraData + } + packed = (packed & BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << BITPOS_EXTRA_DATA); + _packedOwnerships[index] = packed; + } + + /** + * @dev Returns the next extra data for the packed ownership data. + * The returned result is shifted into position. + */ + function _nextExtraData( + address from, + address to, + uint256 prevOwnershipPacked + ) private view returns (uint256) { + uint24 extraData = uint24(prevOwnershipPacked >> BITPOS_EXTRA_DATA); + return uint256(_extraData(from, to, extraData)) << BITPOS_EXTRA_DATA; + } + + /** + * @dev Called during each token transfer to set the 24bit `extraData` field. + * Intended to be overridden by the cosumer contract. + * + * `previousExtraData` - the value of `extraData` before transfer. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _extraData( + address from, + address to, + uint24 previousExtraData + ) internal view virtual returns (uint24) {} + + /** + * @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. + * This includes minting. + * And also called before burning one token. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _beforeTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Hook that is called after a set of serially-ordered token ids have been transferred. + * This includes minting. + * And also called after one token has been burned. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been + * transferred to `to`. + * - When `from` is zero, `tokenId` has been minted for `to`. + * - When `to` is zero, `tokenId` has been burned by `from`. + * - `from` and `to` are never both zero. + */ + function _afterTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Returns the message sender (defaults to `msg.sender`). + * + * If you are writing GSN compatible contracts, you need to override this function. + */ + function _msgSenderERC721A() internal view virtual returns (address) { + return msg.sender; + } + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function _toString(uint256 value) internal pure returns (string memory ptr) { + assembly { + // The maximum value of a uint256 contains 78 digits (1 byte per digit), + // but we allocate 128 bytes to keep the free memory pointer 32-byte word aliged. + // We will need 1 32-byte word to store the length, + // and 3 32-byte words to store a maximum of 78 digits. Total: 32 + 3 * 32 = 128. + ptr := add(mload(0x40), 128) + // Update the free memory pointer to allocate. + mstore(0x40, ptr) + + // Cache the end of the memory to calculate the length later. + let end := ptr + + // We write the string from the rightmost digit to the leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + // Costs a bit more than early returning for the zero case, + // but cheaper in terms of deployment and overall runtime costs. + for { + // Initialize and perform the first pass without check. + let temp := value + // Move the pointer 1 byte leftwards to point to an empty character slot. + ptr := sub(ptr, 1) + // Write the character to the pointer. 48 is the ASCII index of '0'. + mstore8(ptr, add(48, mod(temp, 10))) + temp := div(temp, 10) + } temp { + // Keep dividing `temp` until zero. + temp := div(temp, 10) + } { + // Body of the for loop. + ptr := sub(ptr, 1) + mstore8(ptr, add(48, mod(temp, 10))) + } + + let length := sub(end, ptr) + // Move the pointer 32 bytes leftwards to make room for the length. + ptr := sub(ptr, 32) + // Store the length. + mstore(ptr, length) + } + } +} + + +/////////////////////////////////////////// +// File: erc721a/contracts/IERC721A.sol + +// SPDX-License-Identifier: MIT +// ERC721A Contracts v4.1.0 +// Creator: Chiru Labs + +pragma solidity ^0.8.4; + +/** + * @dev Interface of an ERC721A compliant contract. + */ +interface IERC721A { + /** + * The caller must own the token or be an approved operator. + */ + error ApprovalCallerNotOwnerNorApproved(); + + /** + * The token does not exist. + */ + error ApprovalQueryForNonexistentToken(); + + /** + * The caller cannot approve to their own address. + */ + error ApproveToCaller(); + + /** + * Cannot query the balance for the zero address. + */ + error BalanceQueryForZeroAddress(); + + /** + * Cannot mint to the zero address. + */ + error MintToZeroAddress(); + + /** + * The quantity of tokens minted must be more than zero. + */ + error MintZeroQuantity(); + + /** + * The token does not exist. + */ + error OwnerQueryForNonexistentToken(); + + /** + * The caller must own the token or be an approved operator. + */ + error TransferCallerNotOwnerNorApproved(); + + /** + * The token must be owned by `from`. + */ + error TransferFromIncorrectOwner(); + + /** + * Cannot safely transfer to a contract that does not implement the ERC721Receiver interface. + */ + error TransferToNonERC721ReceiverImplementer(); + + /** + * Cannot transfer to the zero address. + */ + error TransferToZeroAddress(); + + /** + * The token does not exist. + */ + error URIQueryForNonexistentToken(); + + /** + * The `quantity` minted with ERC2309 exceeds the safety limit. + */ + error MintERC2309QuantityExceedsLimit(); + + /** + * The `extraData` cannot be set on an unintialized ownership slot. + */ + error OwnershipNotInitializedForExtraData(); + + struct TokenOwnership { + // The address of the owner. + address addr; + // Keeps track of the start time of ownership with minimal overhead for tokenomics. + uint64 startTimestamp; + // Whether the token has been burned. + bool burned; + // Arbitrary data similar to `startTimestamp` that can be set through `_extraData`. + uint24 extraData; + } + + /** + * @dev Returns the total amount of tokens stored by the contract. + * + * Burned tokens are calculated here, use `_totalMinted()` if you want to count just minted tokens. + */ + function totalSupply() external view returns (uint256); + + // ============================== + // IERC165 + // ============================== + + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); + + // ============================== + // IERC721 + // ============================== + + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + // ============================== + // IERC721Metadata + // ============================== + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); + + // ============================== + // IERC2309 + // ============================== + + /** + * @dev Emitted when tokens in `fromTokenId` to `toTokenId` (inclusive) is transferred from `from` to `to`, + * as defined in the ERC2309 standard. See `_mintERC2309` for more details. + */ + event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); +} + + diff --git a/ethabi/code/0x2204a94f96d39df3b6bc0298cf068c8c82dc8d61.yml b/ethabi/code/0x2204a94f96d39df3b6bc0298cf068c8c82dc8d61.yml new file mode 100644 index 0000000..72651d9 --- /dev/null +++ b/ethabi/code/0x2204a94f96d39df3b6bc0298cf068c8c82dc8d61.yml @@ -0,0 +1,12 @@ +--- +ContractName: Indelible +CompilerVersion: v0.8.14+commit.80d49f37 +OptimizationUsed: '1' +Runs: '200' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: MIT +Proxy: '0' +Implementation: '' +SwarmSource: '' diff --git a/ethabi/code/0x23581767a106ae21c074b2276d25e5c3e136a68b.sol b/ethabi/code/0x23581767a106ae21c074b2276d25e5c3e136a68b.sol new file mode 100644 index 0000000..5ade355 --- /dev/null +++ b/ethabi/code/0x23581767a106ae21c074b2276d25e5c3e136a68b.sol @@ -0,0 +1,4333 @@ +/////////////////////////////////////////// +// File: /contracts/Moonbirds.sol + +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.10 <0.9.0; + +import "@divergencetech/ethier/contracts/crypto/SignatureChecker.sol"; +import "@divergencetech/ethier/contracts/crypto/SignerManager.sol"; +import "@divergencetech/ethier/contracts/erc721/BaseTokenURI.sol"; +import "@divergencetech/ethier/contracts/erc721/ERC721ACommon.sol"; +import "@divergencetech/ethier/contracts/erc721/ERC721Redeemer.sol"; +import "@divergencetech/ethier/contracts/sales/FixedPriceSeller.sol"; +import "@divergencetech/ethier/contracts/utils/Monotonic.sol"; +import "@openzeppelin/contracts/token/common/ERC2981.sol"; +import "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; +import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +interface ITokenURIGenerator { + function tokenURI(uint256 tokenId) external view returns (string memory); +} + +// @author divergence.xyz +contract Moonbirds is + ERC721ACommon, + BaseTokenURI, + FixedPriceSeller, + SignerManager, + ERC2981, + AccessControlEnumerable +{ + using EnumerableSet for EnumerableSet.AddressSet; + using ERC721Redeemer for ERC721Redeemer.Claims; + using Monotonic for Monotonic.Increaser; + using SignatureChecker for EnumerableSet.AddressSet; + + IERC721 public immutable proof; + + /** + @notice Role of administrative users allowed to expel a Moonbird from the + nest. + @dev See expelFromNest(). + */ + bytes32 public constant EXPULSION_ROLE = keccak256("EXPULSION_ROLE"); + + constructor( + string memory name, + string memory symbol, + IERC721 _proof, + address payable beneficiary, + address payable royaltyReceiver + ) + ERC721ACommon(name, symbol) + BaseTokenURI("") + FixedPriceSeller( + 2.5 ether, + // Not including a separate pool for PROOF holders, taking the total + // to 10k. We don't enforce buyer limits here because it's already + // done by only issuing a single signature per address, and double + // enforcement would waste gas. + Seller.SellerConfig({ + totalInventory: 8_000, + lockTotalInventory: true, + maxPerAddress: 0, + maxPerTx: 0, + freeQuota: 125, + lockFreeQuota: false, + reserveFreeQuota: true + }), + beneficiary + ) + { + proof = _proof; + _setDefaultRoyalty(royaltyReceiver, 500); + _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); + } + + /** + @dev Mint tokens purchased via the Seller. + */ + function _handlePurchase( + address to, + uint256 n, + bool + ) internal override { + _safeMint(to, n); + + // We're using two separate pools (one from Seller, and one for PROOF + // minting), so add an extra layer of checks for this invariant. This + // should never fail as each pool has its own restriction, and is in + // place purely for tests (hence assert). + assert(totalSupply() <= 10_000); + } + + /** + @dev Record of already-used signatures. + */ + mapping(bytes32 => bool) public usedMessages; + + /** + @notice Mint as a non-holder of PROOF tokens. + */ + function mintPublic( + address to, + bytes32 nonce, + bytes calldata sig + ) external payable { + signers.requireValidSignature( + signaturePayload(to, nonce), + sig, + usedMessages + ); + _purchase(to, 1); + } + + /** + @notice Returns whether the address has minted with the particular nonce. If + true, future calls to mint() with the same parameters will fail. + @dev In production we will never issue more than a single nonce per address, + but this allows for testing with a single address. + */ + function alreadyMinted(address to, bytes32 nonce) + external + view + returns (bool) + { + return + usedMessages[ + SignatureChecker.generateMessage(signaturePayload(to, nonce)) + ]; + } + + /** + @dev Constructs the buffer that is hashed for validation with a minting + signature. + */ + function signaturePayload(address to, bytes32 nonce) + internal + pure + returns (bytes memory) + { + return abi.encodePacked(to, nonce); + } + + /** + @notice Two guaranteed mints per PROOF holder. + @dev This is specifically tracked because unclaimed tokens will be minted to + the PROOF wallet, so the pool guarantees an upper bound. + */ + uint256 public proofPoolRemaining = 2000; + + ERC721Redeemer.Claims private redeemedPROOF; + + /** + @dev Used by both PROOF-holder and PROOF-admin minting from the pool. + */ + modifier reducePROOFPool(uint256 n) { + require(n <= proofPoolRemaining, "Moonbirds: PROOF pool exhausted"); + proofPoolRemaining -= n; + _; + } + + /** + @notice Flag indicating whether holders of PROOF passes can mint. + */ + bool public proofMintingOpen = false; + + /** + @notice Sets whether holders of PROOF passes can mint. + */ + function setPROOFMintingOpen(bool open) external onlyOwner { + proofMintingOpen = open; + } + + /** + @notice Mint as a holder of a PROOF token. + @dev Repeat a PROOF token ID twice to redeem both of its claims; recurring + values SHOULD be adjacent for improved gas (eg [1,1,2,2] not [1,2,1,2]). + */ + function mintPROOF(uint256[] calldata proofTokenIds) + external + reducePROOFPool(proofTokenIds.length) + { + require(proofMintingOpen, "Moonbirds: PROOF minting closed"); + uint256 n = redeemedPROOF.redeem(2, msg.sender, proof, proofTokenIds); + _handlePurchase(msg.sender, n, true); + } + + /** + @notice Returns how many additional Moonbirds can be claimed with the PROOF + token. + */ + function proofClaimsRemaining(uint256 tokenId) + external + view + returns (uint256) + { + require(tokenId < 1000, "Token doesn't exist"); + return 2 - redeemedPROOF.claimed(tokenId); + } + + /** + @notice Mint unclaimed tokens from the PROOF-holder pool. + */ + function mintUnclaimed(address to, uint256 n) + external + onlyOwner + reducePROOFPool(n) + { + _handlePurchase(to, n, true); + } + + /** + @dev tokenId to nesting start time (0 = not nesting). + */ + mapping(uint256 => uint256) private nestingStarted; + + /** + @dev Cumulative per-token nesting, excluding the current period. + */ + mapping(uint256 => uint256) private nestingTotal; + + /** + @notice Returns the length of time, in seconds, that the Moonbird has + nested. + @dev Nesting is tied to a specific Moonbird, not to the owner, so it doesn't + reset upon sale. + @return nesting Whether the Moonbird is currently nesting. MAY be true with + zero current nesting if in the same block as nesting began. + @return current Zero if not currently nesting, otherwise the length of time + since the most recent nesting began. + @return total Total period of time for which the Moonbird has nested across + its life, including the current period. + */ + function nestingPeriod(uint256 tokenId) + external + view + returns ( + bool nesting, + uint256 current, + uint256 total + ) + { + uint256 start = nestingStarted[tokenId]; + if (start != 0) { + nesting = true; + current = block.timestamp - start; + } + total = current + nestingTotal[tokenId]; + } + + /** + @dev MUST only be modified by safeTransferWhileNesting(); if set to 2 then + the _beforeTokenTransfer() block while nesting is disabled. + */ + uint256 private nestingTransfer = 1; + + /** + @notice Transfer a token between addresses while the Moonbird is minting, + thus not resetting the nesting period. + */ + function safeTransferWhileNesting( + address from, + address to, + uint256 tokenId + ) external { + require(ownerOf(tokenId) == _msgSender(), "Moonbirds: Only owner"); + nestingTransfer = 2; + safeTransferFrom(from, to, tokenId); + nestingTransfer = 1; + } + + /** + @dev Block transfers while nesting. + */ + function _beforeTokenTransfers( + address, + address, + uint256 startTokenId, + uint256 quantity + ) internal view override { + uint256 tokenId = startTokenId; + for (uint256 end = tokenId + quantity; tokenId < end; ++tokenId) { + require( + nestingStarted[tokenId] == 0 || nestingTransfer == 2, + "Moonbirds: nesting" + ); + } + } + + /** + @dev Emitted when a Moonbird begins nesting. + */ + event Nested(uint256 indexed tokenId); + + /** + @dev Emitted when a Moonbird stops nesting; either through standard means or + by expulsion. + */ + event Unnested(uint256 indexed tokenId); + + /** + @dev Emitted when a Moonbird is expelled from the nest. + */ + event Expelled(uint256 indexed tokenId); + + /** + @notice Whether nesting is currently allowed. + @dev If false then nesting is blocked, but unnesting is always allowed. + */ + bool public nestingOpen = false; + + /** + @notice Toggles the `nestingOpen` flag. + */ + function setNestingOpen(bool open) external onlyOwner { + nestingOpen = open; + } + + /** + @notice Changes the Moonbird's nesting status. + */ + function toggleNesting(uint256 tokenId) + internal + onlyApprovedOrOwner(tokenId) + { + uint256 start = nestingStarted[tokenId]; + if (start == 0) { + require(nestingOpen, "Moonbirds: nesting closed"); + nestingStarted[tokenId] = block.timestamp; + emit Nested(tokenId); + } else { + nestingTotal[tokenId] += block.timestamp - start; + nestingStarted[tokenId] = 0; + emit Unnested(tokenId); + } + } + + /** + @notice Changes the Moonbirds' nesting statuss (what's the plural of status? + statii? statuses? status? The plural of sheep is sheep; maybe it's also the + plural of status). + @dev Changes the Moonbirds' nesting sheep (see @notice). + */ + function toggleNesting(uint256[] calldata tokenIds) external { + uint256 n = tokenIds.length; + for (uint256 i = 0; i < n; ++i) { + toggleNesting(tokenIds[i]); + } + } + + /** + @notice Admin-only ability to expel a Moonbird from the nest. + @dev As most sales listings use off-chain signatures it's impossible to + detect someone who has nested and then deliberately undercuts the floor + price in the knowledge that the sale can't proceed. This function allows for + monitoring of such practices and expulsion if abuse is detected, allowing + the undercutting bird to be sold on the open market. Since OpenSea uses + isApprovedForAll() in its pre-listing checks, we can't block by that means + because nesting would then be all-or-nothing for all of a particular owner's + Moonbirds. + */ + function expelFromNest(uint256 tokenId) external onlyRole(EXPULSION_ROLE) { + require(nestingStarted[tokenId] != 0, "Moonbirds: not nested"); + nestingTotal[tokenId] += block.timestamp - nestingStarted[tokenId]; + nestingStarted[tokenId] = 0; + emit Unnested(tokenId); + emit Expelled(tokenId); + } + + /** + @dev Required override to select the correct baseTokenURI. + */ + function _baseURI() + internal + view + override(BaseTokenURI, ERC721A) + returns (string memory) + { + return BaseTokenURI._baseURI(); + } + + /** + @notice If set, contract to which tokenURI() calls are proxied. + */ + ITokenURIGenerator public renderingContract; + + /** + @notice Sets the optional tokenURI override contract. + */ + function setRenderingContract(ITokenURIGenerator _contract) + external + onlyOwner + { + renderingContract = _contract; + } + + /** + @notice If renderingContract is set then returns its tokenURI(tokenId) + return value, otherwise returns the standard baseTokenURI + tokenId. + */ + function tokenURI(uint256 tokenId) + public + view + override + returns (string memory) + { + if (address(renderingContract) != address(0)) { + return renderingContract.tokenURI(tokenId); + } + return super.tokenURI(tokenId); + } + + /** + @notice Sets the contract-wide royalty info. + */ + function setRoyaltyInfo(address receiver, uint96 feeBasisPoints) + external + onlyOwner + { + _setDefaultRoyalty(receiver, feeBasisPoints); + } + + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721ACommon, ERC2981, AccessControlEnumerable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} + + +/////////////////////////////////////////// +// File: erc721a/contracts/ERC721A.sol + +// SPDX-License-Identifier: MIT +// Creator: Chiru Labs + +pragma solidity ^0.8.4; + +import '@openzeppelin/contracts/token/ERC721/IERC721.sol'; +import '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol'; +import '@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol'; +import '@openzeppelin/contracts/utils/Address.sol'; +import '@openzeppelin/contracts/utils/Context.sol'; +import '@openzeppelin/contracts/utils/Strings.sol'; +import '@openzeppelin/contracts/utils/introspection/ERC165.sol'; + +error ApprovalCallerNotOwnerNorApproved(); +error ApprovalQueryForNonexistentToken(); +error ApproveToCaller(); +error ApprovalToCurrentOwner(); +error BalanceQueryForZeroAddress(); +error MintToZeroAddress(); +error MintZeroQuantity(); +error OwnerQueryForNonexistentToken(); +error TransferCallerNotOwnerNorApproved(); +error TransferFromIncorrectOwner(); +error TransferToNonERC721ReceiverImplementer(); +error TransferToZeroAddress(); +error URIQueryForNonexistentToken(); + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including + * the Metadata extension. Built to optimize for lower gas during batch mints. + * + * Assumes serials are sequentially minted starting at _startTokenId() (defaults to 0, e.g. 0, 1, 2, 3..). + * + * Assumes that an owner cannot have more than 2**64 - 1 (max value of uint64) of supply. + * + * Assumes that the maximum token id cannot exceed 2**256 - 1 (max value of uint256). + */ +contract ERC721A is Context, ERC165, IERC721, IERC721Metadata { + using Address for address; + using Strings for uint256; + + // Compiler will pack this into a single 256bit word. + struct TokenOwnership { + // The address of the owner. + address addr; + // Keeps track of the start time of ownership with minimal overhead for tokenomics. + uint64 startTimestamp; + // Whether the token has been burned. + bool burned; + } + + // Compiler will pack this into a single 256bit word. + struct AddressData { + // Realistically, 2**64-1 is more than enough. + uint64 balance; + // Keeps track of mint count with minimal overhead for tokenomics. + uint64 numberMinted; + // Keeps track of burn count with minimal overhead for tokenomics. + uint64 numberBurned; + // For miscellaneous variable(s) pertaining to the address + // (e.g. number of whitelist mint slots used). + // If there are multiple variables, please pack them into a uint64. + uint64 aux; + } + + // The tokenId of the next token to be minted. + uint256 internal _currentIndex; + + // The number of tokens burned. + uint256 internal _burnCounter; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to ownership details + // An empty struct value does not necessarily mean the token is unowned. See _ownershipOf implementation for details. + mapping(uint256 => TokenOwnership) internal _ownerships; + + // Mapping owner address to address data + mapping(address => AddressData) private _addressData; + + // Mapping from token ID to approved address + mapping(uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + _currentIndex = _startTokenId(); + } + + /** + * To change the starting tokenId, please override this function. + */ + function _startTokenId() internal view virtual returns (uint256) { + return 0; + } + + /** + * @dev Burned tokens are calculated here, use _totalMinted() if you want to count just minted tokens. + */ + function totalSupply() public view returns (uint256) { + // Counter underflow is impossible as _burnCounter cannot be incremented + // more than _currentIndex - _startTokenId() times + unchecked { + return _currentIndex - _burnCounter - _startTokenId(); + } + } + + /** + * Returns the total amount of tokens minted in the contract. + */ + function _totalMinted() internal view returns (uint256) { + // Counter underflow is impossible as _currentIndex does not decrement, + // and it is initialized to _startTokenId() + unchecked { + return _currentIndex - _startTokenId(); + } + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view override returns (uint256) { + if (owner == address(0)) revert BalanceQueryForZeroAddress(); + return uint256(_addressData[owner].balance); + } + + /** + * Returns the number of tokens minted by `owner`. + */ + function _numberMinted(address owner) internal view returns (uint256) { + return uint256(_addressData[owner].numberMinted); + } + + /** + * Returns the number of tokens burned by or on behalf of `owner`. + */ + function _numberBurned(address owner) internal view returns (uint256) { + return uint256(_addressData[owner].numberBurned); + } + + /** + * Returns the auxillary data for `owner`. (e.g. number of whitelist mint slots used). + */ + function _getAux(address owner) internal view returns (uint64) { + return _addressData[owner].aux; + } + + /** + * Sets the auxillary data for `owner`. (e.g. number of whitelist mint slots used). + * If there are multiple variables, please pack them into a uint64. + */ + function _setAux(address owner, uint64 aux) internal { + _addressData[owner].aux = aux; + } + + /** + * Gas spent here starts off proportional to the maximum mint batch size. + * It gradually moves to O(1) as tokens get transferred around in the collection over time. + */ + function _ownershipOf(uint256 tokenId) internal view returns (TokenOwnership memory) { + uint256 curr = tokenId; + + unchecked { + if (_startTokenId() <= curr && curr < _currentIndex) { + TokenOwnership memory ownership = _ownerships[curr]; + if (!ownership.burned) { + if (ownership.addr != address(0)) { + return ownership; + } + // Invariant: + // There will always be an ownership that has an address and is not burned + // before an ownership that does not have an address and is not burned. + // Hence, curr will not underflow. + while (true) { + curr--; + ownership = _ownerships[curr]; + if (ownership.addr != address(0)) { + return ownership; + } + } + } + } + } + revert OwnerQueryForNonexistentToken(); + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view override returns (address) { + return _ownershipOf(tokenId).addr; + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + if (!_exists(tokenId)) revert URIQueryForNonexistentToken(); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ''; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, can be overriden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ''; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public override { + address owner = ERC721A.ownerOf(tokenId); + if (to == owner) revert ApprovalToCurrentOwner(); + + if (_msgSender() != owner && !isApprovedForAll(owner, _msgSender())) { + revert ApprovalCallerNotOwnerNorApproved(); + } + + _approve(to, tokenId, owner); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view override returns (address) { + if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken(); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + if (operator == _msgSender()) revert ApproveToCaller(); + + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + _transfer(from, to, tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + safeTransferFrom(from, to, tokenId, ''); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) public virtual override { + _transfer(from, to, tokenId); + if (to.isContract() && !_checkContractOnERC721Received(from, to, tokenId, _data)) { + revert TransferToNonERC721ReceiverImplementer(); + } + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + */ + function _exists(uint256 tokenId) internal view returns (bool) { + return _startTokenId() <= tokenId && tokenId < _currentIndex && + !_ownerships[tokenId].burned; + } + + function _safeMint(address to, uint256 quantity) internal { + _safeMint(to, quantity, ''); + } + + /** + * @dev Safely mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called for each safe transfer. + * - `quantity` must be greater than 0. + * + * Emits a {Transfer} event. + */ + function _safeMint( + address to, + uint256 quantity, + bytes memory _data + ) internal { + _mint(to, quantity, _data, true); + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {Transfer} event. + */ + function _mint( + address to, + uint256 quantity, + bytes memory _data, + bool safe + ) internal { + uint256 startTokenId = _currentIndex; + if (to == address(0)) revert MintToZeroAddress(); + if (quantity == 0) revert MintZeroQuantity(); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are incredibly unrealistic. + // balance or numberMinted overflow if current value of either + quantity > 1.8e19 (2**64) - 1 + // updatedIndex overflows if _currentIndex + quantity > 1.2e77 (2**256) - 1 + unchecked { + _addressData[to].balance += uint64(quantity); + _addressData[to].numberMinted += uint64(quantity); + + _ownerships[startTokenId].addr = to; + _ownerships[startTokenId].startTimestamp = uint64(block.timestamp); + + uint256 updatedIndex = startTokenId; + uint256 end = updatedIndex + quantity; + + if (safe && to.isContract()) { + do { + emit Transfer(address(0), to, updatedIndex); + if (!_checkContractOnERC721Received(address(0), to, updatedIndex++, _data)) { + revert TransferToNonERC721ReceiverImplementer(); + } + } while (updatedIndex != end); + // Reentrancy protection + if (_currentIndex != startTokenId) revert(); + } else { + do { + emit Transfer(address(0), to, updatedIndex++); + } while (updatedIndex != end); + } + _currentIndex = updatedIndex; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer( + address from, + address to, + uint256 tokenId + ) private { + TokenOwnership memory prevOwnership = _ownershipOf(tokenId); + + if (prevOwnership.addr != from) revert TransferFromIncorrectOwner(); + + bool isApprovedOrOwner = (_msgSender() == from || + isApprovedForAll(from, _msgSender()) || + getApproved(tokenId) == _msgSender()); + + if (!isApprovedOrOwner) revert TransferCallerNotOwnerNorApproved(); + if (to == address(0)) revert TransferToZeroAddress(); + + _beforeTokenTransfers(from, to, tokenId, 1); + + // Clear approvals from the previous owner + _approve(address(0), tokenId, from); + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as tokenId would have to be 2**256. + unchecked { + _addressData[from].balance -= 1; + _addressData[to].balance += 1; + + TokenOwnership storage currSlot = _ownerships[tokenId]; + currSlot.addr = to; + currSlot.startTimestamp = uint64(block.timestamp); + + // If the ownership slot of tokenId+1 is not explicitly set, that means the transfer initiator owns it. + // Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls. + uint256 nextTokenId = tokenId + 1; + TokenOwnership storage nextSlot = _ownerships[nextTokenId]; + if (nextSlot.addr == address(0)) { + // This will suffice for checking _exists(nextTokenId), + // as a burned slot cannot contain the zero address. + if (nextTokenId != _currentIndex) { + nextSlot.addr = from; + nextSlot.startTimestamp = prevOwnership.startTimestamp; + } + } + } + + emit Transfer(from, to, tokenId); + _afterTokenTransfers(from, to, tokenId, 1); + } + + /** + * @dev This is equivalent to _burn(tokenId, false) + */ + function _burn(uint256 tokenId) internal virtual { + _burn(tokenId, false); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId, bool approvalCheck) internal virtual { + TokenOwnership memory prevOwnership = _ownershipOf(tokenId); + + address from = prevOwnership.addr; + + if (approvalCheck) { + bool isApprovedOrOwner = (_msgSender() == from || + isApprovedForAll(from, _msgSender()) || + getApproved(tokenId) == _msgSender()); + + if (!isApprovedOrOwner) revert TransferCallerNotOwnerNorApproved(); + } + + _beforeTokenTransfers(from, address(0), tokenId, 1); + + // Clear approvals from the previous owner + _approve(address(0), tokenId, from); + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as tokenId would have to be 2**256. + unchecked { + AddressData storage addressData = _addressData[from]; + addressData.balance -= 1; + addressData.numberBurned += 1; + + // Keep track of who burned the token, and the timestamp of burning. + TokenOwnership storage currSlot = _ownerships[tokenId]; + currSlot.addr = from; + currSlot.startTimestamp = uint64(block.timestamp); + currSlot.burned = true; + + // If the ownership slot of tokenId+1 is not explicitly set, that means the burn initiator owns it. + // Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls. + uint256 nextTokenId = tokenId + 1; + TokenOwnership storage nextSlot = _ownerships[nextTokenId]; + if (nextSlot.addr == address(0)) { + // This will suffice for checking _exists(nextTokenId), + // as a burned slot cannot contain the zero address. + if (nextTokenId != _currentIndex) { + nextSlot.addr = from; + nextSlot.startTimestamp = prevOwnership.startTimestamp; + } + } + } + + emit Transfer(from, address(0), tokenId); + _afterTokenTransfers(from, address(0), tokenId, 1); + + // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times. + unchecked { + _burnCounter++; + } + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * Emits a {Approval} event. + */ + function _approve( + address to, + uint256 tokenId, + address owner + ) private { + _tokenApprovals[tokenId] = to; + emit Approval(owner, to, tokenId); + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkContractOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) private returns (bool) { + try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { + return retval == IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert TransferToNonERC721ReceiverImplementer(); + } else { + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } + + /** + * @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. This includes minting. + * And also called before burning one token. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _beforeTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Hook that is called after a set of serially-ordered token ids have been transferred. This includes + * minting. + * And also called after one token has been burned. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been + * transferred to `to`. + * - When `from` is zero, `tokenId` has been minted for `to`. + * - When `to` is zero, `tokenId` has been burned by `from`. + * - `from` and `to` are never both zero. + */ + function _afterTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/structs/EnumerableSet.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Library for managing + * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive + * types. + * + * Sets have the following properties: + * + * - Elements are added, removed, and checked for existence in constant time + * (O(1)). + * - Elements are enumerated in O(n). No guarantees are made on the ordering. + * + * ``` + * contract Example { + * // Add the library methods + * using EnumerableSet for EnumerableSet.AddressSet; + * + * // Declare a set state variable + * EnumerableSet.AddressSet private mySet; + * } + * ``` + * + * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) + * and `uint256` (`UintSet`) are supported. + */ +library EnumerableSet { + // To implement this library for multiple types with as little code + // repetition as possible, we write it in terms of a generic Set type with + // bytes32 values. + // The Set implementation uses private functions, and user-facing + // implementations (such as AddressSet) are just wrappers around the + // underlying Set. + // This means that we can only create new EnumerableSets for types that fit + // in bytes32. + + struct Set { + // Storage of set values + bytes32[] _values; + // Position of the value in the `values` array, plus 1 because index 0 + // means a value is not in the set. + mapping(bytes32 => uint256) _indexes; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function _add(Set storage set, bytes32 value) private returns (bool) { + if (!_contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + set._indexes[value] = set._values.length; + return true; + } else { + return false; + } + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function _remove(Set storage set, bytes32 value) private returns (bool) { + // We read and store the value's index to prevent multiple reads from the same storage slot + uint256 valueIndex = set._indexes[value]; + + if (valueIndex != 0) { + // Equivalent to contains(set, value) + // To delete an element from the _values array in O(1), we swap the element to delete with the last one in + // the array, and then remove the last element (sometimes called as 'swap and pop'). + // This modifies the order of the array, as noted in {at}. + + uint256 toDeleteIndex = valueIndex - 1; + uint256 lastIndex = set._values.length - 1; + + if (lastIndex != toDeleteIndex) { + bytes32 lastvalue = set._values[lastIndex]; + + // Move the last value to the index where the value to delete is + set._values[toDeleteIndex] = lastvalue; + // Update the index for the moved value + set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex + } + + // Delete the slot where the moved value was stored + set._values.pop(); + + // Delete the index for the deleted slot + delete set._indexes[value]; + + return true; + } else { + return false; + } + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function _contains(Set storage set, bytes32 value) private view returns (bool) { + return set._indexes[value] != 0; + } + + /** + * @dev Returns the number of values on the set. O(1). + */ + function _length(Set storage set) private view returns (uint256) { + return set._values.length; + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function _at(Set storage set, uint256 index) private view returns (bytes32) { + return set._values[index]; + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function _values(Set storage set) private view returns (bytes32[] memory) { + return set._values; + } + + // Bytes32Set + + struct Bytes32Set { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _add(set._inner, value); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _remove(set._inner, value); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { + return _contains(set._inner, value); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(Bytes32Set storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { + return _at(set._inner, index); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { + return _values(set._inner); + } + + // AddressSet + + struct AddressSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(AddressSet storage set, address value) internal returns (bool) { + return _add(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(AddressSet storage set, address value) internal returns (bool) { + return _remove(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(AddressSet storage set, address value) internal view returns (bool) { + return _contains(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(AddressSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(AddressSet storage set, uint256 index) internal view returns (address) { + return address(uint160(uint256(_at(set._inner, index)))); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(AddressSet storage set) internal view returns (address[] memory) { + bytes32[] memory store = _values(set._inner); + address[] memory result; + + assembly { + result := store + } + + return result; + } + + // UintSet + + struct UintSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(UintSet storage set, uint256 value) internal returns (bool) { + return _add(set._inner, bytes32(value)); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(UintSet storage set, uint256 value) internal returns (bool) { + return _remove(set._inner, bytes32(value)); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(UintSet storage set, uint256 value) internal view returns (bool) { + return _contains(set._inner, bytes32(value)); + } + + /** + * @dev Returns the number of values on the set. O(1). + */ + function length(UintSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintSet storage set, uint256 index) internal view returns (uint256) { + return uint256(_at(set._inner, index)); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(UintSet storage set) internal view returns (uint256[] memory) { + bytes32[] memory store = _values(set._inner); + uint256[] memory result; + + assembly { + result := store + } + + return result; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/structs/BitMaps.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/structs/BitMaps.sol) +pragma solidity ^0.8.0; + +/** + * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential. + * Largelly inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor]. + */ +library BitMaps { + struct BitMap { + mapping(uint256 => uint256) _data; + } + + /** + * @dev Returns whether the bit at `index` is set. + */ + function get(BitMap storage bitmap, uint256 index) internal view returns (bool) { + uint256 bucket = index >> 8; + uint256 mask = 1 << (index & 0xff); + return bitmap._data[bucket] & mask != 0; + } + + /** + * @dev Sets the bit at `index` to the boolean `value`. + */ + function setTo( + BitMap storage bitmap, + uint256 index, + bool value + ) internal { + if (value) { + set(bitmap, index); + } else { + unset(bitmap, index); + } + } + + /** + * @dev Sets the bit at `index`. + */ + function set(BitMap storage bitmap, uint256 index) internal { + uint256 bucket = index >> 8; + uint256 mask = 1 << (index & 0xff); + bitmap._data[bucket] |= mask; + } + + /** + * @dev Unsets the bit at `index`. + */ + function unset(BitMap storage bitmap, uint256 index) internal { + uint256 bucket = index >> 8; + uint256 mask = 1 << (index & 0xff); + bitmap._data[bucket] &= ~mask; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/math/Math.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (utils/math/Math.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Standard math utilities missing in the Solidity language. + */ +library Math { + /** + * @dev Returns the largest of two numbers. + */ + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return a >= b ? a : b; + } + + /** + * @dev Returns the smallest of two numbers. + */ + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two numbers. The result is rounded towards + * zero. + */ + function average(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b) / 2 can overflow. + return (a & b) + (a ^ b) / 2; + } + + /** + * @dev Returns the ceiling of the division of two numbers. + * + * This differs from standard division with `/` in that it rounds up instead + * of rounding down. + */ + function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b - 1) / b can overflow on addition, so we distribute. + return a / b + (a % b == 0 ? 0 : 1); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/introspection/IERC165.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/introspection/ERC165.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/cryptography/ECDSA.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol) + +pragma solidity ^0.8.0; + +import "../Strings.sol"; + +/** + * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. + * + * These functions can be used to verify that a message was signed by the holder + * of the private keys of a given address. + */ +library ECDSA { + enum RecoverError { + NoError, + InvalidSignature, + InvalidSignatureLength, + InvalidSignatureS, + InvalidSignatureV + } + + function _throwError(RecoverError error) private pure { + if (error == RecoverError.NoError) { + return; // no error: do nothing + } else if (error == RecoverError.InvalidSignature) { + revert("ECDSA: invalid signature"); + } else if (error == RecoverError.InvalidSignatureLength) { + revert("ECDSA: invalid signature length"); + } else if (error == RecoverError.InvalidSignatureS) { + revert("ECDSA: invalid signature 's' value"); + } else if (error == RecoverError.InvalidSignatureV) { + revert("ECDSA: invalid signature 'v' value"); + } + } + + /** + * @dev Returns the address that signed a hashed message (`hash`) with + * `signature` or error string. This address can then be used for verification purposes. + * + * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: + * this function rejects them by requiring the `s` value to be in the lower + * half order, and the `v` value to be either 27 or 28. + * + * IMPORTANT: `hash` _must_ be the result of a hash operation for the + * verification to be secure: it is possible to craft signatures that + * recover to arbitrary addresses for non-hashed data. A safe way to ensure + * this is by receiving a hash of the original message (which may otherwise + * be too long), and then calling {toEthSignedMessageHash} on it. + * + * Documentation for signature generation: + * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] + * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] + * + * _Available since v4.3._ + */ + function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { + // Check the signature length + // - case 65: r,s,v signature (standard) + // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._ + if (signature.length == 65) { + bytes32 r; + bytes32 s; + uint8 v; + // ecrecover takes the signature parameters, and the only way to get them + // currently is to use assembly. + assembly { + r := mload(add(signature, 0x20)) + s := mload(add(signature, 0x40)) + v := byte(0, mload(add(signature, 0x60))) + } + return tryRecover(hash, v, r, s); + } else if (signature.length == 64) { + bytes32 r; + bytes32 vs; + // ecrecover takes the signature parameters, and the only way to get them + // currently is to use assembly. + assembly { + r := mload(add(signature, 0x20)) + vs := mload(add(signature, 0x40)) + } + return tryRecover(hash, r, vs); + } else { + return (address(0), RecoverError.InvalidSignatureLength); + } + } + + /** + * @dev Returns the address that signed a hashed message (`hash`) with + * `signature`. This address can then be used for verification purposes. + * + * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: + * this function rejects them by requiring the `s` value to be in the lower + * half order, and the `v` value to be either 27 or 28. + * + * IMPORTANT: `hash` _must_ be the result of a hash operation for the + * verification to be secure: it is possible to craft signatures that + * recover to arbitrary addresses for non-hashed data. A safe way to ensure + * this is by receiving a hash of the original message (which may otherwise + * be too long), and then calling {toEthSignedMessageHash} on it. + */ + function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { + (address recovered, RecoverError error) = tryRecover(hash, signature); + _throwError(error); + return recovered; + } + + /** + * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. + * + * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] + * + * _Available since v4.3._ + */ + function tryRecover( + bytes32 hash, + bytes32 r, + bytes32 vs + ) internal pure returns (address, RecoverError) { + bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + uint8 v = uint8((uint256(vs) >> 255) + 27); + return tryRecover(hash, v, r, s); + } + + /** + * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. + * + * _Available since v4.2._ + */ + function recover( + bytes32 hash, + bytes32 r, + bytes32 vs + ) internal pure returns (address) { + (address recovered, RecoverError error) = tryRecover(hash, r, vs); + _throwError(error); + return recovered; + } + + /** + * @dev Overload of {ECDSA-tryRecover} that receives the `v`, + * `r` and `s` signature fields separately. + * + * _Available since v4.3._ + */ + function tryRecover( + bytes32 hash, + uint8 v, + bytes32 r, + bytes32 s + ) internal pure returns (address, RecoverError) { + // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature + // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines + // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most + // signatures from current libraries generate a unique signature with an s-value in the lower half order. + // + // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value + // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or + // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept + // these malleable signatures as well. + if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { + return (address(0), RecoverError.InvalidSignatureS); + } + if (v != 27 && v != 28) { + return (address(0), RecoverError.InvalidSignatureV); + } + + // If the signature is valid (and not malleable), return the signer address + address signer = ecrecover(hash, v, r, s); + if (signer == address(0)) { + return (address(0), RecoverError.InvalidSignature); + } + + return (signer, RecoverError.NoError); + } + + /** + * @dev Overload of {ECDSA-recover} that receives the `v`, + * `r` and `s` signature fields separately. + */ + function recover( + bytes32 hash, + uint8 v, + bytes32 r, + bytes32 s + ) internal pure returns (address) { + (address recovered, RecoverError error) = tryRecover(hash, v, r, s); + _throwError(error); + return recovered; + } + + /** + * @dev Returns an Ethereum Signed Message, created from a `hash`. This + * produces hash corresponding to the one signed with the + * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] + * JSON-RPC method as part of EIP-191. + * + * See {recover}. + */ + function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { + // 32 is the length in bytes of hash, + // enforced by the type signature above + return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); + } + + /** + * @dev Returns an Ethereum Signed Message, created from `s`. This + * produces hash corresponding to the one signed with the + * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] + * JSON-RPC method as part of EIP-191. + * + * See {recover}. + */ + function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { + return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); + } + + /** + * @dev Returns an Ethereum Signed Typed Data, created from a + * `domainSeparator` and a `structHash`. This produces hash corresponding + * to the one signed with the + * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] + * JSON-RPC method as part of EIP-712. + * + * See {recover}. + */ + function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { + return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Strings.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol) + +pragma solidity ^0.8.0; + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + // Inspired by OraclizeAPI's implementation - MIT licence + // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol + + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + while (value != 0) { + digits -= 1; + buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); + value /= 10; + } + return string(buffer); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + if (value == 0) { + return "0x00"; + } + uint256 temp = value; + uint256 length = 0; + while (temp != 0) { + length++; + temp >>= 8; + } + return toHexString(value, length); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _HEX_SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) + +pragma solidity ^0.8.1; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + * + * [IMPORTANT] + * ==== + * You shouldn't rely on `isContract` to protect against flash loan attacks! + * + * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets + * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract + * constructor. + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize/address.code.length, which returns 0 + // for contracts in construction, since the code is only stored at the end + // of the constructor execution. + + return account.code.length > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/common/ERC2981.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/common/ERC2981.sol) + +pragma solidity ^0.8.0; + +import "../../interfaces/IERC2981.sol"; +import "../../utils/introspection/ERC165.sol"; + +/** + * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information. + * + * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for + * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first. + * + * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the + * fee is specified in basis points by default. + * + * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See + * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to + * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. + * + * _Available since v4.5._ + */ +abstract contract ERC2981 is IERC2981, ERC165 { + struct RoyaltyInfo { + address receiver; + uint96 royaltyFraction; + } + + RoyaltyInfo private _defaultRoyaltyInfo; + mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { + return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @inheritdoc IERC2981 + */ + function royaltyInfo(uint256 _tokenId, uint256 _salePrice) + external + view + virtual + override + returns (address, uint256) + { + RoyaltyInfo memory royalty = _tokenRoyaltyInfo[_tokenId]; + + if (royalty.receiver == address(0)) { + royalty = _defaultRoyaltyInfo; + } + + uint256 royaltyAmount = (_salePrice * royalty.royaltyFraction) / _feeDenominator(); + + return (royalty.receiver, royaltyAmount); + } + + /** + * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a + * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an + * override. + */ + function _feeDenominator() internal pure virtual returns (uint96) { + return 10000; + } + + /** + * @dev Sets the royalty information that all ids in this contract will default to. + * + * Requirements: + * + * - `receiver` cannot be the zero address. + * - `feeNumerator` cannot be greater than the fee denominator. + */ + function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual { + require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice"); + require(receiver != address(0), "ERC2981: invalid receiver"); + + _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator); + } + + /** + * @dev Removes default royalty information. + */ + function _deleteDefaultRoyalty() internal virtual { + delete _defaultRoyaltyInfo; + } + + /** + * @dev Sets the royalty information for a specific token id, overriding the global default. + * + * Requirements: + * + * - `tokenId` must be already minted. + * - `receiver` cannot be the zero address. + * - `feeNumerator` cannot be greater than the fee denominator. + */ + function _setTokenRoyalty( + uint256 tokenId, + address receiver, + uint96 feeNumerator + ) internal virtual { + require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice"); + require(receiver != address(0), "ERC2981: Invalid parameters"); + + _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator); + } + + /** + * @dev Resets royalty information for the token id back to the global default. + */ + function _resetTokenRoyalty(uint256 tokenId) internal virtual { + delete _tokenRoyaltyInfo[tokenId]; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol) + +pragma solidity ^0.8.0; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. + */ + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/IERC721.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol) + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external; +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/security/ReentrancyGuard.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor() { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and making it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/security/Pausable.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol) + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +/** + * @dev Contract module which allows children to implement an emergency stop + * mechanism that can be triggered by an authorized account. + * + * This module is used through inheritance. It will make available the + * modifiers `whenNotPaused` and `whenPaused`, which can be applied to + * the functions of your contract. Note that they will not be pausable by + * simply including this module, only once the modifiers are put in place. + */ +abstract contract Pausable is Context { + /** + * @dev Emitted when the pause is triggered by `account`. + */ + event Paused(address account); + + /** + * @dev Emitted when the pause is lifted by `account`. + */ + event Unpaused(address account); + + bool private _paused; + + /** + * @dev Initializes the contract in unpaused state. + */ + constructor() { + _paused = false; + } + + /** + * @dev Returns true if the contract is paused, and false otherwise. + */ + function paused() public view virtual returns (bool) { + return _paused; + } + + /** + * @dev Modifier to make a function callable only when the contract is not paused. + * + * Requirements: + * + * - The contract must not be paused. + */ + modifier whenNotPaused() { + require(!paused(), "Pausable: paused"); + _; + } + + /** + * @dev Modifier to make a function callable only when the contract is paused. + * + * Requirements: + * + * - The contract must be paused. + */ + modifier whenPaused() { + require(paused(), "Pausable: not paused"); + _; + } + + /** + * @dev Triggers stopped state. + * + * Requirements: + * + * - The contract must not be paused. + */ + function _pause() internal virtual whenNotPaused { + _paused = true; + emit Paused(_msgSender()); + } + + /** + * @dev Returns to normal state. + * + * Requirements: + * + * - The contract must be paused. + */ + function _unpause() internal virtual whenPaused { + _paused = false; + emit Unpaused(_msgSender()); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/interfaces/IERC721.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC721/IERC721.sol"; + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/interfaces/IERC2981.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/IERC2981.sol) + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + * + * _Available since v4.5._ + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be payed in that same unit of exchange. + */ + function royaltyInfo(uint256 tokenId, uint256 salePrice) + external + view + returns (address receiver, uint256 royaltyAmount); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/interfaces/IERC165.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) + +pragma solidity ^0.8.0; + +import "../utils/introspection/IERC165.sol"; + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/access/Ownable.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor() { + _transferOwnership(_msgSender()); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/access/IAccessControlEnumerable.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol) + +pragma solidity ^0.8.0; + +import "./IAccessControl.sol"; + +/** + * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. + */ +interface IAccessControlEnumerable is IAccessControl { + /** + * @dev Returns one of the accounts that have `role`. `index` must be a + * value between 0 and {getRoleMemberCount}, non-inclusive. + * + * Role bearers are not sorted in any particular way, and their ordering may + * change at any point. + * + * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure + * you perform all queries on the same block. See the following + * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] + * for more information. + */ + function getRoleMember(bytes32 role, uint256 index) external view returns (address); + + /** + * @dev Returns the number of accounts that have `role`. Can be used + * together with {getRoleMember} to enumerate all bearers of a role. + */ + function getRoleMemberCount(bytes32 role) external view returns (uint256); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/access/IAccessControl.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + +pragma solidity ^0.8.0; + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/access/AccessControlEnumerable.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol) + +pragma solidity ^0.8.0; + +import "./IAccessControlEnumerable.sol"; +import "./AccessControl.sol"; +import "../utils/structs/EnumerableSet.sol"; + +/** + * @dev Extension of {AccessControl} that allows enumerating the members of each role. + */ +abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl { + using EnumerableSet for EnumerableSet.AddressSet; + + mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns one of the accounts that have `role`. `index` must be a + * value between 0 and {getRoleMemberCount}, non-inclusive. + * + * Role bearers are not sorted in any particular way, and their ordering may + * change at any point. + * + * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure + * you perform all queries on the same block. See the following + * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] + * for more information. + */ + function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) { + return _roleMembers[role].at(index); + } + + /** + * @dev Returns the number of accounts that have `role`. Can be used + * together with {getRoleMember} to enumerate all bearers of a role. + */ + function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) { + return _roleMembers[role].length(); + } + + /** + * @dev Overload {_grantRole} to track enumerable memberships + */ + function _grantRole(bytes32 role, address account) internal virtual override { + super._grantRole(role, account); + _roleMembers[role].add(account); + } + + /** + * @dev Overload {_revokeRole} to track enumerable memberships + */ + function _revokeRole(bytes32 role, address account) internal virtual override { + super._revokeRole(role, account); + _roleMembers[role].remove(account); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/access/AccessControl.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControl.sol) + +pragma solidity ^0.8.0; + +import "./IAccessControl.sol"; +import "../utils/Context.sol"; +import "../utils/Strings.sol"; +import "../utils/introspection/ERC165.sol"; + +/** + * @dev Contract module that allows children to implement role-based access + * control mechanisms. This is a lightweight version that doesn't allow enumerating role + * members except through off-chain means by accessing the contract event logs. Some + * applications may benefit from on-chain enumerability, for those cases see + * {AccessControlEnumerable}. + * + * Roles are referred to by their `bytes32` identifier. These should be exposed + * in the external API and be unique. The best way to achieve this is by + * using `public constant` hash digests: + * + * ``` + * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); + * ``` + * + * Roles can be used to represent a set of permissions. To restrict access to a + * function call, use {hasRole}: + * + * ``` + * function foo() public { + * require(hasRole(MY_ROLE, msg.sender)); + * ... + * } + * ``` + * + * Roles can be granted and revoked dynamically via the {grantRole} and + * {revokeRole} functions. Each role has an associated admin role, and only + * accounts that have a role's admin role can call {grantRole} and {revokeRole}. + * + * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means + * that only accounts with this role will be able to grant or revoke other + * roles. More complex role relationships can be created by using + * {_setRoleAdmin}. + * + * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to + * grant and revoke this role. Extra precautions should be taken to secure + * accounts that have been granted it. + */ +abstract contract AccessControl is Context, IAccessControl, ERC165 { + struct RoleData { + mapping(address => bool) members; + bytes32 adminRole; + } + + mapping(bytes32 => RoleData) private _roles; + + bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; + + /** + * @dev Modifier that checks that an account has a specific role. Reverts + * with a standardized message including the required role. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + * + * _Available since v4.1._ + */ + modifier onlyRole(bytes32 role) { + _checkRole(role, _msgSender()); + _; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) public view virtual override returns (bool) { + return _roles[role].members[account]; + } + + /** + * @dev Revert with a standard message if `account` is missing `role`. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + */ + function _checkRole(bytes32 role, address account) internal view virtual { + if (!hasRole(role, account)) { + revert( + string( + abi.encodePacked( + "AccessControl: account ", + Strings.toHexString(uint160(account), 20), + " is missing role ", + Strings.toHexString(uint256(role), 32) + ) + ) + ); + } + } + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { + return _roles[role].adminRole; + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _grantRole(role, account); + } + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _revokeRole(role, account); + } + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been revoked `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) public virtual override { + require(account == _msgSender(), "AccessControl: can only renounce roles for self"); + + _revokeRole(role, account); + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. Note that unlike {grantRole}, this function doesn't perform any + * checks on the calling account. + * + * [WARNING] + * ==== + * This function should only be called from the constructor when setting + * up the initial roles for the system. + * + * Using this function in any other way is effectively circumventing the admin + * system imposed by {AccessControl}. + * ==== + * + * NOTE: This function is deprecated in favor of {_grantRole}. + */ + function _setupRole(bytes32 role, address account) internal virtual { + _grantRole(role, account); + } + + /** + * @dev Sets `adminRole` as ``role``'s admin role. + * + * Emits a {RoleAdminChanged} event. + */ + function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { + bytes32 previousAdminRole = getRoleAdmin(role); + _roles[role].adminRole = adminRole; + emit RoleAdminChanged(role, previousAdminRole, adminRole); + } + + /** + * @dev Grants `role` to `account`. + * + * Internal function without access restriction. + */ + function _grantRole(bytes32 role, address account) internal virtual { + if (!hasRole(role, account)) { + _roles[role].members[account] = true; + emit RoleGranted(role, account, _msgSender()); + } + } + + /** + * @dev Revokes `role` from `account`. + * + * Internal function without access restriction. + */ + function _revokeRole(bytes32 role, address account) internal virtual { + if (hasRole(role, account)) { + _roles[role].members[account] = false; + emit RoleRevoked(role, account, _msgSender()); + } + } +} + + +/////////////////////////////////////////// +// File: @divergencetech/ethier/contracts/utils/OwnerPausable.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) +pragma solidity >=0.8.0 <0.9.0; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/security/Pausable.sol"; + +/// @notice A Pausable contract that can only be toggled by the Owner. +contract OwnerPausable is Ownable, Pausable { + /// @notice Pauses the contract. + function pause() public onlyOwner { + Pausable._pause(); + } + + /// @notice Unpauses the contract. + function unpause() public onlyOwner { + Pausable._unpause(); + } +} + + +/////////////////////////////////////////// +// File: @divergencetech/ethier/contracts/utils/Monotonic.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) +pragma solidity >=0.8.0 <0.9.0; + +/** +@notice Provides monotonic increasing and decreasing values, similar to +OpenZeppelin's Counter but (a) limited in direction, and (b) allowing for steps +> 1. + */ +library Monotonic { + /** + @notice Holds a value that can only increase. + @dev The internal value MUST NOT be accessed directly. Instead use current() + and add(). + */ + struct Increaser { + uint256 value; + } + + /// @notice Returns the current value of the Increaser. + function current(Increaser storage incr) internal view returns (uint256) { + return incr.value; + } + + /// @notice Adds x to the Increaser's value. + function add(Increaser storage incr, uint256 x) internal { + incr.value += x; + } + + /** + @notice Holds a value that can only decrease. + @dev The internal value MUST NOT be accessed directly. Instead use current() + and subtract(). + */ + struct Decreaser { + uint256 value; + } + + /// @notice Returns the current value of the Decreaser. + function current(Decreaser storage decr) internal view returns (uint256) { + return decr.value; + } + + /// @notice Subtracts x from the Decreaser's value. + function subtract(Decreaser storage decr, uint256 x) internal { + decr.value -= x; + } +} + + +/////////////////////////////////////////// +// File: @divergencetech/ethier/contracts/thirdparty/opensea/ProxyRegistry.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) +pragma solidity >=0.8.0 <0.9.0; + +/// @notice A minimal interface describing OpenSea's Wyvern proxy registry. +contract ProxyRegistry { + mapping(address => OwnableDelegateProxy) public proxies; +} + +/** +@dev This pattern of using an empty contract is cargo-culted directly from +OpenSea's example code. TODO: it's likely that the above mapping can be changed +to address => address without affecting anything, but further investigation is +needed (i.e. is there a subtle reason that OpenSea released it like this?). + */ +// solhint-disable-next-line no-empty-blocks +contract OwnableDelegateProxy { + +} + + +/////////////////////////////////////////// +// File: @divergencetech/ethier/contracts/thirdparty/opensea/OpenSeaGasFreeListing.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) +pragma solidity >=0.8.0 <0.9.0; + +// Inspired by BaseOpenSea by Simon Fremaux (@dievardump) but without the need +// to pass specific addresses depending on deployment network. +// https://gist.github.com/dievardump/483eb43bc6ed30b14f01e01842e3339b/ + +import "./ProxyRegistry.sol"; + +/// @notice Library to achieve gas-free listings on OpenSea. +library OpenSeaGasFreeListing { + /** + @notice Returns whether the operator is an OpenSea proxy for the owner, thus + allowing it to list without the token owner paying gas. + @dev ERC{721,1155}.isApprovedForAll should be overriden to also check if + this function returns true. + */ + function isApprovedForAll(address owner, address operator) + internal + view + returns (bool) + { + address proxy = proxyFor(owner); + return proxy != address(0) && proxy == operator; + } + + /** + @notice Returns the OpenSea proxy address for the owner. + */ + function proxyFor(address owner) internal view returns (address) { + address registry; + uint256 chainId; + + assembly { + chainId := chainid() + switch chainId + // Production networks are placed higher to minimise the number of + // checks performed and therefore reduce gas. By the same rationale, + // mainnet comes before Polygon as it's more expensive. + case 1 { + // mainnet + registry := 0xa5409ec958c83c3f309868babaca7c86dcb077c1 + } + case 137 { + // polygon + registry := 0x58807baD0B376efc12F5AD86aAc70E78ed67deaE + } + case 4 { + // rinkeby + registry := 0xf57b2c51ded3a29e6891aba85459d600256cf317 + } + case 80001 { + // mumbai + registry := 0xff7Ca10aF37178BdD056628eF42fD7F799fAc77c + } + case 1337 { + // The geth SimulatedBackend iff used with the ethier + // openseatest package. This is mocked as a Wyvern proxy as it's + // more complex than the 0x ones. + registry := 0xE1a2bbc877b29ADBC56D2659DBcb0ae14ee62071 + } + } + + // Unlike Wyvern, the registry itself is the proxy for all owners on 0x + // chains. + if (registry == address(0) || chainId == 137 || chainId == 80001) { + return registry; + } + + return address(ProxyRegistry(registry).proxies(owner)); + } +} + + +/////////////////////////////////////////// +// File: @divergencetech/ethier/contracts/sales/Seller.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) +pragma solidity >=0.8.0 <0.9.0; + +import "../utils/Monotonic.sol"; +import "../utils/OwnerPausable.sol"; +import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; +import "@openzeppelin/contracts/utils/Context.sol"; +import "@openzeppelin/contracts/utils/math/Math.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; + +/** +@notice An abstract contract providing the _purchase() function to: + - Enforce per-wallet / per-transaction limits + - Calculate required cost, forwarding to a beneficiary, and refunding extra + */ +abstract contract Seller is OwnerPausable, ReentrancyGuard { + using Address for address payable; + using Monotonic for Monotonic.Increaser; + using Strings for uint256; + + /** + @dev Note that the address limits are vulnerable to wallet farming. + @param maxPerAddress Unlimited if zero. + @param maxPerTex Unlimited if zero. + @param freeQuota Maximum number that can be purchased free of charge by + the contract owner. + @param reserveFreeQuota Whether to excplitly reserve the freeQuota amount + and not let it be eroded by regular purchases. + @param lockFreeQuota If true, calls to setSellerConfig() will ignore changes + to freeQuota. Can be locked after initial setting, but not unlocked. This + allows a contract owner to commit to a maximum number of reserved items. + @param lockTotalInventory Similar to lockFreeQuota but applied to + totalInventory. + */ + struct SellerConfig { + uint256 totalInventory; + uint256 maxPerAddress; + uint256 maxPerTx; + uint248 freeQuota; + bool reserveFreeQuota; + bool lockFreeQuota; + bool lockTotalInventory; + } + + constructor(SellerConfig memory config, address payable _beneficiary) { + setSellerConfig(config); + setBeneficiary(_beneficiary); + } + + /// @notice Configuration of purchase limits. + SellerConfig public sellerConfig; + + /// @notice Sets the seller config. + function setSellerConfig(SellerConfig memory config) public onlyOwner { + require( + config.totalInventory >= config.freeQuota, + "Seller: excessive free quota" + ); + require( + config.totalInventory >= _totalSold.current(), + "Seller: inventory < already sold" + ); + require( + config.freeQuota >= purchasedFreeOfCharge.current(), + "Seller: free quota < already used" + ); + + // Overriding the in-memory fields before copying the whole struct, as + // against writing individual fields, gives a greater guarantee of + // correctness as the code is simpler to read. + if (sellerConfig.lockTotalInventory) { + config.lockTotalInventory = true; + config.totalInventory = sellerConfig.totalInventory; + } + if (sellerConfig.lockFreeQuota) { + config.lockFreeQuota = true; + config.freeQuota = sellerConfig.freeQuota; + } + sellerConfig = config; + } + + /// @notice Recipient of revenues. + address payable public beneficiary; + + /// @notice Sets the recipient of revenues. + function setBeneficiary(address payable _beneficiary) public onlyOwner { + beneficiary = _beneficiary; + } + + /** + @dev Must return the current cost of a batch of items. This may be constant + or, for example, decreasing for a Dutch auction or increasing for a bonding + curve. + @param n The number of items being purchased. + @param metadata Arbitrary data, propagated by the call to _purchase() that + can be used to charge different prices. This value is a uint256 instead of + bytes as this allows simple passing of a set cost (see + ArbitraryPriceSeller). + */ + function cost(uint256 n, uint256 metadata) + public + view + virtual + returns (uint256); + + /** + @dev Called by both _purchase() and purchaseFreeOfCharge() after all limits + have been put in place; must perform all contract-specific sale logic, e.g. + ERC721 minting. When _handlePurchase() is called, the value returned by + Seller.totalSold() will be the pre-purchase amount. + @param to The recipient of the item(s). + @param n The number of items allowed to be purchased, which MAY be less than + to the number passed to _purchase() but SHALL be greater than zero. + @param freeOfCharge Indicates that the call originated from + purchaseFreeOfCharge() and not _purchase(). + */ + function _handlePurchase( + address to, + uint256 n, + bool freeOfCharge + ) internal virtual; + + /** + @notice Tracks total number of items sold by this contract, including those + purchased free of charge by the contract owner. + */ + Monotonic.Increaser private _totalSold; + + /// @notice Returns the total number of items sold by this contract. + function totalSold() public view returns (uint256) { + return _totalSold.current(); + } + + /** + @notice Tracks the number of items already bought by an address, regardless + of transferring out (in the case of ERC721). + @dev This isn't public as it may be skewed due to differences in msg.sender + and tx.origin, which it treats in the same way such that + sum(_bought)>=totalSold(). + */ + mapping(address => uint256) private _bought; + + /** + @notice Returns min(n, max(extra items addr can purchase)) and reverts if 0. + @param zeroMsg The message with which to revert on 0 extra. + */ + function _capExtra( + uint256 n, + address addr, + string memory zeroMsg + ) internal view returns (uint256) { + uint256 extra = sellerConfig.maxPerAddress - _bought[addr]; + if (extra == 0) { + revert(string(abi.encodePacked("Seller: ", zeroMsg))); + } + return Math.min(n, extra); + } + + /// @notice Emitted when a buyer is refunded. + event Refund(address indexed buyer, uint256 amount); + + /// @notice Emitted on all purchases of non-zero amount. + event Revenue( + address indexed beneficiary, + uint256 numPurchased, + uint256 amount + ); + + /// @notice Tracks number of items purchased free of charge. + Monotonic.Increaser private purchasedFreeOfCharge; + + /** + @notice Allows the contract owner to purchase without payment, within the + quota enforced by the SellerConfig. + */ + function purchaseFreeOfCharge(address to, uint256 n) + public + onlyOwner + whenNotPaused + { + uint256 freeQuota = sellerConfig.freeQuota; + n = Math.min(n, freeQuota - purchasedFreeOfCharge.current()); + require(n > 0, "Seller: Free quota exceeded"); + + uint256 totalInventory = sellerConfig.totalInventory; + n = Math.min(n, totalInventory - _totalSold.current()); + require(n > 0, "Seller: Sold out"); + + _handlePurchase(to, n, true); + + _totalSold.add(n); + purchasedFreeOfCharge.add(n); + assert(_totalSold.current() <= totalInventory); + assert(purchasedFreeOfCharge.current() <= freeQuota); + } + + /** + @notice Convenience function for calling _purchase() with empty costMetadata + when unneeded. + */ + function _purchase(address to, uint256 requested) internal virtual { + _purchase(to, requested, 0); + } + + /** + @notice Enforces all purchase limits (counts and costs) before calling + _handlePurchase(), after which the received funds are disbursed to the + beneficiary, less any required refunds. + @param to The final recipient of the item(s). + @param requested The number of items requested for purchase, which MAY be + reduced when passed to _handlePurchase(). + @param costMetadata Arbitrary data, propagated in the call to cost(), to be + optionally used in determining the price. + */ + function _purchase( + address to, + uint256 requested, + uint256 costMetadata + ) internal nonReentrant whenNotPaused { + /** + * ##### CHECKS + */ + SellerConfig memory config = sellerConfig; + + uint256 n = config.maxPerTx == 0 + ? requested + : Math.min(requested, config.maxPerTx); + + uint256 maxAvailable; + uint256 sold; + + if (config.reserveFreeQuota) { + maxAvailable = config.totalInventory - config.freeQuota; + sold = _totalSold.current() - purchasedFreeOfCharge.current(); + } else { + maxAvailable = config.totalInventory; + sold = _totalSold.current(); + } + + n = Math.min(n, maxAvailable - sold); + require(n > 0, "Seller: Sold out"); + + if (config.maxPerAddress > 0) { + bool alsoLimitSender = _msgSender() != to; + // solhint-disable-next-line avoid-tx-origin + bool alsoLimitOrigin = tx.origin != _msgSender() && tx.origin != to; + + n = _capExtra(n, to, "Buyer limit"); + if (alsoLimitSender) { + n = _capExtra(n, _msgSender(), "Sender limit"); + } + if (alsoLimitOrigin) { + // solhint-disable-next-line avoid-tx-origin + n = _capExtra(n, tx.origin, "Origin limit"); + } + + _bought[to] += n; + if (alsoLimitSender) { + _bought[_msgSender()] += n; + } + if (alsoLimitOrigin) { + // solhint-disable-next-line avoid-tx-origin + _bought[tx.origin] += n; + } + } + + uint256 _cost = cost(n, costMetadata); + if (msg.value < _cost) { + revert( + string( + abi.encodePacked( + "Seller: Costs ", + (_cost / 1e9).toString(), + " GWei" + ) + ) + ); + } + + /** + * ##### EFFECTS + */ + + _handlePurchase(to, n, false); + _totalSold.add(n); + assert(_totalSold.current() <= config.totalInventory); + + /** + * ##### INTERACTIONS + */ + + // Ideally we'd be using a PullPayment here, but the user experience is + // poor when there's a variable cost or the number of items purchased + // has been capped. We've addressed reentrancy with both a nonReentrant + // modifier and the checks, effects, interactions pattern. + + if (_cost > 0) { + beneficiary.sendValue(_cost); + emit Revenue(beneficiary, n, _cost); + } + + if (msg.value > _cost) { + address payable reimburse = payable(_msgSender()); + uint256 refund = msg.value - _cost; + + // Using Address.sendValue() here would mask the revertMsg upon + // reentrancy, but we want to expose it to allow for more precise + // testing. This otherwise uses the exact same pattern as + // Address.sendValue(). + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returnData) = reimburse.call{ + value: refund + }(""); + // Although `returnData` will have a spurious prefix, all we really + // care about is that it contains the ReentrancyGuard reversion + // message so we can check in the tests. + require(success, string(returnData)); + + emit Refund(reimburse, refund); + } + } +} + + +/////////////////////////////////////////// +// File: @divergencetech/ethier/contracts/sales/FixedPriceSeller.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) +pragma solidity >=0.8.0 <0.9.0; + +import "./Seller.sol"; + +/// @notice A Seller with fixed per-item price. +abstract contract FixedPriceSeller is Seller { + constructor( + uint256 _price, + Seller.SellerConfig memory sellerConfig, + address payable _beneficiary + ) Seller(sellerConfig, _beneficiary) { + setPrice(_price); + } + + /** + @notice The fixed per-item price. + @dev Fixed as in not changing with time nor number of items, but not a + constant. + */ + uint256 public price; + + /// @notice Sets the per-item price. + function setPrice(uint256 _price) public onlyOwner { + price = _price; + } + + /** + @notice Override of Seller.cost() with fixed price. + @dev The second parameter, metadata propagated from the call to _purchase(), + is ignored. + */ + function cost(uint256 n, uint256) public view override returns (uint256) { + return n * price; + } +} + + +/////////////////////////////////////////// +// File: @divergencetech/ethier/contracts/erc721/ERC721Redeemer.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2022 the ethier authors (github.com/divergencetech/ethier) +pragma solidity >=0.8.0 <0.9.0; + +import "@openzeppelin/contracts/interfaces/IERC721.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; +import "@openzeppelin/contracts/utils/structs/BitMaps.sol"; + +/** +@notice Allows holders of ERC721 tokens to redeem rights to some claim; for +example, the right to mint a token of some other collection. +*/ +library ERC721Redeemer { + using BitMaps for BitMaps.BitMap; + using Strings for uint256; + + /** + @notice Storage value to track already-claimed redemptions for a specific + token collection. + */ + struct Claims { + /** + @dev This field MUST NOT be considered part of the public API. Instead, + prefer `using ERC721Redeemer for ERC721Redeemer.Claims` and utilise the + provided functions. + */ + mapping(uint256 => uint256) _total; + } + + /** + @notice Storage value to track already-claimed redemptions for a specific + token collection, given that there is only a single claim allowed per + tokenId. + */ + struct SingleClaims { + /** + @dev This field MUST NOT be considered part of the public API. Instead, + prefer `using ERC721Redeemer for ERC721Redeemer.SingleClaims` and + utilise the provided functions. + */ + BitMaps.BitMap _claimed; + } + + /** + @notice Emitted when a token's claim is redeemed. + */ + event Redemption( + IERC721 indexed token, + address indexed redeemer, + uint256 tokenId, + uint256 n + ); + + /** + @notice Checks that the redeemer is allowed to redeem the claims for the + tokenIds by being either the owner or approved address for all tokenIds, and + updates the Claims to reflect this. + @dev For more efficient gas usage, recurring values in tokenIds SHOULD be + adjacent to one another as this will batch expensive operations. The + simplest way to achieve this is by sorting tokenIds. + @param tokenIds The token IDs for which the claims are being redeemed. If + maxAllowance > 1 then identical tokenIds can be passed more than once; see + dev comments. + @return The number of redeemed claims; either 0 or tokenIds.length; + */ + function redeem( + Claims storage claims, + uint256 maxAllowance, + address redeemer, + IERC721 token, + uint256[] calldata tokenIds + ) internal returns (uint256) { + if (maxAllowance == 0 || tokenIds.length == 0) { + return 0; + } + + // See comment for `endSameId`. + bool multi = maxAllowance > 1; + + for ( + uint256 i = 0; + i < tokenIds.length; /* note increment at end */ + + ) { + uint256 tokenId = tokenIds[i]; + requireOwnerOrApproved(token, tokenId, redeemer); + + uint256 n = 1; + if (multi) { + // If allowed > 1 we can save on expensive operations like + // checking ownership / remaining allowance by batching equal + // tokenIds. The algorithm assumes that equal IDs are adjacent + // in the array. + uint256 endSameId; + for ( + endSameId = i + 1; + endSameId < tokenIds.length && + tokenIds[endSameId] == tokenId; + endSameId++ + ) {} // solhint-disable-line no-empty-blocks + n = endSameId - i; + } + + claims._total[tokenId] += n; + if (claims._total[tokenId] > maxAllowance) { + revertWithTokenId( + "ERC721Redeemer: over allowance for", + tokenId + ); + } + i += n; + + emit Redemption(token, redeemer, tokenId, n); + } + + return tokenIds.length; + } + + /** + @notice Checks that the redeemer is allowed to redeem the single claim for + each of the tokenIds by being either the owner or approved address for all + tokenIds, and updates the SingleClaims to reflect this. + @param tokenIds The token IDs for which the claims are being redeemed. Only + a single claim can be made against a tokenId. + @return The number of redeemed claims; either 0 or tokenIds.length; + */ + function redeem( + SingleClaims storage claims, + address redeemer, + IERC721 token, + uint256[] calldata tokenIds + ) internal returns (uint256) { + if (tokenIds.length == 0) { + return 0; + } + + for (uint256 i = 0; i < tokenIds.length; i++) { + uint256 tokenId = tokenIds[i]; + requireOwnerOrApproved(token, tokenId, redeemer); + + if (claims._claimed.get(tokenId)) { + revertWithTokenId( + "ERC721Redeemer: over allowance for", + tokenId + ); + } + + claims._claimed.set(tokenId); + emit Redemption(token, redeemer, tokenId, 1); + } + return tokenIds.length; + } + + /** + @dev Reverts if neither the owner nor approved for the tokenId. + */ + function requireOwnerOrApproved( + IERC721 token, + uint256 tokenId, + address redeemer + ) private view { + if ( + token.ownerOf(tokenId) != redeemer && + token.getApproved(tokenId) != redeemer + ) { + revertWithTokenId( + "ERC721Redeemer: not approved nor owner of", + tokenId + ); + } + } + + /** + @notice Reverts with the concatenation of revertMsg and tokenId.toString(). + @dev Used to save gas by constructing the revert message only as required, + instead of passing it to require(). + */ + function revertWithTokenId(string memory revertMsg, uint256 tokenId) + private + pure + { + revert(string(abi.encodePacked(revertMsg, " ", tokenId.toString()))); + } + + /** + @notice Returns the number of claimed redemptions for the token. + */ + function claimed(Claims storage claims, uint256 tokenId) + internal + view + returns (uint256) + { + return claims._total[tokenId]; + } + + /** + @notice Returns whether the token has had a claim made against it. + */ + function claimed(SingleClaims storage claims, uint256 tokenId) + internal + view + returns (bool) + { + return claims._claimed.get(tokenId); + } +} + + +/////////////////////////////////////////// +// File: @divergencetech/ethier/contracts/erc721/ERC721APreApproval.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) +pragma solidity >=0.8.0 <0.9.0; + +import "../thirdparty/opensea/OpenSeaGasFreeListing.sol"; +import "erc721a/contracts/ERC721A.sol"; + +/// @notice Pre-approval of OpenSea proxies for gas-less listing +/// @dev This wrapper allows users to revoke the pre-approval of their +/// associated proxy and emits the corresponding events. This is necessary for +/// external tools to index approvals correctly and inform the user. +/// @dev The pre-approval is triggered on a per-wallet basis during the first +/// transfer transactions. It will only be enabled for wallets with an existing +/// proxy. Not having a proxy incurs a gas overhead. +/// @dev This wrapper optimizes for the following scenario: +/// - The majority of users already have a wyvern proxy +/// - Most of them want to transfer tokens via wyvern exchanges +abstract contract ERC721APreApproval is ERC721A { + /// @dev It is important that Active remains at first position, since this + /// is the scenario that we are trying to optimize for. + enum State { + Active, + Inactive + } + + /// @notice The state of the pre-approval for a given owner + mapping(address => State) private state; + + /// @dev Returns true if either standard `isApprovedForAll()` or if the + /// `operator` is the OpenSea proxy for the `owner` provided the + /// pre-approval is active. + function isApprovedForAll(address owner, address operator) + public + view + virtual + override + returns (bool) + { + if (super.isApprovedForAll(owner, operator)) { + return true; + } + + return + state[owner] == State.Active && + OpenSeaGasFreeListing.isApprovedForAll(owner, operator); + } + + /// @dev Uses the standard `setApprovalForAll` or toggles the pre-approval + /// state if `operator` is the OpenSea proxy for the sender. + function setApprovalForAll(address operator, bool approved) + public + virtual + override + { + address owner = _msgSender(); + if (operator == OpenSeaGasFreeListing.proxyFor(owner)) { + state[owner] = approved ? State.Active : State.Inactive; + emit ApprovalForAll(owner, operator, approved); + } else { + super.setApprovalForAll(operator, approved); + } + } + + /// @dev Checks if the receiver has an existing proxy. If not, the + /// pre-approval is disabled. + function _beforeTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual override { + super._beforeTokenTransfers(from, to, startTokenId, quantity); + + // Exclude burns and inactive pre-approvals + if (to == address(0) || state[to] == State.Inactive) { + return; + } + + address operator = OpenSeaGasFreeListing.proxyFor(to); + + // Disable if `to` has no proxy + if (operator == address(0)) { + state[to] = State.Inactive; + return; + } + + // Avoid emitting unnecessary events. + if (balanceOf(to) == 0) { + emit ApprovalForAll(to, operator, true); + } + } +} + + +/////////////////////////////////////////// +// File: @divergencetech/ethier/contracts/erc721/ERC721ACommon.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2022 the ethier authors (github.com/divergencetech/ethier) +pragma solidity >=0.8.0 <0.9.0; + +import "./ERC721APreApproval.sol"; +import "../utils/OwnerPausable.sol"; + +/** +@notice An ERC721A contract with common functionality: + - OpenSea gas-free listings + - Pausable with toggling functions exposed to Owner only + */ +contract ERC721ACommon is ERC721APreApproval, OwnerPausable { + constructor(string memory name, string memory symbol) + ERC721A(name, symbol) + {} // solhint-disable-line no-empty-blocks + + /// @notice Requires that the token exists. + modifier tokenExists(uint256 tokenId) { + require(ERC721A._exists(tokenId), "ERC721ACommon: Token doesn't exist"); + _; + } + + /// @notice Requires that msg.sender owns or is approved for the token. + modifier onlyApprovedOrOwner(uint256 tokenId) { + require( + _ownershipOf(tokenId).addr == _msgSender() || + getApproved(tokenId) == _msgSender(), + "ERC721ACommon: Not approved nor owner" + ); + _; + } + + function _beforeTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual override { + require(!paused(), "ERC721ACommon: paused"); + super._beforeTokenTransfers(from, to, startTokenId, quantity); + } + + /// @notice Overrides supportsInterface as required by inheritance. + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(ERC721A) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} + + +/////////////////////////////////////////// +// File: @divergencetech/ethier/contracts/erc721/BaseTokenURI.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) +pragma solidity >=0.8.0 <0.9.0; + +import "@openzeppelin/contracts/access/Ownable.sol"; + +/** +@notice ERC721 extension that overrides the OpenZeppelin _baseURI() function to +return a prefix that can be set by the contract owner. + */ +contract BaseTokenURI is Ownable { + /// @notice Base token URI used as a prefix by tokenURI(). + string public baseTokenURI; + + constructor(string memory _baseTokenURI) { + setBaseTokenURI(_baseTokenURI); + } + + /// @notice Sets the base token URI prefix. + function setBaseTokenURI(string memory _baseTokenURI) public onlyOwner { + baseTokenURI = _baseTokenURI; + } + + /** + @notice Concatenates and returns the base token URI and the token ID without + any additional characters (e.g. a slash). + @dev This requires that an inheriting contract that also inherits from OZ's + ERC721 will have to override both contracts; although we could simply + require that users implement their own _baseURI() as here, this can easily + be forgotten and the current approach guides them with compiler errors. This + favours the latter half of "APIs should be easy to use and hard to misuse" + from https://www.infoq.com/articles/API-Design-Joshua-Bloch/. + */ + function _baseURI() internal view virtual returns (string memory) { + return baseTokenURI; + } +} + + +/////////////////////////////////////////// +// File: @divergencetech/ethier/contracts/crypto/SignerManager.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2022 the ethier authors (github.com/divergencetech/ethier) +pragma solidity >=0.8.0 <0.9.0; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +/** +@title SignerManager +@notice Manges addition and removal of a core set of addresses from which +valid ECDSA signatures can be accepted; see SignatureChecker. + */ +contract SignerManager is Ownable { + using EnumerableSet for EnumerableSet.AddressSet; + + /** + @dev Addresses from which signatures can be accepted. + */ + EnumerableSet.AddressSet internal signers; + + /** + @notice Add an address to the set of accepted signers. + */ + function addSigner(address signer) external onlyOwner { + signers.add(signer); + } + + /** + @notice Remove an address previously added with addSigner(). + */ + function removeSigner(address signer) external onlyOwner { + signers.remove(signer); + } +} + + +/////////////////////////////////////////// +// File: @divergencetech/ethier/contracts/crypto/SignatureChecker.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) +pragma solidity >=0.8.0 <0.9.0; + +import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +/** +@title SignatureChecker +@notice Additional functions for EnumerableSet.Addresset that require a valid +ECDSA signature of a standardized message, signed by any member of the set. + */ +library SignatureChecker { + using EnumerableSet for EnumerableSet.AddressSet; + + /** + @notice Requires that the message has not been used previously and that the + recovered signer is contained in the signers AddressSet. + @dev Convenience wrapper for message generation + signature verification + + marking message as used + @param signers Set of addresses from which signatures are accepted. + @param usedMessages Set of already-used messages. + @param signature ECDSA signature of message. + */ + function requireValidSignature( + EnumerableSet.AddressSet storage signers, + bytes memory data, + bytes calldata signature, + mapping(bytes32 => bool) storage usedMessages + ) internal { + bytes32 message = generateMessage(data); + require( + !usedMessages[message], + "SignatureChecker: Message already used" + ); + usedMessages[message] = true; + requireValidSignature(signers, message, signature); + } + + /** + @notice Requires that the message has not been used previously and that the + recovered signer is contained in the signers AddressSet. + @dev Convenience wrapper for message generation + signature verification. + */ + function requireValidSignature( + EnumerableSet.AddressSet storage signers, + bytes memory data, + bytes calldata signature + ) internal view { + bytes32 message = generateMessage(data); + requireValidSignature(signers, message, signature); + } + + /** + @notice Requires that the message has not been used previously and that the + recovered signer is contained in the signers AddressSet. + @dev Convenience wrapper for message generation from address + + signature verification. + */ + function requireValidSignature( + EnumerableSet.AddressSet storage signers, + address a, + bytes calldata signature + ) internal view { + bytes32 message = generateMessage(abi.encodePacked(a)); + requireValidSignature(signers, message, signature); + } + + /** + @notice Common validator logic, checking if the recovered signer is + contained in the signers AddressSet. + */ + function validSignature( + EnumerableSet.AddressSet storage signers, + bytes32 message, + bytes calldata signature + ) internal view returns (bool) { + return signers.contains(ECDSA.recover(message, signature)); + } + + /** + @notice Requires that the recovered signer is contained in the signers + AddressSet. + @dev Convenience wrapper that reverts if the signature validation fails. + */ + function requireValidSignature( + EnumerableSet.AddressSet storage signers, + bytes32 message, + bytes calldata signature + ) internal view { + require( + validSignature(signers, message, signature), + "SignatureChecker: Invalid signature" + ); + } + + /** + @notice Generates a message for a given data input that will be signed + off-chain using ECDSA. + @dev For multiple data fields, a standard concatenation using + `abi.encodePacked` is commonly used to build data. + */ + function generateMessage(bytes memory data) + internal + pure + returns (bytes32) + { + return ECDSA.toEthSignedMessageHash(data); + } +} + + diff --git a/ethabi/code/0x23581767a106ae21c074b2276d25e5c3e136a68b.yml b/ethabi/code/0x23581767a106ae21c074b2276d25e5c3e136a68b.yml new file mode 100644 index 0000000..2ec4c48 --- /dev/null +++ b/ethabi/code/0x23581767a106ae21c074b2276d25e5c3e136a68b.yml @@ -0,0 +1,12 @@ +--- +ContractName: Moonbirds +CompilerVersion: v0.8.11+commit.d7f03943 +OptimizationUsed: '1' +Runs: '200' +ConstructorArguments: 00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000008d7c0242953446436f34b4c78fe9da38c73668d000000000000000000000000000ddf0af676ec8e21d77c5af8166a95531a1668000000000000000000000000c8a5592031f93debea5d9e67a396944ee01bb2ca00000000000000000000000000000000000000000000000000000000000000094d6f6f6e6269726473000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084d4f4f4e42495244000000000000000000000000000000000000000000000000 +EVMVersion: Default +Library: '' +LicenseType: '' +Proxy: '0' +Implementation: '' +SwarmSource: '' diff --git a/ethabi/code/0x282bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d.sol b/ethabi/code/0x282bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d.sol new file mode 100644 index 0000000..c832126 --- /dev/null +++ b/ethabi/code/0x282bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d.sol @@ -0,0 +1,1246 @@ +/////////////////////////////////////////// +// File: contracts/PunksV1Wrapper.sol + +// SPDX-License-Identifier: MIT + + +pragma solidity ^0.8.0; + +import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/token/ERC721/ERC721.sol"; +import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/access/Ownable.sol"; +import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/utils/Counters.sol"; +import "./PunksV1Contract.sol"; + +/** + * @title PunksV1Wrapper contract + * @dev Extends ERC721 Non-Fungible Token Standard basic implementation. + * based on the V1 wrapper of @author @foobar, but optimised to work with our MarketPlace contract. + * @author @FrankPoncelet + */ +contract PunksV1Wrapper is Ownable, ERC721 { + + address payable public punkAddress = payable(0x6Ba6f2207e343923BA692e5Cae646Fb0F566DB8D); + string private _baseTokenURI; + uint256 private _tokenSupply; + + + constructor() ERC721("V1 Cryptopunks (Wrapped)", "WPV1") { + _baseTokenURI = "ipfs://Qma3sC19HbnWHqeLgcsQnR7Kvgus4oPQirXNH7QYBeACaq/"; + } + + /** + * @dev Accepts an offer from the punks contract and assigns a wrapped token to msg.sender + */ + function wrap(uint _punkId) external payable { + // Prereq: owner should call `offerPunkForSaleToAddress` with price 0 (or higher if they wish) + (bool isForSale, , address seller, uint minValue, address onlySellTo) = PunksV1Contract(punkAddress).punksOfferedForSale(_punkId); + require(isForSale == true); + require(seller == msg.sender); + require(minValue == 0); + require((onlySellTo == address(this)) || (onlySellTo == address(0x0))); + // Buy the punk + PunksV1Contract(punkAddress).buyPunk{value: msg.value}(_punkId); + _tokenSupply +=1; + // Mint a wrapped punk + _mint(msg.sender, _punkId); + } + + /** + * @dev Burns the wrapped token and transfers the underlying punk to the owner + **/ + function unwrap(uint256 _punkId) external { + require(_isApprovedOrOwner(msg.sender, _punkId)); + _burn(_punkId); + _tokenSupply -=1; + PunksV1Contract(punkAddress).transferPunk(msg.sender, _punkId); + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, can be overriden in child contracts. + */ + function _baseURI() internal view virtual override returns (string memory) { + return _baseTokenURI; + } + + /** + * @dev Set a new base token URI + */ + function setBaseTokenURI(string memory __baseTokenURI) public onlyOwner { + _baseTokenURI = __baseTokenURI; + } + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + * and stop existing when they are burned (`_burn`). + */ + function exists(uint256 tokenId) external view virtual returns (bool) { + return _exists(tokenId); + } + + /** + * @dev Gets the total amount of tokens stored by the contract. + * @return uint256 representing the total amount of tokens + */ + function totalSupply() public view returns (uint256) { + return _tokenSupply; + } +} + +/////////////////////////////////////////// +// File: contracts/PunksV1Contract.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface PunksV1Contract { + + // Events + + event Assign(address indexed to, uint256 punkIndex); + event Transfer(address indexed from, address indexed to, uint256 value); + event PunkTransfer(address indexed from, address indexed to, uint256 punkIndex); + event PunkOffered(uint indexed punkIndex, uint minValue, address indexed toAddress); + event PunkBought(uint indexed punkIndex, uint value, address indexed fromAddress, address indexed toAddress); + event PunkNoLongerForSale(uint indexed punkIndex); + + // Read contract + + function name() external view returns (string memory); + + function punksOfferedForSale(uint id) external view returns (bool isForSale, uint punkIndex, address seller, uint minValue, address onlySellTo); + + function totalSupply() external view returns (uint); + + function decimals() external view returns (uint8); + + function imageHash() external view returns (string memory); + + function nextPunkIndexToAssign() external view returns (uint); + + function punkIndexToAddress(uint id) external view returns (address); + + function standard() external view returns (string memory); + + function balanceOf(address) external view returns (uint); + + function symbol() external view returns (string memory); + + function numberOfPunksToReserve() external view returns (uint); + + function numberOfPunksReserved() external view returns (uint); + + function punksRemainingToAssign() external view returns (uint); + + function pendingWithdrawals(address) external view returns (uint); + + // Write contract + + function reservePunksForOwner(uint maxForThisRun) external; + + function withdraw() external; + + function buyPunk(uint id) external payable; + + function transferPunk(address to, uint id) external; + + function offerPunkForSaleToAddress(uint id, uint minSalePriceInWei, address to) external; + + function offerPunkForSale(uint id, uint minSalePriceInWei) external; + + function getPunk(uint id) external; + + function punkNoLongerForSale(uint id) external; + +} + +/////////////////////////////////////////// +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/utils/Counters.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.0 (utils/Counters.sol) + +pragma solidity ^0.8.0; + +/** + * @title Counters + * @author Matt Condon (@shrugs) + * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number + * of elements in a mapping, issuing ERC721 ids, or counting request ids. + * + * Include with `using Counters for Counters.Counter;` + */ +library Counters { + struct Counter { + // This variable should never be directly accessed by users of the library: interactions must be restricted to + // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add + // this feature: see https://github.com/ethereum/solidity/issues/4637 + uint256 _value; // default: 0 + } + + function current(Counter storage counter) internal view returns (uint256) { + return counter._value; + } + + function increment(Counter storage counter) internal { + unchecked { + counter._value += 1; + } + } + + function decrement(Counter storage counter) internal { + uint256 value = counter._value; + require(value > 0, "Counter: decrement overflow"); + unchecked { + counter._value = value - 1; + } + } + + function reset(Counter storage counter) internal { + counter._value = 0; + } +} + + +/////////////////////////////////////////// +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/access/Ownable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor () { + address msgSender = _msgSender(); + _owner = msgSender; + emit OwnershipTransferred(address(0), msgSender); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } +} + + +/////////////////////////////////////////// +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/token/ERC721/ERC721.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./IERC721.sol"; +import "./IERC721Receiver.sol"; +import "./extensions/IERC721Metadata.sol"; +import "./extensions/IERC721Enumerable.sol"; +import "../../utils/Address.sol"; +import "../../utils/Context.sol"; +import "../../utils/Strings.sol"; +import "../../utils/introspection/ERC165.sol"; + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including + * the Metadata extension, but not including the Enumerable extension, which is available separately as + * {ERC721Enumerable}. + */ +contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { + using Address for address; + using Strings for uint256; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to owner address + mapping (uint256 => address) private _owners; + + // Mapping owner address to token count + mapping (address => uint256) private _balances; + + // Mapping from token ID to approved address + mapping (uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping (address => mapping (address => bool)) private _operatorApprovals; + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + constructor (string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IERC721).interfaceId + || interfaceId == type(IERC721Metadata).interfaceId + || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view virtual override returns (uint256) { + require(owner != address(0), "ERC721: balance query for the zero address"); + return _balances[owner]; + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view virtual override returns (address) { + address owner = _owners[tokenId]; + require(owner != address(0), "ERC721: owner query for nonexistent token"); + return owner; + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length > 0 + ? string(abi.encodePacked(baseURI, tokenId.toString())) + : ''; + } + + /** + * @dev Base URI for computing {tokenURI}. Empty by default, can be overriden + * in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ""; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public virtual override { + address owner = ERC721.ownerOf(tokenId); + require(to != owner, "ERC721: approval to current owner"); + + require(_msgSender() == owner || ERC721.isApprovedForAll(owner, _msgSender()), + "ERC721: approve caller is not owner nor approved for all" + ); + + _approve(to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view virtual override returns (address) { + require(_exists(tokenId), "ERC721: approved query for nonexistent token"); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + require(operator != _msgSender(), "ERC721: approve to caller"); + + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom(address from, address to, uint256 tokenId) public virtual override { + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + + _transfer(from, to, tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { + safeTransferFrom(from, to, tokenId, ""); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override { + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + _safeTransfer(from, to, tokenId, _data); + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * `_data` is additional data, it has no specified format and it is sent in call to `to`. + * + * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. + * implement alternative mechanisms to perform token transfer, such as signature-based. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual { + _transfer(from, to, tokenId); + require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + * and stop existing when they are burned (`_burn`). + */ + function _exists(uint256 tokenId) internal view virtual returns (bool) { + return _owners[tokenId] != address(0); + } + + /** + * @dev Returns whether `spender` is allowed to manage `tokenId`. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { + require(_exists(tokenId), "ERC721: operator query for nonexistent token"); + address owner = ERC721.ownerOf(tokenId); + return (spender == owner || getApproved(tokenId) == spender || ERC721.isApprovedForAll(owner, spender)); + } + + /** + * @dev Safely mints `tokenId` and transfers it to `to`. + * + * Requirements: + * + * - `tokenId` must not exist. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeMint(address to, uint256 tokenId) internal virtual { + _safeMint(to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual { + _mint(to, tokenId); + require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Mints `tokenId` and transfers it to `to`. + * + * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * Emits a {Transfer} event. + */ + function _mint(address to, uint256 tokenId) internal virtual { + require(to != address(0), "ERC721: mint to the zero address"); + require(!_exists(tokenId), "ERC721: token already minted"); + + _beforeTokenTransfer(address(0), to, tokenId); + + _balances[to] += 1; + _owners[tokenId] = to; + + emit Transfer(address(0), to, tokenId); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId) internal virtual { + address owner = ERC721.ownerOf(tokenId); + + _beforeTokenTransfer(owner, address(0), tokenId); + + // Clear approvals + _approve(address(0), tokenId); + + _balances[owner] -= 1; + delete _owners[tokenId]; + + emit Transfer(owner, address(0), tokenId); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer(address from, address to, uint256 tokenId) internal virtual { + require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); + require(to != address(0), "ERC721: transfer to the zero address"); + + _beforeTokenTransfer(from, to, tokenId); + + // Clear approvals from the previous owner + _approve(address(0), tokenId); + + _balances[from] -= 1; + _balances[to] += 1; + _owners[tokenId] = to; + + emit Transfer(from, to, tokenId); + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * Emits a {Approval} event. + */ + function _approve(address to, uint256 tokenId) internal virtual { + _tokenApprovals[tokenId] = to; + emit Approval(ERC721.ownerOf(tokenId), to, tokenId); + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * The call is not executed if the target address is not a contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) + private returns (bool) + { + if (to.isContract()) { + try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { + return retval == IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert("ERC721: transfer to non ERC721Receiver implementer"); + } else { + // solhint-disable-next-line no-inline-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } else { + return true; + } + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, ``from``'s `tokenId` will be burned. + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { } +} + + +/////////////////////////////////////////// +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/utils/introspection/ERC165.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + + +/////////////////////////////////////////// +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/utils/Strings.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant alphabet = "0123456789abcdef"; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + // Inspired by OraclizeAPI's implementation - MIT licence + // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol + + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + while (value != 0) { + digits -= 1; + buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); + value /= 10; + } + return string(buffer); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + if (value == 0) { + return "0x00"; + } + uint256 temp = value; + uint256 length = 0; + while (temp != 0) { + length++; + temp >>= 8; + } + return toHexString(value, length); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = alphabet[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } + +} + + +/////////////////////////////////////////// +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} + + +/////////////////////////////////////////// +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + + +/////////////////////////////////////////// +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/token/ERC721/extensions/IERC721Enumerable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Enumerable is IERC721 { + + /** + * @dev Returns the total amount of tokens stored by the contract. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns a token ID owned by `owner` at a given `index` of its token list. + * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); + + /** + * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. + * Use along with {totalSupply} to enumerate all tokens. + */ + function tokenByIndex(uint256 index) external view returns (uint256); +} + + +/////////////////////////////////////////// +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/token/ERC721/extensions/IERC721Metadata.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} + + +/////////////////////////////////////////// +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/token/ERC721/IERC721Receiver.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. + */ + function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4); +} + + +/////////////////////////////////////////// +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/token/ERC721/IERC721.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; +} + + +/////////////////////////////////////////// +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/utils/introspection/IERC165.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + + diff --git a/ethabi/code/0x282bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d.yml b/ethabi/code/0x282bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d.yml new file mode 100644 index 0000000..2abbfcb --- /dev/null +++ b/ethabi/code/0x282bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d.yml @@ -0,0 +1,12 @@ +--- +ContractName: PunksV1Wrapper +CompilerVersion: v0.8.11+commit.d7f03943 +OptimizationUsed: '1' +Runs: '1000' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: '' +Proxy: '0' +Implementation: '' +SwarmSource: '' diff --git a/ethabi/code/0x34625ecaa75c0ea33733a05c584f4cf112c10b6b.sol b/ethabi/code/0x34625ecaa75c0ea33733a05c584f4cf112c10b6b.sol new file mode 100644 index 0000000..7aac452 --- /dev/null +++ b/ethabi/code/0x34625ecaa75c0ea33733a05c584f4cf112c10b6b.sol @@ -0,0 +1,2768 @@ +/////////////////////////////////////////// +// File: /app/contracts/Indelible.sol + + + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.4; + + import "erc721a/contracts/ERC721A.sol"; + import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; + import "@openzeppelin/contracts/access/Ownable.sol"; + import "@openzeppelin/contracts/utils/Base64.sol"; + import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; + import "@openzeppelin/contracts/utils/Address.sol"; + import "./SSTORE2.sol"; + import "./DynamicBuffer.sol"; + import "./HelperLib.sol"; + + contract Indelible is ERC721A, ReentrancyGuard, Ownable { + using HelperLib for uint; + using DynamicBuffer for bytes; + + struct LinkedTraitDTO { + uint[] traitA; + uint[] traitB; + } + + struct TraitDTO { + string name; + string mimetype; + bytes data; + bool useExistingData; + uint existingDataIndex; + } + + struct Trait { + string name; + string mimetype; + } + + struct ContractData { + string name; + string description; + string image; + string banner; + string website; + uint royalties; + string royaltiesRecipient; + } + + struct WithdrawRecipient { + string name; + string imageUrl; + address recipientAddress; + uint percentage; + } + + mapping(uint => address[]) internal _traitDataPointers; + mapping(uint => mapping(uint => Trait)) internal _traitDetails; + mapping(uint => bool) internal _renderTokenOffChain; + mapping(uint => mapping(uint => uint[])) internal _linkedTraits; + + uint private constant DEVELOPER_FEE = 250; // of 10,000 = 2.5% + uint private constant NUM_LAYERS = 9; + uint private constant MAX_BATCH_MINT = 20; + uint[][NUM_LAYERS] private TIERS; + string[] private LAYER_NAMES = [unicode"Jewelry", unicode"Beauty Marks", unicode"Eyes", unicode"Pretty Mouths", unicode"Necks", unicode"Hair Hats and Wigs", unicode"Punkins", unicode"Zodiak", unicode"Spooky Sky"]; + bool private shouldWrapSVG = true; + string private backgroundColor = "transparent"; + + WithdrawRecipient[1] public withdrawRecipients; + bool public isContractSealed; + uint public constant maxSupply = 6969; + uint public maxPerAddress = 20; + uint public publicMintPrice = 0.006969 ether; + string public baseURI = ""; + bool public isPublicMintActive; + + bytes32 private merkleRoot; + uint public allowListPrice = 0.000 ether; + uint public maxPerAllowList = 3; + bool public isAllowListActive; + + ContractData public contractData = ContractData(unicode"Punkin Spicies", unicode"6969 Little Punk Cuties Derivative Spicy and On Chain", "https://indeliblelabs-prod.s3.us-east-2.amazonaws.com/profile/196f7277-390d-45ff-a605-9c8de357782e", "https://indeliblelabs-prod.s3.us-east-2.amazonaws.com/banner/196f7277-390d-45ff-a605-9c8de357782e", "", 500, "0xf2c0149F0cff4c19b9819d1084f465DF0E1b3795"); + + constructor() ERC721A(unicode"Punkin Spicies", unicode"PunkinSpicies") { + TIERS[0] = [64,206,1744,1752,3203]; +TIERS[1] = [109,321,349,1561,1879,2750]; +TIERS[2] = [53,74,87,100,131,136,144,195,199,208,233,327,440,441,500,518,609,711,749,1114]; +TIERS[3] = [29,65,216,315,592,786,898,1200,1302,1566]; +TIERS[4] = [494,1027,1102,1689,2657]; +TIERS[5] = [9,18,19,29,41,42,51,70,87,89,91,92,104,124,135,144,150,151,172,182,182,193,194,197,201,217,218,235,235,255,261,291,312,384,409,553,832]; +TIERS[6] = [40,80,81,149,185,198,257,342,383,435,674,679,869,1237,1360]; +TIERS[7] = [107,107,160,204,212,545,616,630,803,808,1121,1656]; +TIERS[8] = [6969]; + withdrawRecipients[0] = WithdrawRecipient(unicode"null",unicode"null", 0x5FD2E3ba05C862E62a34B9F63c45C0DF622Ac112, 5000); + } + + modifier whenMintActive() { + require(isMintActive(), "Minting is not active"); + _; + } + + modifier whenUnsealed() { + require(!isContractSealed, "Contract is sealed"); + _; + } + + receive() external payable { + require(isPublicMintActive, "Public minting is not active"); + handleMint(msg.value / publicMintPrice); + } + + function rarityGen(uint _randinput, uint _rarityTier) + internal + view + returns (uint) + { + uint currentLowerBound = 0; + for (uint i = 0; i < TIERS[_rarityTier].length; i++) { + uint thisPercentage = TIERS[_rarityTier][i]; + if ( + _randinput >= currentLowerBound && + _randinput < currentLowerBound + thisPercentage + ) return i; + currentLowerBound = currentLowerBound + thisPercentage; + } + + revert(); + } + + function entropyForExtraData() internal view returns (uint24) { + uint randomNumber = uint( + keccak256( + abi.encodePacked( + tx.gasprice, + block.number, + block.timestamp, + block.difficulty, + blockhash(block.number - 1), + msg.sender + ) + ) + ); + return uint24(randomNumber); + } + + function stringCompare(string memory a, string memory b) internal pure returns (bool) { + return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b)); + } + + function tokensAreDuplicates(uint tokenIdA, uint tokenIdB) public view returns (bool) { + return stringCompare( + tokenIdToHash(tokenIdA), + tokenIdToHash(tokenIdB) + ); + } + + function reRollDuplicate( + uint tokenIdA, + uint tokenIdB + ) public whenUnsealed { + require(tokensAreDuplicates(tokenIdA, tokenIdB), "All tokens must be duplicates"); + + uint largerTokenId = tokenIdA > tokenIdB ? tokenIdA : tokenIdB; + + if (msg.sender != owner()) { + require(msg.sender == ownerOf(largerTokenId), "Only the token owner or contract owner can re-roll"); + } + + _initializeOwnershipAt(largerTokenId); + if (_exists(largerTokenId + 1)) { + _initializeOwnershipAt(largerTokenId + 1); + } + + _setExtraDataAt(largerTokenId, entropyForExtraData()); + } + + function _extraData( + address from, + address to, + uint24 previousExtraData + ) internal view virtual override returns (uint24) { + return from == address(0) ? entropyForExtraData() : previousExtraData; + } + + function getTokenSeed(uint _tokenId) internal view returns (uint24) { + return _ownershipOf(_tokenId).extraData; + } + + function tokenIdToHash( + uint _tokenId + ) public view returns (string memory) { + require(_exists(_tokenId), "Invalid token"); + // This will generate a NUM_LAYERS * 3 character string. + bytes memory hashBytes = DynamicBuffer.allocate(NUM_LAYERS * 4); + + uint[] memory hash = new uint[](NUM_LAYERS); + bool[] memory modifiedLayers = new bool[](NUM_LAYERS); + + for (uint i = 0; i < NUM_LAYERS; i++) { + uint traitIndex = hash[i]; + if (modifiedLayers[i] == false) { + uint _randinput = uint( + uint( + keccak256( + abi.encodePacked( + getTokenSeed(_tokenId), + _tokenId, + _tokenId + i + ) + ) + ) % maxSupply + ); + + traitIndex = rarityGen(_randinput, i); + hash[i] = traitIndex; + } + + if (_linkedTraits[i][traitIndex].length > 0) { + hash[_linkedTraits[i][traitIndex][0]] = _linkedTraits[i][traitIndex][1]; + modifiedLayers[_linkedTraits[i][traitIndex][0]] = true; + } + } + + for (uint i = 0; i < hash.length; i++) { + if (hash[i] < 10) { + hashBytes.appendSafe("00"); + } else if (hash[i] < 100) { + hashBytes.appendSafe("0"); + } + if (hash[i] > 999) { + hashBytes.appendSafe("999"); + } else { + hashBytes.appendSafe(bytes(_toString(hash[i]))); + } + } + + return string(hashBytes); + } + + function handleMint(uint256 _count) internal whenMintActive returns (uint256) { + uint256 totalMinted = _totalMinted(); + require(_count > 0, "Invalid token count"); + require(totalMinted + _count <= maxSupply, "All tokens are gone"); + + + if (isPublicMintActive) { + if (msg.sender != owner()) { + require(_numberMinted(msg.sender) + _count <= maxPerAddress, "Exceeded max mints allowed"); + } + require(msg.sender == tx.origin, "EOAs only"); + require(_count * publicMintPrice == msg.value, "Incorrect amount of ether sent"); + } + + uint256 batchCount = _count / MAX_BATCH_MINT; + uint256 remainder = _count % MAX_BATCH_MINT; + + for (uint256 i = 0; i < batchCount; i++) { + _mint(msg.sender, MAX_BATCH_MINT); + } + + if (remainder > 0) { + _mint(msg.sender, remainder); + } + + return totalMinted; + } + + function mint(uint256 _count, bytes32[] calldata merkleProof) + external + payable + nonReentrant + whenMintActive + returns (uint) + { + + if (!isPublicMintActive) { + if (msg.sender != owner()) { + require(onAllowList(msg.sender, merkleProof), "Not on allow list"); + require(_numberMinted(msg.sender) + _count <= maxPerAllowList, "Exceeded max mints allowed"); + } + require(_count * allowListPrice == msg.value, "Incorrect amount of ether sent"); + } + + uint256 totalMinted = handleMint(_count); + + return totalMinted; + } + + function isMintActive() public view returns (bool) { + return _totalMinted() < maxSupply && (isPublicMintActive || isAllowListActive); + } + + function hashToSVG(string memory _hash) + public + view + returns (string memory) + { + uint thisTraitIndex; + + bytes memory svgBytes = DynamicBuffer.allocate(1024 * 128); + svgBytes.appendSafe('' + ) + ); + + return string( + abi.encodePacked( + "data:image/svg+xml;base64,", + Base64.encode(svgBytes) + ) + ); + } + + function hashToMetadata(string memory _hash) + public + view + returns (string memory) + { + bytes memory metadataBytes = DynamicBuffer.allocate(1024 * 128); + metadataBytes.appendSafe("["); + + for (uint i = 0; i < NUM_LAYERS; i++) { + uint thisTraitIndex = HelperLib.parseInt( + HelperLib._substring(_hash, (i * 3), (i * 3) + 3) + ); + metadataBytes.appendSafe( + abi.encodePacked( + '{"trait_type":"', + LAYER_NAMES[i], + '","value":"', + _traitDetails[i][thisTraitIndex].name, + '"}' + ) + ); + + if (i == NUM_LAYERS - 1) { + metadataBytes.appendSafe("]"); + } else { + metadataBytes.appendSafe(","); + } + } + + return string(metadataBytes); + } + + + function onAllowList(address addr, bytes32[] calldata merkleProof) public view returns (bool) { + return MerkleProof.verify(merkleProof, merkleRoot, keccak256(abi.encodePacked(addr))); + } + + + function tokenURI(uint _tokenId) + public + view + override + returns (string memory) + { + require(_exists(_tokenId), "Invalid token"); + require(_traitDataPointers[0].length > 0, "Traits have not been added"); + + string memory tokenHash = tokenIdToHash(_tokenId); + + bytes memory jsonBytes = DynamicBuffer.allocate(1024 * 128); + jsonBytes.appendSafe(unicode"{\"name\":\"Punkin Spicies #"); + + jsonBytes.appendSafe( + abi.encodePacked( + _toString(_tokenId), + "\",\"description\":\"", + contractData.description, + "\"," + ) + ); + + if (bytes(baseURI).length > 0 && _renderTokenOffChain[_tokenId]) { + jsonBytes.appendSafe( + abi.encodePacked( + '"image":"', + baseURI, + _toString(_tokenId), + "?dna=", + tokenHash, + '&network=mainnet",' + ) + ); + } else { + string memory svgCode = ""; + if (shouldWrapSVG) { + string memory svgString = hashToSVG(tokenHash); + svgCode = string( + abi.encodePacked( + "data:image/svg+xml;base64,", + Base64.encode( + abi.encodePacked( + '' + ) + ) + ) + ); + jsonBytes.appendSafe( + abi.encodePacked( + '"svg_image_data":"', + svgString, + '",' + ) + ); + } else { + svgCode = hashToSVG(tokenHash); + } + + jsonBytes.appendSafe( + abi.encodePacked( + '"image_data":"', + svgCode, + '",' + ) + ); + } + + jsonBytes.appendSafe( + abi.encodePacked( + '"attributes":', + hashToMetadata(tokenHash), + "}" + ) + ); + + return string( + abi.encodePacked( + "data:application/json;base64,", + Base64.encode(jsonBytes) + ) + ); + } + + function contractURI() + public + view + returns (string memory) + { + return string( + abi.encodePacked( + "data:application/json;base64,", + Base64.encode( + abi.encodePacked( + '{"name":"', + contractData.name, + '","description":"', + contractData.description, + '","image":"', + contractData.image, + '","banner":"', + contractData.banner, + '","external_link":"', + contractData.website, + '","seller_fee_basis_points":', + _toString(contractData.royalties), + ',"fee_recipient":"', + contractData.royaltiesRecipient, + '"}' + ) + ) + ) + ); + } + + function tokenIdToSVG(uint _tokenId) + public + view + returns (string memory) + { + return hashToSVG(tokenIdToHash(_tokenId)); + } + + function traitDetails(uint _layerIndex, uint _traitIndex) + public + view + returns (Trait memory) + { + return _traitDetails[_layerIndex][_traitIndex]; + } + + function traitData(uint _layerIndex, uint _traitIndex) + public + view + returns (string memory) + { + return string(SSTORE2.read(_traitDataPointers[_layerIndex][_traitIndex])); + } + + function getLinkedTraits(uint _layerIndex, uint _traitIndex) + public + view + returns (uint[] memory) + { + return _linkedTraits[_layerIndex][_traitIndex]; + } + + function addLayer(uint _layerIndex, TraitDTO[] memory traits) + public + onlyOwner + whenUnsealed + { + require(TIERS[_layerIndex].length == traits.length, "Traits size does not match tiers for this index"); + address[] memory dataPointers = new address[](traits.length); + for (uint i = 0; i < traits.length; i++) { + if (traits[i].useExistingData) { + dataPointers[i] = dataPointers[traits[i].existingDataIndex]; + } else { + dataPointers[i] = SSTORE2.write(traits[i].data); + } + _traitDetails[_layerIndex][i] = Trait(traits[i].name, traits[i].mimetype); + } + _traitDataPointers[_layerIndex] = dataPointers; + return; + } + + function addTrait(uint _layerIndex, uint _traitIndex, TraitDTO memory trait) + public + onlyOwner + whenUnsealed + { + _traitDetails[_layerIndex][_traitIndex] = Trait(trait.name, trait.mimetype); + address[] memory dataPointers = _traitDataPointers[_layerIndex]; + if (trait.useExistingData) { + dataPointers[_traitIndex] = dataPointers[trait.existingDataIndex]; + } else { + dataPointers[_traitIndex] = SSTORE2.write(trait.data); + } + _traitDataPointers[_layerIndex] = dataPointers; + return; + } + + function setLinkedTraits(LinkedTraitDTO[] memory linkedTraits) + public + onlyOwner + whenUnsealed + { + for (uint i = 0; i < linkedTraits.length; i++) { + _linkedTraits[linkedTraits[i].traitA[0]][linkedTraits[i].traitA[1]] = [linkedTraits[i].traitB[0],linkedTraits[i].traitB[1]]; + } + } + + function setContractData(ContractData memory _contractData) external onlyOwner whenUnsealed { + contractData = _contractData; + } + + function setMaxPerAddress(uint _maxPerAddress) external onlyOwner { + maxPerAddress = _maxPerAddress; + } + + function setBaseURI(string memory _baseURI) external onlyOwner { + baseURI = _baseURI; + } + + function setBackgroundColor(string memory _backgroundColor) external onlyOwner whenUnsealed { + backgroundColor = _backgroundColor; + } + + function setRenderOfTokenId(uint _tokenId, bool _renderOffChain) external { + require(msg.sender == ownerOf(_tokenId), "Only the token owner can set the render method"); + _renderTokenOffChain[_tokenId] = _renderOffChain; + } + + + function setMerkleRoot(bytes32 newMerkleRoot) external onlyOwner { + merkleRoot = newMerkleRoot; + } + + function setMaxPerAllowList(uint _maxPerAllowList) external onlyOwner { + maxPerAllowList = _maxPerAllowList; + } + + function setAllowListPrice(uint _allowListPrice) external onlyOwner { + allowListPrice = _allowListPrice; + } + + function toggleAllowListMint() external onlyOwner { + isAllowListActive = !isAllowListActive; + } + + + function toggleWrapSVG() external onlyOwner { + shouldWrapSVG = !shouldWrapSVG; + } + + function togglePublicMint() external onlyOwner { + isPublicMintActive = !isPublicMintActive; + } + + function sealContract() external whenUnsealed onlyOwner { + isContractSealed = true; + } + + function withdraw() external onlyOwner nonReentrant { + uint balance = address(this).balance; + uint amount = (balance * (10000 - DEVELOPER_FEE)) / 10000; + uint distAmount = 0; + uint totalDistributionPercentage = 0; + + address payable receiver = payable(owner()); + address payable dev = payable(0xEA208Da933C43857683C04BC76e3FD331D7bfdf7); + Address.sendValue(dev, balance - amount); + + if (withdrawRecipients.length > 0) { + for (uint i = 0; i < withdrawRecipients.length; i++) { + totalDistributionPercentage = totalDistributionPercentage + withdrawRecipients[i].percentage; + address payable currRecepient = payable(withdrawRecipients[i].recipientAddress); + distAmount = (amount * (10000 - withdrawRecipients[i].percentage)) / 10000; + + Address.sendValue(currRecepient, amount - distAmount); + } + } + balance = address(this).balance; + Address.sendValue(receiver, balance); + } + } + + +/////////////////////////////////////////// +// File: /app/contracts/DynamicBuffer.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) + +pragma solidity >=0.8.0; + +/// @title DynamicBuffer +/// @author David Huber (@cxkoda) and Simon Fremaux (@dievardump). See also +/// https://raw.githubusercontent.com/dievardump/solidity-dynamic-buffer +/// @notice This library is used to allocate a big amount of container memory +// which will be subsequently filled without needing to reallocate +/// memory. +/// @dev First, allocate memory. +/// Then use `buffer.appendUnchecked(theBytes)` or `appendSafe()` if +/// bounds checking is required. +library DynamicBuffer { + /// @notice Allocates container space for the DynamicBuffer + /// @param capacity The intended max amount of bytes in the buffer + /// @return buffer The memory location of the buffer + /// @dev Allocates `capacity + 0x60` bytes of space + /// The buffer array starts at the first container data position, + /// (i.e. `buffer = container + 0x20`) + function allocate(uint256 capacity) + internal + pure + returns (bytes memory buffer) + { + assembly { + // Get next-free memory address + let container := mload(0x40) + + // Allocate memory by setting a new next-free address + { + // Add 2 x 32 bytes in size for the two length fields + // Add 32 bytes safety space for 32B chunked copy + let size := add(capacity, 0x60) + let newNextFree := add(container, size) + mstore(0x40, newNextFree) + } + + // Set the correct container length + { + let length := add(capacity, 0x40) + mstore(container, length) + } + + // The buffer starts at idx 1 in the container (0 is length) + buffer := add(container, 0x20) + + // Init content with length 0 + mstore(buffer, 0) + } + + return buffer; + } + + /// @notice Appends data to buffer, and update buffer length + /// @param buffer the buffer to append the data to + /// @param data the data to append + /// @dev Does not perform out-of-bound checks (container capacity) + /// for efficiency. + function appendUnchecked(bytes memory buffer, bytes memory data) + internal + pure + { + assembly { + let length := mload(data) + for { + data := add(data, 0x20) + let dataEnd := add(data, length) + let copyTo := add(buffer, add(mload(buffer), 0x20)) + } lt(data, dataEnd) { + data := add(data, 0x20) + copyTo := add(copyTo, 0x20) + } { + // Copy 32B chunks from data to buffer. + // This may read over data array boundaries and copy invalid + // bytes, which doesn't matter in the end since we will + // later set the correct buffer length, and have allocated an + // additional word to avoid buffer overflow. + mstore(copyTo, mload(data)) + } + + // Update buffer length + mstore(buffer, add(mload(buffer), length)) + } + } + + /// @notice Appends data to buffer, and update buffer length + /// @param buffer the buffer to append the data to + /// @param data the data to append + /// @dev Performs out-of-bound checks and calls `appendUnchecked`. + function appendSafe(bytes memory buffer, bytes memory data) internal pure { + uint256 capacity; + uint256 length; + assembly { + capacity := sub(mload(sub(buffer, 0x20)), 0x40) + length := mload(buffer) + } + + require( + length + data.length <= capacity, + "DynamicBuffer: Appending out of bounds." + ); + appendUnchecked(buffer, data); + } +} + +/////////////////////////////////////////// +// File: /app/contracts/HelperLib.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.14; + +library HelperLib { + function parseInt(string memory _a) + internal + pure + returns (uint8 _parsedInt) + { + bytes memory bresult = bytes(_a); + uint8 mint = 0; + for (uint8 i = 0; i < bresult.length; i++) { + if ( + (uint8(uint8(bresult[i])) >= 48) && + (uint8(uint8(bresult[i])) <= 57) + ) { + mint *= 10; + mint += uint8(bresult[i]) - 48; + } + } + return mint; + } + + function _substring( + string memory str, + uint256 startIndex, + uint256 endIndex + ) internal pure returns (string memory) { + bytes memory strBytes = bytes(str); + bytes memory result = new bytes(endIndex - startIndex); + for (uint256 i = startIndex; i < endIndex; i++) { + result[i - startIndex] = strBytes[i]; + } + return string(result); + } +} + +/////////////////////////////////////////// +// File: /app/contracts/SSTORE2.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./utils/Bytecode.sol"; + +/** + @title A key-value storage with auto-generated keys for storing chunks of data with a lower write & read cost. + @author Agustin Aguilar + + Readme: https://github.com/0xsequence/sstore2#readme +*/ +library SSTORE2 { + error WriteError(); + + /** + @notice Stores `_data` and returns `pointer` as key for later retrieval + @dev The pointer is a contract address with `_data` as code + @param _data to be written + @return pointer Pointer to the written `_data` + */ + function write(bytes memory _data) internal returns (address pointer) { + // Append 00 to _data so contract can't be called + // Build init code + bytes memory code = Bytecode.creationCodeFor( + abi.encodePacked( + hex'00', + _data + ) + ); + + // Deploy contract using create + assembly { pointer := create(0, add(code, 32), mload(code)) } + + // Address MUST be non-zero + if (pointer == address(0)) revert WriteError(); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @return data read from `_pointer` contract + */ + function read(address _pointer) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, 1, type(uint256).max); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @param _start number of bytes to skip + @return data read from `_pointer` contract + */ + function read(address _pointer, uint256 _start) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, _start + 1, type(uint256).max); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @param _start number of bytes to skip + @param _end index before which to end extraction + @return data read from `_pointer` contract + */ + function read(address _pointer, uint256 _start, uint256 _end) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, _start + 1, _end + 1); + } +} + +/////////////////////////////////////////// +// File: /app/contracts/utils/Bytecode.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + + +library Bytecode { + error InvalidCodeAtRange(uint256 _size, uint256 _start, uint256 _end); + + /** + @notice Generate a creation code that results on a contract with `_code` as bytecode + @param _code The returning value of the resulting `creationCode` + @return creationCode (constructor) for new contract + */ + function creationCodeFor(bytes memory _code) internal pure returns (bytes memory) { + /* + 0x00 0x63 0x63XXXXXX PUSH4 _code.length size + 0x01 0x80 0x80 DUP1 size size + 0x02 0x60 0x600e PUSH1 14 14 size size + 0x03 0x60 0x6000 PUSH1 00 0 14 size size + 0x04 0x39 0x39 CODECOPY size + 0x05 0x60 0x6000 PUSH1 00 0 size + 0x06 0xf3 0xf3 RETURN + + */ + + return abi.encodePacked( + hex"63", + uint32(_code.length), + hex"80_60_0E_60_00_39_60_00_F3", + _code + ); + } + + /** + @notice Returns the size of the code on a given address + @param _addr Address that may or may not contain code + @return size of the code on the given `_addr` + */ + function codeSize(address _addr) internal view returns (uint256 size) { + assembly { size := extcodesize(_addr) } + } + + /** + @notice Returns the code of a given address + @dev It will fail if `_end < _start` + @param _addr Address that may or may not contain code + @param _start number of bytes of code to skip on read + @param _end index before which to end extraction + @return oCode read from `_addr` deployed bytecode + + Forked from: https://gist.github.com/KardanovIR/fe98661df9338c842b4a30306d507fbd + */ + function codeAt(address _addr, uint256 _start, uint256 _end) internal view returns (bytes memory oCode) { + uint256 csize = codeSize(_addr); + if (csize == 0) return bytes(""); + + if (_start > csize) return bytes(""); + if (_end < _start) revert InvalidCodeAtRange(csize, _start, _end); + + unchecked { + uint256 reqSize = _end - _start; + uint256 maxSize = csize - _start; + + uint256 size = maxSize < reqSize ? maxSize : reqSize; + + assembly { + // allocate output byte array - this could also be done without assembly + // by using o_code = new bytes(size) + oCode := mload(0x40) + // new "memory end" including padding + mstore(0x40, add(oCode, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + // store length in memory + mstore(oCode, size) + // actually retrieve the code, this needs assembly + extcodecopy(_addr, add(oCode, 0x20), _start, size) + } + } + } +} + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/access/Ownable.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor() { + _transferOwnership(_msgSender()); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/security/ReentrancyGuard.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor() { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and making it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) + +pragma solidity ^0.8.1; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + * + * [IMPORTANT] + * ==== + * You shouldn't rely on `isContract` to protect against flash loan attacks! + * + * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets + * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract + * constructor. + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize/address.code.length, which returns 0 + // for contracts in construction, since the code is only stored at the end + // of the constructor execution. + + return account.code.length > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Base64.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (utils/Base64.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides a set of functions to operate with Base64 strings. + * + * _Available since v4.5._ + */ +library Base64 { + /** + * @dev Base64 Encoding/Decoding Table + */ + string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** + * @dev Converts a `bytes` to its Bytes64 `string` representation. + */ + function encode(bytes memory data) internal pure returns (string memory) { + /** + * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence + * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol + */ + if (data.length == 0) return ""; + + // Loads the table into memory + string memory table = _TABLE; + + // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter + // and split into 4 numbers of 6 bits. + // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up + // - `data.length + 2` -> Round up + // - `/ 3` -> Number of 3-bytes chunks + // - `4 *` -> 4 characters for each chunk + string memory result = new string(4 * ((data.length + 2) / 3)); + + assembly { + // Prepare the lookup table (skip the first "length" byte) + let tablePtr := add(table, 1) + + // Prepare result pointer, jump over length + let resultPtr := add(result, 32) + + // Run over the input, 3 bytes at a time + for { + let dataPtr := data + let endPtr := add(data, mload(data)) + } lt(dataPtr, endPtr) { + + } { + // Advance 3 bytes + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + + // To write each character, shift the 3 bytes (18 bits) chunk + // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) + // and apply logical AND with 0x3F which is the number of + // the previous character in the ASCII table prior to the Base64 Table + // The result is then added to the table to get the character to write, + // and finally write it in the result pointer but with a left shift + // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits + + mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + } + + // When data `bytes` is not exactly 3 bytes long + // it is padded with `=` characters at the end + switch mod(mload(data), 3) + case 1 { + mstore8(sub(resultPtr, 1), 0x3d) + mstore8(sub(resultPtr, 2), 0x3d) + } + case 2 { + mstore8(sub(resultPtr, 1), 0x3d) + } + } + + return result; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/cryptography/MerkleProof.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (utils/cryptography/MerkleProof.sol) + +pragma solidity ^0.8.0; + +/** + * @dev These functions deal with verification of Merkle Trees proofs. + * + * The proofs can be generated using the JavaScript library + * https://github.com/miguelmota/merkletreejs[merkletreejs]. + * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled. + * + * See `test/utils/cryptography/MerkleProof.test.js` for some examples. + * + * WARNING: You should avoid using leaf values that are 64 bytes long prior to + * hashing, or use a hash function other than keccak256 for hashing leaves. + * This is because the concatenation of a sorted pair of internal nodes in + * the merkle tree could be reinterpreted as a leaf value. + */ +library MerkleProof { + /** + * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree + * defined by `root`. For this, a `proof` must be provided, containing + * sibling hashes on the branch from the leaf to the root of the tree. Each + * pair of leaves and each pair of pre-images are assumed to be sorted. + */ + function verify( + bytes32[] memory proof, + bytes32 root, + bytes32 leaf + ) internal pure returns (bool) { + return processProof(proof, leaf) == root; + } + + /** + * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up + * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt + * hash matches the root of the tree. When processing the proof, the pairs + * of leafs & pre-images are assumed to be sorted. + * + * _Available since v4.4._ + */ + function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + bytes32 proofElement = proof[i]; + if (computedHash <= proofElement) { + // Hash(current computed hash + current element of the proof) + computedHash = _efficientHash(computedHash, proofElement); + } else { + // Hash(current element of the proof + current computed hash) + computedHash = _efficientHash(proofElement, computedHash); + } + } + return computedHash; + } + + function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { + assembly { + mstore(0x00, a) + mstore(0x20, b) + value := keccak256(0x00, 0x40) + } + } +} + + +/////////////////////////////////////////// +// File: erc721a/contracts/ERC721A.sol + +// SPDX-License-Identifier: MIT +// ERC721A Contracts v4.1.0 +// Creator: Chiru Labs + +pragma solidity ^0.8.4; + +import './IERC721A.sol'; + +/** + * @dev ERC721 token receiver interface. + */ +interface ERC721A__IERC721Receiver { + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, + * including the Metadata extension. Built to optimize for lower gas during batch mints. + * + * Assumes serials are sequentially minted starting at `_startTokenId()` + * (defaults to 0, e.g. 0, 1, 2, 3..). + * + * Assumes that an owner cannot have more than 2**64 - 1 (max value of uint64) of supply. + * + * Assumes that the maximum token id cannot exceed 2**256 - 1 (max value of uint256). + */ +contract ERC721A is IERC721A { + // Mask of an entry in packed address data. + uint256 private constant BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1; + + // The bit position of `numberMinted` in packed address data. + uint256 private constant BITPOS_NUMBER_MINTED = 64; + + // The bit position of `numberBurned` in packed address data. + uint256 private constant BITPOS_NUMBER_BURNED = 128; + + // The bit position of `aux` in packed address data. + uint256 private constant BITPOS_AUX = 192; + + // Mask of all 256 bits in packed address data except the 64 bits for `aux`. + uint256 private constant BITMASK_AUX_COMPLEMENT = (1 << 192) - 1; + + // The bit position of `startTimestamp` in packed ownership. + uint256 private constant BITPOS_START_TIMESTAMP = 160; + + // The bit mask of the `burned` bit in packed ownership. + uint256 private constant BITMASK_BURNED = 1 << 224; + + // The bit position of the `nextInitialized` bit in packed ownership. + uint256 private constant BITPOS_NEXT_INITIALIZED = 225; + + // The bit mask of the `nextInitialized` bit in packed ownership. + uint256 private constant BITMASK_NEXT_INITIALIZED = 1 << 225; + + // The bit position of `extraData` in packed ownership. + uint256 private constant BITPOS_EXTRA_DATA = 232; + + // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`. + uint256 private constant BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1; + + // The mask of the lower 160 bits for addresses. + uint256 private constant BITMASK_ADDRESS = (1 << 160) - 1; + + // The maximum `quantity` that can be minted with `_mintERC2309`. + // This limit is to prevent overflows on the address data entries. + // For a limit of 5000, a total of 3.689e15 calls to `_mintERC2309` + // is required to cause an overflow, which is unrealistic. + uint256 private constant MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000; + + // The tokenId of the next token to be minted. + uint256 private _currentIndex; + + // The number of tokens burned. + uint256 private _burnCounter; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to ownership details + // An empty struct value does not necessarily mean the token is unowned. + // See `_packedOwnershipOf` implementation for details. + // + // Bits Layout: + // - [0..159] `addr` + // - [160..223] `startTimestamp` + // - [224] `burned` + // - [225] `nextInitialized` + // - [232..255] `extraData` + mapping(uint256 => uint256) private _packedOwnerships; + + // Mapping owner address to address data. + // + // Bits Layout: + // - [0..63] `balance` + // - [64..127] `numberMinted` + // - [128..191] `numberBurned` + // - [192..255] `aux` + mapping(address => uint256) private _packedAddressData; + + // Mapping from token ID to approved address. + mapping(uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + _currentIndex = _startTokenId(); + } + + /** + * @dev Returns the starting token ID. + * To change the starting token ID, please override this function. + */ + function _startTokenId() internal view virtual returns (uint256) { + return 0; + } + + /** + * @dev Returns the next token ID to be minted. + */ + function _nextTokenId() internal view returns (uint256) { + return _currentIndex; + } + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see `_totalMinted`. + */ + function totalSupply() public view override returns (uint256) { + // Counter underflow is impossible as _burnCounter cannot be incremented + // more than `_currentIndex - _startTokenId()` times. + unchecked { + return _currentIndex - _burnCounter - _startTokenId(); + } + } + + /** + * @dev Returns the total amount of tokens minted in the contract. + */ + function _totalMinted() internal view returns (uint256) { + // Counter underflow is impossible as _currentIndex does not decrement, + // and it is initialized to `_startTokenId()` + unchecked { + return _currentIndex - _startTokenId(); + } + } + + /** + * @dev Returns the total number of tokens burned. + */ + function _totalBurned() internal view returns (uint256) { + return _burnCounter; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + // The interface IDs are constants representing the first 4 bytes of the XOR of + // all function selectors in the interface. See: https://eips.ethereum.org/EIPS/eip-165 + // e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)` + return + interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165. + interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721. + interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata. + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view override returns (uint256) { + if (owner == address(0)) revert BalanceQueryForZeroAddress(); + return _packedAddressData[owner] & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the number of tokens minted by `owner`. + */ + function _numberMinted(address owner) internal view returns (uint256) { + return (_packedAddressData[owner] >> BITPOS_NUMBER_MINTED) & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the number of tokens burned by or on behalf of `owner`. + */ + function _numberBurned(address owner) internal view returns (uint256) { + return (_packedAddressData[owner] >> BITPOS_NUMBER_BURNED) & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). + */ + function _getAux(address owner) internal view returns (uint64) { + return uint64(_packedAddressData[owner] >> BITPOS_AUX); + } + + /** + * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). + * If there are multiple variables, please pack them into a uint64. + */ + function _setAux(address owner, uint64 aux) internal { + uint256 packed = _packedAddressData[owner]; + uint256 auxCasted; + // Cast `aux` with assembly to avoid redundant masking. + assembly { + auxCasted := aux + } + packed = (packed & BITMASK_AUX_COMPLEMENT) | (auxCasted << BITPOS_AUX); + _packedAddressData[owner] = packed; + } + + /** + * Returns the packed ownership data of `tokenId`. + */ + function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) { + uint256 curr = tokenId; + + unchecked { + if (_startTokenId() <= curr) + if (curr < _currentIndex) { + uint256 packed = _packedOwnerships[curr]; + // If not burned. + if (packed & BITMASK_BURNED == 0) { + // Invariant: + // There will always be an ownership that has an address and is not burned + // before an ownership that does not have an address and is not burned. + // Hence, curr will not underflow. + // + // We can directly compare the packed value. + // If the address is zero, packed is zero. + while (packed == 0) { + packed = _packedOwnerships[--curr]; + } + return packed; + } + } + } + revert OwnerQueryForNonexistentToken(); + } + + /** + * Returns the unpacked `TokenOwnership` struct from `packed`. + */ + function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) { + ownership.addr = address(uint160(packed)); + ownership.startTimestamp = uint64(packed >> BITPOS_START_TIMESTAMP); + ownership.burned = packed & BITMASK_BURNED != 0; + ownership.extraData = uint24(packed >> BITPOS_EXTRA_DATA); + } + + /** + * Returns the unpacked `TokenOwnership` struct at `index`. + */ + function _ownershipAt(uint256 index) internal view returns (TokenOwnership memory) { + return _unpackedOwnership(_packedOwnerships[index]); + } + + /** + * @dev Initializes the ownership slot minted at `index` for efficiency purposes. + */ + function _initializeOwnershipAt(uint256 index) internal { + if (_packedOwnerships[index] == 0) { + _packedOwnerships[index] = _packedOwnershipOf(index); + } + } + + /** + * Gas spent here starts off proportional to the maximum mint batch size. + * It gradually moves to O(1) as tokens get transferred around in the collection over time. + */ + function _ownershipOf(uint256 tokenId) internal view returns (TokenOwnership memory) { + return _unpackedOwnership(_packedOwnershipOf(tokenId)); + } + + /** + * @dev Packs ownership data into a single uint256. + */ + function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) { + assembly { + // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. + owner := and(owner, BITMASK_ADDRESS) + // `owner | (block.timestamp << BITPOS_START_TIMESTAMP) | flags`. + result := or(owner, or(shl(BITPOS_START_TIMESTAMP, timestamp()), flags)) + } + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view override returns (address) { + return address(uint160(_packedOwnershipOf(tokenId))); + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + if (!_exists(tokenId)) revert URIQueryForNonexistentToken(); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : ''; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, it can be overridden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ''; + } + + /** + * @dev Returns the `nextInitialized` flag set if `quantity` equals 1. + */ + function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) { + // For branchless setting of the `nextInitialized` flag. + assembly { + // `(quantity == 1) << BITPOS_NEXT_INITIALIZED`. + result := shl(BITPOS_NEXT_INITIALIZED, eq(quantity, 1)) + } + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public override { + address owner = ownerOf(tokenId); + + if (_msgSenderERC721A() != owner) + if (!isApprovedForAll(owner, _msgSenderERC721A())) { + revert ApprovalCallerNotOwnerNorApproved(); + } + + _tokenApprovals[tokenId] = to; + emit Approval(owner, to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view override returns (address) { + if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken(); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + if (operator == _msgSenderERC721A()) revert ApproveToCaller(); + + _operatorApprovals[_msgSenderERC721A()][operator] = approved; + emit ApprovalForAll(_msgSenderERC721A(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + safeTransferFrom(from, to, tokenId, ''); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) public virtual override { + transferFrom(from, to, tokenId); + if (to.code.length != 0) + if (!_checkContractOnERC721Received(from, to, tokenId, _data)) { + revert TransferToNonERC721ReceiverImplementer(); + } + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + */ + function _exists(uint256 tokenId) internal view returns (bool) { + return + _startTokenId() <= tokenId && + tokenId < _currentIndex && // If within bounds, + _packedOwnerships[tokenId] & BITMASK_BURNED == 0; // and not burned. + } + + /** + * @dev Equivalent to `_safeMint(to, quantity, '')`. + */ + function _safeMint(address to, uint256 quantity) internal { + _safeMint(to, quantity, ''); + } + + /** + * @dev Safely mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called for each safe transfer. + * - `quantity` must be greater than 0. + * + * See {_mint}. + * + * Emits a {Transfer} event for each mint. + */ + function _safeMint( + address to, + uint256 quantity, + bytes memory _data + ) internal { + _mint(to, quantity); + + unchecked { + if (to.code.length != 0) { + uint256 end = _currentIndex; + uint256 index = end - quantity; + do { + if (!_checkContractOnERC721Received(address(0), to, index++, _data)) { + revert TransferToNonERC721ReceiverImplementer(); + } + } while (index < end); + // Reentrancy protection. + if (_currentIndex != end) revert(); + } + } + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {Transfer} event for each mint. + */ + function _mint(address to, uint256 quantity) internal { + uint256 startTokenId = _currentIndex; + if (to == address(0)) revert MintToZeroAddress(); + if (quantity == 0) revert MintZeroQuantity(); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are incredibly unrealistic. + // `balance` and `numberMinted` have a maximum limit of 2**64. + // `tokenId` has a maximum limit of 2**256. + unchecked { + // Updates: + // - `balance += quantity`. + // - `numberMinted += quantity`. + // + // We can directly add to the `balance` and `numberMinted`. + _packedAddressData[to] += quantity * ((1 << BITPOS_NUMBER_MINTED) | 1); + + // Updates: + // - `address` to the owner. + // - `startTimestamp` to the timestamp of minting. + // - `burned` to `false`. + // - `nextInitialized` to `quantity == 1`. + _packedOwnerships[startTokenId] = _packOwnershipData( + to, + _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) + ); + + uint256 tokenId = startTokenId; + uint256 end = startTokenId + quantity; + do { + emit Transfer(address(0), to, tokenId++); + } while (tokenId < end); + + _currentIndex = end; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * This function is intended for efficient minting only during contract creation. + * + * It emits only one {ConsecutiveTransfer} as defined in + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309), + * instead of a sequence of {Transfer} event(s). + * + * Calling this function outside of contract creation WILL make your contract + * non-compliant with the ERC721 standard. + * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309 + * {ConsecutiveTransfer} event is only permissible during contract creation. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {ConsecutiveTransfer} event. + */ + function _mintERC2309(address to, uint256 quantity) internal { + uint256 startTokenId = _currentIndex; + if (to == address(0)) revert MintToZeroAddress(); + if (quantity == 0) revert MintZeroQuantity(); + if (quantity > MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit(); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are unrealistic due to the above check for `quantity` to be below the limit. + unchecked { + // Updates: + // - `balance += quantity`. + // - `numberMinted += quantity`. + // + // We can directly add to the `balance` and `numberMinted`. + _packedAddressData[to] += quantity * ((1 << BITPOS_NUMBER_MINTED) | 1); + + // Updates: + // - `address` to the owner. + // - `startTimestamp` to the timestamp of minting. + // - `burned` to `false`. + // - `nextInitialized` to `quantity == 1`. + _packedOwnerships[startTokenId] = _packOwnershipData( + to, + _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) + ); + + emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to); + + _currentIndex = startTokenId + quantity; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Returns the storage slot and value for the approved address of `tokenId`. + */ + function _getApprovedAddress(uint256 tokenId) + private + view + returns (uint256 approvedAddressSlot, address approvedAddress) + { + mapping(uint256 => address) storage tokenApprovalsPtr = _tokenApprovals; + // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId]`. + assembly { + // Compute the slot. + mstore(0x00, tokenId) + mstore(0x20, tokenApprovalsPtr.slot) + approvedAddressSlot := keccak256(0x00, 0x40) + // Load the slot's value from storage. + approvedAddress := sload(approvedAddressSlot) + } + } + + /** + * @dev Returns whether the `approvedAddress` is equals to `from` or `msgSender`. + */ + function _isOwnerOrApproved( + address approvedAddress, + address from, + address msgSender + ) private pure returns (bool result) { + assembly { + // Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean. + from := and(from, BITMASK_ADDRESS) + // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean. + msgSender := and(msgSender, BITMASK_ADDRESS) + // `msgSender == from || msgSender == approvedAddress`. + result := or(eq(msgSender, from), eq(msgSender, approvedAddress)) + } + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); + + if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner(); + + (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedAddress(tokenId); + + // The nested ifs save around 20+ gas over a compound boolean condition. + if (!_isOwnerOrApproved(approvedAddress, from, _msgSenderERC721A())) + if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved(); + + if (to == address(0)) revert TransferToZeroAddress(); + + _beforeTokenTransfers(from, to, tokenId, 1); + + // Clear approvals from the previous owner. + assembly { + if approvedAddress { + // This is equivalent to `delete _tokenApprovals[tokenId]`. + sstore(approvedAddressSlot, 0) + } + } + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as tokenId would have to be 2**256. + unchecked { + // We can directly increment and decrement the balances. + --_packedAddressData[from]; // Updates: `balance -= 1`. + ++_packedAddressData[to]; // Updates: `balance += 1`. + + // Updates: + // - `address` to the next owner. + // - `startTimestamp` to the timestamp of transfering. + // - `burned` to `false`. + // - `nextInitialized` to `true`. + _packedOwnerships[tokenId] = _packOwnershipData( + to, + BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked) + ); + + // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . + if (prevOwnershipPacked & BITMASK_NEXT_INITIALIZED == 0) { + uint256 nextTokenId = tokenId + 1; + // If the next slot's address is zero and not burned (i.e. packed value is zero). + if (_packedOwnerships[nextTokenId] == 0) { + // If the next slot is within bounds. + if (nextTokenId != _currentIndex) { + // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. + _packedOwnerships[nextTokenId] = prevOwnershipPacked; + } + } + } + } + + emit Transfer(from, to, tokenId); + _afterTokenTransfers(from, to, tokenId, 1); + } + + /** + * @dev Equivalent to `_burn(tokenId, false)`. + */ + function _burn(uint256 tokenId) internal virtual { + _burn(tokenId, false); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId, bool approvalCheck) internal virtual { + uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); + + address from = address(uint160(prevOwnershipPacked)); + + (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedAddress(tokenId); + + if (approvalCheck) { + // The nested ifs save around 20+ gas over a compound boolean condition. + if (!_isOwnerOrApproved(approvedAddress, from, _msgSenderERC721A())) + if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved(); + } + + _beforeTokenTransfers(from, address(0), tokenId, 1); + + // Clear approvals from the previous owner. + assembly { + if approvedAddress { + // This is equivalent to `delete _tokenApprovals[tokenId]`. + sstore(approvedAddressSlot, 0) + } + } + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. + unchecked { + // Updates: + // - `balance -= 1`. + // - `numberBurned += 1`. + // + // We can directly decrement the balance, and increment the number burned. + // This is equivalent to `packed -= 1; packed += 1 << BITPOS_NUMBER_BURNED;`. + _packedAddressData[from] += (1 << BITPOS_NUMBER_BURNED) - 1; + + // Updates: + // - `address` to the last owner. + // - `startTimestamp` to the timestamp of burning. + // - `burned` to `true`. + // - `nextInitialized` to `true`. + _packedOwnerships[tokenId] = _packOwnershipData( + from, + (BITMASK_BURNED | BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked) + ); + + // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . + if (prevOwnershipPacked & BITMASK_NEXT_INITIALIZED == 0) { + uint256 nextTokenId = tokenId + 1; + // If the next slot's address is zero and not burned (i.e. packed value is zero). + if (_packedOwnerships[nextTokenId] == 0) { + // If the next slot is within bounds. + if (nextTokenId != _currentIndex) { + // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. + _packedOwnerships[nextTokenId] = prevOwnershipPacked; + } + } + } + } + + emit Transfer(from, address(0), tokenId); + _afterTokenTransfers(from, address(0), tokenId, 1); + + // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times. + unchecked { + _burnCounter++; + } + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkContractOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) private returns (bool) { + try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns ( + bytes4 retval + ) { + return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert TransferToNonERC721ReceiverImplementer(); + } else { + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } + + /** + * @dev Directly sets the extra data for the ownership data `index`. + */ + function _setExtraDataAt(uint256 index, uint24 extraData) internal { + uint256 packed = _packedOwnerships[index]; + if (packed == 0) revert OwnershipNotInitializedForExtraData(); + uint256 extraDataCasted; + // Cast `extraData` with assembly to avoid redundant masking. + assembly { + extraDataCasted := extraData + } + packed = (packed & BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << BITPOS_EXTRA_DATA); + _packedOwnerships[index] = packed; + } + + /** + * @dev Returns the next extra data for the packed ownership data. + * The returned result is shifted into position. + */ + function _nextExtraData( + address from, + address to, + uint256 prevOwnershipPacked + ) private view returns (uint256) { + uint24 extraData = uint24(prevOwnershipPacked >> BITPOS_EXTRA_DATA); + return uint256(_extraData(from, to, extraData)) << BITPOS_EXTRA_DATA; + } + + /** + * @dev Called during each token transfer to set the 24bit `extraData` field. + * Intended to be overridden by the cosumer contract. + * + * `previousExtraData` - the value of `extraData` before transfer. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _extraData( + address from, + address to, + uint24 previousExtraData + ) internal view virtual returns (uint24) {} + + /** + * @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. + * This includes minting. + * And also called before burning one token. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _beforeTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Hook that is called after a set of serially-ordered token ids have been transferred. + * This includes minting. + * And also called after one token has been burned. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been + * transferred to `to`. + * - When `from` is zero, `tokenId` has been minted for `to`. + * - When `to` is zero, `tokenId` has been burned by `from`. + * - `from` and `to` are never both zero. + */ + function _afterTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Returns the message sender (defaults to `msg.sender`). + * + * If you are writing GSN compatible contracts, you need to override this function. + */ + function _msgSenderERC721A() internal view virtual returns (address) { + return msg.sender; + } + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function _toString(uint256 value) internal pure returns (string memory ptr) { + assembly { + // The maximum value of a uint256 contains 78 digits (1 byte per digit), + // but we allocate 128 bytes to keep the free memory pointer 32-byte word aliged. + // We will need 1 32-byte word to store the length, + // and 3 32-byte words to store a maximum of 78 digits. Total: 32 + 3 * 32 = 128. + ptr := add(mload(0x40), 128) + // Update the free memory pointer to allocate. + mstore(0x40, ptr) + + // Cache the end of the memory to calculate the length later. + let end := ptr + + // We write the string from the rightmost digit to the leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + // Costs a bit more than early returning for the zero case, + // but cheaper in terms of deployment and overall runtime costs. + for { + // Initialize and perform the first pass without check. + let temp := value + // Move the pointer 1 byte leftwards to point to an empty character slot. + ptr := sub(ptr, 1) + // Write the character to the pointer. 48 is the ASCII index of '0'. + mstore8(ptr, add(48, mod(temp, 10))) + temp := div(temp, 10) + } temp { + // Keep dividing `temp` until zero. + temp := div(temp, 10) + } { + // Body of the for loop. + ptr := sub(ptr, 1) + mstore8(ptr, add(48, mod(temp, 10))) + } + + let length := sub(end, ptr) + // Move the pointer 32 bytes leftwards to make room for the length. + ptr := sub(ptr, 32) + // Store the length. + mstore(ptr, length) + } + } +} + + +/////////////////////////////////////////// +// File: erc721a/contracts/IERC721A.sol + +// SPDX-License-Identifier: MIT +// ERC721A Contracts v4.1.0 +// Creator: Chiru Labs + +pragma solidity ^0.8.4; + +/** + * @dev Interface of an ERC721A compliant contract. + */ +interface IERC721A { + /** + * The caller must own the token or be an approved operator. + */ + error ApprovalCallerNotOwnerNorApproved(); + + /** + * The token does not exist. + */ + error ApprovalQueryForNonexistentToken(); + + /** + * The caller cannot approve to their own address. + */ + error ApproveToCaller(); + + /** + * Cannot query the balance for the zero address. + */ + error BalanceQueryForZeroAddress(); + + /** + * Cannot mint to the zero address. + */ + error MintToZeroAddress(); + + /** + * The quantity of tokens minted must be more than zero. + */ + error MintZeroQuantity(); + + /** + * The token does not exist. + */ + error OwnerQueryForNonexistentToken(); + + /** + * The caller must own the token or be an approved operator. + */ + error TransferCallerNotOwnerNorApproved(); + + /** + * The token must be owned by `from`. + */ + error TransferFromIncorrectOwner(); + + /** + * Cannot safely transfer to a contract that does not implement the ERC721Receiver interface. + */ + error TransferToNonERC721ReceiverImplementer(); + + /** + * Cannot transfer to the zero address. + */ + error TransferToZeroAddress(); + + /** + * The token does not exist. + */ + error URIQueryForNonexistentToken(); + + /** + * The `quantity` minted with ERC2309 exceeds the safety limit. + */ + error MintERC2309QuantityExceedsLimit(); + + /** + * The `extraData` cannot be set on an unintialized ownership slot. + */ + error OwnershipNotInitializedForExtraData(); + + struct TokenOwnership { + // The address of the owner. + address addr; + // Keeps track of the start time of ownership with minimal overhead for tokenomics. + uint64 startTimestamp; + // Whether the token has been burned. + bool burned; + // Arbitrary data similar to `startTimestamp` that can be set through `_extraData`. + uint24 extraData; + } + + /** + * @dev Returns the total amount of tokens stored by the contract. + * + * Burned tokens are calculated here, use `_totalMinted()` if you want to count just minted tokens. + */ + function totalSupply() external view returns (uint256); + + // ============================== + // IERC165 + // ============================== + + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); + + // ============================== + // IERC721 + // ============================== + + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + // ============================== + // IERC721Metadata + // ============================== + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); + + // ============================== + // IERC2309 + // ============================== + + /** + * @dev Emitted when tokens in `fromTokenId` to `toTokenId` (inclusive) is transferred from `from` to `to`, + * as defined in the ERC2309 standard. See `_mintERC2309` for more details. + */ + event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); +} + + diff --git a/ethabi/code/0x34625ecaa75c0ea33733a05c584f4cf112c10b6b.yml b/ethabi/code/0x34625ecaa75c0ea33733a05c584f4cf112c10b6b.yml new file mode 100644 index 0000000..72651d9 --- /dev/null +++ b/ethabi/code/0x34625ecaa75c0ea33733a05c584f4cf112c10b6b.yml @@ -0,0 +1,12 @@ +--- +ContractName: Indelible +CompilerVersion: v0.8.14+commit.80d49f37 +OptimizationUsed: '1' +Runs: '200' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: MIT +Proxy: '0' +Implementation: '' +SwarmSource: '' diff --git a/ethabi/code/0x58e90596c2065befd3060767736c829c18f3474c.sol b/ethabi/code/0x58e90596c2065befd3060767736c829c18f3474c.sol new file mode 100644 index 0000000..bb311b1 --- /dev/null +++ b/ethabi/code/0x58e90596c2065befd3060767736c829c18f3474c.sol @@ -0,0 +1,1085 @@ +// SPDX-License-Identifier: MIT +// Author: tycoon.eth, thanks to @geraldb & @samwilsn on Github for inspiration! +// Version: v0.0.2 +// Note: The MIT license is for the source code only. Images registered through +// this contract retain all of their owner's rights. This contract +// is a non-profit "library" project and intended to archive & preserve punk +// images, so that they can become widely accessible for decentralized +// applications, including marketplaces, wallets, galleries, etc. +pragma solidity ^0.8.17; +/** + + ███████████ █████ +░░███░░░░░███ ░░███ + ░███ ░███ █████ ████ ████████ ░███ █████ + ░██████████ ░░███ ░███ ░░███░░███ ░███░░███ + ░███░░░░░░ ░███ ░███ ░███ ░███ ░██████░ + ░███ ░███ ░███ ░███ ░███ ░███░░███ + █████ ░░████████ ████ █████ ████ █████ +░░░░░ ░░░░░░░░ ░░░░ ░░░░░ ░░░░ ░░░░░ + + + + ███████████ ████ █████ +░░███░░░░░███░░███ ░░███ + ░███ ░███ ░███ ██████ ██████ ░███ █████ █████ + ░██████████ ░███ ███░░███ ███░░███ ░███░░███ ███░░ + ░███░░░░░███ ░███ ░███ ░███░███ ░░░ ░██████░ ░░█████ + ░███ ░███ ░███ ░███ ░███░███ ███ ░███░░███ ░░░░███ + ███████████ █████░░██████ ░░██████ ████ █████ ██████ +░░░░░░░░░░░ ░░░░░ ░░░░░░ ░░░░░░ ░░░░ ░░░░░ ░░░░░░ + + A Registry of 24x24 png images + +This contract: + +1. Stores all the classic traits of the CryptoPunks in +individual png files, 100% on-chain. These are then used as +blocks to construct CryptoPunk images. Outputted as SVGs. + +2. Any of the 10,000 "classic" CryptoPunks can be generated +by supplying desired arguments to a function, such as +the id of a punk, or a list of the traits. + +3. An unlimited number of new punk images can be generated from +the existing classic set of traits, or even from new traits! + +4. New traits (blocks) can be added to the contract by +registering them with the `registerBlock` function. + +Further documentation: +https://github.com/0xTycoon/punk-blocks + +*/ +contract PunkBlocks { + // Layer is in the order of rendering + enum Layer { + Base, // 0 Base is the face. Determines if m or f version will be used to render the remaining layers + Cheeks, // 1 (Rosy Cheeks) + Blemish, // 2 (Mole, Spots) + Hair, // 3 (Purple Hair, Shaved Head, Pigtails, ...) + Beard, // 4 (Big Beard, Front Beard, Goat, ...) + Eyes, // 5 (Clown Eyes Green, Green Eye Shadow, ...) + Eyewear, // 6 (VR, 3D Glass, Eye Mask, Regular Shades, Welding Glasses, ...) + Nose, // 7 (Clown Nose) + Mouth, // 8 (Hot Lipstick, Smile, Buck Teeth, ...) + MouthProp, // 9 (Medical Mask, Cigarette, ...) + Earring, // 10 (Earring) + Headgear, // 11 (Beanie, Fedora, Hoodie, Police Cap, Tiara, Headband, ...) + Neck // 12 (Choker, Silver Chain, Gold Chain) + } + struct Block { + Layer layer; // 13 possible layers + bytes dataMale; // male version of this attribute + bytes dataFemale;// female version of this attribute + } + mapping(bytes32 => Block) public blocks; // stores punk attributes as a png + uint256 public nextId; // next id to use when adding a block + mapping(uint256 => bytes32) public index; // index of each block by its sequence + event NewBlock(address, uint256, string); + /** + * Here we initialize `blocks` storage with the entire set of original CryptoPunk attributes + */ + constructor() { + // Initial blocks that were sourced from https://github.com/cryptopunksnotdead/punks.js/blob/master/yeoldepunks/yeoldepunks-24x24.png + Block storage b = blocks[bytes32(hex"9039da071f773e85254cbd0f99efa70230c4c11d63fce84323db9eca8e8ef283")]; + b.layer = Layer(0); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb00000012504c5445000000000000713f1d8b532c5626007237092b4acd040000000174524e530040e6d8660000004f4944415478da62a00a1014141480b11995949414611c2165252525989490113247092747c549c945006698629092a800c264b8324674030489315a49118f3284ab9590fc23045783cc01040000ffffd8690b6ca3604b190000000049454e44ae426082"; + index[nextId] = bytes32(hex"9039da071f773e85254cbd0f99efa70230c4c11d63fce84323db9eca8e8ef283"); + nextId++; + b = blocks[bytes32(hex"dfcbad4edd134a08c17026fc7af40e146af242a3412600cee7c0719d0ac42d53")]; + b.layer = Layer(0); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb00000012504c5445000000000000ae8b61b69f8286581ea77c470e17bdef0000000174524e530040e6d8660000004f4944415478da62a00a1014141480b11995949414611c2165252525989490113247092747c549c945006698629092a800c264b8324674030489315a49118f3284ab9590fc23045783cc01040000ffffd8690b6ca3604b190000000049454e44ae426082"; + index[nextId] = bytes32(hex"dfcbad4edd134a08c17026fc7af40e146af242a3412600cee7c0719d0ac42d53"); + nextId++; + b = blocks[bytes32(hex"ed94d667f893279240c415151388f335b32027819fa6a4661afaacce342f4c54")]; + b.layer = Layer(0); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb00000012504c5445000000000000dbb180e7cba9a66e2cd29d601a5e5ef40000000174524e530040e6d8660000004f4944415478da62a00a1014141480b11995949414611c2165252525989490113247092747c549c945006698629092a800c264b8324674030489315a49118f3284ab9590fc23045783cc01040000ffffd8690b6ca3604b190000000049454e44ae426082"; + index[nextId] = bytes32(hex"ed94d667f893279240c415151388f335b32027819fa6a4661afaacce342f4c54"); + nextId++; + b = blocks[bytes32(hex"1323f587f8837b162082b8d221e381c5e015d390305ce6be8ade3ff70e70446e")]; + b.layer = Layer(0); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb00000012504c5445000000000000ead9d9ffffffa58d8dc9b2b21adbe9c60000000174524e530040e6d8660000004f4944415478da62a00a1014141480b11995949414611c2165252525989490113247092747c549c945006698629092a800c264b8324674030489315a49118f3284ab9590fc23045783cc01040000ffffd8690b6ca3604b190000000049454e44ae426082"; + index[nextId] = bytes32(hex"1323f587f8837b162082b8d221e381c5e015d390305ce6be8ade3ff70e70446e"); + nextId++; + b = blocks[bytes32(hex"1bb61a688fea4953cb586baa1eadb220020829a1e284be38d2ea8fb996dd7286")]; + b.layer = Layer(0); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb00000015504c5445000000000000713f1d8b532c5626007237094a120162eb383b0000000174524e530040e6d8660000004c4944415478da62a03160141414807384949414e112ca4a4a4a302946255c1c2115272517384731484914c61154c26380102e19b5343807c5390c42082d208b0419905c2d80c901040000ffff2f3c090f8ffce8ac0000000049454e44ae426082"; + index[nextId] = bytes32(hex"1bb61a688fea4953cb586baa1eadb220020829a1e284be38d2ea8fb996dd7286"); + nextId++; + b = blocks[bytes32(hex"47cc6a8e17679da04a479e5d29625d737670c27b21f8ccfb334e6af61bf6885a")]; + b.layer = Layer(0); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb00000015504c5445000000000000ae8b61b69f8286581ea77c475f1d096e17a6860000000174524e530040e6d8660000004c4944415478da62a03160141414807384949414e112ca4a4a4a302946255c1c2115272517384731484914c61154c26380102e19b5343807c5390c42082d208b0419905c2d80c901040000ffff2f3c090f8ffce8ac0000000049454e44ae426082"; + index[nextId] = bytes32(hex"47cc6a8e17679da04a479e5d29625d737670c27b21f8ccfb334e6af61bf6885a"); + nextId++; + b = blocks[bytes32(hex"80547b534287b04dc7e9afb751db65a7515fde92b8c2394ae341e3ae0955d519")]; + b.layer = Layer(0); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb00000015504c5445000000000000dbb180e7cba9a66e2cd29d60711010e7210e7f0000000174524e530040e6d8660000004c4944415478da62a03160141414807384949414e112ca4a4a4a302946255c1c2115272517384731484914c61154c26380102e19b5343807c5390c42082d208b0419905c2d80c901040000ffff2f3c090f8ffce8ac0000000049454e44ae426082"; + index[nextId] = bytes32(hex"80547b534287b04dc7e9afb751db65a7515fde92b8c2394ae341e3ae0955d519"); + nextId++; + b = blocks[bytes32(hex"c0c9e42e9d271c94b57d055fc963197e4c62d5933e371a7449ef5d59f26be00a")]; + b.layer = Layer(0); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb00000015504c5445000000000000ead9d9ffffffa58d8dc9b2b2711010f69870510000000174524e530040e6d8660000004c4944415478da62a03160141414807384949414e112ca4a4a4a302946255c1c2115272517384731484914c61154c26380102e19b5343807c5390c42082d208b0419905c2d80c901040000ffff2f3c090f8ffce8ac0000000049454e44ae426082"; + index[nextId] = bytes32(hex"c0c9e42e9d271c94b57d055fc963197e4c62d5933e371a7449ef5d59f26be00a"); + nextId++; + b = blocks[bytes32(hex"f41cb73ce9ba5c1f594bcdfd56e2d14e42d2ecc23f0a4863835bdd4baacd8b72")]; + b.layer = Layer(0); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb00000012504c54450000000000007da2699bbc885e7253ff00007efb409c0000000174524e530040e6d866000000534944415478da62a00a1014141480b11995949414611c2165252525989490113247092747c549c945006698aa9052209ca3a2a4e404e3a01b20488cd14a8ac8ca545095215cad84e41f21b81a640e200000ffffea5f0b90848c25f90000000049454e44ae426082"; + index[nextId] = bytes32(hex"f41cb73ce9ba5c1f594bcdfd56e2d14e42d2ecc23f0a4863835bdd4baacd8b72"); + nextId++; + b = blocks[bytes32(hex"b1ea1507d58429e4dfa3f444cd2e584ba8909c931969bbfb5f1e21e2ac8b758d")]; + b.layer = Layer(0); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb00000012504c5445000000000000352410856f566a563fa98c6b35cdf9490000000174524e530040e6d866000000604944415478daaccfd11180200c0350d980c0390071821a37d00ddc7f17bf68eb9d9ff2c5bb062e5d7e3900eabc179263a29164fdc4009a43921cc7a9abcecfecd6ea48b1f27eb3990528ed31c9b10ef4409e0cc9a275daa779e58c270000ffff866f0d065247e95a0000000049454e44ae426082"; + index[nextId] = bytes32(hex"b1ea1507d58429e4dfa3f444cd2e584ba8909c931969bbfb5f1e21e2ac8b758d"); + nextId++; + b = blocks[bytes32(hex"62223f0b03d25507f52a69efbbdbcfdc7579756a7a08a95a2f0e72ada31e32b8")]; + b.layer = Layer(0); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb00000012504c5445000000000000c8fbfb9be0e0f1ffff75bdbd4053c1210000000174524e530040e6d866000000564944415478daac8fb11180300c03c906b198207fb040466003f65f86061335ee70e53feb6469fb6522a2e7de8091a003c8932e070a683ac5fd82e698ec7d399b0ca61bd4e07f22542658a9b13efa340e4f000000ffffe3a70b7c1e9e0e0b0000000049454e44ae426082"; + index[nextId] = bytes32(hex"62223f0b03d25507f52a69efbbdbcfdc7579756a7a08a95a2f0e72ada31e32b8"); + nextId++; + b = blocks[bytes32(hex"047228ad95cec16eb926f7cd21ac9cc9a3288d911a6c2917a24555eac7a2c0e2")]; + b.layer = Layer(1); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df8000000374944415478da6262a03118b560d482510b462d18b5806e165c62603006616ce254f3811e03c35986c1084653d1a805940340000000ffff94c80439947873b80000000049454e44ae426082"; + index[nextId] = bytes32(hex"047228ad95cec16eb926f7cd21ac9cc9a3288d911a6c2917a24555eac7a2c0e2"); + nextId++; + b = blocks[bytes32(hex"ce1f93a7afe9aad7ebb13c0add89c79d42b5e9b1272fdd1573aac99fe5d860d0")]; + b.layer = Layer(4); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000000000692f08d8a2a9300000000174524e530040e6d866000000284944415478da62a01f608452018c0e202a34144c852d45e2318486322051a22170cd80000000ffffb3a4056366b432730000000049454e44ae426082"; + index[nextId] = bytes32(hex"ce1f93a7afe9aad7ebb13c0add89c79d42b5e9b1272fdd1573aac99fe5d860d0"); + nextId++; + b = blocks[bytes32(hex"bfac272e71cad64427175cd77d774a7884f98c7901ebc4909ada29d464c8981e")]; + b.layer = Layer(3); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c544500000028b143000000cc9ab8ec0000000174524e530040e6d8660000003e4944415478da62c00b181d5841142b03a3030303832803630003034308184129d6100686500718c508a218181802204a04c008041418280480000000ffff40c405ad8a2523500000000049454e44ae426082"; + index[nextId] = bytes32(hex"bfac272e71cad64427175cd77d774a7884f98c7901ebc4909ada29d464c8981e"); + nextId++; + b = blocks[bytes32(hex"a71068a671b554f75b7cc31ce4f8d63c377f276333d11989e77bc4a9205b5e42")]; + b.layer = Layer(3); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d866000000294944415478daa4c0211100300800c097130b30b1280443109e3b2af0c6c547a0907838b63a0000ffff7250017908940adc0000000049454e44ae426082"; + index[nextId] = bytes32(hex"a71068a671b554f75b7cc31ce4f8d63c377f276333d11989e77bc4a9205b5e42"); + nextId++; + b = blocks[bytes32(hex"9a132de8409f80845eaec43154ff43d7bd61df75e52d96b4ded0b64626e4c88a")]; + b.layer = Layer(11); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000794b11502f0566020e390000000174524e530040e6d8660000002a4944415478da62c0010244402463682806c5c2b56a558303036b686868a803480c22496300080000ffff65920776511a3f8f0000000049454e44ae426082"; + index[nextId] = bytes32(hex"9a132de8409f80845eaec43154ff43d7bd61df75e52d96b4ded0b64626e4c88a"); + nextId++; + b = blocks[bytes32(hex"fca4c5f86ef326916536dfdae74031d6960e41e10d38c624294334c3833974e2")]; + b.layer = Layer(4); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df80000002f4944415478da6262a03118b560d482510b462d18b560d40210602141ed4c2c62e90c030d462379045800080000ffff60530131658c7b950000000049454e44ae426082"; + index[nextId] = bytes32(hex"fca4c5f86ef326916536dfdae74031d6960e41e10d38c624294334c3833974e2"); + nextId++; + b = blocks[bytes32(hex"4483a654781ca58fa6ba3590c74c005bce612263e17c70445d6cd167e55e900b")]; + b.layer = Layer(7); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000d600002c63f04d0000000174524e530040e6d866000000134944415478da62201bf040317e00080000ffff03c000197c38ad200000000049454e44ae426082"; + index[nextId] = bytes32(hex"4483a654781ca58fa6ba3590c74c005bce612263e17c70445d6cd167e55e900b"); + nextId++; + b = blocks[bytes32(hex"1885fe71e225eade934ab7040d533bd49efc5d66e8f2d4b5aa42477ae9892ec9")]; + b.layer = Layer(9); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df80000004b4944415478da6262a03118b560d482510b869a0577efde6d180da2116801cd010b057affe31067c4c921c5f063c78e6108ca4c4d60905b7a0bc55c465afb806134990eb80580000000ffff78ff0b44c51816510000000049454e44ae426082"; + index[nextId] = bytes32(hex"1885fe71e225eade934ab7040d533bd49efc5d66e8f2d4b5aa42477ae9892ec9"); + nextId++; + b = blocks[bytes32(hex"7411db1fe7a50d41767858710dc8b8432ac0c4fd26503ba78d2ed17789ce4f72")]; + b.layer = Layer(6); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c544500000000000080dbda669cd55e0000000174524e530040e6d866000000224944415478da62a01608157560606060cc8c02510c99520e08416a0040000000ffff0567031c1296b7680000000049454e44ae426082"; + index[nextId] = bytes32(hex"7411db1fe7a50d41767858710dc8b8432ac0c4fd26503ba78d2ed17789ce4f72"); + nextId++; + b = blocks[bytes32(hex"dd7231e98344a83b64e1ac7a07b39d2ecc2b21128681123a9030e17a12422527")]; + b.layer = Layer(6); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d8660000001d4944415478da622005b0ff3fc0c0f0f90003436203b15a00010000ffffca27045b28df4bb90000000049454e44ae426082"; + index[nextId] = bytes32(hex"dd7231e98344a83b64e1ac7a07b39d2ecc2b21128681123a9030e17a12422527"); + nextId++; + b = blocks[bytes32(hex"24dd0364c2b2d0e6540c7deb5a0acf9177d47737a2bf41ca29b553eb69558ef9")]; + b.layer = Layer(11); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c5445000000000000933709ca4e11586029880000000174524e530040e6d866000000264944415478da622005fcff032299ffff075152ab564d60606090debd7b0203ed01200000ffff89c6081c0afc0fac0000000049454e44ae426082"; + index[nextId] = bytes32(hex"24dd0364c2b2d0e6540c7deb5a0acf9177d47737a2bf41ca29b553eb69558ef9"); + nextId++; + b = blocks[bytes32(hex"ea5efa009543229e434689349c866e4d254811928ae8a1320abb82a36d3be53f")]; + b.layer = Layer(4); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df80000004a4944415478da6262a03118b560d482510b462d18b5801e16f8d2c307be94388085488790ed13165214b784c9c2d935ab1e13a587910aaedf4c691c6c26d770ba80a19fd100010000ffff17b506cc6c8ffcb10000000049454e44ae426082"; + index[nextId] = bytes32(hex"ea5efa009543229e434689349c866e4d254811928ae8a1320abb82a36d3be53f"); + nextId++; + b = blocks[bytes32(hex"2df03e79022dc10f7539f01da354ffe10da3ef91f1e18bc7fd096db00c381de8")]; + b.layer = Layer(8); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d866000000124944415478da62a02a50c01001040000ffff02a00021e29936ae0000000049454e44ae426082"; + index[nextId] = bytes32(hex"2df03e79022dc10f7539f01da354ffe10da3ef91f1e18bc7fd096db00c381de8"); + nextId++; + b = blocks[bytes32(hex"f0ac7cf8c022008e16b983f22d22dae3a15b9b5abcc635bc5c20beb4d7c91800")]; + b.layer = Layer(11); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c54450000000000003535355151511dd8d71d0000000174524e530040e6d866000000314944415478da62c00f42434024e3febf208aedff7f07060606f6afa10120ead6aa250c0c0caca11035340680000000ffff5f8a097e7a97a9b90000000049454e44ae426082"; + index[nextId] = bytes32(hex"f0ac7cf8c022008e16b983f22d22dae3a15b9b5abcc635bc5c20beb4d7c91800"); + nextId++; + b = blocks[bytes32(hex"8580e735d58252637afd6fef159c826c5e7e6a5dcf1fe2d8398b3bf92c376d42")]; + b.layer = Layer(4); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000a66e2c00000080c0c2990000000174524e530040e6d8660000001a4944415478da62185c80310099624a808836303000020000ffff12f9018505211f590000000049454e44ae426082"; + index[nextId] = bytes32(hex"8580e735d58252637afd6fef159c826c5e7e6a5dcf1fe2d8398b3bf92c376d42"); + nextId++; + b = blocks[bytes32(hex"041bf83549434251cc54c0632896c8d3176b48d06150048c1bce6b6102c4e90c")]; + b.layer = Layer(2); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df80000002c4944415478da6262a03118b560d482510b462d18b5607858a0202796c63098c168248f5a403900040000ffff01a900e96b1795ed0000000049454e44ae426082"; + index[nextId] = bytes32(hex"041bf83549434251cc54c0632896c8d3176b48d06150048c1bce6b6102c4e90c"); + nextId++; + b = blocks[bytes32(hex"591f84c8a41edd0013624b89d5e6b96cd3b0c6f1e214d4ea13a35639412f07e6")]; + b.layer = Layer(3); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000710cc759e1a3b70000000174524e530040e6d8660000003f4944415478da6cc6b10d40501000d017f989465cab905843c50a463a7b8bd368245ef57c1c741771d3174ba538d32e8dd83061c58019ed7df3eb090000fffff8b007a7fc0c1ce10000000049454e44ae426082"; + index[nextId] = bytes32(hex"591f84c8a41edd0013624b89d5e6b96cd3b0c6f1e214d4ea13a35639412f07e6"); + nextId++; + b = blocks[bytes32(hex"54917cb8cff2411930ac1b1d36a674f855c6b16c8662806266734b5f718a9890")]; + b.layer = Layer(6); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d8660000001b4944415478da62200530fe6760604a66606048265a0b200000ffff54c701c9074dcd420000000049454e44ae426082"; + index[nextId] = bytes32(hex"54917cb8cff2411930ac1b1d36a674f855c6b16c8662806266734b5f718a9890"); + nextId++; + b = blocks[bytes32(hex"274ae610f9d7dec1e425c54ad990e7d265ba95c4f84683be4333542088ecb8e7")]; + b.layer = Layer(3); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df8000000384944415478da6262a03118b5600458c042849a8978e4f229f5c1440ae5074710e553e20386d1643a6ac1a805a3168c5a400500080000ffff2ea40355b76925600000000049454e44ae426082"; + index[nextId] = bytes32(hex"274ae610f9d7dec1e425c54ad990e7d265ba95c4f84683be4333542088ecb8e7"); + nextId++; + b = blocks[bytes32(hex"6a400b1508bfd84ab2f4cb067d6d74dc46f74cdae7efd8b2a2d990c9f037e426")]; + b.layer = Layer(6); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c54450000000000005c390fc775146685ecb00000000174524e530040e6d866000000214944415478da62a012600c0d7500d1995260aa561e4c89b052cb7c40000000ffffe5a902a473b175720000000049454e44ae426082"; + index[nextId] = bytes32(hex"6a400b1508bfd84ab2f4cb067d6d74dc46f74cdae7efd8b2a2d990c9f037e426"); + nextId++; + b = blocks[bytes32(hex"3e6bc8fc06a569840c9490f8122e6b7f08a7598486649b64477b548602362516")]; + b.layer = Layer(9); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c54450000000000005959590040ff401523b30000000174524e530040e6d8660000001b4944415478da621838c01aea00a2a4563b20f1700140000000ffff5249023a69668c5f0000000049454e44ae426082"; + index[nextId] = bytes32(hex"3e6bc8fc06a569840c9490f8122e6b7f08a7598486649b64477b548602362516"); + nextId++; + b = blocks[bytes32(hex"2c382a7f1f32a6a2d0e9b0d378cb95e3dad70fe6909ff13888fe2a250bd10bb0")]; + b.layer = Layer(12); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000dfdfdf337edd570000000174524e530040e6d866000000134944415478da62a015603c00a600010000ffff04e700c22f5ee81e0000000049454e44ae426082"; + index[nextId] = bytes32(hex"2c382a7f1f32a6a2d0e9b0d378cb95e3dad70fe6909ff13888fe2a250bd10bb0"); + nextId++; + b = blocks[bytes32(hex"8968ce85cb55abb5d9f6f678baeeb565638b6bad5d9be0ea2e703a34f4593566")]; + b.layer = Layer(8); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d866000000124944415478da62a00a50c02903080000ffff03a0002126a77fa30000000049454e44ae426082"; + index[nextId] = bytes32(hex"8968ce85cb55abb5d9f6f678baeeb565638b6bad5d9be0ea2e703a34f4593566"); + nextId++; + b = blocks[bytes32(hex"c3075202748482832362d1b854d8274a38bf56c5ad38d418e590f46113ff10b1")]; + b.layer = Layer(6); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb0000000f504c5445000000000000690c458c0d5bad21606331bdda0000000174524e530040e6d866000000324944415478da621828c02828c8282808e328290a2a29423982c6868cc6863019174746174798264101101a0c00100000ffffe5da0307c5d3f79f0000000049454e44ae426082"; + index[nextId] = bytes32(hex"c3075202748482832362d1b854d8274a38bf56c5ad38d418e590f46113ff10b1"); + nextId++; + b = blocks[bytes32(hex"971f7c3d5d14436a3b5ef2d658445ea527464a6409bd5f9a44f3d72e30d1eba8")]; + b.layer = Layer(3); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c544500000000000055555535d909f10000000174524e530040e6d8660000001a4944415478da6280034608c5e680856242911b0800080000ffff990c011c0109f9070000000049454e44ae426082"; + index[nextId] = bytes32(hex"971f7c3d5d14436a3b5ef2d658445ea527464a6409bd5f9a44f3d72e30d1eba8"); + nextId++; + b = blocks[bytes32(hex"1f7b5107846b1e32944ccf8aedeaa871fc859506f51e7d12d6e9ad594a4d7619")]; + b.layer = Layer(11); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb00000012504c54450000000060c3e4eb173cc300000000d604049007f3910000000174524e530040e6d866000000334944415478da622001300a0a22f15890d8824aaa0108554aaaa170092125a5d000b82a252475c6c6c6060c431600020000ffff8e2f043f67fbc8370000000049454e44ae426082"; + index[nextId] = bytes32(hex"1f7b5107846b1e32944ccf8aedeaa871fc859506f51e7d12d6e9ad594a4d7619"); + nextId++; + b = blocks[bytes32(hex"d35b2735e5fcc86991c8501996742b3b8c35772d92b69859de58ddd3559be46c")]; + b.layer = Layer(11); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c54450000008119b7b261dc8e83430a0000000174524e530040e6d866000000254944415478da62c00f4243402463682a88620d8d84506051d6d0d05006ba0140000000fffff131041f8da125b90000000049454e44ae426082"; + index[nextId] = bytes32(hex"d35b2735e5fcc86991c8501996742b3b8c35772d92b69859de58ddd3559be46c"); + nextId++; + b = blocks[bytes32(hex"2004722753f61acb2cefde9b14d2c01c6bcb589d749b4ea616b4e47d83fdb056")]; + b.layer = Layer(5); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c544500000028b1432c95412964343ee6dbfc0000000174524e530040e6d8660000001c4944415478da62a016106001531a5c608a871959900a00100000ffff23b6006aaf575b4b0000000049454e44ae426082"; + index[nextId] = bytes32(hex"2004722753f61acb2cefde9b14d2c01c6bcb589d749b4ea616b4e47d83fdb056"); + nextId++; + b = blocks[bytes32(hex"05a5afe13f23e20e6cebabae910a492c91f4b862c2e1a5822914be79ab519bd8")]; + b.layer = Layer(4); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c544500000000000086581eeeb664cd0000000174524e530040e6d866000000244944415478da62a01f6084520e6006636828980a5b0a1685f0184443706806040000ffff718d02fe68c219c00000000049454e44ae426082"; + index[nextId] = bytes32(hex"05a5afe13f23e20e6cebabae910a492c91f4b862c2e1a5822914be79ab519bd8"); + nextId++; + b = blocks[bytes32(hex"ac5194b2986dd9939aedf83029a6e0a1d7d482eb00a5dafa05fc0aaa9b616582")]; + b.layer = Layer(9); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000c9c9c9b1b1b1dfe0055e0000000174524e530040e6d8660000002a4944415478da62a0096081508c50ae0384213a0542858029d508b092d0506441d6001c2602020000ffff944e033f6ebf94330000000049454e44ae426082"; + index[nextId] = bytes32(hex"ac5194b2986dd9939aedf83029a6e0a1d7d482eb00a5dafa05fc0aaa9b616582"); + nextId++; + b = blocks[bytes32(hex"f94798c1aedb2dce1990e0dae94c15178ddd4229aff8031c9a5b7a77743a34d4")]; + b.layer = Layer(4); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000a66e2c00000080c0c2990000000174524e530040e6d866000000244944415478da62a01f6084520e6006636828980a5b0a1685f0184443706806040000ffff718d02fe68c219c00000000049454e44ae426082"; + index[nextId] = bytes32(hex"f94798c1aedb2dce1990e0dae94c15178ddd4229aff8031c9a5b7a77743a34d4"); + nextId++; + b = blocks[bytes32(hex"15854f7a2b735373aa76722c01e2f289d8b18cb1a70575796be435e4ce55e57a")]; + b.layer = Layer(6); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c54450000000000008d8d8db4b4b44f7060b00000000174524e530040e6d866000000284944415478da62a01884863a30303030eeff3f81818181ed6ae805040515842aa10800020000ffff69b20a7394f432b40000000049454e44ae426082"; + index[nextId] = bytes32(hex"15854f7a2b735373aa76722c01e2f289d8b18cb1a70575796be435e4ce55e57a"); + nextId++; + b = blocks[bytes32(hex"d91f640608a7c1b2b750276d97d603512a02f4b84ca13c875a585b12a24320c2")]; + b.layer = Layer(5); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d8660000001a4944415478da62201630fe676060f800c509446b03040000ffffa0210341317dad5b0000000049454e44ae426082"; + index[nextId] = bytes32(hex"d91f640608a7c1b2b750276d97d603512a02f4b84ca13c875a585b12a24320c2"); + nextId++; + b = blocks[bytes32(hex"6bb15b5e619a28950bae0eb6a03f13daea1b430ef5ded0c5606b335f5b077cda")]; + b.layer = Layer(3); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d8660000003d4944415478da624006ccfc0d0cc2ff0d18e4ff3f6090ffff81811f447f7ec0603ff300033fc303067986070ce20c20f601060e0607062200200000ffffb9320f35dcea59b30000000049454e44ae426082"; + index[nextId] = bytes32(hex"6bb15b5e619a28950bae0eb6a03f13daea1b430ef5ded0c5606b335f5b077cda"); + nextId++; + b = blocks[bytes32(hex"7a8b4abb14bfe7b505902c23a9c4e59e5a70c7daf6e28a5f83049c13142cde5e")]; + b.layer = Layer(11); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000000000dc1d1d9b9a25510000000174524e530040e6d8660000002e4944415478da628001c6d05010c51a1aea808be25ab5aa818181413434348081812134343484816e00100000ffff612d08a80a65c2450000000049454e44ae426082"; + index[nextId] = bytes32(hex"7a8b4abb14bfe7b505902c23a9c4e59e5a70c7daf6e28a5f83049c13142cde5e"); + nextId++; + b = blocks[bytes32(hex"72efa89c7645580b2d0d03f51f1a2b64a425844a5cd69f1b3bb6609a4a06e47f")]; + b.layer = Layer(11); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c54450000001a43c81637a4142c7c2bcdbdcc0000000174524e530040e6d866000000314944415478da62200aac5a05229942431b18181838c1145beeaa30060606c60d0c2b40d401b03a46065a0140000000ffff35c90742649028070000000049454e44ae426082"; + index[nextId] = bytes32(hex"72efa89c7645580b2d0d03f51f1a2b64a425844a5cd69f1b3bb6609a4a06e47f"); + nextId++; + b = blocks[bytes32(hex"fc1c0134d4441a1d7c81368f23d7dfcdeab3776687073c12af9d268e00d6c0a8")]; + b.layer = Layer(4); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000c28946a66e2cc99988650000000174524e530040e6d866000000184944415478da621830c0b6044c717020533801200000ffff22f000cb47eae9030000000049454e44ae426082"; + index[nextId] = bytes32(hex"fc1c0134d4441a1d7c81368f23d7dfcdeab3776687073c12af9d268e00d6c0a8"); + nextId++; + b = blocks[bytes32(hex"6ced067c29d04b367c1f3cb5e7721ad5a662f5e338ee3e10c7d64d9d109ed606")]; + b.layer = Layer(3); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c54450000000000002a2a2a02692f080000000174524e530040e6d866000000354944415478da62c00142434024636a2888629d1aeac0c0c0201a1a1a80490542284710c920cae000d600318495816a00100000ffff912107d1f05714420000000049454e44ae426082"; + index[nextId] = bytes32(hex"6ced067c29d04b367c1f3cb5e7721ad5a662f5e338ee3e10c7d64d9d109ed606"); + nextId++; + b = blocks[bytes32(hex"66a6c35fd6db8b93449f29befe26e2e4bcb09799d56216ada0ef901c53cf439f")]; + b.layer = Layer(3); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000e226260000001337790f0000000174524e530040e6d866000000434944415478da6240038c0c0e208ad5350044b386ba82a8d0d0d000060616d1d0d05090586868084830c005240756c7c01800d19d0031054a39408da40200040000ffff0b6408c6ffc386f40000000049454e44ae426082"; + index[nextId] = bytes32(hex"66a6c35fd6db8b93449f29befe26e2e4bcb09799d56216ada0ef901c53cf439f"); + nextId++; + b = blocks[bytes32(hex"85c5daead3bc85feb0d62d1f185f82fdc2627bdbc7f1f2ffed1c721c6fcc4b4d")]; + b.layer = Layer(11); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb0000000f504c544500000000000026314affffffffd8001025743b0000000174524e530040e6d866000000364944415478da622005080a2098824a8a302ea392928a9292229ca304e7300883004c97a010920c03a3a0a0a020c3500580000000ffff347603a082b51cae0000000049454e44ae426082"; + index[nextId] = bytes32(hex"85c5daead3bc85feb0d62d1f185f82fdc2627bdbc7f1f2ffed1c721c6fcc4b4d"); + nextId++; + b = blocks[bytes32(hex"3d1f5637dfc56d4147818053fdcc0c0a35886121b7e4fc1a7cff584e4bb6414f")]; + b.layer = Layer(8); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000ffffffa5d99fdd0000000174524e530040e6d866000000124944415478da62a01a10c12a0a080000ffff02180015518fefb80000000049454e44ae426082"; + index[nextId] = bytes32(hex"3d1f5637dfc56d4147818053fdcc0c0a35886121b7e4fc1a7cff584e4bb6414f"); + nextId++; + b = blocks[bytes32(hex"64b53b34ebe074820dbda2f80085c52f209d5eba6c783abdae0a19950f0787ec")]; + b.layer = Layer(11); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c54450000004c4c4c63636367c20ce50000000174524e530040e6d8660000001f4944415478da62200584868048c6d45030351542858632d00100020000ffff4d8702fb0f1c34300000000049454e44ae426082"; + index[nextId] = bytes32(hex"64b53b34ebe074820dbda2f80085c52f209d5eba6c783abdae0a19950f0787ec"); + nextId++; + b = blocks[bytes32(hex"833ca1b7f8f2ce28f7003fb78b72e259d5a484b13477ad8212edb844217225ac")]; + b.layer = Layer(4); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000a66e2c00000080c0c2990000000174524e530040e6d8660000001f4944415478da621830c01a02a6585890798c01c814d302b86a40000000ffff2fa301ff0f47294e0000000049454e44ae426082"; + index[nextId] = bytes32(hex"833ca1b7f8f2ce28f7003fb78b72e259d5a484b13477ad8212edb844217225ac"); + nextId++; + b = blocks[bytes32(hex"44c2482a71c9d39dac1cf9a7daf6de80db79735c0042846cb9d47f85ccc3ba9b")]; + b.layer = Layer(2); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df8000000364944415478da6262a03118b560d4826166810301fec080d148a6d882018dc8a1958a1c466e300d8a7c3038cba0e1535400020000ffff98f50225e7db2e020000000049454e44ae426082"; + index[nextId] = bytes32(hex"44c2482a71c9d39dac1cf9a7daf6de80db79735c0042846cb9d47f85ccc3ba9b"); + nextId++; + b = blocks[bytes32(hex"4acd7797c5821ccc56add3739a55bcfd4e4cfd72b30274ec6c156b6c1d9185eb")]; + b.layer = Layer(4); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000000000a66e2c9730e2d80000000174524e530040e6d8660000002f4944415478da62a03fd05a05229956ad9ac0c0c020b5820b4c4179108a11423184ad7200518ca10c0c80000000ffff51890b8e68fe91ee0000000049454e44ae426082"; + index[nextId] = bytes32(hex"4acd7797c5821ccc56add3739a55bcfd4e4cfd72b30274ec6c156b6c1d9185eb"); + nextId++; + b = blocks[bytes32(hex"c0ac7bb45040825a6d9a997dc99a6ec94027d27133145018c0561b880ecdb389")]; + b.layer = Layer(3); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d866000000214944415478da62c009fe313030ce656060e480605c8011861bb04a03020000ffff7e1c023207c1f3860000000049454e44ae426082"; + index[nextId] = bytes32(hex"c0ac7bb45040825a6d9a997dc99a6ec94027d27133145018c0561b880ecdb389"); + nextId++; + b = blocks[bytes32(hex"a756817780c8e400f79cdd974270d70e0cd172aa662d7cf7c9fe0b63a4a71d95")]; + b.layer = Layer(3); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d866000000264944415478da620083100606867f10ccf89f8181f1230303b3650303830003a500100000ffff8fa8050f2a3982bb0000000049454e44ae426082"; + index[nextId] = bytes32(hex"a756817780c8e400f79cdd974270d70e0cd172aa662d7cf7c9fe0b63a4a71d95"); + nextId++; + b = blocks[bytes32(hex"71c5ce05a579f7a6bbc9fb7517851ae9394c8cb6e4fcad99245ce296b6a3c541")]; + b.layer = Layer(4); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000a66e2c00000080c0c2990000000174524e530040e6d866000000244944415478da62a01f6084520e8c481443000a251a02511300a69816c03503020000ffff46850284e24691b90000000049454e44ae426082"; + index[nextId] = bytes32(hex"71c5ce05a579f7a6bbc9fb7517851ae9394c8cb6e4fcad99245ce296b6a3c541"); + nextId++; + b = blocks[bytes32(hex"283597377fbec1d21fb9d58af5fa0c43990b1f7c2fc6168412ceb4837d9bf86c")]; + b.layer = Layer(11); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c54450000003d2f1e000000c8d065ca0000000174524e530040e6d8660000002b4944415478da62c0014403c054680812c5181a0aa2b856ad6a008985824419434321a2340680000000ffff28a206e959ceed270000000049454e44ae426082"; + index[nextId] = bytes32(hex"283597377fbec1d21fb9d58af5fa0c43990b1f7c2fc6168412ceb4837d9bf86c"); + nextId++; + b = blocks[bytes32(hex"bb1f372f67259011c2e9e7346c8a03a11f260853a1fe248ddd29540219788747")]; + b.layer = Layer(10); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000000000ffd926bf0c26860000000174524e530040e6d866000000154944415478da62a00348805002949801080000ffff1df8007172dffd610000000049454e44ae426082"; + index[nextId] = bytes32(hex"bb1f372f67259011c2e9e7346c8a03a11f260853a1fe248ddd29540219788747"); + nextId++; + b = blocks[bytes32(hex"d5de5c20969a9e22f93842ca4d65bac0c0387225cee45a944a14f03f9221fd4a")]; + b.layer = Layer(6); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df80000004b4944415478da6262a03118b560d482510be860010b01f9ff2498c5488e050ca79ffd2d84b14da598fbb1884dc0e71026125dc588c3a58c0316070ca3c974d482510b86810580000000ffffcf460a37173d31500000000049454e44ae426082"; + index[nextId] = bytes32(hex"d5de5c20969a9e22f93842ca4d65bac0c0387225cee45a944a14f03f9221fd4a"); + nextId++; + b = blocks[bytes32(hex"b040fea53c68833d052aa3e7c8552b04390371501b9976c938d3bd8ec66e4734")]; + b.layer = Layer(11); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000ffffff1a6ed56fb0c5a50000000174524e530040e6d8660000001a4944415478da62201d3086868228a655ab18e80700010000ffffdec602021e01f4d60000000049454e44ae426082"; + index[nextId] = bytes32(hex"b040fea53c68833d052aa3e7c8552b04390371501b9976c938d3bd8ec66e4734"); + nextId++; + b = blocks[bytes32(hex"74ca947c09f7b62348c4f3c81b91973356ec81529d6220ff891012154ce517c7")]; + b.layer = Layer(9); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df8000000704944415478da6262a03118b560d482510b462dc00276eedcd940330b6086235b42f3206218f27130b27df09f963ef8df1a28826ec97f2c988191121f802ca95eff06660ecc523080895312078c2043907df2f8f51706649a521fa00717dcf019477ec0cd66a45184c3cd05040000ffffe2512fe56a94b4330000000049454e44ae426082"; + index[nextId] = bytes32(hex"74ca947c09f7b62348c4f3c81b91973356ec81529d6220ff891012154ce517c7"); + nextId++; + b = blocks[bytes32(hex"30146eda149865d57c6ae9dac707d809120563fadb039d7bca3231041bea6b2e")]; + b.layer = Layer(3); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d8660000002b4944415478da62c0007f191818ff333030ff3fc0c0febf8181f9770303bbe70106860e067200200000ffff2b95085cdd2d2f2d0000000049454e44ae426082"; + index[nextId] = bytes32(hex"30146eda149865d57c6ae9dac707d809120563fadb039d7bca3231041bea6b2e"); + nextId++; + b = blocks[bytes32(hex"8394d1b7af0d52a25908dc9123cc00aa0670debcac95a76c3e9a20dd6c7e7c23")]; + b.layer = Layer(4); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c544500000068461f000000b80d8ed70000000174524e530040e6d8660000001f4944415478da621830c01a02a6585890798c01c814d302b86a40000000ffff2fa301ff0f47294e0000000049454e44ae426082"; + index[nextId] = bytes32(hex"8394d1b7af0d52a25908dc9123cc00aa0670debcac95a76c3e9a20dd6c7e7c23"); + nextId++; + b = blocks[bytes32(hex"eb787e7727b2d8d912a02d9ad4c30c964b40f4cebe754bb4d3bfb09959565c91")]; + b.layer = Layer(11); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c544500000000000055555535d909f10000000174524e530040e6d866000000604944415478da7ccdb10dc4200c85e1df050c71d330c4817457d3c03414648334f194d12352bac4b2fc59966cf310212dfe53d5fc10d15dd38ffb007a2e3bd0305157aa6d60037e37f10b25bd62f35a9858d531cbfa50434f8b0dce000000ffffa30d1684d4b69ae10000000049454e44ae426082"; + index[nextId] = bytes32(hex"eb787e7727b2d8d912a02d9ad4c30c964b40f4cebe754bb4d3bfb09959565c91"); + nextId++; + b = blocks[bytes32(hex"6a36bcf4268827203e8a3f374b49c1ff69b62623e234e96858ff0f2d32fbf268")]; + b.layer = Layer(12); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000ffc926d3ca64d80000000174524e530040e6d866000000184944415478da62a0366004110d0c0c0c0e602e200000ffff06ef00c28387215b0000000049454e44ae426082"; + index[nextId] = bytes32(hex"6a36bcf4268827203e8a3f374b49c1ff69b62623e234e96858ff0f2d32fbf268"); + nextId++; + b = blocks[bytes32(hex"2f237bd68c6e318a6d0aa26172032a8a73a5e0e968ad3d74ef1178e64d209b48")]; + b.layer = Layer(4); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000a66e2cb134b2d70000000174524e530040e6d8660000001d4944415478da62a004308270230303e34106068683589500020000ffff340b0207ed983fca0000000049454e44ae426082"; + index[nextId] = bytes32(hex"2f237bd68c6e318a6d0aa26172032a8a73a5e0e968ad3d74ef1178e64d209b48"); + nextId++; + b = blocks[bytes32(hex"ad07511765ae4becdc5300c486c7806cd661840b0670d0f6670e8c4014de37b0")]; + b.layer = Layer(3); + b.dataMale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d8660000001d4944415478da62c00a0418181842a078110303c324067201200000ffff79f001ed2e0ca9360000000049454e44ae426082"; + index[nextId] = bytes32(hex"ad07511765ae4becdc5300c486c7806cd661840b0670d0f6670e8c4014de37b0"); + nextId++; + b = blocks[bytes32(hex"49e0947b696384a658eeca7f5746ffbdd90a5f5526f8d15e6396056b7a0dc8af")]; + b.layer = Layer(6); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000000000d7d7d7dd6bdeda0000000174524e530040e6d866000000214944415478da62a012600c0d7500518e01208a3531024c4104a90100010000ffff324a03ab83e6711a0000000049454e44ae426082"; + index[nextId] = bytes32(hex"49e0947b696384a658eeca7f5746ffbdd90a5f5526f8d15e6396056b7a0dc8af"); + nextId++; + b = blocks[bytes32(hex"c1695b389d89c71dc7afd5111f17f6540b3a28261e4d2bf5631c1484f322fc68")]; + b.layer = Layer(6); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c5445000000f0f0f0328dfdfd3232d47923120000000174524e530040e6d866000000214944415478da62a012600d0d7560606060ccaa07510c500a22480d00080000ffff5dd3042db0f16dd40000000049454e44ae426082"; + index[nextId] = bytes32(hex"c1695b389d89c71dc7afd5111f17f6540b3a28261e4d2bf5631c1484f322fc68"); + nextId++; + b = blocks[bytes32(hex"09c36cad1064f6107d2e3bef439f87a16c8ef2e95905a827b2ce7f111dd801d7")]; + b.layer = Layer(5); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c54450000002858b12c5195293e64cf044ab90000000174524e530040e6d8660000001c4944415478da62a016106001531a5c608a871959900a00100000ffff23b6006aaf575b4b0000000049454e44ae426082"; + index[nextId] = bytes32(hex"09c36cad1064f6107d2e3bef439f87a16c8ef2e95905a827b2ce7f111dd801d7"); + nextId++; + b = blocks[bytes32(hex"eb92e34266f6fa01c275db8379f6a521f15ab6f96297fe3266df2fe6b0e1422e")]; + b.layer = Layer(3); + b.dataMale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c544500000000000085561ea66e2c6852a3220000000174524e530040e6d866000000264944415478da6240800030c978014cb143286908a57f004c31432886030c740780000000ffffcd2f05565fc3044d0000000049454e44ae426082"; + index[nextId] = bytes32(hex"eb92e34266f6fa01c275db8379f6a521f15ab6f96297fe3266df2fe6b0e1422e"); + nextId++; + b = blocks[bytes32(hex"1892c4c9cf47baf2c613f184114519fe8208c2bebabb732405aeac1c3031dc2b")]; + b.layer = Layer(11); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c54450000002d6b6200000080dbda32008fdd0000000174524e530040e6d866000000354944415478da62200a888680a955ab4024d3bffd0d20ead77a30b5320b443186863a303030b03230e0a41889a6b00040000000ffff4bc30b42e46330a00000000049454e44ae426082"; + index[nextId] = bytes32(hex"1892c4c9cf47baf2c613f184114519fe8208c2bebabb732405aeac1c3031dc2b"); + nextId++; + b = blocks[bytes32(hex"250be814c80d8ca10bbef531b679392db8221a6fab289a6b5e637df663f48699")]; + b.layer = Layer(11); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c544500000000000022900000558084ff9e8a0000000174524e530040e6d8660000004d4944415478da6240078c0e608a7d0298927b02a6a4b780a9bcb76015bb7783d430be7b07a2d857ad0629656b6002530c0c208a098562234c4935302d01f318413c46060607346701020000ffff3d76119d224fcf200000000049454e44ae426082"; + index[nextId] = bytes32(hex"250be814c80d8ca10bbef531b679392db8221a6fab289a6b5e637df663f48699"); + nextId++; + b = blocks[bytes32(hex"cd87356aa78c4fcb95e51f57578570d377440e347e0869cf1b4749d5a26340b5")]; + b.layer = Layer(8); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000c42110a2e982d40000000174524e530040e6d866000000124944415478da62a01a90c12a0a080000ffff02c8001d72b777ad0000000049454e44ae426082"; + index[nextId] = bytes32(hex"cd87356aa78c4fcb95e51f57578570d377440e347e0869cf1b4749d5a26340b5"); + nextId++; + b = blocks[bytes32(hex"4fa682c6066fcc513a0511418aa85a0037ac59a899e9491c512b63e253697a8c")]; + b.layer = Layer(5); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df8000000384944415478da6262a03118b560d482510b462da09605da65536682302131b22db8da95934e8cd88080d154346ac1a80574b000100000ffffc4410bcb596becd80000000049454e44ae426082"; + index[nextId] = bytes32(hex"4fa682c6066fcc513a0511418aa85a0037ac59a899e9491c512b63e253697a8c"); + nextId++; + b = blocks[bytes32(hex"36f07f03014f047728880d9f390629140a5e7c44477290695c4c1ddda356d365")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d8660000002f4944415478da62c00bea181818fe333030fe6f60603ed8c0c0dc00c1ec0c58302312666e606067079b00080000ffffd1030b1b1e3ca1240000000049454e44ae426082"; + index[nextId] = bytes32(hex"36f07f03014f047728880d9f390629140a5e7c44477290695c4c1ddda356d365"); + nextId++; + b = blocks[bytes32(hex"68107f52c261820bd73e4046eb3fb5d5a1e0926611562c07054a3b89334cef34")]; + b.layer = Layer(12); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d8660000001a4944415478da62a03a70606060486060603000f300010000ffff08c000d178549d360000000049454e44ae426082"; + index[nextId] = bytes32(hex"68107f52c261820bd73e4046eb3fb5d5a1e0926611562c07054a3b89334cef34"); + nextId++; + b = blocks[bytes32(hex"66a6c35fd6db8b93449f29befe26e2e4bcb09799d56216ada0ef901c53cf439f")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000e226261ed2bbd80000000174524e530040e6d866000000454944415478da6240011a0c0c4c2b191898ea0b1858ff3730b0fd7fc020dedcc0c0cff081819de101031bc307061e86040616060730cdc6e0c0c0c4e0c0800700020000ffff86820ac86b32f7cc0000000049454e44ae426082"; + index[nextId] = bytes32(hex"66a6c35fd6db8b93449f29befe26e2e4bcb09799d56216ada0ef901c53cf439f"); + nextId++; + b = blocks[bytes32(hex"dd7231e98344a83b64e1ac7a07b39d2ecc2b21128681123a9030e17a12422527")]; + b.layer = Layer(6); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d8660000001c4944415478da62200530ff6f6060f8dec0c0904cb41640000000ffff9e67035db5442bc60000000049454e44ae426082"; + index[nextId] = bytes32(hex"dd7231e98344a83b64e1ac7a07b39d2ecc2b21128681123a9030e17a12422527"); + nextId++; + b = blocks[bytes32(hex"d395cf4acda004fbc9963f85c65bf3f190c2aceb0744a535d543bc261caf6ff0")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000fff68e5319653e0000000174524e530040e6d8660000004f4944415478da624001c20c0c0ce71d1898df3730b0d7fd60e0fdff8041feff0106f6c31f18f8955e30c8b31430f0305430c8305430f0301430c831043070332c60e06330606061c00a00010000ffff3f7f0e31b0bc620f0000000049454e44ae426082"; + index[nextId] = bytes32(hex"d395cf4acda004fbc9963f85c65bf3f190c2aceb0744a535d543bc261caf6ff0"); + nextId++; + b = blocks[bytes32(hex"c1695b389d89c71dc7afd5111f17f6540b3a28261e4d2bf5631c1484f322fc68")]; + b.layer = Layer(6); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c5445000000f0f0f0328dfdfd3232d47923120000000174524e530040e6d8660000001f4944415478da62a02e600c0d75005159f5208a014a4104290280000000ffff3f3b04294160e2b30000000049454e44ae426082"; + index[nextId] = bytes32(hex"c1695b389d89c71dc7afd5111f17f6540b3a28261e4d2bf5631c1484f322fc68"); + nextId++; + b = blocks[bytes32(hex"041bf83549434251cc54c0632896c8d3176b48d06150048c1bce6b6102c4e90c")]; + b.layer = Layer(2); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df80000002c4944415478da6262a03118b560d482510b462d18b560f858a0202796c63058c168248f5a403900040000fffffeb200e9e342816b0000000049454e44ae426082"; + index[nextId] = bytes32(hex"041bf83549434251cc54c0632896c8d3176b48d06150048c1bce6b6102c4e90c"); + nextId++; + b = blocks[bytes32(hex"bad0fc475e9d35de67c426fc37eebb7fa38141bc2135fabd5504a911e1b05540")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000ffffffa5d99fdd0000000174524e530040e6d866000000454944415478da62c00a6c191818eb181818ff3b30b0ff5fc0c07cff0103fbca030cdc1d0f18d8390218b8581218e4181218d8180a18d8181c1838181418700040000000ffff367b0a7764b3c52f0000000049454e44ae426082"; + index[nextId] = bytes32(hex"bad0fc475e9d35de67c426fc37eebb7fa38141bc2135fabd5504a911e1b05540"); + nextId++; + b = blocks[bytes32(hex"44c2482a71c9d39dac1cf9a7daf6de80db79735c0042846cb9d47f85ccc3ba9b")]; + b.layer = Layer(2); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df80000003d4944415478da6262a03118b560d482510b28b0a027ca7e26d55d43134387761c0c68900c9af8601ad4ae1d14c134f88a8a41979b877e710d080000fffff2580c5583685c2e0000000049454e44ae426082"; + index[nextId] = bytes32(hex"44c2482a71c9d39dac1cf9a7daf6de80db79735c0042846cb9d47f85ccc3ba9b"); + nextId++; + b = blocks[bytes32(hex"6ced067c29d04b367c1f3cb5e7721ad5a662f5e338ee3e10c7d64d9d109ed606")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c54450000000000002a2a2a02692f080000000174524e530040e6d8660000003c4944415478da62c00f42434024636a2888629d1aeac0c0c0201a1a1a8049054228c70001903606071130c58044854028113825c0403c00040000ffffd90d09b1ff89a89f0000000049454e44ae426082"; + index[nextId] = bytes32(hex"6ced067c29d04b367c1f3cb5e7721ad5a662f5e338ee3e10c7d64d9d109ed606"); + nextId++; + b = blocks[bytes32(hex"7411db1fe7a50d41767858710dc8b8432ac0c4fd26503ba78d2ed17789ce4f72")]; + b.layer = Layer(6); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c544500000000000080dbda669cd55e0000000174524e530040e6d866000000234944415478da62a03208157560606060cc8c02510c9952604a8495627301010000ffffca38028b89ad68880000000049454e44ae426082"; + index[nextId] = bytes32(hex"7411db1fe7a50d41767858710dc8b8432ac0c4fd26503ba78d2ed17789ce4f72"); + nextId++; + b = blocks[bytes32(hex"d10bc0475e2a0eea9f6aca91e6e82c6416f894f27fc26bb0735f29b84c54a3e6")]; + b.layer = Layer(11); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000ffba00ff2a00ec23aa7c0000000174524e530040e6d8660000001b4944415478da62201f888a40680730c9380199477500080000ffff7648013b91a176490000000049454e44ae426082"; + index[nextId] = bytes32(hex"d10bc0475e2a0eea9f6aca91e6e82c6416f894f27fc26bb0735f29b84c54a3e6"); + nextId++; + b = blocks[bytes32(hex"a0a2010e841ab7b343263c98f47a16b88656913e1353d96914f5fe492511893f")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000e65700fdf2de4e0000000174524e530040e6d866000000324944415478da62c0096c181818fe333030fe6f80e0d6030ccc0c10cc04c50c0c0f3031e303060666106e009902080000ffff4fd30f33b75f06fe0000000049454e44ae426082"; + index[nextId] = bytes32(hex"a0a2010e841ab7b343263c98f47a16b88656913e1353d96914f5fe492511893f"); + nextId++; + b = blocks[bytes32(hex"0e6769a10f786458ca82b57684746fe8899e35f7772543acb6a8869c4ac780cd")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000e226261ed2bbd80000000174524e530040e6d8660000001b4944415478da62c0001c0c0c0c120c0c0c16509a3200080000ffff1f400071228f4c0b0000000049454e44ae426082"; + index[nextId] = bytes32(hex"0e6769a10f786458ca82b57684746fe8899e35f7772543acb6a8869c4ac780cd"); + nextId++; + b = blocks[bytes32(hex"30146eda149865d57c6ae9dac707d809120563fadb039d7bca3231041bea6b2e")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d8660000002b4944415478da62c0007f191818ff333030ff3fc0c0febf8181f9770303bbe70106860e067200200000ffff2b95085cdd2d2f2d0000000049454e44ae426082"; + index[nextId] = bytes32(hex"30146eda149865d57c6ae9dac707d809120563fadb039d7bca3231041bea6b2e"); + nextId++; + b = blocks[bytes32(hex"09c36cad1064f6107d2e3bef439f87a16c8ef2e95905a827b2ce7f111dd801d7")]; + b.layer = Layer(5); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb0000000f504c54450000002858b12c5195000000293e648e458eca0000000174524e530040e6d866000000234944415478da6218848091814100ce615260508273981d184cb02ba33700040000ffff7ae900dec03f69060000000049454e44ae426082"; + index[nextId] = bytes32(hex"09c36cad1064f6107d2e3bef439f87a16c8ef2e95905a827b2ce7f111dd801d7"); + nextId++; + b = blocks[bytes32(hex"74ca947c09f7b62348c4f3c81b91973356ec81529d6220ff891012154ce517c7")]; + b.layer = Layer(9); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df8000000704944415478da6262a03118b560d482510b462dc00276eedcd940330b6086235b42f3206218f27130b27df09f963ef8df1a28826ec97f2c988191121f802ca95eff06660ecc523080895312078c2043907df2f8f51706649a521fa00717dcf019477ec0cd66a45184c3cd05040000ffffe2512fe56a94b4330000000049454e44ae426082"; + index[nextId] = bytes32(hex"74ca947c09f7b62348c4f3c81b91973356ec81529d6220ff891012154ce517c7"); + nextId++; + b = blocks[bytes32(hex"6bb15b5e619a28950bae0eb6a03f13daea1b430ef5ded0c5606b335f5b077cda")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d8660000004c4944415478da62800326060626970606d6fc090ce2ff1730f0ff7fc020ffff0384fe7c80c17ee603067e860f0cf20c0f18c419206c2e0607062606070616060706060605062c00100000ffff1b1511db1ceba4170000000049454e44ae426082"; + index[nextId] = bytes32(hex"6bb15b5e619a28950bae0eb6a03f13daea1b430ef5ded0c5606b335f5b077cda"); + nextId++; + b = blocks[bytes32(hex"1004d2d00ccf8794739c7b7cbbe6048841f4c8af046b37d59e9a801a167544e2")]; + b.layer = Layer(5); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df8000000384944415478da6262a03118b560d482510b462da09605db18d6cf04614262645be0c510984e8cd88080d154346ac1a80574b000100000ffff94270a2bdc4a43550000000049454e44ae426082"; + index[nextId] = bytes32(hex"1004d2d00ccf8794739c7b7cbbe6048841f4c8af046b37d59e9a801a167544e2"); + nextId++; + b = blocks[bytes32(hex"ad07511765ae4becdc5300c486c7806cd661840b0670d0f6670e8c4014de37b0")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d8660000001b4944415478da622008b4181818421918185631900300010000ffff41aa012a18d810ed0000000049454e44ae426082"; + index[nextId] = bytes32(hex"ad07511765ae4becdc5300c486c7806cd661840b0670d0f6670e8c4014de37b0"); + nextId++; + b = blocks[bytes32(hex"629e82a55845ea763431647fcaecfb232e275a36d8427f2568377864193801cb")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d8660000003a4944415478da62c009ea181818fe333030fe6f6060fe7f0082273c60606780603686070c7c50cccff08141bef1030373e301745300010000ffffc5ab1058fff3c7650000000049454e44ae426082"; + index[nextId] = bytes32(hex"629e82a55845ea763431647fcaecfb232e275a36d8427f2568377864193801cb"); + nextId++; + b = blocks[bytes32(hex"d91f640608a7c1b2b750276d97d603512a02f4b84ca13c875a585b12a24320c2")]; + b.layer = Layer(6); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d8660000001a4944415478da62200530fe676060f800c509446901040000ffff932103411ff574e90000000049454e44ae426082"; + index[nextId] = bytes32(hex"d91f640608a7c1b2b750276d97d603512a02f4b84ca13c875a585b12a24320c2"); + nextId++; + b = blocks[bytes32(hex"cd3633a5e96d615b834e90e67029f7f9f507b832e1cb263a29685b8e25f678cf")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000fff68e5319653e0000000174524e530040e6d8660000002d4944415478da62c00a6a181818fe313030fe07e1060666106e696060e66860606280604646066200200000ffffdcdb0815f637cf1a0000000049454e44ae426082"; + index[nextId] = bytes32(hex"cd3633a5e96d615b834e90e67029f7f9f507b832e1cb263a29685b8e25f678cf"); + nextId++; + b = blocks[bytes32(hex"6a400b1508bfd84ab2f4cb067d6d74dc46f74cdae7efd8b2a2d990c9f037e426")]; + b.layer = Layer(6); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c54450000000000005c390fc775146685ecb00000000174524e530040e6d866000000204944415478da62a02e600c0d7500d1995260aa561e4c89b0526c30200000ffffd33402a4b41fa11a0000000049454e44ae426082"; + index[nextId] = bytes32(hex"6a400b1508bfd84ab2f4cb067d6d74dc46f74cdae7efd8b2a2d990c9f037e426"); + nextId++; + b = blocks[bytes32(hex"49e0947b696384a658eeca7f5746ffbdd90a5f5526f8d15e6396056b7a0dc8af")]; + b.layer = Layer(6); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000000000d7d7d7dd6bdeda0000000174524e530040e6d866000000214944415478da62a02e600c0d7500518e01208a3531024c4104290280000000ffff18a403ab4ed4e1740000000049454e44ae426082"; + index[nextId] = bytes32(hex"49e0947b696384a658eeca7f5746ffbdd90a5f5526f8d15e6396056b7a0dc8af"); + nextId++; + b = blocks[bytes32(hex"bfac272e71cad64427175cd77d774a7884f98c7901ebc4909ada29d464c8981e")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c544500000028b143000000cc9ab8ec0000000174524e530040e6d866000000474944415478da94c7b10d80300c05d18b447a0ad880411821856fff55906d898e825ff8f9f8d8bcf30eadd0cc5317a0c6cb704d1348a2604134477351ef0e6ccdcf3d010000ffffff6c099ea706747f0000000049454e44ae426082"; + index[nextId] = bytes32(hex"bfac272e71cad64427175cd77d774a7884f98c7901ebc4909ada29d464c8981e"); + nextId++; + b = blocks[bytes32(hex"d35b2735e5fcc86991c8501996742b3b8c35772d92b69859de58ddd3559be46c")]; + b.layer = Layer(11); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c54450000008119b7b261dc8e83430a0000000174524e530040e6d866000000254944415478da62200a888682a9d04807060606c6d03008151a0aa51c18680e00010000fffffb9604856eb921470000000049454e44ae426082"; + index[nextId] = bytes32(hex"d35b2735e5fcc86991c8501996742b3b8c35772d92b69859de58ddd3559be46c"); + nextId++; + b = blocks[bytes32(hex"ac5194b2986dd9939aedf83029a6e0a1d7d482eb00a5dafa05fc0aaa9b616582")]; + b.layer = Layer(9); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000c9c9c9b1b1b1dfe0055e0000000174524e530040e6d866000000274944415478da62a0256084d20e1086e814081502a65423c0546828b2206b000ea300010000ffff92de033acd8c71070000000049454e44ae426082"; + index[nextId] = bytes32(hex"ac5194b2986dd9939aedf83029a6e0a1d7d482eb00a5dafa05fc0aaa9b616582"); + nextId++; + b = blocks[bytes32(hex"72efa89c7645580b2d0d03f51f1a2b64a425844a5cd69f1b3bb6609a4a06e47f")]; + b.layer = Layer(11); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c54450000001a43c81637a4142c7c2bcdbdcc0000000174524e530040e6d866000000314944415478da622005ac5a05229942431b18181838c1145beeaa30060606c60d0c2b40d401b03a4606aa0340000000ffff03020742f02d25cf0000000049454e44ae426082"; + index[nextId] = bytes32(hex"72efa89c7645580b2d0d03f51f1a2b64a425844a5cd69f1b3bb6609a4a06e47f"); + nextId++; + b = blocks[bytes32(hex"e81a9c78c0ec4339dc6772f1b9bbf406b53063f8408a91fe29f63ba1c2bc7b5a")]; + b.layer = Layer(8); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000cd00cb30a6a7e40000000174524e530040e6d866000000124944415478da62a01a90c12a0a080000ffff02c8001d72b777ad0000000049454e44ae426082"; + index[nextId] = bytes32(hex"e81a9c78c0ec4339dc6772f1b9bbf406b53063f8408a91fe29f63ba1c2bc7b5a"); + nextId++; + b = blocks[bytes32(hex"4483a654781ca58fa6ba3590c74c005bce612263e17c70445d6cd167e55e900b")]; + b.layer = Layer(7); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000d600002c63f04d0000000174524e530040e6d866000000134944415478da62a008f040316e00080000ffff0360001902542c490000000049454e44ae426082"; + index[nextId] = bytes32(hex"4483a654781ca58fa6ba3590c74c005bce612263e17c70445d6cd167e55e900b"); + nextId++; + b = blocks[bytes32(hex"b040fea53c68833d052aa3e7c8552b04390371501b9976c938d3bd8ec66e4734")]; + b.layer = Layer(11); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c5445000000000000ffffff1a6ed5d93a1bf30000000174524e530040e6d866000000424944415478da6220033830824846d110070606069655ab0418181844feff17015160c420808d0a61600845a14419c04c08c518c20062b242a900343b01010000ffff7f5108b501fb5fc90000000049454e44ae426082"; + index[nextId] = bytes32(hex"b040fea53c68833d052aa3e7c8552b04390371501b9976c938d3bd8ec66e4734"); + nextId++; + b = blocks[bytes32(hex"e11278d6c191c8199a5b8bb49be7f806b837a9811195c903d844a74c4c4a704e")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000000000ffd926bf0c26860000000174524e530040e6d866000000404944415478da62200a888680c880d050560606c6b0d0d0a90e0caca1a1a1a1010cac81018cae010cac8e0e0c8c010cac0e0c208a11a4da81819a00100000ffff496407d2e13d1cb20000000049454e44ae426082"; + index[nextId] = bytes32(hex"e11278d6c191c8199a5b8bb49be7f806b837a9811195c903d844a74c4c4a704e"); + nextId++; + b = blocks[bytes32(hex"411ec1566affa22bd67b13a7c49ac060c018e1c806cd314cd2186118dd55e129")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000fff68e5319653e0000000174524e530040e6d866000000304944415478da7cccb10900300c03c1372ab475d06a99cc81b8f7c3b5cfda011aaa836e50865954b082fd0f2f0000ffffd0db0b19f8088baf0000000049454e44ae426082"; + index[nextId] = bytes32(hex"411ec1566affa22bd67b13a7c49ac060c018e1c806cd314cd2186118dd55e129"); + nextId++; + b = blocks[bytes32(hex"24dd0364c2b2d0e6540c7deb5a0acf9177d47737a2bf41ca29b553eb69558ef9")]; + b.layer = Layer(11); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c5445000000000000933709ca4e11586029880000000174524e530040e6d8660000002a4944415478da62200a888680a9fabf2092f1ff7f07060606b655ab2680a877ef2e30d01e00020000ffffcdba08c1f8ca1c3c0000000049454e44ae426082"; + index[nextId] = bytes32(hex"24dd0364c2b2d0e6540c7deb5a0acf9177d47737a2bf41ca29b553eb69558ef9"); + nextId++; + b = blocks[bytes32(hex"2004722753f61acb2cefde9b14d2c01c6bcb589d749b4ea616b4e47d83fdb056")]; + b.layer = Layer(5); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb0000000f504c544500000028b1432c95410000002964344cdbc5fd0000000174524e530040e6d866000000234944415478da6218848091814100ce615260508273981d184cb02ba33700040000ffff7ae900dec03f69060000000049454e44ae426082"; + index[nextId] = bytes32(hex"2004722753f61acb2cefde9b14d2c01c6bcb589d749b4ea616b4e47d83fdb056"); + nextId++; + b = blocks[bytes32(hex"1885fe71e225eade934ab7040d533bd49efc5d66e8f2d4b5aa42477ae9892ec9")]; + b.layer = Layer(9); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df80000004b4944415478da6262a03118b560d482510b869a0577efde6d180da2116801cd010b057affe31067c4c921c5f063c78e6108ca4c4d60905b7a0bc55c465afb806134990eb80580000000ffff78ff0b44c51816510000000049454e44ae426082"; + index[nextId] = bytes32(hex"1885fe71e225eade934ab7040d533bd49efc5d66e8f2d4b5aa42477ae9892ec9"); + nextId++; + b = blocks[bytes32(hex"1868a04ecae06e10c5b6dcbbed4befac1ed03dda2cf86ddbd855466cc588809f")]; + b.layer = Layer(6); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c54450000001c1a00534c0080dbda6080589f0000000174524e530040e6d866000000254944415478da62200364463930303030eecb6f40a232a5c0820c0c0e0cb40080000000ffff32d20565dbf243f00000000049454e44ae426082"; + index[nextId] = bytes32(hex"1868a04ecae06e10c5b6dcbbed4befac1ed03dda2cf86ddbd855466cc588809f"); + nextId++; + b = blocks[bytes32(hex"971f7c3d5d14436a3b5ef2d658445ea527464a6409bd5f9a44f3d72e30d1eba8")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c544500000000000055555535d909f10000000174524e530040e6d8660000001b4944415478da62c0051cc024e3042c1443030a8f2e00100000ffff765a0305a5b614880000000049454e44ae426082"; + index[nextId] = bytes32(hex"971f7c3d5d14436a3b5ef2d658445ea527464a6409bd5f9a44f3d72e30d1eba8"); + nextId++; + b = blocks[bytes32(hex"6a36bcf4268827203e8a3f374b49c1ff69b62623e234e96858ff0f2d32fbf268")]; + b.layer = Layer(12); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000ffc926d3ca64d80000000174524e530040e6d866000000124944415478da62a01928009380000000ffff0300007135fa2b640000000049454e44ae426082"; + index[nextId] = bytes32(hex"6a36bcf4268827203e8a3f374b49c1ff69b62623e234e96858ff0f2d32fbf268"); + nextId++; + b = blocks[bytes32(hex"15854f7a2b735373aa76722c01e2f289d8b18cb1a70575796be435e4ce55e57a")]; + b.layer = Layer(6); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c54450000000000008d8d8db4b4b44f7060b00000000174524e530040e6d866000000284944415478da62a032080d7560606060dcff7f02030303dbd5d00b080a2a0855422200040000ffffd7670a737ec363890000000049454e44ae426082"; + index[nextId] = bytes32(hex"15854f7a2b735373aa76722c01e2f289d8b18cb1a70575796be435e4ce55e57a"); + nextId++; + b = blocks[bytes32(hex"3e6bc8fc06a569840c9490f8122e6b7f08a7598486649b64477b548602362516")]; + b.layer = Layer(9); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c54450000000000005959590040ff401523b30000000174524e530040e6d8660000001b4944415478da621838c01aea00a2a4563b20f1700140000000ffff5249023a69668c5f0000000049454e44ae426082"; + index[nextId] = bytes32(hex"3e6bc8fc06a569840c9490f8122e6b7f08a7598486649b64477b548602362516"); + nextId++; + b = blocks[bytes32(hex"3511b04ac6a3d46305172269904dc469a40f380a4e7afa8742ce6e6a44825c4a")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c5445000000ff8ebe000000ffffff4ae3beda0000000174524e530040e6d866000000484944415478da62200568ad0053ab578148a655af1ac0d42a10c5181aeac0c0c0c0ea181000a2181c409408034308030383281e8a958101acc1811144313a303a60b71a100000ffff0f6e0bf3e2fa2eec0000000049454e44ae426082"; + index[nextId] = bytes32(hex"3511b04ac6a3d46305172269904dc469a40f380a4e7afa8742ce6e6a44825c4a"); + nextId++; + b = blocks[bytes32(hex"2857e47dcac3b744dd7d41617ce362f1dd3ae8eb836685cc18338714205b036c")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000fff68e5319653e0000000174524e530040e6d866000000394944415478da62c00aea181818ff83700303f3df030ccc15071898050e30b0331c6060836276307e00c6fc0d1f18980f36603309100000ffffaa950e78c9a6ec2c0000000049454e44ae426082"; + index[nextId] = bytes32(hex"2857e47dcac3b744dd7d41617ce362f1dd3ae8eb836685cc18338714205b036c"); + nextId++; + b = blocks[bytes32(hex"eb92e34266f6fa01c275db8379f6a521f15ab6f96297fe3266df2fe6b0e1422e")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b0000000c504c544500000000000085561ea66e2c6852a3220000000174524e530040e6d866000000244944415478da62c005442054099864fc02a6d82014f707881c943260a00300040000ffff252e04932174d5ed0000000049454e44ae426082"; + index[nextId] = bytes32(hex"eb92e34266f6fa01c275db8379f6a521f15ab6f96297fe3266df2fe6b0e1422e"); + nextId++; + b = blocks[bytes32(hex"c3075202748482832362d1b854d8274a38bf56c5ad38d418e590f46113ff10b1")]; + b.layer = Layer(6); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180403000000125920cb0000000f504c5445000000000000690c458c0d5bad21606331bdda0000000174524e530040e6d866000000324944415478da62187c80515090515010c651521454528472048d0d198d0d61322e8e8c2e8e304d820220443f00080000ffff973e030740dbe40c0000000049454e44ae426082"; + index[nextId] = bytes32(hex"c3075202748482832362d1b854d8274a38bf56c5ad38d418e590f46113ff10b1"); + nextId++; + b = blocks[bytes32(hex"bb1f372f67259011c2e9e7346c8a03a11f260853a1fe248ddd29540219788747")]; + b.layer = Layer(10); + b.dataFemale = hex"89504e470d0a1a0a0000000d49484452000000180000001802030000009d19d56b00000009504c5445000000000000ffd926bf0c26860000000174524e530040e6d866000000154944415478da62a0039080502c949801080000ffff07fc001da05932af0000000049454e44ae426082"; + index[nextId] = bytes32(hex"bb1f372f67259011c2e9e7346c8a03a11f260853a1fe248ddd29540219788747"); + nextId++; + b = blocks[bytes32(hex"2e9a5434da70e5ea2ed439b3a33aac60bd252c92698c1ba37e9ed77f975c6cab")]; + b.layer = Layer(5); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df8000000384944415478da6262a03118b560d482510b462da09605da531c6782302131b22db89ab33f9d18b10101a3a968d482510be86001200000ffffd02f0b616aa9c37e0000000049454e44ae426082"; + index[nextId] = bytes32(hex"2e9a5434da70e5ea2ed439b3a33aac60bd252c92698c1ba37e9ed77f975c6cab"); + nextId++; + b = blocks[bytes32(hex"8c0e60b85ff0f8be1a87b28ae066a63dcc3c02589a213b0856321a73882515f9")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c544500000051360c48b320160000000174524e530040e6d8660000002f4944415478da62c00bea181818fe333030fe6f60603ed8c0c0dc00c1ec0c58302312666e606067079b00080000ffffd1030b1b1e3ca1240000000049454e44ae426082"; + index[nextId] = bytes32(hex"8c0e60b85ff0f8be1a87b28ae066a63dcc3c02589a213b0856321a73882515f9"); + nextId++; + b = blocks[bytes32(hex"047228ad95cec16eb926f7cd21ac9cc9a3288d911a6c2917a24555eac7a2c0e2")]; + b.layer = Layer(1); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df80000002f4944415478da6262a03118b560d482510b462d18b5806e164c916250036142620302462379d482216001200000ffff8e55037f0295ca130000000049454e44ae426082"; + index[nextId] = bytes32(hex"047228ad95cec16eb926f7cd21ac9cc9a3288d911a6c2917a24555eac7a2c0e2"); + nextId++; + b = blocks[bytes32(hex"e651be5dd43261e6e9c1098ec114ab5c44e7cb07377dc674336f1b3d34428fe4")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d866000000364944415478da62c00a0a1818187f303030bf6060607fc0c0c07e808181bd8181811f861920980f19373030c83320301400020000ffff746d06dbf514328c0000000049454e44ae426082"; + index[nextId] = bytes32(hex"e651be5dd43261e6e9c1098ec114ab5c44e7cb07377dc674336f1b3d34428fe4"); + nextId++; + b = blocks[bytes32(hex"a71068a671b554f75b7cc31ce4f8d63c377f276333d11989e77bc4a9205b5e42")]; + b.layer = Layer(3); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d866000000294944415478da9cc0310d00300800b01ecbae65125042f02f8b9b971a2e3e0285c4c3b1d5010000ffff337800bd4717cafb0000000049454e44ae426082"; + index[nextId] = bytes32(hex"a71068a671b554f75b7cc31ce4f8d63c377f276333d11989e77bc4a9205b5e42"); + nextId++; + b = blocks[bytes32(hex"1cd064e6db4e7c5180ccf5f2afe1370c6539b525fe3bea9c358f24a7cbdb50ad")]; + b.layer = Layer(8); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000000000a567b9cf0000000174524e530040e6d866000000124944415478da62a01a90c12a0a080000ffff02c8001d72b777ad0000000049454e44ae426082"; + index[nextId] = bytes32(hex"1cd064e6db4e7c5180ccf5f2afe1370c6539b525fe3bea9c358f24a7cbdb50ad"); + nextId++; + b = blocks[bytes32(hex"d5de5c20969a9e22f93842ca4d65bac0c0387225cee45a944a14f03f9221fd4a")]; + b.layer = Layer(6); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df8000000484944415478da6262a03118b560d482510b8683052c04e4ff13690e23b916309c7ef6b710c6369562eec725466e103162e13312eb7abac401c368321db560d402da5b00080000ffffbe8c09370dfcbb5e0000000049454e44ae426082"; + index[nextId] = bytes32(hex"d5de5c20969a9e22f93842ca4d65bac0c0387225cee45a944a14f03f9221fd4a"); + nextId++; + b = blocks[bytes32(hex"2c382a7f1f32a6a2d0e9b0d378cb95e3dad70fe6909ff13888fe2a250bd10bb0")]; + b.layer = Layer(12); + b.dataFemale = hex"89504e470d0a1a0a0000000d4948445200000018000000180103000000dab9afbb00000006504c5445000000dfdfdf337edd570000000174524e530040e6d866000000124944415478da62a01928009380000000ffff0300007135fa2b640000000049454e44ae426082"; + index[nextId] = bytes32(hex"2c382a7f1f32a6a2d0e9b0d378cb95e3dad70fe6909ff13888fe2a250bd10bb0"); + nextId++; + } + + /** + * @dev registerBlock allows anybody to add a new block to the contract. + * Either _dataMale or _dataFemale, or both, must contain a byte stream of a png file. + * It's best if the png is using an 'index palette' and the lowest bit depth possible, + * while keeping the highest compression setting. + * @param _dataMale png data for the male version, 24x24 + * @param _dataFemale png data for the female version, 24x24 + * @param _layer 0 to 12, corresponding to the Layer enum type. + * @param _name the name of the trait, Camel Case. e.g. "Luxurious Beard" + */ + function registerBlock( + bytes calldata _dataMale, + bytes calldata _dataFemale, + uint8 _layer, + string memory _name) external + { + bytes32 key = keccak256(abi.encodePacked(_name)); + Block storage b = blocks[key]; + require (_layer < 13, "invalid _layer"); + unchecked{ + require (_dataMale.length + _dataFemale.length > 0, "no data"); + require (b.dataMale.length + b.dataFemale.length == 0, "slot taken"); + } + if (_layer==0 && _dataMale.length > 0 && _dataFemale.length > 0) { + revert("layer0 cannot have both versions"); + } + if (_dataMale.length > 0) { + require (_validatePng(_dataMale), "invalid m png"); + b.dataMale = _dataMale; + } + if (_dataFemale.length > 0) { + require (_validatePng(_dataFemale), "invalid f png"); + b.dataFemale = _dataFemale; + } + b.layer = Layer(_layer); + index[nextId] = key; + emit NewBlock(msg.sender, nextId, _name); + unchecked{nextId++;} + } + + /** + * @dev Just a limited png validation. Only verifies that the png is 24x24 and has a png structure, + * but doesn't validate any checksums or any other validation + */ + function _validatePng(bytes calldata _data) pure internal returns (bool) { + unchecked { + if (_data.length < 8) { + return false; + } + bytes memory pngHeader = bytes("\x89PNG\r\n\x1a\n"); // first 8 bytes + uint pos; + while (pos < 8) { + if (_data[pos] != pngHeader[pos]) { + return false; + } + pos++; + } + int32 chunkLen; + while (true) { + // next 4 bytes represent a big-endian int32, the chunk length + chunkLen = int32(uint32(uint8(_data[pos+3])) + | uint32(uint8(_data[pos+2]))<<8 + | uint32(uint8(_data[pos+1]))<<16 + | uint32(uint8(_data[pos]))<<24); + pos += 4; + if ( + _data[pos] == bytes1("I") && + _data[pos+1] == bytes1("H") && + _data[pos+2] == bytes1("D") && + _data[pos+3] == bytes1("R")) { // IHDR + if (24 != int32(uint32(uint8(_data[pos+7])) + | uint32(uint8(_data[pos+6]))<<8 + | uint32(uint8(_data[pos+5]))<<16 + | uint32(uint8(_data[pos+4]))<<24)) { // width needs to be 24 + return false; + } + if (24 != int32(uint32(uint8(_data[pos+11])) + | uint32(uint8(_data[pos+10]))<<8 + | uint32(uint8(_data[pos+9]))<<16 + | uint32(uint8(_data[pos+8]))<<24)) { // height needs to be 24 + return false; + } + } else if ( + _data[pos] == bytes1("P") && + _data[pos+1] == bytes1("L") && + _data[pos+2] == bytes1("T") && + _data[pos+3] == bytes1("E")) { // PLTE + } else if ( + _data[pos] == bytes1("t") && + _data[pos+1] == bytes1("R") && + _data[pos+2] == bytes1("N") && + _data[pos+3] == bytes1("S")) { // tRNS + } else if ( + _data[pos] == bytes1("I") && + _data[pos+1] == bytes1("D") && + _data[pos+2] == bytes1("A") && + _data[pos+3] == bytes1("T")) { // IDAT + } else if ( + _data[pos] == bytes1("I") && + _data[pos+1] == bytes1("E") && + _data[pos+2] == bytes1("N") && + _data[pos+3] == bytes1("D")) { // IEND + return true; // png is valid (without checking the CRC) + } else { + return false; + } + pos += 4 + uint(int(chunkLen)) + 4; // skip the payload, ignore CRC + } + } //unchecked + return true; + } + + /** + * @dev svgFromNames returns the svg data as a string + * @param _attributeNames a list of attribute names, eg "Male 1", "Goat" + * must have at least 1 layer 0 attribute (eg. Male, Female, Alien, Ape, Zombie) + * e.g. ["Male 1","Goat"] + * Where "Male 1" is a layer 0 attribute, that decides what version of + * image to use for the higher + * layers (dataMale or dataFemale) + */ + function svgFromNames(string[] calldata _attributeNames) external view returns (string memory){ + bytes32[] memory attributeKeys = new bytes32[](_attributeNames.length); + for (uint i = 0; i < _attributeNames.length; i++) { + attributeKeys[i] = keccak256( + abi.encodePacked(_attributeNames[i]) + ); + } + return _svg(attributeKeys); + } + + /** + * @dev svgFromKeys returns the svg data as a string + * @param _attributeKeys a list of attribute names that have been hashed, + * eg keccak256("Male 1"), keccak256("Goat") + * must have at least 1 layer 0 attribute (eg. keccak256("Male 1")) which + * decides what version of image to use for the higher layers + * (dataMale or dataFemale) + * e.g. ["0x9039da071f773e85254cbd0f99efa70230c4c11d63fce84323db9eca8e8ef283", + * "0xd5de5c20969a9e22f93842ca4d65bac0c0387225cee45a944a14f03f9221fd4a"] + */ + function svgFromKeys(bytes32[] calldata _attributeKeys) external view returns (string memory) { + return _svg(_attributeKeys); + } + + /** + * @dev svgFromIDs returns the svg data as a string + * e.g. [9,55,99] + * One of the elements must be must be a layer 0 block. + * This element decides what version of image to use for the higher layers + * (dataMale or dataFemale) + * @param _ids uint256 ids of an attribute, by it's index of creation + */ + function svgFromIDs(uint256[] calldata _ids) external view returns (string memory) { + bytes32[] memory attributeKeys = new bytes32[](_ids.length); + for (uint i = 0; i < _ids.length; i++) { + attributeKeys[i] = index[_ids[i]]; + } + return _svg(attributeKeys); + } + + /** + * @dev svgFromPunkID returns the svg data as a string given a punk id + * @param _tokenID uint256 IDs a punk id, 0-9999 + */ + function svgFromPunkID(uint256 _tokenID) external view returns (string memory) { + // Get the attributes first, using https://github.com/0xTycoon/punks-token-uri + IAttrParser p = IAttrParser(0xD8E916C3016bE144eb2907778cf972C4b01645fC); + string[8] memory _attributeNames = p.parseAttributes(_tokenID); + uint count; + for (uint i = 0; i < 8; i++) { + if (bytes(_attributeNames[i]).length == 0) { + break; + } + count++; + } + bytes32[] memory attributeKeys = new bytes32[](count); + for (uint i = 0; i < count; i++) { + attributeKeys[i] = keccak256( + abi.encodePacked(_attributeNames[i]) + ); + } + return _svg(attributeKeys); + } + + /** + * @dev _svg build the svg, layer by layer. The first layer determines if dataFemale or dataMale is used for + * the afterward layers. Empty layers will be ignored. + * @return string of the svg image + */ + function _svg(bytes32[] memory _keys) internal view returns (string memory) { + string memory start = ''; + string memory end = ''; + string memory imgStart = ''; + string memory images; + Block[] memory layers = new Block[](13); + // load the block layers in + for (uint i = 0; i < _keys.length; i++) { + Block memory b = blocks[_keys[i]]; + require (b.dataFemale.length + b.dataMale.length > 0, "invalid attribute"); + layers[uint256(b.layer)] = b; + } + bool isFemale; + if (layers[0].dataFemale.length > 0) { + isFemale = true; + } else { + require (layers[0].dataMale.length > 0, "base layer attribute unspecified"); + } + for (uint i = 0; i < 13; i++) { + if (isFemale && layers[i].dataFemale.length > 0) { + images = string(abi.encodePacked( + images, + imgStart, + Base64.encode(layers[i].dataFemale), + imgEnd + )); + } else if (!isFemale && layers[i].dataMale.length > 0) { + images = string(abi.encodePacked( + images, + imgStart, + Base64.encode(layers[i].dataMale), + imgEnd + )); + } + } + return string(abi.encodePacked( + start, + images, + end + )); + } + + /** + * @dev getBlocks returns a sequential list of blocks in a single call + * @param _fromID is which id to begin from + * @param _count how many items to retrieve. + * @return Block[] list of blocks, uint256 next id + */ + function getBlocks(uint _fromID, uint _count) external view returns(Block[] memory, uint256) { + Block[] memory ret = new Block[](_count); + while (_count != 0) { + ret[_count-1] = blocks[index[_fromID + _count -1]]; + _count--; + } + return (ret, nextId); + } +} +// IAttrParser implemented by 0x4e776fCbb241a0e0Ea2904d642baa4c7E171a1E9 +interface IAttrParser { + function parseAttributes(uint256 _tokenId) external view returns (string[8] memory); +} + +library Base64 { + /** + * @dev Base64 Encoding/Decoding Table + */ + string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** + * @dev Converts a `bytes` to its Bytes64 `string` representation. + */ + function encode(bytes memory data) internal pure returns (string memory) { + /** + * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence + * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol + */ + if (data.length == 0) return ""; + + // Loads the table into memory + string memory table = _TABLE; + + // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter + // and split into 4 numbers of 6 bits. + // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up + // - `data.length + 2` -> Round up + // - `/ 3` -> Number of 3-bytes chunks + // - `4 *` -> 4 characters for each chunk + string memory result = new string(4 * ((data.length + 2) / 3)); + + /// @solidity memory-safe-assembly + assembly { + // Prepare the lookup table (skip the first "length" byte) + let tablePtr := add(table, 1) + + // Prepare result pointer, jump over length + let resultPtr := add(result, 32) + + // Run over the input, 3 bytes at a time + for { + let dataPtr := data + let endPtr := add(data, mload(data)) + } lt(dataPtr, endPtr) { + + } { + // Advance 3 bytes + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + + // To write each character, shift the 3 bytes (18 bits) chunk + // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) + // and apply logical AND with 0x3F which is the number of + // the previous character in the ASCII table prior to the Base64 Table + // The result is then added to the table to get the character to write, + // and finally write it in the result pointer but with a left shift + // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits + + mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + } + + // When data `bytes` is not exactly 3 bytes long + // it is padded with `=` characters at the end + switch mod(mload(data), 3) + case 1 { + mstore8(sub(resultPtr, 1), 0x3d) + mstore8(sub(resultPtr, 2), 0x3d) + } + case 2 { + mstore8(sub(resultPtr, 1), 0x3d) + } + } + return result; + } +} \ No newline at end of file diff --git a/ethabi/code/0x58e90596c2065befd3060767736c829c18f3474c.yml b/ethabi/code/0x58e90596c2065befd3060767736c829c18f3474c.yml new file mode 100644 index 0000000..a055ae0 --- /dev/null +++ b/ethabi/code/0x58e90596c2065befd3060767736c829c18f3474c.yml @@ -0,0 +1,12 @@ +--- +ContractName: PunkBlocks +CompilerVersion: v0.8.17+commit.8df45f5f +OptimizationUsed: '0' +Runs: '200' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: MIT +Proxy: '0' +Implementation: '' +SwarmSource: ipfs://32ad0fbc576ca3e373c18d9fa8a6a0bc02f0077ebfb274d6760570e76ebf86e6 diff --git a/ethabi/code/0x60cd862c9c687a9de49aecdc3a99b74a4fc54ab6.sol b/ethabi/code/0x60cd862c9c687a9de49aecdc3a99b74a4fc54ab6.sol new file mode 100644 index 0000000..c7c05de --- /dev/null +++ b/ethabi/code/0x60cd862c9c687a9de49aecdc3a99b74a4fc54ab6.sol @@ -0,0 +1,331 @@ +pragma solidity ^0.4.13; + +contract MoonCatRescue { + enum Modes { Inactive, Disabled, Test, Live } + + Modes public mode = Modes.Inactive; + + address owner; + + bytes16 public imageGenerationCodeMD5 = 0xdbad5c08ec98bec48490e3c196eec683; // use this to verify mooncatparser.js the cat image data generation javascript file. + + string public name = "MoonCats"; + string public symbol = "?"; // unicode cat symbol + uint8 public decimals = 0; + + uint256 public totalSupply = 25600; + uint16 public remainingCats = 25600 - 256; // there will only ever be 25,000 cats + uint16 public remainingGenesisCats = 256; // there can only be a maximum of 256 genesis cats + uint16 public rescueIndex = 0; + + bytes5[25600] public rescueOrder; + + bytes32 public searchSeed = 0x0; // gets set with the immediately preceding blockhash when the contract is activated to prevent "premining" + + struct AdoptionOffer { + bool exists; + bytes5 catId; + address seller; + uint price; + address onlyOfferTo; + } + + struct AdoptionRequest{ + bool exists; + bytes5 catId; + address requester; + uint price; + } + + mapping (bytes5 => AdoptionOffer) public adoptionOffers; + mapping (bytes5 => AdoptionRequest) public adoptionRequests; + + mapping (bytes5 => bytes32) public catNames; + mapping (bytes5 => address) public catOwners; + mapping (address => uint256) public balanceOf; //number of cats owned by a given address + mapping (address => uint) public pendingWithdrawals; + + /* events */ + + event CatRescued(address indexed to, bytes5 indexed catId); + event CatNamed(bytes5 indexed catId, bytes32 catName); + event Transfer(address indexed from, address indexed to, uint256 value); + event CatAdopted(bytes5 indexed catId, uint price, address indexed from, address indexed to); + event AdoptionOffered(bytes5 indexed catId, uint price, address indexed toAddress); + event AdoptionOfferCancelled(bytes5 indexed catId); + event AdoptionRequested(bytes5 indexed catId, uint price, address indexed from); + event AdoptionRequestCancelled(bytes5 indexed catId); + event GenesisCatsAdded(bytes5[16] catIds); + + function MoonCatRescue() payable { + owner = msg.sender; + assert((remainingCats + remainingGenesisCats) == totalSupply); + assert(rescueOrder.length == totalSupply); + assert(rescueIndex == 0); + } + + /* registers and validates cats that are found */ + function rescueCat(bytes32 seed) activeMode returns (bytes5) { + require(remainingCats > 0); // cannot register any cats once supply limit is reached + bytes32 catIdHash = keccak256(seed, searchSeed); // generate the prospective catIdHash + require(catIdHash[0] | catIdHash[1] | catIdHash[2] == 0x0); // ensures the validity of the catIdHash + bytes5 catId = bytes5((catIdHash & 0xffffffff) << 216); // one byte to indicate genesis, and the last 4 bytes of the catIdHash + require(catOwners[catId] == 0x0); // if the cat is already registered, throw an error. All cats are unique. + + rescueOrder[rescueIndex] = catId; + rescueIndex++; + + catOwners[catId] = msg.sender; + balanceOf[msg.sender]++; + remainingCats--; + + CatRescued(msg.sender, catId); + + return catId; + } + + /* assigns a name to a cat, once a name is assigned it cannot be changed */ + function nameCat(bytes5 catId, bytes32 catName) onlyCatOwner(catId) { + require(catNames[catId] == 0x0); // ensure the current name is empty; cats can only be named once + require(!adoptionOffers[catId].exists); // cats cannot be named while they are up for adoption + catNames[catId] = catName; + CatNamed(catId, catName); + } + + /* puts a cat up for anyone to adopt */ + function makeAdoptionOffer(bytes5 catId, uint price) onlyCatOwner(catId) { + require(price > 0); + adoptionOffers[catId] = AdoptionOffer(true, catId, msg.sender, price, 0x0); + AdoptionOffered(catId, price, 0x0); + } + + /* puts a cat up for a specific address to adopt */ + function makeAdoptionOfferToAddress(bytes5 catId, uint price, address to) onlyCatOwner(catId) isNotSender(to){ + adoptionOffers[catId] = AdoptionOffer(true, catId, msg.sender, price, to); + AdoptionOffered(catId, price, to); + } + + /* cancel an adoption offer */ + function cancelAdoptionOffer(bytes5 catId) onlyCatOwner(catId) { + adoptionOffers[catId] = AdoptionOffer(false, catId, 0x0, 0, 0x0); + AdoptionOfferCancelled(catId); + } + + /* accepts an adoption offer */ + function acceptAdoptionOffer(bytes5 catId) payable { + AdoptionOffer storage offer = adoptionOffers[catId]; + require(offer.exists); + require(offer.onlyOfferTo == 0x0 || offer.onlyOfferTo == msg.sender); + require(msg.value >= offer.price); + if(msg.value > offer.price) { + pendingWithdrawals[msg.sender] += (msg.value - offer.price); // if the submitted amount exceeds the price allow the buyer to withdraw the difference + } + transferCat(catId, catOwners[catId], msg.sender, offer.price); + } + + /* transfer a cat directly without payment */ + function giveCat(bytes5 catId, address to) onlyCatOwner(catId) { + transferCat(catId, msg.sender, to, 0); + } + + /* requests adoption of a cat with an ETH offer */ + function makeAdoptionRequest(bytes5 catId) payable isNotSender(catOwners[catId]) { + require(catOwners[catId] != 0x0); // the cat must be owned + AdoptionRequest storage existingRequest = adoptionRequests[catId]; + require(msg.value > 0); + require(msg.value > existingRequest.price); + + + if(existingRequest.price > 0) { + pendingWithdrawals[existingRequest.requester] += existingRequest.price; + } + + adoptionRequests[catId] = AdoptionRequest(true, catId, msg.sender, msg.value); + AdoptionRequested(catId, msg.value, msg.sender); + + } + + /* allows the owner of the cat to accept an adoption request */ + function acceptAdoptionRequest(bytes5 catId) onlyCatOwner(catId) { + AdoptionRequest storage existingRequest = adoptionRequests[catId]; + require(existingRequest.exists); + address existingRequester = existingRequest.requester; + uint existingPrice = existingRequest.price; + adoptionRequests[catId] = AdoptionRequest(false, catId, 0x0, 0); // the adoption request must be cancelled before calling transferCat to prevent refunding the requester. + transferCat(catId, msg.sender, existingRequester, existingPrice); + } + + /* allows the requester to cancel their adoption request */ + function cancelAdoptionRequest(bytes5 catId) { + AdoptionRequest storage existingRequest = adoptionRequests[catId]; + require(existingRequest.exists); + require(existingRequest.requester == msg.sender); + + uint price = existingRequest.price; + + adoptionRequests[catId] = AdoptionRequest(false, catId, 0x0, 0); + + msg.sender.transfer(price); + + AdoptionRequestCancelled(catId); + } + + + function withdraw() { + uint amount = pendingWithdrawals[msg.sender]; + pendingWithdrawals[msg.sender] = 0; + msg.sender.transfer(amount); + } + + /* owner only functions */ + + /* disable contract before activation. A safeguard if a bug is found before the contract is activated */ + function disableBeforeActivation() onlyOwner inactiveMode { + mode = Modes.Disabled; // once the contract is disabled it's mode cannot be changed + } + + /* activates the contract in *Live* mode which sets the searchSeed and enables rescuing */ + function activate() onlyOwner inactiveMode { + searchSeed = block.blockhash(block.number - 1); // once the searchSeed is set it cannot be changed; + mode = Modes.Live; // once the contract is activated it's mode cannot be changed + } + + /* activates the contract in *Test* mode which sets the searchSeed and enables rescuing */ + function activateInTestMode() onlyOwner inactiveMode { // + searchSeed = 0x5713bdf5d1c3398a8f12f881f0f03b5025b6f9c17a97441a694d5752beb92a3d; // once the searchSeed is set it cannot be changed; + mode = Modes.Test; // once the contract is activated it's mode cannot be changed + } + + /* add genesis cats in groups of 16 */ + function addGenesisCatGroup() onlyOwner activeMode { + require(remainingGenesisCats > 0); + bytes5[16] memory newCatIds; + uint256 price = (17 - (remainingGenesisCats / 16)) * 300000000000000000; + for(uint8 i = 0; i < 16; i++) { + + uint16 genesisCatIndex = 256 - remainingGenesisCats; + bytes5 genesisCatId = (bytes5(genesisCatIndex) << 24) | 0xff00000ca7; + + newCatIds[i] = genesisCatId; + + rescueOrder[rescueIndex] = genesisCatId; + rescueIndex++; + balanceOf[0x0]++; + remainingGenesisCats--; + + adoptionOffers[genesisCatId] = AdoptionOffer(true, genesisCatId, owner, price, 0x0); + } + GenesisCatsAdded(newCatIds); + } + + + /* aggregate getters */ + + function getCatIds() constant returns (bytes5[]) { + bytes5[] memory catIds = new bytes5[](rescueIndex); + for (uint i = 0; i < rescueIndex; i++) { + catIds[i] = rescueOrder[i]; + } + return catIds; + } + + + function getCatNames() constant returns (bytes32[]) { + bytes32[] memory names = new bytes32[](rescueIndex); + for (uint i = 0; i < rescueIndex; i++) { + names[i] = catNames[rescueOrder[i]]; + } + return names; + } + + function getCatOwners() constant returns (address[]) { + address[] memory owners = new address[](rescueIndex); + for (uint i = 0; i < rescueIndex; i++) { + owners[i] = catOwners[rescueOrder[i]]; + } + return owners; + } + + function getCatOfferPrices() constant returns (uint[]) { + uint[] memory catOffers = new uint[](rescueIndex); + for (uint i = 0; i < rescueIndex; i++) { + bytes5 catId = rescueOrder[i]; + if(adoptionOffers[catId].exists && adoptionOffers[catId].onlyOfferTo == 0x0) { + catOffers[i] = adoptionOffers[catId].price; + } + } + return catOffers; + } + + function getCatRequestPrices() constant returns (uint[]) { + uint[] memory catRequests = new uint[](rescueIndex); + for (uint i = 0; i < rescueIndex; i++) { + bytes5 catId = rescueOrder[i]; + catRequests[i] = adoptionRequests[catId].price; + } + return catRequests; + } + + function getCatDetails(bytes5 catId) constant returns (bytes5 id, + address owner, + bytes32 name, + address onlyOfferTo, + uint offerPrice, + address requester, + uint requestPrice) { + + return (catId, + catOwners[catId], + catNames[catId], + adoptionOffers[catId].onlyOfferTo, + adoptionOffers[catId].price, + adoptionRequests[catId].requester, + adoptionRequests[catId].price); + } + + /* modifiers */ + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + + modifier inactiveMode() { + require(mode == Modes.Inactive); + _; + } + + modifier activeMode() { + require(mode == Modes.Live || mode == Modes.Test); + _; + } + + modifier onlyCatOwner(bytes5 catId) { + require(catOwners[catId] == msg.sender); + _; + } + + modifier isNotSender(address a) { + require(msg.sender != a); + _; + } + + /* transfer helper */ + function transferCat(bytes5 catId, address from, address to, uint price) private { + catOwners[catId] = to; + balanceOf[from]--; + balanceOf[to]++; + adoptionOffers[catId] = AdoptionOffer(false, catId, 0x0, 0, 0x0); // cancel any existing adoption offer when cat is transferred + + AdoptionRequest storage request = adoptionRequests[catId]; //if the recipient has a pending adoption request, cancel it + if(request.requester == to) { + pendingWithdrawals[to] += request.price; + adoptionRequests[catId] = AdoptionRequest(false, catId, 0x0, 0); + } + + pendingWithdrawals[from] += price; + + Transfer(from, to, 1); + CatAdopted(catId, price, from, to); + } + +} \ No newline at end of file diff --git a/ethabi/code/0x60cd862c9c687a9de49aecdc3a99b74a4fc54ab6.yml b/ethabi/code/0x60cd862c9c687a9de49aecdc3a99b74a4fc54ab6.yml new file mode 100644 index 0000000..74e6752 --- /dev/null +++ b/ethabi/code/0x60cd862c9c687a9de49aecdc3a99b74a4fc54ab6.yml @@ -0,0 +1,12 @@ +--- +ContractName: MoonCatRescue +CompilerVersion: v0.4.14+commit.c2215d46 +OptimizationUsed: '1' +Runs: '200' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: '' +Proxy: '0' +Implementation: '' +SwarmSource: bzzr://a4e578d3d7c9a384b5985a5957dd2477a19f9d32052121927063bf9f549c6032 diff --git a/ethabi/code/0x6ba6f2207e343923ba692e5cae646fb0f566db8d.sol b/ethabi/code/0x6ba6f2207e343923ba692e5cae646fb0f566db8d.sol new file mode 100644 index 0000000..7d6ff2c --- /dev/null +++ b/ethabi/code/0x6ba6f2207e343923ba692e5cae646fb0f566db8d.sol @@ -0,0 +1,136 @@ +pragma solidity ^0.4.8; +contract CryptoPunks { + + // You can use this hash to verify the image file containing all the punks + string public imageHash = "ac39af4793119ee46bbff351d8cb6b5f23da60222126add4268e261199a2921b"; + + address owner; + + string public standard = 'CryptoPunks'; + string public name; + string public symbol; + uint8 public decimals; + uint256 public totalSupply; + + uint public nextPunkIndexToAssign = 0; + + //bool public allPunksAssigned = false; + uint public punksRemainingToAssign = 0; + uint public numberOfPunksToReserve; + uint public numberOfPunksReserved = 0; + + //mapping (address => uint) public addressToPunkIndex; + mapping (uint => address) public punkIndexToAddress; + + /* This creates an array with all balances */ + mapping (address => uint256) public balanceOf; + + struct Offer { + bool isForSale; + uint punkIndex; + address seller; + uint minValue; // in ether + address onlySellTo; // specify to sell only to a specific person + } + + // A record of punks that are offered for sale at a specific minimum value, and perhaps to a specific person + mapping (uint => Offer) public punksOfferedForSale; + + mapping (address => uint) public pendingWithdrawals; + + event Assign(address indexed to, uint256 punkIndex); + event Transfer(address indexed from, address indexed to, uint256 value); + event PunkTransfer(address indexed from, address indexed to, uint256 punkIndex); + event PunkOffered(uint indexed punkIndex, uint minValue, address indexed toAddress); + event PunkBought(uint indexed punkIndex, uint value, address indexed fromAddress, address indexed toAddress); + event PunkNoLongerForSale(uint indexed punkIndex); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + function CryptoPunks() payable { + // balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens + owner = msg.sender; + totalSupply = 10000; // Update total supply + punksRemainingToAssign = totalSupply; + numberOfPunksToReserve = 1000; + name = "CRYPTOPUNKS"; // Set the name for display purposes + symbol = "Ͼ"; // Set the symbol for display purposes + decimals = 0; // Amount of decimals for display purposes + } + + function reservePunksForOwner(uint maxForThisRun) { + if (msg.sender != owner) throw; + if (numberOfPunksReserved >= numberOfPunksToReserve) throw; + uint numberPunksReservedThisRun = 0; + while (numberOfPunksReserved < numberOfPunksToReserve && numberPunksReservedThisRun < maxForThisRun) { + punkIndexToAddress[nextPunkIndexToAssign] = msg.sender; + Assign(msg.sender, nextPunkIndexToAssign); + numberPunksReservedThisRun++; + nextPunkIndexToAssign++; + } + punksRemainingToAssign -= numberPunksReservedThisRun; + numberOfPunksReserved += numberPunksReservedThisRun; + balanceOf[msg.sender] += numberPunksReservedThisRun; + } + + function getPunk(uint punkIndex) { + if (punksRemainingToAssign == 0) throw; + if (punkIndexToAddress[punkIndex] != 0x0) throw; + punkIndexToAddress[punkIndex] = msg.sender; + balanceOf[msg.sender]++; + punksRemainingToAssign--; + Assign(msg.sender, punkIndex); + } + + // Transfer ownership of a punk to another user without requiring payment + function transferPunk(address to, uint punkIndex) { + if (punkIndexToAddress[punkIndex] != msg.sender) throw; + punkIndexToAddress[punkIndex] = to; + balanceOf[msg.sender]--; + balanceOf[to]++; + Transfer(msg.sender, to, 1); + PunkTransfer(msg.sender, to, punkIndex); + } + + function punkNoLongerForSale(uint punkIndex) { + if (punkIndexToAddress[punkIndex] != msg.sender) throw; + punksOfferedForSale[punkIndex] = Offer(false, punkIndex, msg.sender, 0, 0x0); + PunkNoLongerForSale(punkIndex); + } + + function offerPunkForSale(uint punkIndex, uint minSalePriceInWei) { + if (punkIndexToAddress[punkIndex] != msg.sender) throw; + punksOfferedForSale[punkIndex] = Offer(true, punkIndex, msg.sender, minSalePriceInWei, 0x0); + PunkOffered(punkIndex, minSalePriceInWei, 0x0); + } + + function offerPunkForSaleToAddress(uint punkIndex, uint minSalePriceInWei, address toAddress) { + if (punkIndexToAddress[punkIndex] != msg.sender) throw; + punksOfferedForSale[punkIndex] = Offer(true, punkIndex, msg.sender, minSalePriceInWei, toAddress); + PunkOffered(punkIndex, minSalePriceInWei, toAddress); + } + + function buyPunk(uint punkIndex) payable { + Offer offer = punksOfferedForSale[punkIndex]; + if (!offer.isForSale) throw; // punk not actually for sale + if (offer.onlySellTo != 0x0 && offer.onlySellTo != msg.sender) throw; // punk not supposed to be sold to this user + if (msg.value < offer.minValue) throw; // Didn't send enough ETH + if (offer.seller != punkIndexToAddress[punkIndex]) throw; // Seller no longer owner of punk + + punkIndexToAddress[punkIndex] = msg.sender; + balanceOf[offer.seller]--; + balanceOf[msg.sender]++; + Transfer(offer.seller, msg.sender, 1); + + punkNoLongerForSale(punkIndex); + pendingWithdrawals[offer.seller] += msg.value; + PunkBought(punkIndex, msg.value, offer.seller, msg.sender); + } + + function withdraw() { + uint amount = pendingWithdrawals[msg.sender]; + // Remember to zero the pending refund before + // sending to prevent re-entrancy attacks + pendingWithdrawals[msg.sender] = 0; + msg.sender.transfer(amount); + } +} \ No newline at end of file diff --git a/ethabi/code/0x6ba6f2207e343923ba692e5cae646fb0f566db8d.yml b/ethabi/code/0x6ba6f2207e343923ba692e5cae646fb0f566db8d.yml new file mode 100644 index 0000000..e28b203 --- /dev/null +++ b/ethabi/code/0x6ba6f2207e343923ba692e5cae646fb0f566db8d.yml @@ -0,0 +1,12 @@ +--- +ContractName: CryptoPunks +CompilerVersion: v0.4.11+commit.68ef5810 +OptimizationUsed: '1' +Runs: '200' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: '' +Proxy: '0' +Implementation: '' +SwarmSource: bzzr://cd1903deb8c3a00bcd5580c74884b992d2c40cb0e3a57a0f6045d55ce504d0a4 diff --git a/ethabi/code/0x71eb5c179ceb640160853144cbb8df5bd24ab5cc.sol b/ethabi/code/0x71eb5c179ceb640160853144cbb8df5bd24ab5cc.sol new file mode 100644 index 0000000..386b426 --- /dev/null +++ b/ethabi/code/0x71eb5c179ceb640160853144cbb8df5bd24ab5cc.sol @@ -0,0 +1,1070 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.11; + +// File: @openzeppelin/contracts/utils/Context.sol + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + +// File: @openzeppelin/contracts/access/Ownable.sol + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor() { + _setOwner(_msgSender()); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _setOwner(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _setOwner(newOwner); + } + + function _setOwner(address newOwner) private { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} + +// File: @openzeppelin/contracts/utils/Address.sol + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + assembly { + size := extcodesize(account) + } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/utils/introspection/IERC165.sol + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// File: @openzeppelin/contracts/utils/introspection/ERC165.sol + + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + +// File: @openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol + +/** + * @dev _Available since v3.1._ + */ +interface IERC1155Receiver is IERC165 { + /** + @dev Handles the receipt of a single ERC1155 token type. This function is + called at the end of a `safeTransferFrom` after the balance has been updated. + To accept the transfer, this must return + `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` + (i.e. 0xf23a6e61, or its own function selector). + @param operator The address which initiated the transfer (i.e. msg.sender) + @param from The address which previously owned the token + @param id The ID of the token being transferred + @param value The amount of tokens being transferred + @param data Additional data with no specified format + @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed + */ + function onERC1155Received( + address operator, + address from, + uint256 id, + uint256 value, + bytes calldata data + ) external returns (bytes4); + + /** + @dev Handles the receipt of a multiple ERC1155 token types. This function + is called at the end of a `safeBatchTransferFrom` after the balances have + been updated. To accept the transfer(s), this must return + `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` + (i.e. 0xbc197c81, or its own function selector). + @param operator The address which initiated the batch transfer (i.e. msg.sender) + @param from The address which previously owned the token + @param ids An array containing ids of each token being transferred (order and length must match values array) + @param values An array containing amounts of each token being transferred (order and length must match ids array) + @param data Additional data with no specified format + @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed + */ + function onERC1155BatchReceived( + address operator, + address from, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) external returns (bytes4); +} + +// File: @openzeppelin/contracts/token/ERC1155/IERC1155.sol + +/** + * @dev Required interface of an ERC1155 compliant contract, as defined in the + * https://eips.ethereum.org/EIPS/eip-1155[EIP]. + * + * _Available since v3.1._ + */ +interface IERC1155 is IERC165 { + /** + * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. + */ + event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); + + /** + * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all + * transfers. + */ + event TransferBatch( + address indexed operator, + address indexed from, + address indexed to, + uint256[] ids, + uint256[] values + ); + + /** + * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to + * `approved`. + */ + event ApprovalForAll(address indexed account, address indexed operator, bool approved); + + /** + * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. + * + * If an {URI} event was emitted for `id`, the standard + * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value + * returned by {IERC1155MetadataURI-uri}. + */ + event URI(string value, uint256 indexed id); + + /** + * @dev Returns the amount of tokens of token type `id` owned by `account`. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function balanceOf(address account, uint256 id) external view returns (uint256); + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) + external + view + returns (uint256[] memory); + + /** + * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, + * + * Emits an {ApprovalForAll} event. + * + * Requirements: + * + * - `operator` cannot be the caller. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address account, address operator) external view returns (bool); + + /** + * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}. + * - `from` must have a balance of tokens of type `id` of at least `amount`. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes calldata data + ) external; + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function safeBatchTransferFrom( + address from, + address to, + uint256[] calldata ids, + uint256[] calldata amounts, + bytes calldata data + ) external; +} + +// File: @openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol + +/** + * @dev Interface of the optional ERC1155MetadataExtension interface, as defined + * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP]. + * + * _Available since v3.1._ + */ +interface IERC1155MetadataURI is IERC1155 { + /** + * @dev Returns the URI for token type `id`. + * + * If the `\{id\}` substring is present in the URI, it must be replaced by + * clients with the actual token type ID. + */ + function uri(uint256 id) external view returns (string memory); +} + +// File: @openzeppelin/contracts/token/ERC1155/ERC1155.sol + +/** + * @dev Implementation of the basic standard multi-token. + * See https://eips.ethereum.org/EIPS/eip-1155 + * Originally based on code by Enjin: https://github.com/enjin/erc-1155 + * + * _Available since v3.1._ + */ +contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { + using Address for address; + + // Mapping from token ID to account balances + mapping(uint256 => mapping(address => uint256)) private _balances; + + // Mapping from account to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json + string private _uri; + + /** + * @dev See {_setURI}. + */ + constructor(string memory uri_) { + _setURI(uri_); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC1155).interfaceId || + interfaceId == type(IERC1155MetadataURI).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC1155MetadataURI-uri}. + * + * This implementation returns the same URI for *all* token types. It relies + * on the token type ID substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * Clients calling this function must replace the `\{id\}` substring with the + * actual token type ID. + */ + function uri(uint256) public view virtual override returns (string memory) { + return _uri; + } + + /** + * @dev See {IERC1155-balanceOf}. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function balanceOf(address account, uint256 id) public view virtual override returns (uint256) { + require(account != address(0), "ERC1155: balance query for the zero address"); + return _balances[id][account]; + } + + /** + * @dev See {IERC1155-balanceOfBatch}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBatch(address[] memory accounts, uint256[] memory ids) + public + view + virtual + override + returns (uint256[] memory) + { + require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch"); + + uint256[] memory batchBalances = new uint256[](accounts.length); + + for (uint256 i = 0; i < accounts.length; ++i) { + batchBalances[i] = balanceOf(accounts[i], ids[i]); + } + + return batchBalances; + } + + /** + * @dev See {IERC1155-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + require(_msgSender() != operator, "ERC1155: setting approval status for self"); + + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC1155-isApprovedForAll}. + */ + function isApprovedForAll(address account, address operator) public view virtual override returns (bool) { + return _operatorApprovals[account][operator]; + } + + /** + * @dev See {IERC1155-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) public virtual override { + require( + from == _msgSender() || isApprovedForAll(from, _msgSender()), + "ERC1155: caller is not owner nor approved" + ); + _safeTransferFrom(from, to, id, amount, data); + } + + /** + * @dev See {IERC1155-safeBatchTransferFrom}. + */ + function safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) public virtual override { + require( + from == _msgSender() || isApprovedForAll(from, _msgSender()), + "ERC1155: transfer caller is not owner nor approved" + ); + _safeBatchTransferFrom(from, to, ids, amounts, data); + } + + /** + * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `from` must have a balance of tokens of type `id` of at least `amount`. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) internal virtual { + require(to != address(0), "ERC1155: transfer to the zero address"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data); + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); + unchecked { + _balances[id][from] = fromBalance - amount; + } + _balances[id][to] += amount; + + emit TransferSingle(operator, from, to, id, amount); + + _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function _safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual { + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + require(to != address(0), "ERC1155: transfer to the zero address"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, from, to, ids, amounts, data); + + for (uint256 i = 0; i < ids.length; ++i) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); + unchecked { + _balances[id][from] = fromBalance - amount; + } + _balances[id][to] += amount; + } + + emit TransferBatch(operator, from, to, ids, amounts); + + _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); + } + + /** + * @dev Sets a new URI for all token types, by relying on the token type ID + * substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * By this mechanism, any occurrence of the `\{id\}` substring in either the + * URI or any of the amounts in the JSON file at said URI will be replaced by + * clients with the token type ID. + * + * For example, the `https://token-cdn-domain/\{id\}.json` URI would be + * interpreted by clients as + * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json` + * for token type ID 0x4cce0. + * + * See {uri}. + * + * Because these URIs cannot be meaningfully represented by the {URI} event, + * this function emits no events. + */ + function _setURI(string memory newuri) internal virtual { + _uri = newuri; + } + + /** + * @dev Creates `amount` tokens of token type `id`, and assigns them to `account`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `account` cannot be the zero address. + * - If `account` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _mint( + address account, + uint256 id, + uint256 amount, + bytes memory data + ) internal virtual { + require(account != address(0), "ERC1155: mint to the zero address"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, address(0), account, _asSingletonArray(id), _asSingletonArray(amount), data); + + _balances[id][account] += amount; + emit TransferSingle(operator, address(0), account, id, amount); + + _doSafeTransferAcceptanceCheck(operator, address(0), account, id, amount, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function _mintBatch( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual { + require(to != address(0), "ERC1155: mint to the zero address"); + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); + + for (uint256 i = 0; i < ids.length; i++) { + _balances[ids[i]][to] += amounts[i]; + } + + emit TransferBatch(operator, address(0), to, ids, amounts); + + _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); + } + + /** + * @dev Destroys `amount` tokens of token type `id` from `account` + * + * Requirements: + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens of token type `id`. + */ + function _burn( + address account, + uint256 id, + uint256 amount + ) internal virtual { + require(account != address(0), "ERC1155: burn from the zero address"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, account, address(0), _asSingletonArray(id), _asSingletonArray(amount), ""); + + uint256 accountBalance = _balances[id][account]; + require(accountBalance >= amount, "ERC1155: burn amount exceeds balance"); + unchecked { + _balances[id][account] = accountBalance - amount; + } + + emit TransferSingle(operator, account, address(0), id, amount); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + */ + function _burnBatch( + address account, + uint256[] memory ids, + uint256[] memory amounts + ) internal virtual { + require(account != address(0), "ERC1155: burn from the zero address"); + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, account, address(0), ids, amounts, ""); + + for (uint256 i = 0; i < ids.length; i++) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + + uint256 accountBalance = _balances[id][account]; + require(accountBalance >= amount, "ERC1155: burn amount exceeds balance"); + unchecked { + _balances[id][account] = accountBalance - amount; + } + } + + emit TransferBatch(operator, account, address(0), ids, amounts); + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning, as well as batched variants. + * + * The same hook is called on both single and batched variants. For single + * transfers, the length of the `id` and `amount` arrays will be 1. + * + * Calling conditions (for each `id` and `amount` pair): + * + * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * of token type `id` will be transferred to `to`. + * - When `from` is zero, `amount` tokens of token type `id` will be minted + * for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` + * will be burned. + * - `from` and `to` are never both zero. + * - `ids` and `amounts` have the same, non-zero length. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual {} + + function _doSafeTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) private { + if (to.isContract()) { + try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) { + if (response != IERC1155Receiver.onERC1155Received.selector) { + revert("ERC1155: ERC1155Receiver rejected tokens"); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert("ERC1155: transfer to non ERC1155Receiver implementer"); + } + } + } + + function _doSafeBatchTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) private { + if (to.isContract()) { + try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns ( + bytes4 response + ) { + if (response != IERC1155Receiver.onERC1155BatchReceived.selector) { + revert("ERC1155: ERC1155Receiver rejected tokens"); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert("ERC1155: transfer to non ERC1155Receiver implementer"); + } + } + } + + function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) { + uint256[] memory array = new uint256[](1); + array[0] = element; + + return array; + } +} + +contract ExpansionPhunks is ERC1155, Ownable { + string public constant name = "ExpansionPhunks"; + string public constant symbol = "PHUNX"; + + uint32 public totalSupply = 0; + uint256 public constant phunkPrice = 0.02 ether; + uint256 public constant bulkPrice = 0.015 ether; + + uint32 public saleStart = 1640894400; + uint32 public constant startSupply = 10000; + uint32 public maxSupply = 10000; + + address private wallet1 = 0xD44F85aA20b03cc773309f10d67cC4eaB0BD26a6; + address private wallet2 = 0xB9e1cc664a0140953c2512f57BCd36Bb92c2eEf6; + + constructor(string memory uri) ERC1155(uri) {} + + function setURI(string memory uri) public onlyOwner { + _setURI(uri); + } + + function setSaleStart(uint32 timestamp) public onlyOwner { + saleStart = timestamp; + } + + function saleIsActive() public view returns (bool) { + return saleStart <= block.timestamp; + } + + function setMaxSupply(uint32 _supply) public onlyOwner { + maxSupply = _supply; + } + + function mint(address to, uint32 count) internal { + if (count > 1) { + uint256[] memory ids = new uint256[](uint256(count)); + uint256[] memory amounts = new uint256[](uint256(count)); + + for (uint32 i = 0; i < count; i++) { + ids[i] = startSupply + totalSupply + i; + amounts[i] = 1; + } + + _mintBatch(to, ids, amounts, ""); + } else { + _mint(to, startSupply + totalSupply, 1, ""); + } + + totalSupply += count; + } + + function purchase(uint32 count) external payable { + require(saleIsActive(), "Sale inactive"); + require(count > 0, "Count must be greater than 0"); + require(count < 51, "Count must be less than or equal to 50"); + require(totalSupply + count <= maxSupply, "Exceeds max supply"); + + if (count > 9) { + require(msg.value >= bulkPrice * count, "Insufficient funds"); + } else { + require(msg.value >= phunkPrice * count, "Insufficient funds"); + } + + mint(msg.sender, count); + } + + function teamMint(uint32 count) external onlyOwner { + require(totalSupply + count <= maxSupply, "Exceeds max supply"); + mint(msg.sender, count); + } + + function withdraw() external onlyOwner { + uint256 balance = address(this).balance; + uint256 balance1 = balance * 85 / 100; + uint256 balance2 = balance * 10 / 100; + uint256 balance3 = balance * 5 / 100; + + payable(wallet1).transfer(balance1); + payable(wallet2).transfer(balance2); + payable(msg.sender).transfer(balance3); + } +} \ No newline at end of file diff --git a/ethabi/code/0x71eb5c179ceb640160853144cbb8df5bd24ab5cc.yml b/ethabi/code/0x71eb5c179ceb640160853144cbb8df5bd24ab5cc.yml new file mode 100644 index 0000000..2fbca85 --- /dev/null +++ b/ethabi/code/0x71eb5c179ceb640160853144cbb8df5bd24ab5cc.yml @@ -0,0 +1,12 @@ +--- +ContractName: ExpansionPhunks +CompilerVersion: v0.8.11+commit.d7f03943 +OptimizationUsed: '1' +Runs: '200' +ConstructorArguments: 0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002b68747470733a2f2f657870616e73696f6e7068756e6b732e76657263656c2e6170702f6170692f7b69647d000000000000000000000000000000000000000000 +EVMVersion: Default +Library: '' +LicenseType: MIT +Proxy: '0' +Implementation: '' +SwarmSource: ipfs://d006bc8ea26a437f7545e0e0df0b2b9bd7838b08d6634c55d8306514a1c82a2e diff --git a/ethabi/code/0x7c40c393dc0f283f318791d746d894ddd3693572.sol b/ethabi/code/0x7c40c393dc0f283f318791d746d894ddd3693572.sol new file mode 100644 index 0000000..8443d05 --- /dev/null +++ b/ethabi/code/0x7c40c393dc0f283f318791d746d894ddd3693572.sol @@ -0,0 +1,1870 @@ +/////////////////////////////////////////// +// File: contracts/MoonCatsWrapped.sol + + +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Counters.sol + +// SPDX-License-Identifier: MIT + + +pragma solidity ^0.7.6; + + +/** + * @title Counters + * @author Matt Condon (@shrugs) + * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number + * of elements in a mapping, issuing ERC721 ids, or counting request ids. + * + * Include with `using Counters for Counters.Counter;` + * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath} + * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never + * directly accessed. + */ +library Counters { + using SafeMath for uint256; + + struct Counter { + // This variable should never be directly accessed by users of the library: interactions must be restricted to + // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add + // this feature: see https://github.com/ethereum/solidity/issues/4637 + uint256 _value; // default: 0 + } + + function current(Counter storage counter) internal view returns (uint256) { + return counter._value; + } + + function increment(Counter storage counter) internal { + // The {SafeMath} overflow check can be skipped here, see the comment at the top + counter._value += 1; + } + + function decrement(Counter storage counter) internal { + counter._value = counter._value.sub(1); + } +} + +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Strings.sol + + + +pragma solidity ^0.7.6; + +/** + * @dev String operations. + */ +library Strings { + /** + * @dev Converts a `uint256` to its ASCII `string` representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + // Inspired by OraclizeAPI's implementation - MIT licence + // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol + + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + uint256 index = digits - 1; + temp = value; + while (temp != 0) { + buffer[index--] = byte(uint8(48 + temp % 10)); + temp /= 10; + } + return string(buffer); + } +} + +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/EnumerableMap.sol + + + +pragma solidity ^0.7.6; + +/** + * @dev Library for managing an enumerable variant of Solidity's + * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] + * type. + * + * Maps have the following properties: + * + * - Entries are added, removed, and checked for existence in constant time + * (O(1)). + * - Entries are enumerated in O(n). No guarantees are made on the ordering. + * + * ``` + * contract Example { + * // Add the library methods + * using EnumerableMap for EnumerableMap.UintToAddressMap; + * + * // Declare a set state variable + * EnumerableMap.UintToAddressMap private myMap; + * } + * ``` + * + * As of v3.0.0, only maps of type `uint256 -> address` (`UintToAddressMap`) are + * supported. + */ +library EnumerableMap { + // To implement this library for multiple types with as little code + // repetition as possible, we write it in terms of a generic Map type with + // bytes32 keys and values. + // The Map implementation uses private functions, and user-facing + // implementations (such as Uint256ToAddressMap) are just wrappers around + // the underlying Map. + // This means that we can only create new EnumerableMaps for types that fit + // in bytes32. + + struct MapEntry { + bytes32 _key; + bytes32 _value; + } + + struct Map { + // Storage of map keys and values + MapEntry[] _entries; + + // Position of the entry defined by a key in the `entries` array, plus 1 + // because index 0 means a key is not in the map. + mapping (bytes32 => uint256) _indexes; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function _set(Map storage map, bytes32 key, bytes32 value) private returns (bool) { + // We read and store the key's index to prevent multiple reads from the same storage slot + uint256 keyIndex = map._indexes[key]; + + if (keyIndex == 0) { // Equivalent to !contains(map, key) + map._entries.push(MapEntry({ _key: key, _value: value })); + // The entry is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + map._indexes[key] = map._entries.length; + return true; + } else { + map._entries[keyIndex - 1]._value = value; + return false; + } + } + + /** + * @dev Removes a key-value pair from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function _remove(Map storage map, bytes32 key) private returns (bool) { + // We read and store the key's index to prevent multiple reads from the same storage slot + uint256 keyIndex = map._indexes[key]; + + if (keyIndex != 0) { // Equivalent to contains(map, key) + // To delete a key-value pair from the _entries array in O(1), we swap the entry to delete with the last one + // in the array, and then remove the last entry (sometimes called as 'swap and pop'). + // This modifies the order of the array, as noted in {at}. + + uint256 toDeleteIndex = keyIndex - 1; + uint256 lastIndex = map._entries.length - 1; + + // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs + // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. + + MapEntry storage lastEntry = map._entries[lastIndex]; + + // Move the last entry to the index where the entry to delete is + map._entries[toDeleteIndex] = lastEntry; + // Update the index for the moved entry + map._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based + + // Delete the slot where the moved entry was stored + map._entries.pop(); + + // Delete the index for the deleted slot + delete map._indexes[key]; + + return true; + } else { + return false; + } + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function _contains(Map storage map, bytes32 key) private view returns (bool) { + return map._indexes[key] != 0; + } + + /** + * @dev Returns the number of key-value pairs in the map. O(1). + */ + function _length(Map storage map) private view returns (uint256) { + return map._entries.length; + } + + /** + * @dev Returns the key-value pair stored at position `index` in the map. O(1). + * + * Note that there are no guarantees on the ordering of entries inside the + * array, and it may change when more entries are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function _at(Map storage map, uint256 index) private view returns (bytes32, bytes32) { + require(map._entries.length > index, "EnumerableMap: index out of bounds"); + + MapEntry storage entry = map._entries[index]; + return (entry._key, entry._value); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function _get(Map storage map, bytes32 key) private view returns (bytes32) { + return _get(map, key, "EnumerableMap: nonexistent key"); + } + + /** + * @dev Same as {_get}, with a custom error message when `key` is not in the map. + */ + function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) { + uint256 keyIndex = map._indexes[key]; + require(keyIndex != 0, errorMessage); // Equivalent to contains(map, key) + return map._entries[keyIndex - 1]._value; // All indexes are 1-based + } + + // UintToAddressMap + + struct UintToAddressMap { + Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) { + return _set(map._inner, bytes32(key), bytes32(uint256(value))); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { + return _remove(map._inner, bytes32(key)); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { + return _contains(map._inner, bytes32(key)); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(UintToAddressMap storage map) internal view returns (uint256) { + return _length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the set. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { + (bytes32 key, bytes32 value) = _at(map._inner, index); + return (uint256(key), address(uint256(value))); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { + return address(uint256(_get(map._inner, bytes32(key)))); + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + */ + function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) { + return address(uint256(_get(map._inner, bytes32(key), errorMessage))); + } +} + +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/EnumerableSet.sol + + + +pragma solidity ^0.7.6; + +/** + * @dev Library for managing + * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive + * types. + * + * Sets have the following properties: + * + * - Elements are added, removed, and checked for existence in constant time + * (O(1)). + * - Elements are enumerated in O(n). No guarantees are made on the ordering. + * + * ``` + * contract Example { + * // Add the library methods + * using EnumerableSet for EnumerableSet.AddressSet; + * + * // Declare a set state variable + * EnumerableSet.AddressSet private mySet; + * } + * ``` + * + * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) + * and `uint256` (`UintSet`) are supported. + */ +library EnumerableSet { + // To implement this library for multiple types with as little code + // repetition as possible, we write it in terms of a generic Set type with + // bytes32 values. + // The Set implementation uses private functions, and user-facing + // implementations (such as AddressSet) are just wrappers around the + // underlying Set. + // This means that we can only create new EnumerableSets for types that fit + // in bytes32. + + struct Set { + // Storage of set values + bytes32[] _values; + + // Position of the value in the `values` array, plus 1 because index 0 + // means a value is not in the set. + mapping (bytes32 => uint256) _indexes; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function _add(Set storage set, bytes32 value) private returns (bool) { + if (!_contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + set._indexes[value] = set._values.length; + return true; + } else { + return false; + } + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function _remove(Set storage set, bytes32 value) private returns (bool) { + // We read and store the value's index to prevent multiple reads from the same storage slot + uint256 valueIndex = set._indexes[value]; + + if (valueIndex != 0) { // Equivalent to contains(set, value) + // To delete an element from the _values array in O(1), we swap the element to delete with the last one in + // the array, and then remove the last element (sometimes called as 'swap and pop'). + // This modifies the order of the array, as noted in {at}. + + uint256 toDeleteIndex = valueIndex - 1; + uint256 lastIndex = set._values.length - 1; + + // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs + // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. + + bytes32 lastvalue = set._values[lastIndex]; + + // Move the last value to the index where the value to delete is + set._values[toDeleteIndex] = lastvalue; + // Update the index for the moved value + set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based + + // Delete the slot where the moved value was stored + set._values.pop(); + + // Delete the index for the deleted slot + delete set._indexes[value]; + + return true; + } else { + return false; + } + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function _contains(Set storage set, bytes32 value) private view returns (bool) { + return set._indexes[value] != 0; + } + + /** + * @dev Returns the number of values on the set. O(1). + */ + function _length(Set storage set) private view returns (uint256) { + return set._values.length; + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function _at(Set storage set, uint256 index) private view returns (bytes32) { + require(set._values.length > index, "EnumerableSet: index out of bounds"); + return set._values[index]; + } + + // Bytes32Set + + struct Bytes32Set { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _add(set._inner, value); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _remove(set._inner, value); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { + return _contains(set._inner, value); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(Bytes32Set storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { + return _at(set._inner, index); + } + + // AddressSet + + struct AddressSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(AddressSet storage set, address value) internal returns (bool) { + return _add(set._inner, bytes32(uint256(value))); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(AddressSet storage set, address value) internal returns (bool) { + return _remove(set._inner, bytes32(uint256(value))); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(AddressSet storage set, address value) internal view returns (bool) { + return _contains(set._inner, bytes32(uint256(value))); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(AddressSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(AddressSet storage set, uint256 index) internal view returns (address) { + return address(uint256(_at(set._inner, index))); + } + + + // UintSet + + struct UintSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(UintSet storage set, uint256 value) internal returns (bool) { + return _add(set._inner, bytes32(value)); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(UintSet storage set, uint256 value) internal returns (bool) { + return _remove(set._inner, bytes32(value)); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(UintSet storage set, uint256 value) internal view returns (bool) { + return _contains(set._inner, bytes32(value)); + } + + /** + * @dev Returns the number of values on the set. O(1). + */ + function length(UintSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintSet storage set, uint256 index) internal view returns (uint256) { + return uint256(_at(set._inner, index)); + } +} + +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol + + + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.3._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.3._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol + + + +pragma solidity ^0.7.6; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + return sub(a, b, "SafeMath: subtraction overflow"); + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + uint256 c = a - b; + + return c; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) { + return 0; + } + + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers. Reverts on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + return div(a, b, "SafeMath: division by zero"); + } + + /** + * @dev Returns the integer division of two unsigned integers. Reverts with custom message on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + uint256 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + + return c; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * Reverts when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + return mod(a, b, "SafeMath: modulo by zero"); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * Reverts with custom message when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b != 0, errorMessage); + return a % b; + } +} + + + + +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/introspection/IERC165.sol + + + +pragma solidity ^0.7.6; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/introspection/ERC165.sol + + + +pragma solidity ^0.7.6; + + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts may inherit from this and call {_registerInterface} to declare + * their support of an interface. + */ +abstract contract ERC165 is IERC165 { + /* + * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 + */ + bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; + + /** + * @dev Mapping of interface ids to whether or not it's supported. + */ + mapping(bytes4 => bool) private _supportedInterfaces; + + constructor () internal { + // Derived contracts need only register support for their own interfaces, + // we register support for ERC165 itself here + _registerInterface(_INTERFACE_ID_ERC165); + } + + /** + * @dev See {IERC165-supportsInterface}. + * + * Time complexity O(1), guaranteed to always use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) public view override returns (bool) { + return _supportedInterfaces[interfaceId]; + } + + /** + * @dev Registers the contract as an implementer of the interface defined by + * `interfaceId`. Support of the actual ERC165 interface is automatic and + * registering its interface id is not required. + * + * See {IERC165-supportsInterface}. + * + * Requirements: + * + * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). + */ + function _registerInterface(bytes4 interfaceId) internal virtual { + require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); + _supportedInterfaces[interfaceId] = true; + } +} + +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/IERC721Receiver.sol + + + +pragma solidity ^0.7.6; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. + */ + function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4); +} + +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/IERC721.sol + + + +pragma solidity >=0.6.2 <0.8.0; + + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; +} + +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/IERC721Enumerable.sol + + + +pragma solidity >=0.6.2 <0.8.0; + + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Enumerable is IERC721 { + + /** + * @dev Returns the total amount of tokens stored by the contract. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns a token ID owned by `owner` at a given `index` of its token list. + * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); + + /** + * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. + * Use along with {totalSupply} to enumerate all tokens. + */ + function tokenByIndex(uint256 index) external view returns (uint256); +} + +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/IERC721Metadata.sol + + + +pragma solidity >=0.6.2 <0.8.0; + + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} + + +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/GSN/Context.sol + + + +pragma solidity ^0.7.6; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with GSN meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address payable) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes memory) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} + +// File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol + + + +pragma solidity ^0.7.6; + + + + + + + + + + + + +/** + * @title ERC721 Non-Fungible Token Standard basic implementation + * @dev see https://eips.ethereum.org/EIPS/eip-721 + */ +contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable { + using SafeMath for uint256; + using Address for address; + using EnumerableSet for EnumerableSet.UintSet; + using EnumerableMap for EnumerableMap.UintToAddressMap; + using Strings for uint256; + + // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` + // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` + bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; + + // Mapping from holder address to their (enumerable) set of owned tokens + mapping (address => EnumerableSet.UintSet) private _holderTokens; + + // Enumerable mapping from token ids to their owners + EnumerableMap.UintToAddressMap private _tokenOwners; + + // Mapping from token ID to approved address + mapping (uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping (address => mapping (address => bool)) private _operatorApprovals; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Optional mapping for token URIs + mapping (uint256 => string) private _tokenURIs; + + // Base URI + string private _baseURI; + + /* + * bytes4(keccak256('balanceOf(address)')) == 0x70a08231 + * bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e + * bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3 + * bytes4(keccak256('getApproved(uint256)')) == 0x081812fc + * bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465 + * bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5 + * bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd + * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e + * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde + * + * => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^ + * 0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd + */ + bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd; + + /* + * bytes4(keccak256('name()')) == 0x06fdde03 + * bytes4(keccak256('symbol()')) == 0x95d89b41 + * bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd + * + * => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f + */ + bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f; + + /* + * bytes4(keccak256('totalSupply()')) == 0x18160ddd + * bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59 + * bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7 + * + * => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63 + */ + bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63; + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + constructor (string memory name_, string memory symbol_) public { + _name = name_; + _symbol = symbol_; + + // register the supported interfaces to conform to ERC721 via ERC165 + _registerInterface(_INTERFACE_ID_ERC721); + _registerInterface(_INTERFACE_ID_ERC721_METADATA); + _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view override returns (uint256) { + require(owner != address(0), "ERC721: balance query for the zero address"); + + return _holderTokens[owner].length(); + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view override returns (address) { + return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token"); + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public virtual view override returns (string memory) { + require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); + + string memory _tokenURI = _tokenURIs[tokenId]; + + // If there is no base URI, return the token URI. + if (bytes(_baseURI).length == 0) { + return _tokenURI; + } + // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked). + if (bytes(_tokenURI).length > 0) { + return string(abi.encodePacked(_baseURI, _tokenURI)); + } + // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI. + return string(abi.encodePacked(_baseURI, tokenId.toString())); + } + + /** + * @dev Returns the base URI set via {_setBaseURI}. This will be + * automatically added as a prefix in {tokenURI} to each token's URI, or + * to the token ID if no specific URI is set for that token ID. + */ + function baseURI() public view returns (string memory) { + return _baseURI; + } + + /** + * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) public view override returns (uint256) { + return _holderTokens[owner].at(index); + } + + /** + * @dev See {IERC721Enumerable-totalSupply}. + */ + function totalSupply() public view override returns (uint256) { + // _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds + return _tokenOwners.length(); + } + + /** + * @dev See {IERC721Enumerable-tokenByIndex}. + */ + function tokenByIndex(uint256 index) public view override returns (uint256) { + (uint256 tokenId, ) = _tokenOwners.at(index); + return tokenId; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public virtual override { + address owner = ownerOf(tokenId); + require(to != owner, "ERC721: approval to current owner"); + + require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()), + "ERC721: approve caller is not owner nor approved for all" + ); + + _approve(to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view override returns (address) { + require(_exists(tokenId), "ERC721: approved query for nonexistent token"); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + require(operator != _msgSender(), "ERC721: approve to caller"); + + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom(address from, address to, uint256 tokenId) public virtual override { + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + + _transfer(from, to, tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { + safeTransferFrom(from, to, tokenId, ""); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override { + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + _safeTransfer(from, to, tokenId, _data); + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * `_data` is additional data, it has no specified format and it is sent in call to `to`. + * + * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. + * implement alternative mechanisms to perform token transfer, such as signature-based. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual { + _transfer(from, to, tokenId); + require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + * and stop existing when they are burned (`_burn`). + */ + function _exists(uint256 tokenId) internal view returns (bool) { + return _tokenOwners.contains(tokenId); + } + + /** + * @dev Returns whether `spender` is allowed to manage `tokenId`. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) { + require(_exists(tokenId), "ERC721: operator query for nonexistent token"); + address owner = ownerOf(tokenId); + return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); + } + + /** + * @dev Safely mints `tokenId` and transfers it to `to`. + * + * Requirements: + d* + * - `tokenId` must not exist. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeMint(address to, uint256 tokenId) internal virtual { + _safeMint(to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual { + _mint(to, tokenId); + require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Mints `tokenId` and transfers it to `to`. + * + * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * Emits a {Transfer} event. + */ + function _mint(address to, uint256 tokenId) internal virtual { + require(to != address(0), "ERC721: mint to the zero address"); + require(!_exists(tokenId), "ERC721: token already minted"); + + _beforeTokenTransfer(address(0), to, tokenId); + + _holderTokens[to].add(tokenId); + + _tokenOwners.set(tokenId, to); + + emit Transfer(address(0), to, tokenId); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId) internal virtual { + address owner = ownerOf(tokenId); + + _beforeTokenTransfer(owner, address(0), tokenId); + + // Clear approvals + _approve(address(0), tokenId); + + // Clear metadata (if any) + if (bytes(_tokenURIs[tokenId]).length != 0) { + delete _tokenURIs[tokenId]; + } + + _holderTokens[owner].remove(tokenId); + + _tokenOwners.remove(tokenId); + + emit Transfer(owner, address(0), tokenId); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer(address from, address to, uint256 tokenId) internal virtual { + require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); + require(to != address(0), "ERC721: transfer to the zero address"); + + _beforeTokenTransfer(from, to, tokenId); + + // Clear approvals from the previous owner + _approve(address(0), tokenId); + + _holderTokens[from].remove(tokenId); + _holderTokens[to].add(tokenId); + + _tokenOwners.set(tokenId, to); + + emit Transfer(from, to, tokenId); + } + + /** + * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { + require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token"); + _tokenURIs[tokenId] = _tokenURI; + } + + /** + * @dev Internal function to set the base URI for all token IDs. It is + * automatically added as a prefix to the value returned in {tokenURI}, + * or to the token ID if {tokenURI} is empty. + */ + function _setBaseURI(string memory baseURI_) internal virtual { + _baseURI = baseURI_; + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * The call is not executed if the target address is not a contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) + private returns (bool) + { + if (!to.isContract()) { + return true; + } + bytes memory returndata = to.functionCall(abi.encodeWithSelector( + IERC721Receiver(to).onERC721Received.selector, + _msgSender(), + from, + tokenId, + _data + ), "ERC721: transfer to non ERC721Receiver implementer"); + bytes4 retval = abi.decode(returndata, (bytes4)); + return (retval == _ERC721_RECEIVED); + } + + function _approve(address to, uint256 tokenId) private { + _tokenApprovals[tokenId] = to; + emit Approval(ownerOf(tokenId), to, tokenId); + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, ``from``'s `tokenId` will be burned. + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { } +} + +// File: browser/MoonCatsWrapped.sol + +pragma solidity ^0.7.6; +pragma abicoder v2; + + + +interface MoonCatsRescue { + struct AdoptionOffer { + bool exists; + bytes5 catId; + address seller; + uint price; + address onlyOfferTo; + } + + function acceptAdoptionOffer(bytes5 catId) external payable; + function giveCat(bytes5 catId, address to) external; + function adoptionOffers(bytes5 catId) external returns (AdoptionOffer memory); +} + +contract MoonCatsWrapped is ERC721 { + + using Counters for Counters.Counter; + Counters.Counter private _tokenIdTracker; + + MoonCatsRescue public _moonCats = MoonCatsRescue(0x60cd862c9C687A9dE49aecdC3A99b74A4fc54aB6); + + mapping(bytes5 => uint) public _catIDToTokenID; + mapping(uint => bytes5) public _tokenIDToCatID; + string private _baseTokenURI; + address public _owner = 0xD2927a91570146218eD700566DF516d67C5ECFAB; + + + event Wrapped(bytes5 indexed catId, uint tokenID); + event Unwrapped(bytes5 indexed catId, uint tokenID); + + constructor() ERC721("Wrapped MoonCatsRescue", "WMCR") {} + + function setBaseURI(string memory _newBaseURI) public { + require(_msgSender() == _owner); + _baseTokenURI = _newBaseURI; + } + + function renounceOwnership() public { + require(_msgSender() == _owner); + _owner = address(0x0); + } + + + function _baseURI() public view virtual returns (string memory) { + return _baseTokenURI; + } + + + function wrap(bytes5 catId) public { + MoonCatsRescue.AdoptionOffer memory offer = _moonCats.adoptionOffers(catId); + require(offer.seller == _msgSender()); //only owner can wrap + _moonCats.acceptAdoptionOffer(catId); + + + //check if it was previously assigned + uint tokenID = _catIDToTokenID[catId]; + uint tokenIDToAssign = tokenID; + + if (tokenID == 0) { + tokenIDToAssign = _tokenIdTracker.current(); + _tokenIdTracker.increment(); + _catIDToTokenID[catId] = tokenIDToAssign; + _tokenIDToCatID[tokenIDToAssign] = catId; + } + _mint(_msgSender(), tokenIDToAssign); + emit Wrapped(catId, tokenIDToAssign); + + } + + function unwrap(uint256 tokenID) public { + bytes5 catId = _tokenIDToCatID[tokenID]; + address owner = ownerOf(tokenID); + require(owner == _msgSender()); //only owner can unwrap + _moonCats.giveCat(catId, owner); + _burn(tokenID); + emit Unwrapped(catId, tokenID); + } + +} + + diff --git a/ethabi/code/0x7c40c393dc0f283f318791d746d894ddd3693572.yml b/ethabi/code/0x7c40c393dc0f283f318791d746d894ddd3693572.yml new file mode 100644 index 0000000..82a183e --- /dev/null +++ b/ethabi/code/0x7c40c393dc0f283f318791d746d894ddd3693572.yml @@ -0,0 +1,12 @@ +--- +ContractName: MoonCatsWrapped +CompilerVersion: v0.7.6+commit.7338295f +OptimizationUsed: '0' +Runs: '1000' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: '' +Proxy: '0' +Implementation: '' +SwarmSource: '' diff --git a/ethabi/code/0x9b66d03fc1eee61a512341058e95f1a68dc3a913.sol b/ethabi/code/0x9b66d03fc1eee61a512341058e95f1a68dc3a913.sol new file mode 100644 index 0000000..0dc1d73 --- /dev/null +++ b/ethabi/code/0x9b66d03fc1eee61a512341058e95f1a68dc3a913.sol @@ -0,0 +1,2746 @@ +/////////////////////////////////////////// +// File: /var/app/current/contracts/Indelible.sol + + + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.4; + + import "erc721a/contracts/ERC721A.sol"; + import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; + import "@openzeppelin/contracts/access/Ownable.sol"; + import "@openzeppelin/contracts/utils/Base64.sol"; + import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; + import "@openzeppelin/contracts/utils/Address.sol"; + import "./SSTORE2.sol"; + import "./DynamicBuffer.sol"; + import "./HelperLib.sol"; + + contract Indelible is ERC721A, ReentrancyGuard, Ownable { + using HelperLib for uint; + using DynamicBuffer for bytes; + + struct LinkedTraitDTO { + uint[] traitA; + uint[] traitB; + } + + struct TraitDTO { + string name; + string mimetype; + bytes data; + bool useExistingData; + uint existingDataIndex; + } + + struct Trait { + string name; + string mimetype; + } + + struct ContractData { + string name; + string description; + string image; + string banner; + string website; + uint royalties; + string royaltiesRecipient; + } + + mapping(uint => address[]) internal _traitDataPointers; + mapping(uint => mapping(uint => Trait)) internal _traitDetails; + mapping(uint => bool) internal _renderTokenOffChain; + mapping(uint => mapping(uint => uint[])) internal _linkedTraits; + + uint private constant DEVELOPER_FEE = 250; // of 10,000 = 2.5% + uint private constant NUM_LAYERS = 8; + uint private constant MAX_BATCH_MINT = 20; + uint[][NUM_LAYERS] private TIERS; + string[] private LAYER_NAMES = [unicode"Mouth", unicode"Neck", unicode"Earring", unicode"Eyes", unicode"Head", unicode"Ape", unicode"Background", unicode"Future Origin"]; + bool private shouldWrapSVG = true; + string private backgroundColor = "transparent"; + + bool public isContractSealed; + uint public constant maxSupply = 5000; + uint public maxPerAddress = 30; + uint public publicMintPrice = 0.008 ether; + string public baseURI = ""; + bool public isPublicMintActive; + + bytes32 private merkleRoot; + uint public allowListPrice = 0.0 ether; + uint public maxPerAllowList = 1; + bool public isAllowListActive; + + ContractData public contractData = ContractData(unicode"Phunk APE Origins", unicode"5000 On-Chain Phunks, reimagined, APES only. CC0 - 0% Royalties, in true Phunk phashion, this project is for the community. Phunk Ape Origins pays homage to the CryptoPhunk culture as well as to the Great Apes.", "https://indeliblelabs-prod.s3.us-east-2.amazonaws.com/profile/fcfba559-6a07-4784-af02-dda7bcabbad1", "https://indeliblelabs-prod.s3.us-east-2.amazonaws.com/banner/fcfba559-6a07-4784-af02-dda7bcabbad1", "", 0, "0xD503B89b39E5d820399e94Ba6250b90fA22B9812"); + + constructor() ERC721A(unicode"Phunk APE Origins", unicode"PAO") { + TIERS[0] = [210,250,300,300,380,390,400,435,435,1900]; +TIERS[1] = [260,420,420,570,610,640,640,1440]; +TIERS[2] = [300,400,600,650,700,750,750,850]; +TIERS[3] = [90,90,90,90,90,100,110,110,180,200,240,240,240,240,240,250,390,390,660,960]; +TIERS[4] = [20,30,40,50,60,60,61,61,80,80,80,80,80,80,80,80,90,90,90,90,90,90,90,90,160,160,160,160,160,160,160,160,160,170,170,170,170,286,286,566]; +TIERS[5] = [35,65,95,125,180,410,530,550,590,590,610,610,610]; +TIERS[6] = [800,950,950,1100,1200]; +TIERS[7] = [275,675,675,675,675,675,675,675]; + } + + modifier whenMintActive() { + require(isMintActive(), "Minting is not active"); + _; + } + + modifier whenUnsealed() { + require(!isContractSealed, "Contract is sealed"); + _; + } + + receive() external payable { + require(isPublicMintActive, "Public minting is not active"); + handleMint(msg.value / publicMintPrice); + } + + function rarityGen(uint _randinput, uint _rarityTier) + internal + view + returns (uint) + { + uint currentLowerBound = 0; + for (uint i = 0; i < TIERS[_rarityTier].length; i++) { + uint thisPercentage = TIERS[_rarityTier][i]; + if ( + _randinput >= currentLowerBound && + _randinput < currentLowerBound + thisPercentage + ) return i; + currentLowerBound = currentLowerBound + thisPercentage; + } + + revert(); + } + + function entropyForExtraData() internal view returns (uint24) { + uint randomNumber = uint( + keccak256( + abi.encodePacked( + tx.gasprice, + block.number, + block.timestamp, + block.difficulty, + blockhash(block.number - 1), + msg.sender + ) + ) + ); + return uint24(randomNumber); + } + + function stringCompare(string memory a, string memory b) internal pure returns (bool) { + return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b)); + } + + function tokensAreDuplicates(uint tokenIdA, uint tokenIdB) public view returns (bool) { + return stringCompare( + tokenIdToHash(tokenIdA), + tokenIdToHash(tokenIdB) + ); + } + + function reRollDuplicate( + uint tokenIdA, + uint tokenIdB + ) public whenUnsealed { + require(tokensAreDuplicates(tokenIdA, tokenIdB), "All tokens must be duplicates"); + + uint largerTokenId = tokenIdA > tokenIdB ? tokenIdA : tokenIdB; + + if (msg.sender != owner()) { + require(msg.sender == ownerOf(largerTokenId), "Only the token owner or contract owner can re-roll"); + } + + _initializeOwnershipAt(largerTokenId); + if (_exists(largerTokenId + 1)) { + _initializeOwnershipAt(largerTokenId + 1); + } + + _setExtraDataAt(largerTokenId, entropyForExtraData()); + } + + function _extraData( + address from, + address to, + uint24 previousExtraData + ) internal view virtual override returns (uint24) { + return from == address(0) ? entropyForExtraData() : previousExtraData; + } + + function getTokenSeed(uint _tokenId) internal view returns (uint24) { + return _ownershipOf(_tokenId).extraData; + } + + function tokenIdToHash( + uint _tokenId + ) public view returns (string memory) { + require(_exists(_tokenId), "Invalid token"); + // This will generate a NUM_LAYERS * 3 character string. + bytes memory hashBytes = DynamicBuffer.allocate(NUM_LAYERS * 4); + + uint[] memory hash = new uint[](NUM_LAYERS); + bool[] memory modifiedLayers = new bool[](NUM_LAYERS); + + for (uint i = 0; i < NUM_LAYERS; i++) { + uint traitIndex = hash[i]; + if (modifiedLayers[i] == false) { + uint _randinput = uint( + uint( + keccak256( + abi.encodePacked( + getTokenSeed(_tokenId), + _tokenId, + _tokenId + i + ) + ) + ) % maxSupply + ); + + traitIndex = rarityGen(_randinput, i); + hash[i] = traitIndex; + } + + if (_linkedTraits[i][traitIndex].length > 0) { + hash[_linkedTraits[i][traitIndex][0]] = _linkedTraits[i][traitIndex][1]; + modifiedLayers[_linkedTraits[i][traitIndex][0]] = true; + } + } + + for (uint i = 0; i < hash.length; i++) { + if (hash[i] < 10) { + hashBytes.appendSafe("00"); + } else if (hash[i] < 100) { + hashBytes.appendSafe("0"); + } + if (hash[i] > 999) { + hashBytes.appendSafe("999"); + } else { + hashBytes.appendSafe(bytes(_toString(hash[i]))); + } + } + + return string(hashBytes); + } + + function handleMint(uint256 _count) internal whenMintActive returns (uint256) { + uint256 totalMinted = _totalMinted(); + require(_count > 0, "Invalid token count"); + require(totalMinted + _count <= maxSupply, "All tokens are gone"); + + + if (isPublicMintActive) { + if (msg.sender != owner()) { + require(_numberMinted(msg.sender) + _count <= maxPerAddress, "Exceeded max mints allowed"); + } + require(msg.sender == tx.origin, "EOAs only"); + require(_count * publicMintPrice == msg.value, "Incorrect amount of ether sent"); + } + + uint256 batchCount = _count / MAX_BATCH_MINT; + uint256 remainder = _count % MAX_BATCH_MINT; + + for (uint256 i = 0; i < batchCount; i++) { + _mint(msg.sender, MAX_BATCH_MINT); + } + + if (remainder > 0) { + _mint(msg.sender, remainder); + } + + return totalMinted; + } + + function mint(uint256 _count, bytes32[] calldata merkleProof) + external + payable + nonReentrant + whenMintActive + returns (uint) + { + + if (!isPublicMintActive) { + if (msg.sender != owner()) { + require(onAllowList(msg.sender, merkleProof), "Not on allow list"); + require(_numberMinted(msg.sender) + _count <= maxPerAllowList, "Exceeded max mints allowed"); + } + require(_count * allowListPrice == msg.value, "Incorrect amount of ether sent"); + } + + uint256 totalMinted = handleMint(_count); + + return totalMinted; + } + + function isMintActive() public view returns (bool) { + return _totalMinted() < maxSupply && (isPublicMintActive || isAllowListActive); + } + + function hashToSVG(string memory _hash) + public + view + returns (string memory) + { + uint thisTraitIndex; + + bytes memory svgBytes = DynamicBuffer.allocate(1024 * 128); + svgBytes.appendSafe('' + ) + ); + + return string( + abi.encodePacked( + "data:image/svg+xml;base64,", + Base64.encode(svgBytes) + ) + ); + } + + function hashToMetadata(string memory _hash) + public + view + returns (string memory) + { + bytes memory metadataBytes = DynamicBuffer.allocate(1024 * 128); + metadataBytes.appendSafe("["); + + for (uint i = 0; i < NUM_LAYERS; i++) { + uint thisTraitIndex = HelperLib.parseInt( + HelperLib._substring(_hash, (i * 3), (i * 3) + 3) + ); + metadataBytes.appendSafe( + abi.encodePacked( + '{"trait_type":"', + LAYER_NAMES[i], + '","value":"', + _traitDetails[i][thisTraitIndex].name, + '"}' + ) + ); + + if (i == NUM_LAYERS - 1) { + metadataBytes.appendSafe("]"); + } else { + metadataBytes.appendSafe(","); + } + } + + return string(metadataBytes); + } + + + function onAllowList(address addr, bytes32[] calldata merkleProof) public view returns (bool) { + return MerkleProof.verify(merkleProof, merkleRoot, keccak256(abi.encodePacked(addr))); + } + + + function tokenURI(uint _tokenId) + public + view + override + returns (string memory) + { + require(_exists(_tokenId), "Invalid token"); + require(_traitDataPointers[0].length > 0, "Traits have not been added"); + + string memory tokenHash = tokenIdToHash(_tokenId); + + bytes memory jsonBytes = DynamicBuffer.allocate(1024 * 128); + jsonBytes.appendSafe(unicode"{\"name\":\"Phunk APE Origins #"); + + jsonBytes.appendSafe( + abi.encodePacked( + _toString(_tokenId), + "\",\"description\":\"", + contractData.description, + "\"," + ) + ); + + if (bytes(baseURI).length > 0 && _renderTokenOffChain[_tokenId]) { + jsonBytes.appendSafe( + abi.encodePacked( + '"image":"', + baseURI, + _toString(_tokenId), + "?dna=", + tokenHash, + '&network=mainnet",' + ) + ); + } else { + string memory svgCode = ""; + if (shouldWrapSVG) { + string memory svgString = hashToSVG(tokenHash); + svgCode = string( + abi.encodePacked( + "data:image/svg+xml;base64,", + Base64.encode( + abi.encodePacked( + '' + ) + ) + ) + ); + jsonBytes.appendSafe( + abi.encodePacked( + '"svg_image_data":"', + svgString, + '",' + ) + ); + } else { + svgCode = hashToSVG(tokenHash); + } + + jsonBytes.appendSafe( + abi.encodePacked( + '"image_data":"', + svgCode, + '",' + ) + ); + } + + jsonBytes.appendSafe( + abi.encodePacked( + '"attributes":', + hashToMetadata(tokenHash), + "}" + ) + ); + + return string( + abi.encodePacked( + "data:application/json;base64,", + Base64.encode(jsonBytes) + ) + ); + } + + function contractURI() + public + view + returns (string memory) + { + return string( + abi.encodePacked( + "data:application/json;base64,", + Base64.encode( + abi.encodePacked( + '{"name":"', + contractData.name, + '","description":"', + contractData.description, + '","image":"', + contractData.image, + '","banner":"', + contractData.banner, + '","external_link":"', + contractData.website, + '","seller_fee_basis_points":', + _toString(contractData.royalties), + ',"fee_recipient":"', + contractData.royaltiesRecipient, + '"}' + ) + ) + ) + ); + } + + function tokenIdToSVG(uint _tokenId) + public + view + returns (string memory) + { + return hashToSVG(tokenIdToHash(_tokenId)); + } + + function traitDetails(uint _layerIndex, uint _traitIndex) + public + view + returns (Trait memory) + { + return _traitDetails[_layerIndex][_traitIndex]; + } + + function traitData(uint _layerIndex, uint _traitIndex) + public + view + returns (string memory) + { + return string(SSTORE2.read(_traitDataPointers[_layerIndex][_traitIndex])); + } + + function getLinkedTraits(uint _layerIndex, uint _traitIndex) + public + view + returns (uint[] memory) + { + return _linkedTraits[_layerIndex][_traitIndex]; + } + + function addLayer(uint _layerIndex, TraitDTO[] memory traits) + public + onlyOwner + whenUnsealed + { + require(TIERS[_layerIndex].length == traits.length, "Traits size does not match tiers for this index"); + address[] memory dataPointers = new address[](traits.length); + for (uint i = 0; i < traits.length; i++) { + if (traits[i].useExistingData) { + dataPointers[i] = dataPointers[traits[i].existingDataIndex]; + } else { + dataPointers[i] = SSTORE2.write(traits[i].data); + } + _traitDetails[_layerIndex][i] = Trait(traits[i].name, traits[i].mimetype); + } + _traitDataPointers[_layerIndex] = dataPointers; + return; + } + + function addTrait(uint _layerIndex, uint _traitIndex, TraitDTO memory trait) + public + onlyOwner + whenUnsealed + { + _traitDetails[_layerIndex][_traitIndex] = Trait(trait.name, trait.mimetype); + address[] memory dataPointers = _traitDataPointers[_layerIndex]; + if (trait.useExistingData) { + dataPointers[_traitIndex] = dataPointers[trait.existingDataIndex]; + } else { + dataPointers[_traitIndex] = SSTORE2.write(trait.data); + } + _traitDataPointers[_layerIndex] = dataPointers; + return; + } + + function setLinkedTraits(LinkedTraitDTO[] memory linkedTraits) + public + onlyOwner + whenUnsealed + { + for (uint i = 0; i < linkedTraits.length; i++) { + _linkedTraits[linkedTraits[i].traitA[0]][linkedTraits[i].traitA[1]] = [linkedTraits[i].traitB[0],linkedTraits[i].traitB[1]]; + } + } + + function setContractData(ContractData memory _contractData) external onlyOwner whenUnsealed { + contractData = _contractData; + } + + function setMaxPerAddress(uint _maxPerAddress) external onlyOwner { + maxPerAddress = _maxPerAddress; + } + + function setBaseURI(string memory _baseURI) external onlyOwner { + baseURI = _baseURI; + } + + function setBackgroundColor(string memory _backgroundColor) external onlyOwner whenUnsealed { + backgroundColor = _backgroundColor; + } + + function setRenderOfTokenId(uint _tokenId, bool _renderOffChain) external { + require(msg.sender == ownerOf(_tokenId), "Only the token owner can set the render method"); + _renderTokenOffChain[_tokenId] = _renderOffChain; + } + + + function setMerkleRoot(bytes32 newMerkleRoot) external onlyOwner { + merkleRoot = newMerkleRoot; + } + + function setMaxPerAllowList(uint _maxPerAllowList) external onlyOwner { + maxPerAllowList = _maxPerAllowList; + } + + function setAllowListPrice(uint _allowListPrice) external onlyOwner { + allowListPrice = _allowListPrice; + } + + function toggleAllowListMint() external onlyOwner { + isAllowListActive = !isAllowListActive; + } + + + function toggleWrapSVG() external onlyOwner { + shouldWrapSVG = !shouldWrapSVG; + } + + function togglePublicMint() external onlyOwner { + isPublicMintActive = !isPublicMintActive; + } + + function sealContract() external whenUnsealed onlyOwner { + isContractSealed = true; + } + + function withdraw() external onlyOwner nonReentrant { + uint balance = address(this).balance; + uint amount = (balance * (10000 - DEVELOPER_FEE)) / 10000; + + address payable receiver = payable(owner()); + address payable dev = payable(0xEA208Da933C43857683C04BC76e3FD331D7bfdf7); + + Address.sendValue(receiver, amount); + Address.sendValue(dev, balance - amount); + } + } + + +/////////////////////////////////////////// +// File: /var/app/current/contracts/DynamicBuffer.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) + +pragma solidity >=0.8.0; + +/// @title DynamicBuffer +/// @author David Huber (@cxkoda) and Simon Fremaux (@dievardump). See also +/// https://raw.githubusercontent.com/dievardump/solidity-dynamic-buffer +/// @notice This library is used to allocate a big amount of container memory +// which will be subsequently filled without needing to reallocate +/// memory. +/// @dev First, allocate memory. +/// Then use `buffer.appendUnchecked(theBytes)` or `appendSafe()` if +/// bounds checking is required. +library DynamicBuffer { + /// @notice Allocates container space for the DynamicBuffer + /// @param capacity The intended max amount of bytes in the buffer + /// @return buffer The memory location of the buffer + /// @dev Allocates `capacity + 0x60` bytes of space + /// The buffer array starts at the first container data position, + /// (i.e. `buffer = container + 0x20`) + function allocate(uint256 capacity) + internal + pure + returns (bytes memory buffer) + { + assembly { + // Get next-free memory address + let container := mload(0x40) + + // Allocate memory by setting a new next-free address + { + // Add 2 x 32 bytes in size for the two length fields + // Add 32 bytes safety space for 32B chunked copy + let size := add(capacity, 0x60) + let newNextFree := add(container, size) + mstore(0x40, newNextFree) + } + + // Set the correct container length + { + let length := add(capacity, 0x40) + mstore(container, length) + } + + // The buffer starts at idx 1 in the container (0 is length) + buffer := add(container, 0x20) + + // Init content with length 0 + mstore(buffer, 0) + } + + return buffer; + } + + /// @notice Appends data to buffer, and update buffer length + /// @param buffer the buffer to append the data to + /// @param data the data to append + /// @dev Does not perform out-of-bound checks (container capacity) + /// for efficiency. + function appendUnchecked(bytes memory buffer, bytes memory data) + internal + pure + { + assembly { + let length := mload(data) + for { + data := add(data, 0x20) + let dataEnd := add(data, length) + let copyTo := add(buffer, add(mload(buffer), 0x20)) + } lt(data, dataEnd) { + data := add(data, 0x20) + copyTo := add(copyTo, 0x20) + } { + // Copy 32B chunks from data to buffer. + // This may read over data array boundaries and copy invalid + // bytes, which doesn't matter in the end since we will + // later set the correct buffer length, and have allocated an + // additional word to avoid buffer overflow. + mstore(copyTo, mload(data)) + } + + // Update buffer length + mstore(buffer, add(mload(buffer), length)) + } + } + + /// @notice Appends data to buffer, and update buffer length + /// @param buffer the buffer to append the data to + /// @param data the data to append + /// @dev Performs out-of-bound checks and calls `appendUnchecked`. + function appendSafe(bytes memory buffer, bytes memory data) internal pure { + uint256 capacity; + uint256 length; + assembly { + capacity := sub(mload(sub(buffer, 0x20)), 0x40) + length := mload(buffer) + } + + require( + length + data.length <= capacity, + "DynamicBuffer: Appending out of bounds." + ); + appendUnchecked(buffer, data); + } +} + +/////////////////////////////////////////// +// File: /var/app/current/contracts/HelperLib.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.14; + +library HelperLib { + function parseInt(string memory _a) + internal + pure + returns (uint8 _parsedInt) + { + bytes memory bresult = bytes(_a); + uint8 mint = 0; + for (uint8 i = 0; i < bresult.length; i++) { + if ( + (uint8(uint8(bresult[i])) >= 48) && + (uint8(uint8(bresult[i])) <= 57) + ) { + mint *= 10; + mint += uint8(bresult[i]) - 48; + } + } + return mint; + } + + function _substring( + string memory str, + uint256 startIndex, + uint256 endIndex + ) internal pure returns (string memory) { + bytes memory strBytes = bytes(str); + bytes memory result = new bytes(endIndex - startIndex); + for (uint256 i = startIndex; i < endIndex; i++) { + result[i - startIndex] = strBytes[i]; + } + return string(result); + } +} + +/////////////////////////////////////////// +// File: /var/app/current/contracts/SSTORE2.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./utils/Bytecode.sol"; + +/** + @title A key-value storage with auto-generated keys for storing chunks of data with a lower write & read cost. + @author Agustin Aguilar + + Readme: https://github.com/0xsequence/sstore2#readme +*/ +library SSTORE2 { + error WriteError(); + + /** + @notice Stores `_data` and returns `pointer` as key for later retrieval + @dev The pointer is a contract address with `_data` as code + @param _data to be written + @return pointer Pointer to the written `_data` + */ + function write(bytes memory _data) internal returns (address pointer) { + // Append 00 to _data so contract can't be called + // Build init code + bytes memory code = Bytecode.creationCodeFor( + abi.encodePacked( + hex'00', + _data + ) + ); + + // Deploy contract using create + assembly { pointer := create(0, add(code, 32), mload(code)) } + + // Address MUST be non-zero + if (pointer == address(0)) revert WriteError(); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @return data read from `_pointer` contract + */ + function read(address _pointer) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, 1, type(uint256).max); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @param _start number of bytes to skip + @return data read from `_pointer` contract + */ + function read(address _pointer, uint256 _start) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, _start + 1, type(uint256).max); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @param _start number of bytes to skip + @param _end index before which to end extraction + @return data read from `_pointer` contract + */ + function read(address _pointer, uint256 _start, uint256 _end) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, _start + 1, _end + 1); + } +} + +/////////////////////////////////////////// +// File: /var/app/current/contracts/utils/Bytecode.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + + +library Bytecode { + error InvalidCodeAtRange(uint256 _size, uint256 _start, uint256 _end); + + /** + @notice Generate a creation code that results on a contract with `_code` as bytecode + @param _code The returning value of the resulting `creationCode` + @return creationCode (constructor) for new contract + */ + function creationCodeFor(bytes memory _code) internal pure returns (bytes memory) { + /* + 0x00 0x63 0x63XXXXXX PUSH4 _code.length size + 0x01 0x80 0x80 DUP1 size size + 0x02 0x60 0x600e PUSH1 14 14 size size + 0x03 0x60 0x6000 PUSH1 00 0 14 size size + 0x04 0x39 0x39 CODECOPY size + 0x05 0x60 0x6000 PUSH1 00 0 size + 0x06 0xf3 0xf3 RETURN + + */ + + return abi.encodePacked( + hex"63", + uint32(_code.length), + hex"80_60_0E_60_00_39_60_00_F3", + _code + ); + } + + /** + @notice Returns the size of the code on a given address + @param _addr Address that may or may not contain code + @return size of the code on the given `_addr` + */ + function codeSize(address _addr) internal view returns (uint256 size) { + assembly { size := extcodesize(_addr) } + } + + /** + @notice Returns the code of a given address + @dev It will fail if `_end < _start` + @param _addr Address that may or may not contain code + @param _start number of bytes of code to skip on read + @param _end index before which to end extraction + @return oCode read from `_addr` deployed bytecode + + Forked from: https://gist.github.com/KardanovIR/fe98661df9338c842b4a30306d507fbd + */ + function codeAt(address _addr, uint256 _start, uint256 _end) internal view returns (bytes memory oCode) { + uint256 csize = codeSize(_addr); + if (csize == 0) return bytes(""); + + if (_start > csize) return bytes(""); + if (_end < _start) revert InvalidCodeAtRange(csize, _start, _end); + + unchecked { + uint256 reqSize = _end - _start; + uint256 maxSize = csize - _start; + + uint256 size = maxSize < reqSize ? maxSize : reqSize; + + assembly { + // allocate output byte array - this could also be done without assembly + // by using o_code = new bytes(size) + oCode := mload(0x40) + // new "memory end" including padding + mstore(0x40, add(oCode, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + // store length in memory + mstore(oCode, size) + // actually retrieve the code, this needs assembly + extcodecopy(_addr, add(oCode, 0x20), _start, size) + } + } + } +} + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/access/Ownable.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor() { + _transferOwnership(_msgSender()); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/security/ReentrancyGuard.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor() { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and making it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) + +pragma solidity ^0.8.1; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + * + * [IMPORTANT] + * ==== + * You shouldn't rely on `isContract` to protect against flash loan attacks! + * + * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets + * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract + * constructor. + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize/address.code.length, which returns 0 + // for contracts in construction, since the code is only stored at the end + // of the constructor execution. + + return account.code.length > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Base64.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (utils/Base64.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides a set of functions to operate with Base64 strings. + * + * _Available since v4.5._ + */ +library Base64 { + /** + * @dev Base64 Encoding/Decoding Table + */ + string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** + * @dev Converts a `bytes` to its Bytes64 `string` representation. + */ + function encode(bytes memory data) internal pure returns (string memory) { + /** + * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence + * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol + */ + if (data.length == 0) return ""; + + // Loads the table into memory + string memory table = _TABLE; + + // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter + // and split into 4 numbers of 6 bits. + // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up + // - `data.length + 2` -> Round up + // - `/ 3` -> Number of 3-bytes chunks + // - `4 *` -> 4 characters for each chunk + string memory result = new string(4 * ((data.length + 2) / 3)); + + assembly { + // Prepare the lookup table (skip the first "length" byte) + let tablePtr := add(table, 1) + + // Prepare result pointer, jump over length + let resultPtr := add(result, 32) + + // Run over the input, 3 bytes at a time + for { + let dataPtr := data + let endPtr := add(data, mload(data)) + } lt(dataPtr, endPtr) { + + } { + // Advance 3 bytes + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + + // To write each character, shift the 3 bytes (18 bits) chunk + // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) + // and apply logical AND with 0x3F which is the number of + // the previous character in the ASCII table prior to the Base64 Table + // The result is then added to the table to get the character to write, + // and finally write it in the result pointer but with a left shift + // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits + + mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + } + + // When data `bytes` is not exactly 3 bytes long + // it is padded with `=` characters at the end + switch mod(mload(data), 3) + case 1 { + mstore8(sub(resultPtr, 1), 0x3d) + mstore8(sub(resultPtr, 2), 0x3d) + } + case 2 { + mstore8(sub(resultPtr, 1), 0x3d) + } + } + + return result; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/cryptography/MerkleProof.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (utils/cryptography/MerkleProof.sol) + +pragma solidity ^0.8.0; + +/** + * @dev These functions deal with verification of Merkle Trees proofs. + * + * The proofs can be generated using the JavaScript library + * https://github.com/miguelmota/merkletreejs[merkletreejs]. + * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled. + * + * See `test/utils/cryptography/MerkleProof.test.js` for some examples. + * + * WARNING: You should avoid using leaf values that are 64 bytes long prior to + * hashing, or use a hash function other than keccak256 for hashing leaves. + * This is because the concatenation of a sorted pair of internal nodes in + * the merkle tree could be reinterpreted as a leaf value. + */ +library MerkleProof { + /** + * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree + * defined by `root`. For this, a `proof` must be provided, containing + * sibling hashes on the branch from the leaf to the root of the tree. Each + * pair of leaves and each pair of pre-images are assumed to be sorted. + */ + function verify( + bytes32[] memory proof, + bytes32 root, + bytes32 leaf + ) internal pure returns (bool) { + return processProof(proof, leaf) == root; + } + + /** + * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up + * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt + * hash matches the root of the tree. When processing the proof, the pairs + * of leafs & pre-images are assumed to be sorted. + * + * _Available since v4.4._ + */ + function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + bytes32 proofElement = proof[i]; + if (computedHash <= proofElement) { + // Hash(current computed hash + current element of the proof) + computedHash = _efficientHash(computedHash, proofElement); + } else { + // Hash(current element of the proof + current computed hash) + computedHash = _efficientHash(proofElement, computedHash); + } + } + return computedHash; + } + + function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { + assembly { + mstore(0x00, a) + mstore(0x20, b) + value := keccak256(0x00, 0x40) + } + } +} + + +/////////////////////////////////////////// +// File: erc721a/contracts/ERC721A.sol + +// SPDX-License-Identifier: MIT +// ERC721A Contracts v4.1.0 +// Creator: Chiru Labs + +pragma solidity ^0.8.4; + +import './IERC721A.sol'; + +/** + * @dev ERC721 token receiver interface. + */ +interface ERC721A__IERC721Receiver { + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, + * including the Metadata extension. Built to optimize for lower gas during batch mints. + * + * Assumes serials are sequentially minted starting at `_startTokenId()` + * (defaults to 0, e.g. 0, 1, 2, 3..). + * + * Assumes that an owner cannot have more than 2**64 - 1 (max value of uint64) of supply. + * + * Assumes that the maximum token id cannot exceed 2**256 - 1 (max value of uint256). + */ +contract ERC721A is IERC721A { + // Mask of an entry in packed address data. + uint256 private constant BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1; + + // The bit position of `numberMinted` in packed address data. + uint256 private constant BITPOS_NUMBER_MINTED = 64; + + // The bit position of `numberBurned` in packed address data. + uint256 private constant BITPOS_NUMBER_BURNED = 128; + + // The bit position of `aux` in packed address data. + uint256 private constant BITPOS_AUX = 192; + + // Mask of all 256 bits in packed address data except the 64 bits for `aux`. + uint256 private constant BITMASK_AUX_COMPLEMENT = (1 << 192) - 1; + + // The bit position of `startTimestamp` in packed ownership. + uint256 private constant BITPOS_START_TIMESTAMP = 160; + + // The bit mask of the `burned` bit in packed ownership. + uint256 private constant BITMASK_BURNED = 1 << 224; + + // The bit position of the `nextInitialized` bit in packed ownership. + uint256 private constant BITPOS_NEXT_INITIALIZED = 225; + + // The bit mask of the `nextInitialized` bit in packed ownership. + uint256 private constant BITMASK_NEXT_INITIALIZED = 1 << 225; + + // The bit position of `extraData` in packed ownership. + uint256 private constant BITPOS_EXTRA_DATA = 232; + + // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`. + uint256 private constant BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1; + + // The mask of the lower 160 bits for addresses. + uint256 private constant BITMASK_ADDRESS = (1 << 160) - 1; + + // The maximum `quantity` that can be minted with `_mintERC2309`. + // This limit is to prevent overflows on the address data entries. + // For a limit of 5000, a total of 3.689e15 calls to `_mintERC2309` + // is required to cause an overflow, which is unrealistic. + uint256 private constant MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000; + + // The tokenId of the next token to be minted. + uint256 private _currentIndex; + + // The number of tokens burned. + uint256 private _burnCounter; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to ownership details + // An empty struct value does not necessarily mean the token is unowned. + // See `_packedOwnershipOf` implementation for details. + // + // Bits Layout: + // - [0..159] `addr` + // - [160..223] `startTimestamp` + // - [224] `burned` + // - [225] `nextInitialized` + // - [232..255] `extraData` + mapping(uint256 => uint256) private _packedOwnerships; + + // Mapping owner address to address data. + // + // Bits Layout: + // - [0..63] `balance` + // - [64..127] `numberMinted` + // - [128..191] `numberBurned` + // - [192..255] `aux` + mapping(address => uint256) private _packedAddressData; + + // Mapping from token ID to approved address. + mapping(uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + _currentIndex = _startTokenId(); + } + + /** + * @dev Returns the starting token ID. + * To change the starting token ID, please override this function. + */ + function _startTokenId() internal view virtual returns (uint256) { + return 0; + } + + /** + * @dev Returns the next token ID to be minted. + */ + function _nextTokenId() internal view returns (uint256) { + return _currentIndex; + } + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see `_totalMinted`. + */ + function totalSupply() public view override returns (uint256) { + // Counter underflow is impossible as _burnCounter cannot be incremented + // more than `_currentIndex - _startTokenId()` times. + unchecked { + return _currentIndex - _burnCounter - _startTokenId(); + } + } + + /** + * @dev Returns the total amount of tokens minted in the contract. + */ + function _totalMinted() internal view returns (uint256) { + // Counter underflow is impossible as _currentIndex does not decrement, + // and it is initialized to `_startTokenId()` + unchecked { + return _currentIndex - _startTokenId(); + } + } + + /** + * @dev Returns the total number of tokens burned. + */ + function _totalBurned() internal view returns (uint256) { + return _burnCounter; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + // The interface IDs are constants representing the first 4 bytes of the XOR of + // all function selectors in the interface. See: https://eips.ethereum.org/EIPS/eip-165 + // e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)` + return + interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165. + interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721. + interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata. + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view override returns (uint256) { + if (owner == address(0)) revert BalanceQueryForZeroAddress(); + return _packedAddressData[owner] & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the number of tokens minted by `owner`. + */ + function _numberMinted(address owner) internal view returns (uint256) { + return (_packedAddressData[owner] >> BITPOS_NUMBER_MINTED) & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the number of tokens burned by or on behalf of `owner`. + */ + function _numberBurned(address owner) internal view returns (uint256) { + return (_packedAddressData[owner] >> BITPOS_NUMBER_BURNED) & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). + */ + function _getAux(address owner) internal view returns (uint64) { + return uint64(_packedAddressData[owner] >> BITPOS_AUX); + } + + /** + * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). + * If there are multiple variables, please pack them into a uint64. + */ + function _setAux(address owner, uint64 aux) internal { + uint256 packed = _packedAddressData[owner]; + uint256 auxCasted; + // Cast `aux` with assembly to avoid redundant masking. + assembly { + auxCasted := aux + } + packed = (packed & BITMASK_AUX_COMPLEMENT) | (auxCasted << BITPOS_AUX); + _packedAddressData[owner] = packed; + } + + /** + * Returns the packed ownership data of `tokenId`. + */ + function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) { + uint256 curr = tokenId; + + unchecked { + if (_startTokenId() <= curr) + if (curr < _currentIndex) { + uint256 packed = _packedOwnerships[curr]; + // If not burned. + if (packed & BITMASK_BURNED == 0) { + // Invariant: + // There will always be an ownership that has an address and is not burned + // before an ownership that does not have an address and is not burned. + // Hence, curr will not underflow. + // + // We can directly compare the packed value. + // If the address is zero, packed is zero. + while (packed == 0) { + packed = _packedOwnerships[--curr]; + } + return packed; + } + } + } + revert OwnerQueryForNonexistentToken(); + } + + /** + * Returns the unpacked `TokenOwnership` struct from `packed`. + */ + function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) { + ownership.addr = address(uint160(packed)); + ownership.startTimestamp = uint64(packed >> BITPOS_START_TIMESTAMP); + ownership.burned = packed & BITMASK_BURNED != 0; + ownership.extraData = uint24(packed >> BITPOS_EXTRA_DATA); + } + + /** + * Returns the unpacked `TokenOwnership` struct at `index`. + */ + function _ownershipAt(uint256 index) internal view returns (TokenOwnership memory) { + return _unpackedOwnership(_packedOwnerships[index]); + } + + /** + * @dev Initializes the ownership slot minted at `index` for efficiency purposes. + */ + function _initializeOwnershipAt(uint256 index) internal { + if (_packedOwnerships[index] == 0) { + _packedOwnerships[index] = _packedOwnershipOf(index); + } + } + + /** + * Gas spent here starts off proportional to the maximum mint batch size. + * It gradually moves to O(1) as tokens get transferred around in the collection over time. + */ + function _ownershipOf(uint256 tokenId) internal view returns (TokenOwnership memory) { + return _unpackedOwnership(_packedOwnershipOf(tokenId)); + } + + /** + * @dev Packs ownership data into a single uint256. + */ + function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) { + assembly { + // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. + owner := and(owner, BITMASK_ADDRESS) + // `owner | (block.timestamp << BITPOS_START_TIMESTAMP) | flags`. + result := or(owner, or(shl(BITPOS_START_TIMESTAMP, timestamp()), flags)) + } + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view override returns (address) { + return address(uint160(_packedOwnershipOf(tokenId))); + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + if (!_exists(tokenId)) revert URIQueryForNonexistentToken(); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : ''; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, it can be overridden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ''; + } + + /** + * @dev Returns the `nextInitialized` flag set if `quantity` equals 1. + */ + function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) { + // For branchless setting of the `nextInitialized` flag. + assembly { + // `(quantity == 1) << BITPOS_NEXT_INITIALIZED`. + result := shl(BITPOS_NEXT_INITIALIZED, eq(quantity, 1)) + } + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public override { + address owner = ownerOf(tokenId); + + if (_msgSenderERC721A() != owner) + if (!isApprovedForAll(owner, _msgSenderERC721A())) { + revert ApprovalCallerNotOwnerNorApproved(); + } + + _tokenApprovals[tokenId] = to; + emit Approval(owner, to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view override returns (address) { + if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken(); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + if (operator == _msgSenderERC721A()) revert ApproveToCaller(); + + _operatorApprovals[_msgSenderERC721A()][operator] = approved; + emit ApprovalForAll(_msgSenderERC721A(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + safeTransferFrom(from, to, tokenId, ''); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) public virtual override { + transferFrom(from, to, tokenId); + if (to.code.length != 0) + if (!_checkContractOnERC721Received(from, to, tokenId, _data)) { + revert TransferToNonERC721ReceiverImplementer(); + } + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + */ + function _exists(uint256 tokenId) internal view returns (bool) { + return + _startTokenId() <= tokenId && + tokenId < _currentIndex && // If within bounds, + _packedOwnerships[tokenId] & BITMASK_BURNED == 0; // and not burned. + } + + /** + * @dev Equivalent to `_safeMint(to, quantity, '')`. + */ + function _safeMint(address to, uint256 quantity) internal { + _safeMint(to, quantity, ''); + } + + /** + * @dev Safely mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called for each safe transfer. + * - `quantity` must be greater than 0. + * + * See {_mint}. + * + * Emits a {Transfer} event for each mint. + */ + function _safeMint( + address to, + uint256 quantity, + bytes memory _data + ) internal { + _mint(to, quantity); + + unchecked { + if (to.code.length != 0) { + uint256 end = _currentIndex; + uint256 index = end - quantity; + do { + if (!_checkContractOnERC721Received(address(0), to, index++, _data)) { + revert TransferToNonERC721ReceiverImplementer(); + } + } while (index < end); + // Reentrancy protection. + if (_currentIndex != end) revert(); + } + } + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {Transfer} event for each mint. + */ + function _mint(address to, uint256 quantity) internal { + uint256 startTokenId = _currentIndex; + if (to == address(0)) revert MintToZeroAddress(); + if (quantity == 0) revert MintZeroQuantity(); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are incredibly unrealistic. + // `balance` and `numberMinted` have a maximum limit of 2**64. + // `tokenId` has a maximum limit of 2**256. + unchecked { + // Updates: + // - `balance += quantity`. + // - `numberMinted += quantity`. + // + // We can directly add to the `balance` and `numberMinted`. + _packedAddressData[to] += quantity * ((1 << BITPOS_NUMBER_MINTED) | 1); + + // Updates: + // - `address` to the owner. + // - `startTimestamp` to the timestamp of minting. + // - `burned` to `false`. + // - `nextInitialized` to `quantity == 1`. + _packedOwnerships[startTokenId] = _packOwnershipData( + to, + _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) + ); + + uint256 tokenId = startTokenId; + uint256 end = startTokenId + quantity; + do { + emit Transfer(address(0), to, tokenId++); + } while (tokenId < end); + + _currentIndex = end; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * This function is intended for efficient minting only during contract creation. + * + * It emits only one {ConsecutiveTransfer} as defined in + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309), + * instead of a sequence of {Transfer} event(s). + * + * Calling this function outside of contract creation WILL make your contract + * non-compliant with the ERC721 standard. + * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309 + * {ConsecutiveTransfer} event is only permissible during contract creation. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {ConsecutiveTransfer} event. + */ + function _mintERC2309(address to, uint256 quantity) internal { + uint256 startTokenId = _currentIndex; + if (to == address(0)) revert MintToZeroAddress(); + if (quantity == 0) revert MintZeroQuantity(); + if (quantity > MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit(); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are unrealistic due to the above check for `quantity` to be below the limit. + unchecked { + // Updates: + // - `balance += quantity`. + // - `numberMinted += quantity`. + // + // We can directly add to the `balance` and `numberMinted`. + _packedAddressData[to] += quantity * ((1 << BITPOS_NUMBER_MINTED) | 1); + + // Updates: + // - `address` to the owner. + // - `startTimestamp` to the timestamp of minting. + // - `burned` to `false`. + // - `nextInitialized` to `quantity == 1`. + _packedOwnerships[startTokenId] = _packOwnershipData( + to, + _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) + ); + + emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to); + + _currentIndex = startTokenId + quantity; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Returns the storage slot and value for the approved address of `tokenId`. + */ + function _getApprovedAddress(uint256 tokenId) + private + view + returns (uint256 approvedAddressSlot, address approvedAddress) + { + mapping(uint256 => address) storage tokenApprovalsPtr = _tokenApprovals; + // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId]`. + assembly { + // Compute the slot. + mstore(0x00, tokenId) + mstore(0x20, tokenApprovalsPtr.slot) + approvedAddressSlot := keccak256(0x00, 0x40) + // Load the slot's value from storage. + approvedAddress := sload(approvedAddressSlot) + } + } + + /** + * @dev Returns whether the `approvedAddress` is equals to `from` or `msgSender`. + */ + function _isOwnerOrApproved( + address approvedAddress, + address from, + address msgSender + ) private pure returns (bool result) { + assembly { + // Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean. + from := and(from, BITMASK_ADDRESS) + // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean. + msgSender := and(msgSender, BITMASK_ADDRESS) + // `msgSender == from || msgSender == approvedAddress`. + result := or(eq(msgSender, from), eq(msgSender, approvedAddress)) + } + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); + + if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner(); + + (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedAddress(tokenId); + + // The nested ifs save around 20+ gas over a compound boolean condition. + if (!_isOwnerOrApproved(approvedAddress, from, _msgSenderERC721A())) + if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved(); + + if (to == address(0)) revert TransferToZeroAddress(); + + _beforeTokenTransfers(from, to, tokenId, 1); + + // Clear approvals from the previous owner. + assembly { + if approvedAddress { + // This is equivalent to `delete _tokenApprovals[tokenId]`. + sstore(approvedAddressSlot, 0) + } + } + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as tokenId would have to be 2**256. + unchecked { + // We can directly increment and decrement the balances. + --_packedAddressData[from]; // Updates: `balance -= 1`. + ++_packedAddressData[to]; // Updates: `balance += 1`. + + // Updates: + // - `address` to the next owner. + // - `startTimestamp` to the timestamp of transfering. + // - `burned` to `false`. + // - `nextInitialized` to `true`. + _packedOwnerships[tokenId] = _packOwnershipData( + to, + BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked) + ); + + // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . + if (prevOwnershipPacked & BITMASK_NEXT_INITIALIZED == 0) { + uint256 nextTokenId = tokenId + 1; + // If the next slot's address is zero and not burned (i.e. packed value is zero). + if (_packedOwnerships[nextTokenId] == 0) { + // If the next slot is within bounds. + if (nextTokenId != _currentIndex) { + // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. + _packedOwnerships[nextTokenId] = prevOwnershipPacked; + } + } + } + } + + emit Transfer(from, to, tokenId); + _afterTokenTransfers(from, to, tokenId, 1); + } + + /** + * @dev Equivalent to `_burn(tokenId, false)`. + */ + function _burn(uint256 tokenId) internal virtual { + _burn(tokenId, false); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId, bool approvalCheck) internal virtual { + uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); + + address from = address(uint160(prevOwnershipPacked)); + + (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedAddress(tokenId); + + if (approvalCheck) { + // The nested ifs save around 20+ gas over a compound boolean condition. + if (!_isOwnerOrApproved(approvedAddress, from, _msgSenderERC721A())) + if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved(); + } + + _beforeTokenTransfers(from, address(0), tokenId, 1); + + // Clear approvals from the previous owner. + assembly { + if approvedAddress { + // This is equivalent to `delete _tokenApprovals[tokenId]`. + sstore(approvedAddressSlot, 0) + } + } + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. + unchecked { + // Updates: + // - `balance -= 1`. + // - `numberBurned += 1`. + // + // We can directly decrement the balance, and increment the number burned. + // This is equivalent to `packed -= 1; packed += 1 << BITPOS_NUMBER_BURNED;`. + _packedAddressData[from] += (1 << BITPOS_NUMBER_BURNED) - 1; + + // Updates: + // - `address` to the last owner. + // - `startTimestamp` to the timestamp of burning. + // - `burned` to `true`. + // - `nextInitialized` to `true`. + _packedOwnerships[tokenId] = _packOwnershipData( + from, + (BITMASK_BURNED | BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked) + ); + + // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . + if (prevOwnershipPacked & BITMASK_NEXT_INITIALIZED == 0) { + uint256 nextTokenId = tokenId + 1; + // If the next slot's address is zero and not burned (i.e. packed value is zero). + if (_packedOwnerships[nextTokenId] == 0) { + // If the next slot is within bounds. + if (nextTokenId != _currentIndex) { + // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. + _packedOwnerships[nextTokenId] = prevOwnershipPacked; + } + } + } + } + + emit Transfer(from, address(0), tokenId); + _afterTokenTransfers(from, address(0), tokenId, 1); + + // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times. + unchecked { + _burnCounter++; + } + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkContractOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) private returns (bool) { + try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns ( + bytes4 retval + ) { + return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert TransferToNonERC721ReceiverImplementer(); + } else { + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } + + /** + * @dev Directly sets the extra data for the ownership data `index`. + */ + function _setExtraDataAt(uint256 index, uint24 extraData) internal { + uint256 packed = _packedOwnerships[index]; + if (packed == 0) revert OwnershipNotInitializedForExtraData(); + uint256 extraDataCasted; + // Cast `extraData` with assembly to avoid redundant masking. + assembly { + extraDataCasted := extraData + } + packed = (packed & BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << BITPOS_EXTRA_DATA); + _packedOwnerships[index] = packed; + } + + /** + * @dev Returns the next extra data for the packed ownership data. + * The returned result is shifted into position. + */ + function _nextExtraData( + address from, + address to, + uint256 prevOwnershipPacked + ) private view returns (uint256) { + uint24 extraData = uint24(prevOwnershipPacked >> BITPOS_EXTRA_DATA); + return uint256(_extraData(from, to, extraData)) << BITPOS_EXTRA_DATA; + } + + /** + * @dev Called during each token transfer to set the 24bit `extraData` field. + * Intended to be overridden by the cosumer contract. + * + * `previousExtraData` - the value of `extraData` before transfer. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _extraData( + address from, + address to, + uint24 previousExtraData + ) internal view virtual returns (uint24) {} + + /** + * @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. + * This includes minting. + * And also called before burning one token. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _beforeTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Hook that is called after a set of serially-ordered token ids have been transferred. + * This includes minting. + * And also called after one token has been burned. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been + * transferred to `to`. + * - When `from` is zero, `tokenId` has been minted for `to`. + * - When `to` is zero, `tokenId` has been burned by `from`. + * - `from` and `to` are never both zero. + */ + function _afterTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Returns the message sender (defaults to `msg.sender`). + * + * If you are writing GSN compatible contracts, you need to override this function. + */ + function _msgSenderERC721A() internal view virtual returns (address) { + return msg.sender; + } + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function _toString(uint256 value) internal pure returns (string memory ptr) { + assembly { + // The maximum value of a uint256 contains 78 digits (1 byte per digit), + // but we allocate 128 bytes to keep the free memory pointer 32-byte word aliged. + // We will need 1 32-byte word to store the length, + // and 3 32-byte words to store a maximum of 78 digits. Total: 32 + 3 * 32 = 128. + ptr := add(mload(0x40), 128) + // Update the free memory pointer to allocate. + mstore(0x40, ptr) + + // Cache the end of the memory to calculate the length later. + let end := ptr + + // We write the string from the rightmost digit to the leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + // Costs a bit more than early returning for the zero case, + // but cheaper in terms of deployment and overall runtime costs. + for { + // Initialize and perform the first pass without check. + let temp := value + // Move the pointer 1 byte leftwards to point to an empty character slot. + ptr := sub(ptr, 1) + // Write the character to the pointer. 48 is the ASCII index of '0'. + mstore8(ptr, add(48, mod(temp, 10))) + temp := div(temp, 10) + } temp { + // Keep dividing `temp` until zero. + temp := div(temp, 10) + } { + // Body of the for loop. + ptr := sub(ptr, 1) + mstore8(ptr, add(48, mod(temp, 10))) + } + + let length := sub(end, ptr) + // Move the pointer 32 bytes leftwards to make room for the length. + ptr := sub(ptr, 32) + // Store the length. + mstore(ptr, length) + } + } +} + + +/////////////////////////////////////////// +// File: erc721a/contracts/IERC721A.sol + +// SPDX-License-Identifier: MIT +// ERC721A Contracts v4.1.0 +// Creator: Chiru Labs + +pragma solidity ^0.8.4; + +/** + * @dev Interface of an ERC721A compliant contract. + */ +interface IERC721A { + /** + * The caller must own the token or be an approved operator. + */ + error ApprovalCallerNotOwnerNorApproved(); + + /** + * The token does not exist. + */ + error ApprovalQueryForNonexistentToken(); + + /** + * The caller cannot approve to their own address. + */ + error ApproveToCaller(); + + /** + * Cannot query the balance for the zero address. + */ + error BalanceQueryForZeroAddress(); + + /** + * Cannot mint to the zero address. + */ + error MintToZeroAddress(); + + /** + * The quantity of tokens minted must be more than zero. + */ + error MintZeroQuantity(); + + /** + * The token does not exist. + */ + error OwnerQueryForNonexistentToken(); + + /** + * The caller must own the token or be an approved operator. + */ + error TransferCallerNotOwnerNorApproved(); + + /** + * The token must be owned by `from`. + */ + error TransferFromIncorrectOwner(); + + /** + * Cannot safely transfer to a contract that does not implement the ERC721Receiver interface. + */ + error TransferToNonERC721ReceiverImplementer(); + + /** + * Cannot transfer to the zero address. + */ + error TransferToZeroAddress(); + + /** + * The token does not exist. + */ + error URIQueryForNonexistentToken(); + + /** + * The `quantity` minted with ERC2309 exceeds the safety limit. + */ + error MintERC2309QuantityExceedsLimit(); + + /** + * The `extraData` cannot be set on an unintialized ownership slot. + */ + error OwnershipNotInitializedForExtraData(); + + struct TokenOwnership { + // The address of the owner. + address addr; + // Keeps track of the start time of ownership with minimal overhead for tokenomics. + uint64 startTimestamp; + // Whether the token has been burned. + bool burned; + // Arbitrary data similar to `startTimestamp` that can be set through `_extraData`. + uint24 extraData; + } + + /** + * @dev Returns the total amount of tokens stored by the contract. + * + * Burned tokens are calculated here, use `_totalMinted()` if you want to count just minted tokens. + */ + function totalSupply() external view returns (uint256); + + // ============================== + // IERC165 + // ============================== + + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); + + // ============================== + // IERC721 + // ============================== + + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + // ============================== + // IERC721Metadata + // ============================== + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); + + // ============================== + // IERC2309 + // ============================== + + /** + * @dev Emitted when tokens in `fromTokenId` to `toTokenId` (inclusive) is transferred from `from` to `to`, + * as defined in the ERC2309 standard. See `_mintERC2309` for more details. + */ + event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); +} + + diff --git a/ethabi/code/0x9b66d03fc1eee61a512341058e95f1a68dc3a913.yml b/ethabi/code/0x9b66d03fc1eee61a512341058e95f1a68dc3a913.yml new file mode 100644 index 0000000..72651d9 --- /dev/null +++ b/ethabi/code/0x9b66d03fc1eee61a512341058e95f1a68dc3a913.yml @@ -0,0 +1,12 @@ +--- +ContractName: Indelible +CompilerVersion: v0.8.14+commit.80d49f37 +OptimizationUsed: '1' +Runs: '200' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: MIT +Proxy: '0' +Implementation: '' +SwarmSource: '' diff --git a/ethabi/code/0xa19f0378a6f3f3361d8e962f3589ec28f4f8f159.sol b/ethabi/code/0xa19f0378a6f3f3361d8e962f3589ec28f4f8f159.sol new file mode 100644 index 0000000..9966887 --- /dev/null +++ b/ethabi/code/0xa19f0378a6f3f3361d8e962f3589ec28f4f8f159.sol @@ -0,0 +1,2232 @@ +/////////////////////////////////////////// +// File: V3Phunks.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.9; + +import {ConfigSettings} from "gwei-slim-nft-contracts/contracts/base/ERC721Base.sol"; +import {ERC721Delegated} from "gwei-slim-nft-contracts/contracts/base/ERC721Delegated.sol"; +import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; +import "@openzeppelin/contracts/utils/Counters.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; + +contract V3Phunks is ERC721Delegated, ReentrancyGuard { + using Counters for Counters.Counter; + + constructor(address baseFactory, string memory customBaseURI_) + ERC721Delegated( + baseFactory, + "V3 Phunks", + "V3PHNKS", + ConfigSettings({ + royaltyBps: 1000, + uriBase: customBaseURI_, + uriExtension: "", + hasTransferHook: false + }) + ) + {} + + /** MINTING **/ + + uint256 public constant MAX_SUPPLY = 5353; + + uint256 public constant MAX_MULTIMINT = 100; + + uint256 public constant PRICE = 10000000000000000; + + Counters.Counter private supplyCounter; + + function mint(uint256 count) public payable nonReentrant { + require(saleIsActive, "Sale not active"); + + require(totalSupply() + count - 1 < MAX_SUPPLY, "Exceeds max supply"); + + require(count <= MAX_MULTIMINT, "Mint at most 100 at a time"); + + require( + msg.value >= PRICE * count, "Insufficient payment, 0.01 ETH per item" + ); + + for (uint256 i = 0; i < count; i++) { + _mint(msg.sender, totalSupply()); + + supplyCounter.increment(); + } + } + + function totalSupply() public view returns (uint256) { + return supplyCounter.current(); + } + + /** ACTIVATION **/ + + bool public saleIsActive = true; + + function setSaleIsActive(bool saleIsActive_) external onlyOwner { + saleIsActive = saleIsActive_; + } + + /** URI HANDLING **/ + + function setBaseURI(string memory customBaseURI_) external onlyOwner { + _setBaseURI(customBaseURI_, ""); + } + + /** PAYOUT **/ + + function withdraw() public nonReentrant { + uint256 balance = address(this).balance; + + Address.sendValue(payable(_owner()), balance); + } +} + +// Contract created with Studio 721 v1.5.0 +// https://721.so + +/////////////////////////////////////////// +// File: gwei-slim-nft-contracts/contracts/base/ERC721Base.sol + +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.9; + +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {IERC2981Upgradeable, IERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/interfaces/IERC2981Upgradeable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {StringsUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; +import {CountersUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol"; +import {IBaseERC721Interface} from "./IBaseERC721Interface.sol"; + +struct ConfigSettings { + uint16 royaltyBps; + string uriBase; + string uriExtension; + bool hasTransferHook; +} + +/** + This smart contract adds features and allows for a ownership only by another smart contract as fallback behavior + while also implementing all normal ERC721 functions as expected +*/ +contract ERC721Base is + ERC721Upgradeable, + IBaseERC721Interface, + IERC2981Upgradeable, + OwnableUpgradeable +{ + using CountersUpgradeable for CountersUpgradeable.Counter; + // Minted counter for totalSupply() + CountersUpgradeable.Counter private mintedCounter; + + modifier onlyInternal() { + require(msg.sender == address(this), "Only internal"); + _; + } + + /// on-chain record of when this contract was deployed + uint256 public immutable deployedBlock; + + ConfigSettings public advancedConfig; + + /// Constructor called once when the base contract is deployed + constructor() { + // Can be used to verify contract implementation is correct at address + deployedBlock = block.number; + } + + /// Initializer that's called when a new child nft is setup + /// @param newOwner Owner for the new derived nft + /// @param _name name of NFT contract + /// @param _symbol symbol of NFT contract + /// @param settings configuration settings for uri, royalty, and hooks features + function initialize( + address newOwner, + string memory _name, + string memory _symbol, + ConfigSettings memory settings + ) public initializer { + __ERC721_init(_name, _symbol); + __Ownable_init(); + + advancedConfig = settings; + + transferOwnership(newOwner); + } + + /// Getter to expose appoval status to root contract + function isApprovedForAll(address _owner, address operator) + public + view + override + returns (bool) + { + return + ERC721Upgradeable.isApprovedForAll(_owner, operator) || + operator == address(this); + } + + /// internal getter for approval by all + /// When isApprovedForAll is overridden, this can be used to call original impl + function __isApprovedForAll(address _owner, address operator) + public + view + override + returns (bool) + { + return isApprovedForAll(_owner, operator); + } + + /// Hook that when enabled manually calls _beforeTokenTransfer on + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId + ) internal override { + if (advancedConfig.hasTransferHook) { + (bool success, ) = address(this).delegatecall( + abi.encodeWithSignature( + "_beforeTokenTransfer(address,address,uint256)", + from, + to, + tokenId + ) + ); + // Raise error again from result if error exists + assembly { + switch success + // delegatecall returns 0 on error. + case 0 { + returndatacopy(0, 0, returndatasize()) + revert(0, returndatasize()) + } + } + } + } + + /// Internal-only function to update the base uri + function __setBaseURI(string memory uriBase, string memory uriExtension) + public + override + onlyInternal + { + advancedConfig.uriBase = uriBase; + advancedConfig.uriExtension = uriExtension; + } + + /// @dev returns the number of minted tokens + /// uses some extra gas but makes etherscan and users happy so :shrug: + /// partial erc721enumerable implemntation + function totalSupply() public view returns (uint256) { + return mintedCounter.current(); + } + + /** + Internal-only + @param to address to send the newly minted NFT to + @dev This mints one edition to the given address by an allowed minter on the edition instance. + */ + function __mint(address to, uint256 tokenId) + external + override + onlyInternal + { + _mint(to, tokenId); + mintedCounter.increment(); + } + + /** + @param tokenId Token ID to burn + User burn function for token id + */ + function burn(uint256 tokenId) public { + require(_isApprovedOrOwner(_msgSender(), tokenId), "Not allowed"); + _burn(tokenId); + mintedCounter.decrement(); + } + + /// Internal only + function __burn(uint256 tokenId) public onlyInternal { + _burn(tokenId); + mintedCounter.decrement(); + } + + /** + Simple override for owner interface. + */ + function owner() + public + view + override(OwnableUpgradeable) + returns (address) + { + return super.owner(); + } + + /// internal alias for overrides + function __owner() + public + view + override(IBaseERC721Interface) + returns (address) + { + return owner(); + } + + /// Get royalty information for token + /// ignored token id to get royalty info. able to override and set per-token royalties + /// @param _salePrice sales price for token to determine royalty split + function royaltyInfo(uint256, uint256 _salePrice) + external + view + override + returns (address receiver, uint256 royaltyAmount) + { + // If ownership is revoked, don't set royalties. + if (owner() == address(0x0)) { + return (owner(), 0); + } + return (owner(), (_salePrice * advancedConfig.royaltyBps) / 10_000); + } + + /// Default simple token-uri implementation. works for ipfs folders too + /// @param tokenId token id ot get uri for + /// @return default uri getter functionality + function tokenURI(uint256 tokenId) + public + view + override + returns (string memory) + { + require(_exists(tokenId), "No token"); + + return + string( + abi.encodePacked( + advancedConfig.uriBase, + StringsUpgradeable.toString(tokenId), + advancedConfig.uriExtension + ) + ); + } + + /// internal base override + function __tokenURI(uint256 tokenId) + public + view + onlyInternal + returns (string memory) + { + return tokenURI(tokenId); + } + + /// Exposing token exists check for base contract + function __exists(uint256 tokenId) external view override returns (bool) { + return _exists(tokenId); + } + + /// Getter for approved or owner + function __isApprovedOrOwner(address spender, uint256 tokenId) + external + view + override + onlyInternal + returns (bool) + { + return _isApprovedOrOwner(spender, tokenId); + } + + /// IERC165 getter + /// @param interfaceId interfaceId bytes4 to check support for + function supportsInterface(bytes4 interfaceId) + public + view + override(ERC721Upgradeable, IERC165Upgradeable) + returns (bool) + { + return + type(IERC2981Upgradeable).interfaceId == interfaceId || + type(IBaseERC721Interface).interfaceId == interfaceId || + ERC721Upgradeable.supportsInterface(interfaceId); + } +} + + +/////////////////////////////////////////// +// File: gwei-slim-nft-contracts/contracts/base/ERC721Delegated.sol + +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.9; + +import {StorageSlotUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/StorageSlotUpgradeable.sol"; + +import {IBaseERC721Interface, ConfigSettings} from "./ERC721Base.sol"; + +contract ERC721Delegated { + uint256[100000] gap; + bytes32 internal constant _IMPLEMENTATION_SLOT = + 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + + // Reference to base NFT implementation + function implementation() public view returns (address) { + return + StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value; + } + + function _initImplementation(address _nftImplementation) private { + StorageSlotUpgradeable + .getAddressSlot(_IMPLEMENTATION_SLOT) + .value = _nftImplementation; + } + + /// Constructor that sets up the + constructor( + address _nftImplementation, + string memory name, + string memory symbol, + ConfigSettings memory settings + ) { + /// Removed for gas saving reasons, the check below implictly accomplishes this + // require( + // _nftImplementation.supportsInterface( + // type(IBaseERC721Interface).interfaceId + // ) + // ); + _initImplementation(_nftImplementation); + (bool success, ) = _nftImplementation.delegatecall( + abi.encodeWithSignature( + "initialize(address,string,string,(uint16,string,string,bool))", + msg.sender, + name, + symbol, + settings + ) + ); + require(success); + } + + /// OnlyOwner implemntation that proxies to base ownable contract for info + modifier onlyOwner() { + require(msg.sender == base().__owner(), "Not owner"); + _; + } + + /// Getter to return the base implementation contract to call methods from + /// Don't expose base contract to parent due to need to call private internal base functions + function base() private view returns (IBaseERC721Interface) { + return IBaseERC721Interface(address(this)); + } + + // helpers to mimic Openzeppelin internal functions + + /// Getter for the contract owner + /// @return address owner address + function _owner() internal view returns (address) { + return base().__owner(); + } + + /// Internal burn function, only accessible from within contract + /// @param id nft id to burn + function _burn(uint256 id) internal { + base().__burn(id); + } + + /// Internal mint function, only accessible from within contract + /// @param to address to mint NFT to + /// @param id nft id to mint + function _mint(address to, uint256 id) internal { + base().__mint(to, id); + } + + /// Internal exists function to determine if fn exists + /// @param id nft id to check if exists + function _exists(uint256 id) internal view returns (bool) { + return base().__exists(id); + } + + /// Internal getter for tokenURI + /// @param tokenId id of token to get tokenURI for + function _tokenURI(uint256 tokenId) internal view returns (string memory) { + return base().__tokenURI(tokenId); + } + + /// is approved for all getter underlying getter + /// @param owner to check + /// @param operator to check + function _isApprovedForAll(address owner, address operator) + internal + view + returns (bool) + { + return base().__isApprovedForAll(owner, operator); + } + + /// Internal getter for approved or owner for a given operator + /// @param operator address of operator to check + /// @param id id of nft to check for + function _isApprovedOrOwner(address operator, uint256 id) + internal + view + returns (bool) + { + return base().__isApprovedOrOwner(operator, id); + } + + /// Sets the base URI of the contract. Allowed only by parent contract + /// @param newUri new uri base (http://URI) followed by number string of nft followed by extension string + /// @param newExtension optional uri extension + function _setBaseURI(string memory newUri, string memory newExtension) + internal + { + base().__setBaseURI(newUri, newExtension); + } + + /** + * @dev Delegates the current call to nftImplementation. + * + * This function does not return to its internall call site, it will return directly to the external caller. + */ + function _fallback() internal virtual { + address impl = implementation(); + + assembly { + // Copy msg.data. We take full control of memory in this inline assembly + // block because it will not return to Solidity code. We overwrite the + // Solidity scratch pad at memory position 0. + calldatacopy(0, 0, calldatasize()) + + // Call the implementation. + // out and outsize are 0 because we don't know the size yet. + let result := delegatecall(gas(), impl, 0, calldatasize(), 0, 0) + + // Copy the returned data. + returndatacopy(0, 0, returndatasize()) + + switch result + // delegatecall returns 0 on error. + case 0 { + revert(0, returndatasize()) + } + default { + return(0, returndatasize()) + } + } + } + + /** + * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other + * function in the contract matches the call data. + */ + fallback() external virtual { + _fallback(); + } + + /** + * @dev No base NFT functions receive any value + */ + receive() external payable { + revert(); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/security/ReentrancyGuard.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor() { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and make it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Counters.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @title Counters + * @author Matt Condon (@shrugs) + * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number + * of elements in a mapping, issuing ERC721 ids, or counting request ids. + * + * Include with `using Counters for Counters.Counter;` + */ +library Counters { + struct Counter { + // This variable should never be directly accessed by users of the library: interactions must be restricted to + // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add + // this feature: see https://github.com/ethereum/solidity/issues/4637 + uint256 _value; // default: 0 + } + + function current(Counter storage counter) internal view returns (uint256) { + return counter._value; + } + + function increment(Counter storage counter) internal { + unchecked { + counter._value += 1; + } + } + + function decrement(Counter storage counter) internal { + uint256 value = counter._value; + require(value > 0, "Counter: decrement overflow"); + unchecked { + counter._value = value - 1; + } + } + + function reset(Counter storage counter) internal { + counter._value = 0; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + assembly { + size := extcodesize(account) + } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./IERC721Upgradeable.sol"; +import "./IERC721ReceiverUpgradeable.sol"; +import "./extensions/IERC721MetadataUpgradeable.sol"; +import "../../utils/AddressUpgradeable.sol"; +import "../../utils/ContextUpgradeable.sol"; +import "../../utils/StringsUpgradeable.sol"; +import "../../utils/introspection/ERC165Upgradeable.sol"; +import "../../proxy/utils/Initializable.sol"; + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including + * the Metadata extension, but not including the Enumerable extension, which is available separately as + * {ERC721Enumerable}. + */ +contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable { + using AddressUpgradeable for address; + using StringsUpgradeable for uint256; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to owner address + mapping(uint256 => address) private _owners; + + // Mapping owner address to token count + mapping(address => uint256) private _balances; + + // Mapping from token ID to approved address + mapping(uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + function __ERC721_init(string memory name_, string memory symbol_) internal initializer { + __Context_init_unchained(); + __ERC165_init_unchained(); + __ERC721_init_unchained(name_, symbol_); + } + + function __ERC721_init_unchained(string memory name_, string memory symbol_) internal initializer { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165Upgradeable) returns (bool) { + return + interfaceId == type(IERC721Upgradeable).interfaceId || + interfaceId == type(IERC721MetadataUpgradeable).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view virtual override returns (uint256) { + require(owner != address(0), "ERC721: balance query for the zero address"); + return _balances[owner]; + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view virtual override returns (address) { + address owner = _owners[tokenId]; + require(owner != address(0), "ERC721: owner query for nonexistent token"); + return owner; + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, can be overriden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ""; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public virtual override { + address owner = ERC721Upgradeable.ownerOf(tokenId); + require(to != owner, "ERC721: approval to current owner"); + + require( + _msgSender() == owner || isApprovedForAll(owner, _msgSender()), + "ERC721: approve caller is not owner nor approved for all" + ); + + _approve(to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view virtual override returns (address) { + require(_exists(tokenId), "ERC721: approved query for nonexistent token"); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + require(operator != _msgSender(), "ERC721: approve to caller"); + + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + + _transfer(from, to, tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + safeTransferFrom(from, to, tokenId, ""); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) public virtual override { + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + _safeTransfer(from, to, tokenId, _data); + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * `_data` is additional data, it has no specified format and it is sent in call to `to`. + * + * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. + * implement alternative mechanisms to perform token transfer, such as signature-based. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeTransfer( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) internal virtual { + _transfer(from, to, tokenId); + require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + * and stop existing when they are burned (`_burn`). + */ + function _exists(uint256 tokenId) internal view virtual returns (bool) { + return _owners[tokenId] != address(0); + } + + /** + * @dev Returns whether `spender` is allowed to manage `tokenId`. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { + require(_exists(tokenId), "ERC721: operator query for nonexistent token"); + address owner = ERC721Upgradeable.ownerOf(tokenId); + return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); + } + + /** + * @dev Safely mints `tokenId` and transfers it to `to`. + * + * Requirements: + * + * - `tokenId` must not exist. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeMint(address to, uint256 tokenId) internal virtual { + _safeMint(to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeMint( + address to, + uint256 tokenId, + bytes memory _data + ) internal virtual { + _mint(to, tokenId); + require( + _checkOnERC721Received(address(0), to, tokenId, _data), + "ERC721: transfer to non ERC721Receiver implementer" + ); + } + + /** + * @dev Mints `tokenId` and transfers it to `to`. + * + * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * Emits a {Transfer} event. + */ + function _mint(address to, uint256 tokenId) internal virtual { + require(to != address(0), "ERC721: mint to the zero address"); + require(!_exists(tokenId), "ERC721: token already minted"); + + _beforeTokenTransfer(address(0), to, tokenId); + + _balances[to] += 1; + _owners[tokenId] = to; + + emit Transfer(address(0), to, tokenId); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId) internal virtual { + address owner = ERC721Upgradeable.ownerOf(tokenId); + + _beforeTokenTransfer(owner, address(0), tokenId); + + // Clear approvals + _approve(address(0), tokenId); + + _balances[owner] -= 1; + delete _owners[tokenId]; + + emit Transfer(owner, address(0), tokenId); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer( + address from, + address to, + uint256 tokenId + ) internal virtual { + require(ERC721Upgradeable.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); + require(to != address(0), "ERC721: transfer to the zero address"); + + _beforeTokenTransfer(from, to, tokenId); + + // Clear approvals from the previous owner + _approve(address(0), tokenId); + + _balances[from] -= 1; + _balances[to] += 1; + _owners[tokenId] = to; + + emit Transfer(from, to, tokenId); + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * Emits a {Approval} event. + */ + function _approve(address to, uint256 tokenId) internal virtual { + _tokenApprovals[tokenId] = to; + emit Approval(ERC721Upgradeable.ownerOf(tokenId), to, tokenId); + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * The call is not executed if the target address is not a contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) private returns (bool) { + if (to.isContract()) { + try IERC721ReceiverUpgradeable(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { + return retval == IERC721ReceiverUpgradeable.onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert("ERC721: transfer to non ERC721Receiver implementer"); + } else { + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } else { + return true; + } + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, ``from``'s `tokenId` will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId + ) internal virtual {} + uint256[44] private __gap; +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts-upgradeable/interfaces/IERC2981Upgradeable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./IERC165Upgradeable.sol"; + +/** + * @dev Interface for the NFT Royalty Standard + */ +interface IERC2981Upgradeable is IERC165Upgradeable { + /** + * @dev Called with the sale price to determine how much royalty is owed and to whom. + * @param tokenId - the NFT asset queried for royalty information + * @param salePrice - the sale price of the NFT asset specified by `tokenId` + * @return receiver - address of who should be sent the royalty payment + * @return royaltyAmount - the royalty payment amount for `salePrice` + */ + function royaltyInfo(uint256 tokenId, uint256 salePrice) + external + view + returns (address receiver, uint256 royaltyAmount); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/ContextUpgradeable.sol"; +import "../proxy/utils/Initializable.sol"; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + function __Ownable_init() internal initializer { + __Context_init_unchained(); + __Ownable_init_unchained(); + } + + function __Ownable_init_unchained() internal initializer { + _setOwner(_msgSender()); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _setOwner(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _setOwner(newOwner); + } + + function _setOwner(address newOwner) private { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } + uint256[49] private __gap; +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev String operations. + */ +library StringsUpgradeable { + bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + // Inspired by OraclizeAPI's implementation - MIT licence + // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol + + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + while (value != 0) { + digits -= 1; + buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); + value /= 10; + } + return string(buffer); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + if (value == 0) { + return "0x00"; + } + uint256 temp = value; + uint256 length = 0; + while (temp != 0) { + length++; + temp >>= 8; + } + return toHexString(value, length); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _HEX_SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @title Counters + * @author Matt Condon (@shrugs) + * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number + * of elements in a mapping, issuing ERC721 ids, or counting request ids. + * + * Include with `using Counters for Counters.Counter;` + */ +library CountersUpgradeable { + struct Counter { + // This variable should never be directly accessed by users of the library: interactions must be restricted to + // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add + // this feature: see https://github.com/ethereum/solidity/issues/4637 + uint256 _value; // default: 0 + } + + function current(Counter storage counter) internal view returns (uint256) { + return counter._value; + } + + function increment(Counter storage counter) internal { + unchecked { + counter._value += 1; + } + } + + function decrement(Counter storage counter) internal { + uint256 value = counter._value; + require(value > 0, "Counter: decrement overflow"); + unchecked { + counter._value = value - 1; + } + } + + function reset(Counter storage counter) internal { + counter._value = 0; + } +} + + +/////////////////////////////////////////// +// File: gwei-slim-nft-contracts/contracts/base/IBaseERC721Interface.sol + +// SPDX-License-Identifier: GPL-3.0 +pragma solidity 0.8.9; + +/// Additional features and functions assigned to the +/// Base721 contract for hooks and overrides +interface IBaseERC721Interface { + /* + Exposing common NFT internal functionality for base contract overrides + To save gas and make API cleaner this is only for new functionality not exposed in + the core ERC721 contract + */ + + /// Mint an NFT. Allowed to mint by owner, approval or by the parent contract + /// @param tokenId id to burn + function __burn(uint256 tokenId) external; + + /// Mint an NFT. Allowed only by the parent contract + /// @param to address to mint to + /// @param tokenId token id to mint + function __mint(address to, uint256 tokenId) external; + + /// Set the base URI of the contract. Allowed only by parent contract + /// @param base base uri + /// @param extension extension + function __setBaseURI(string memory base, string memory extension) external; + + /* Exposes common internal read features for public use */ + + /// Token exists + /// @param tokenId token id to see if it exists + function __exists(uint256 tokenId) external view returns (bool); + + /// Simple approval for operation check on token for address + /// @param spender address spending/changing token + /// @param tokenId tokenID to change / operate on + function __isApprovedOrOwner(address spender, uint256 tokenId) + external + view + returns (bool); + + function __isApprovedForAll(address owner, address operator) + external + view + returns (bool); + + function __tokenURI(uint256 tokenId) external view returns (string memory); + + function __owner() external view returns (address); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts-upgradeable/utils/StorageSlotUpgradeable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Library for reading and writing primitive types to specific storage slots. + * + * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. + * This library helps with reading and writing to such slots without the need for inline assembly. + * + * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. + * + * Example usage to set ERC1967 implementation slot: + * ``` + * contract ERC1967 { + * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + * + * function _getImplementation() internal view returns (address) { + * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; + * } + * + * function _setImplementation(address newImplementation) internal { + * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); + * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; + * } + * } + * ``` + * + * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ + */ +library StorageSlotUpgradeable { + struct AddressSlot { + address value; + } + + struct BooleanSlot { + bool value; + } + + struct Bytes32Slot { + bytes32 value; + } + + struct Uint256Slot { + uint256 value; + } + + /** + * @dev Returns an `AddressSlot` with member `value` located at `slot`. + */ + function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `BooleanSlot` with member `value` located at `slot`. + */ + function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. + */ + function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `Uint256Slot` with member `value` located at `slot`. + */ + function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { + assembly { + r.slot := slot + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165Upgradeable.sol"; + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721Upgradeable is IERC165Upgradeable { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external; +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721ReceiverUpgradeable { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. + */ + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721MetadataUpgradeable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../IERC721Upgradeable.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721MetadataUpgradeable is IERC721Upgradeable { + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library AddressUpgradeable { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + assembly { + size := extcodesize(account) + } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +import "../proxy/utils/Initializable.sol"; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract ContextUpgradeable is Initializable { + function __Context_init() internal initializer { + __Context_init_unchained(); + } + + function __Context_init_unchained() internal initializer { + } + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } + uint256[50] private __gap; +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./IERC165Upgradeable.sol"; +import "../../proxy/utils/Initializable.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable { + function __ERC165_init() internal initializer { + __ERC165_init_unchained(); + } + + function __ERC165_init_unchained() internal initializer { + } + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165Upgradeable).interfaceId; + } + uint256[50] private __gap; +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + */ +abstract contract Initializable { + /** + * @dev Indicates that the contract has been initialized. + */ + bool private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Modifier to protect an initializer function from being invoked twice. + */ + modifier initializer() { + require(_initializing || !_initialized, "Initializable: contract is already initialized"); + + bool isTopLevelCall = !_initializing; + if (isTopLevelCall) { + _initializing = true; + _initialized = true; + } + + _; + + if (isTopLevelCall) { + _initializing = false; + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts-upgradeable/interfaces/IERC165Upgradeable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/introspection/IERC165Upgradeable.sol"; + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165Upgradeable { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + + diff --git a/ethabi/code/0xa19f0378a6f3f3361d8e962f3589ec28f4f8f159.yml b/ethabi/code/0xa19f0378a6f3f3361d8e962f3589ec28f4f8f159.yml new file mode 100644 index 0000000..5382dfa --- /dev/null +++ b/ethabi/code/0xa19f0378a6f3f3361d8e962f3589ec28f4f8f159.yml @@ -0,0 +1,12 @@ +--- +ContractName: V3Phunks +CompilerVersion: v0.8.9+commit.e5eed63a +OptimizationUsed: '1' +Runs: '200' +ConstructorArguments: '00000000000000000000000043955024b1985e2b933a59021500ae5f55b040910000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005168747470733a2f2f676174657761792e70696e6174612e636c6f75642f697066732f516d51636f5879594b6f6b7942487a4e33797844596750503235636d5a6b6d3547717035627a5a735444463763642f000000000000000000000000000000' +EVMVersion: Default +Library: '' +LicenseType: '' +Proxy: '0' +Implementation: '' +SwarmSource: '' diff --git a/ethabi/code/0xa82f3a61f002f83eba7d184c50bb2a8b359ca1ce.sol b/ethabi/code/0xa82f3a61f002f83eba7d184c50bb2a8b359ca1ce.sol new file mode 100644 index 0000000..80adabc --- /dev/null +++ b/ethabi/code/0xa82f3a61f002f83eba7d184c50bb2a8b359ca1ce.sol @@ -0,0 +1,1652 @@ +/////////////////////////////////////////// +// File: contracts/CryptoPhunks.sol + +// SPDX-License-Identifier: UNLICENSE +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; +import "@openzeppelin/contracts/utils/Counters.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; + +contract CryptoPhunks is Ownable, ERC721Enumerable, ReentrancyGuard { + using Counters for Counters.Counter; + using Strings for uint256; + + // You can use this hash to verify the image file containing all the phunks + string public constant imageHash = + "122dab9670c21ad538dafdbb87191c4d7114c389af616c42c54556aa2211b899"; + + constructor() ERC721("CryptoPhunks", "PHUNK") {} + + bool public isSaleOn = false; + bool public isFreeSaleOn = false; + + // this is to ensure free sale only happens once before real sale starts + bool public freeSaleHasHappened = false; + bool public saleHasBeenStarted = false; + + uint256 public constant MAX_MINTABLE_AT_ONCE = 50; + + uint256[10000] private _availableTokens; + uint256 private _numAvailableTokens = 10000; + + function numTotalPhunks() public view virtual returns (uint256) { + return 10000; + } + + function maxNumFreeDevPhunks() public view virtual returns (uint256) { + // max number of phunks we keeping + return 500; + } + + function maxNumFreePhunks() public view virtual returns (uint256) { + // how many phunks that will cost 0. + // the number we give away will be (700 - however many free dev phunks are minted) + return 700; + } + + function mint(uint256 _numToMint) public payable nonReentrant() { + require(isSaleOn || isFreeSaleOn, "Sale hasn't started."); + uint256 totalSupply = totalSupply(); + + if (isFreeSaleOn) { + require( + totalSupply < maxNumFreePhunks(), + "No more free phunks for sale." + ); + require(_numToMint == 1, "Can only mint one free phunk."); + require( + balanceOf(msg.sender) == 0, + "Can only receive a free phunk if you don't have a phunk already." + ); + } else { + require( + totalSupply < numTotalPhunks(), + "All phunks have been sold already." + ); + require( + totalSupply + _numToMint <= numTotalPhunks(), + "There aren't this many phunks left." + ); + uint256 costForMintingPhunks = getCostForMintingPhunks(_numToMint); + require( + msg.value >= costForMintingPhunks, + "Too little sent, please send more eth." + ); + if (msg.value > costForMintingPhunks) { + payable(msg.sender).transfer(msg.value - costForMintingPhunks); + } + } + + _mint(_numToMint); + } + + // internal minting function + function _mint(uint256 _numToMint) internal { + require(_numToMint <= MAX_MINTABLE_AT_ONCE, "Minting too many at once."); + + uint256 updatedNumAvailableTokens = _numAvailableTokens; + for (uint256 i = 0; i < _numToMint; i++) { + uint256 newTokenId = useRandomAvailableToken(_numToMint, i); + _safeMint(msg.sender, newTokenId); + updatedNumAvailableTokens--; + } + _numAvailableTokens = updatedNumAvailableTokens; + } + + function useRandomAvailableToken(uint256 _numToFetch, uint256 _i) + internal + returns (uint256) + { + uint256 randomNum = + uint256( + keccak256( + abi.encode( + msg.sender, + tx.gasprice, + block.number, + block.timestamp, + blockhash(block.number - 1), + _numToFetch, + _i + ) + ) + ); + + uint256 randomIndex = randomNum % _numAvailableTokens; + + uint256 valAtIndex = _availableTokens[randomIndex]; + uint256 result; + if (valAtIndex == 0) { + // This means the index itself is still an available token + result = randomIndex; + } else { + // This means the index itself is not an available token, but the val at that index is. + result = valAtIndex; + } + + uint256 lastIndex = _numAvailableTokens - 1; + if (randomIndex != lastIndex) { + // Replace the value at randomIndex, now that it's been used. + // Replace it with the data from the last index in the array, since we are going to decrease the array size afterwards. + uint256 lastValInArray = _availableTokens[lastIndex]; + if (lastValInArray == 0) { + // This means the index itself is still an available token + _availableTokens[randomIndex] = lastIndex; + } else { + // This means the index itself is not an available token, but the val at that index is. + _availableTokens[randomIndex] = lastValInArray; + } + } + + _numAvailableTokens--; + return result; + } + + function getCostForMintingPhunk(uint256 _numMinted) + private + view + returns (uint256) + { + if (isFreeSaleOn) { + return 0.00 ether; + } else if (_numMinted < 900) { + return 0.03 ether; + } else if (_numMinted < 1500) { + return 0.05 ether; + } else if (_numMinted < 3000) { + return 0.08 ether; + } else if (_numMinted < 4500) { + return 0.10 ether; + } else if (_numMinted < 5900) { + return 0.15 ether; + } else if (_numMinted < 7300) { + return 0.25 ether; + } else if (_numMinted < 8600) { + return 0.30 ether; + } else if (_numMinted < 9300) { + return 0.45 ether; + } else if (_numMinted < 9900) { + return 0.60 ether; + } else if (_numMinted < 10000) { + return 0.75 ether; + } + + return 0.0 ether; + } + + function getCostForMintingPhunks(uint256 _numToMint) + public + view + returns (uint256) + { + require( + totalSupply() + _numToMint <= numTotalPhunks(), + "There aren't this many phunks left." + ); + + uint256 _cost; + uint256 _index; + + for (_index; _index < _numToMint; _index++) { + _cost += getCostForMintingPhunk(totalSupply() + _index); + } + return _cost; + } + + function getPhunksBelongingToOwner(address _owner) + external + view + returns (uint256[] memory) + { + uint256 numPhunks = balanceOf(_owner); + if (numPhunks == 0) { + return new uint256[](0); + } else { + uint256[] memory result = new uint256[](numPhunks); + for (uint256 i = 0; i < numPhunks; i++) { + result[i] = tokenOfOwnerByIndex(_owner, i); + } + return result; + } + } + + /* + * Dev stuff. + */ + + // metadata URI + string private _baseTokenURI; + + function _baseURI() internal view virtual override returns (string memory) { + return _baseTokenURI; + } + + function tokenURI(uint256 _tokenId) + public + view + override + returns (string memory) + { + string memory base = _baseURI(); + string memory _tokenURI = Strings.toString(_tokenId); + + // If there is no base URI, return the token URI. + if (bytes(base).length == 0) { + return _tokenURI; + } + + return string(abi.encodePacked(base, _tokenURI)); + } + + // contract metadata URI for opensea + string public contractURI; + + /* + * Owner stuff + */ + + function startSale() public onlyOwner { + require( + !isFreeSaleOn, + "Can not start sale while free sale is on. End the free sale first." + ); + isSaleOn = true; + saleHasBeenStarted = true; + } + + function endSale() public onlyOwner { + isSaleOn = false; + } + + function startFreeSale() public onlyOwner { + require( + !saleHasBeenStarted, + "Can only start the free sale if the real sale hasn't started yet." + ); + isFreeSaleOn = true; + } + + function endFreeSale() public onlyOwner { + isFreeSaleOn = false; + freeSaleHasHappened = true; + } + + // URIs + function setBaseURI(string memory baseURI) external onlyOwner { + _baseTokenURI = baseURI; + } + + function setContractURI(string memory _contractURI) external onlyOwner { + contractURI = _contractURI; + } + + function withdrawMoney() public payable onlyOwner { + (bool success, ) = msg.sender.call{value: address(this).balance}(""); + require(success, "Transfer failed."); + } + + // special, reserved for devs + function ownerMint(uint256 _numToMint) public onlyOwner { + require( + !isSaleOn && !isFreeSaleOn && !freeSaleHasHappened && !saleHasBeenStarted, + "Owner mint cannot happen after free sale or real sale has started." + ); + + require( + balanceOf(msg.sender) < maxNumFreeDevPhunks(), + "Devs have already minted all available dev phunks." + ); + + // limit the number for minting + uint256 toMint; + if (_numToMint < MAX_MINTABLE_AT_ONCE) { + toMint = _numToMint; + } else { + toMint = MAX_MINTABLE_AT_ONCE; + } + + // mint the max number if possible + if (balanceOf(msg.sender) + toMint <= maxNumFreeDevPhunks()) { + _mint(toMint); + } else { + uint256 phunksLeftForDevs = maxNumFreeDevPhunks() - balanceOf(msg.sender); + // else mint as many as possible + _mint(phunksLeftForDevs); + } + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId + ) internal virtual override(ERC721Enumerable) { + super._beforeTokenTransfer(from, to, tokenId); + } + + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(ERC721Enumerable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/access/Ownable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor () { + address msgSender = _msgSender(); + _owner = msgSender; + emit OwnershipTransferred(address(0), msgSender); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/security/ReentrancyGuard.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor () { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and make it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/ERC721.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./IERC721.sol"; +import "./IERC721Receiver.sol"; +import "./extensions/IERC721Metadata.sol"; +import "../../utils/Address.sol"; +import "../../utils/Context.sol"; +import "../../utils/Strings.sol"; +import "../../utils/introspection/ERC165.sol"; + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including + * the Metadata extension, but not including the Enumerable extension, which is available separately as + * {ERC721Enumerable}. + */ +contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { + using Address for address; + using Strings for uint256; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to owner address + mapping (uint256 => address) private _owners; + + // Mapping owner address to token count + mapping (address => uint256) private _balances; + + // Mapping from token ID to approved address + mapping (uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping (address => mapping (address => bool)) private _operatorApprovals; + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + constructor (string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IERC721).interfaceId + || interfaceId == type(IERC721Metadata).interfaceId + || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view virtual override returns (uint256) { + require(owner != address(0), "ERC721: balance query for the zero address"); + return _balances[owner]; + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view virtual override returns (address) { + address owner = _owners[tokenId]; + require(owner != address(0), "ERC721: owner query for nonexistent token"); + return owner; + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length > 0 + ? string(abi.encodePacked(baseURI, tokenId.toString())) + : ''; + } + + /** + * @dev Base URI for computing {tokenURI}. Empty by default, can be overriden + * in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ""; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public virtual override { + address owner = ERC721.ownerOf(tokenId); + require(to != owner, "ERC721: approval to current owner"); + + require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()), + "ERC721: approve caller is not owner nor approved for all" + ); + + _approve(to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view virtual override returns (address) { + require(_exists(tokenId), "ERC721: approved query for nonexistent token"); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + require(operator != _msgSender(), "ERC721: approve to caller"); + + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom(address from, address to, uint256 tokenId) public virtual override { + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + + _transfer(from, to, tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { + safeTransferFrom(from, to, tokenId, ""); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override { + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + _safeTransfer(from, to, tokenId, _data); + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * `_data` is additional data, it has no specified format and it is sent in call to `to`. + * + * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. + * implement alternative mechanisms to perform token transfer, such as signature-based. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual { + _transfer(from, to, tokenId); + require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + * and stop existing when they are burned (`_burn`). + */ + function _exists(uint256 tokenId) internal view virtual returns (bool) { + return _owners[tokenId] != address(0); + } + + /** + * @dev Returns whether `spender` is allowed to manage `tokenId`. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { + require(_exists(tokenId), "ERC721: operator query for nonexistent token"); + address owner = ERC721.ownerOf(tokenId); + return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); + } + + /** + * @dev Safely mints `tokenId` and transfers it to `to`. + * + * Requirements: + * + * - `tokenId` must not exist. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeMint(address to, uint256 tokenId) internal virtual { + _safeMint(to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual { + _mint(to, tokenId); + require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Mints `tokenId` and transfers it to `to`. + * + * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * Emits a {Transfer} event. + */ + function _mint(address to, uint256 tokenId) internal virtual { + require(to != address(0), "ERC721: mint to the zero address"); + require(!_exists(tokenId), "ERC721: token already minted"); + + _beforeTokenTransfer(address(0), to, tokenId); + + _balances[to] += 1; + _owners[tokenId] = to; + + emit Transfer(address(0), to, tokenId); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId) internal virtual { + address owner = ERC721.ownerOf(tokenId); + + _beforeTokenTransfer(owner, address(0), tokenId); + + // Clear approvals + _approve(address(0), tokenId); + + _balances[owner] -= 1; + delete _owners[tokenId]; + + emit Transfer(owner, address(0), tokenId); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer(address from, address to, uint256 tokenId) internal virtual { + require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); + require(to != address(0), "ERC721: transfer to the zero address"); + + _beforeTokenTransfer(from, to, tokenId); + + // Clear approvals from the previous owner + _approve(address(0), tokenId); + + _balances[from] -= 1; + _balances[to] += 1; + _owners[tokenId] = to; + + emit Transfer(from, to, tokenId); + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * Emits a {Approval} event. + */ + function _approve(address to, uint256 tokenId) internal virtual { + _tokenApprovals[tokenId] = to; + emit Approval(ERC721.ownerOf(tokenId), to, tokenId); + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * The call is not executed if the target address is not a contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) + private returns (bool) + { + if (to.isContract()) { + try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { + return retval == IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert("ERC721: transfer to non ERC721Receiver implementer"); + } else { + // solhint-disable-next-line no-inline-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } else { + return true; + } + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, ``from``'s `tokenId` will be burned. + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "./IERC721Enumerable.sol"; + +/** + * @dev This implements an optional extension of {ERC721} defined in the EIP that adds + * enumerability of all the token ids in the contract as well as all token ids owned by each + * account. + */ +abstract contract ERC721Enumerable is ERC721, IERC721Enumerable { + // Mapping from owner to list of owned token IDs + mapping(address => mapping(uint256 => uint256)) private _ownedTokens; + + // Mapping from token ID to index of the owner tokens list + mapping(uint256 => uint256) private _ownedTokensIndex; + + // Array with all token ids, used for enumeration + uint256[] private _allTokens; + + // Mapping from token id to position in the allTokens array + mapping(uint256 => uint256) private _allTokensIndex; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { + return interfaceId == type(IERC721Enumerable).interfaceId + || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { + require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); + return _ownedTokens[owner][index]; + } + + /** + * @dev See {IERC721Enumerable-totalSupply}. + */ + function totalSupply() public view virtual override returns (uint256) { + return _allTokens.length; + } + + /** + * @dev See {IERC721Enumerable-tokenByIndex}. + */ + function tokenByIndex(uint256 index) public view virtual override returns (uint256) { + require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds"); + return _allTokens[index]; + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, ``from``'s `tokenId` will be burned. + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override { + super._beforeTokenTransfer(from, to, tokenId); + + if (from == address(0)) { + _addTokenToAllTokensEnumeration(tokenId); + } else if (from != to) { + _removeTokenFromOwnerEnumeration(from, tokenId); + } + if (to == address(0)) { + _removeTokenFromAllTokensEnumeration(tokenId); + } else if (to != from) { + _addTokenToOwnerEnumeration(to, tokenId); + } + } + + /** + * @dev Private function to add a token to this extension's ownership-tracking data structures. + * @param to address representing the new owner of the given token ID + * @param tokenId uint256 ID of the token to be added to the tokens list of the given address + */ + function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { + uint256 length = ERC721.balanceOf(to); + _ownedTokens[to][length] = tokenId; + _ownedTokensIndex[tokenId] = length; + } + + /** + * @dev Private function to add a token to this extension's token tracking data structures. + * @param tokenId uint256 ID of the token to be added to the tokens list + */ + function _addTokenToAllTokensEnumeration(uint256 tokenId) private { + _allTokensIndex[tokenId] = _allTokens.length; + _allTokens.push(tokenId); + } + + /** + * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that + * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for + * gas optimizations e.g. when performing a transfer operation (avoiding double writes). + * This has O(1) time complexity, but alters the order of the _ownedTokens array. + * @param from address representing the previous owner of the given token ID + * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address + */ + function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { + // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and + // then delete the last slot (swap and pop). + + uint256 lastTokenIndex = ERC721.balanceOf(from) - 1; + uint256 tokenIndex = _ownedTokensIndex[tokenId]; + + // When the token to delete is the last token, the swap operation is unnecessary + if (tokenIndex != lastTokenIndex) { + uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; + + _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token + _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index + } + + // This also deletes the contents at the last position of the array + delete _ownedTokensIndex[tokenId]; + delete _ownedTokens[from][lastTokenIndex]; + } + + /** + * @dev Private function to remove a token from this extension's token tracking data structures. + * This has O(1) time complexity, but alters the order of the _allTokens array. + * @param tokenId uint256 ID of the token to be removed from the tokens list + */ + function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { + // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and + // then delete the last slot (swap and pop). + + uint256 lastTokenIndex = _allTokens.length - 1; + uint256 tokenIndex = _allTokensIndex[tokenId]; + + // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so + // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding + // an 'if' statement (like in _removeTokenFromOwnerEnumeration) + uint256 lastTokenId = _allTokens[lastTokenIndex]; + + _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token + _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index + + // This also deletes the contents at the last position of the array + delete _allTokensIndex[tokenId]; + _allTokens.pop(); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Counters.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @title Counters + * @author Matt Condon (@shrugs) + * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number + * of elements in a mapping, issuing ERC721 ids, or counting request ids. + * + * Include with `using Counters for Counters.Counter;` + */ +library Counters { + struct Counter { + // This variable should never be directly accessed by users of the library: interactions must be restricted to + // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add + // this feature: see https://github.com/ethereum/solidity/issues/4637 + uint256 _value; // default: 0 + } + + function current(Counter storage counter) internal view returns (uint256) { + return counter._value; + } + + function increment(Counter storage counter) internal { + unchecked { + counter._value += 1; + } + } + + function decrement(Counter storage counter) internal { + uint256 value = counter._value; + require(value > 0, "Counter: decrement overflow"); + unchecked { + counter._value = value - 1; + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Strings.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant alphabet = "0123456789abcdef"; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + // Inspired by OraclizeAPI's implementation - MIT licence + // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol + + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + while (value != 0) { + digits -= 1; + buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); + value /= 10; + } + return string(buffer); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + if (value == 0) { + return "0x00"; + } + uint256 temp = value; + uint256 length = 0; + while (temp != 0) { + length++; + temp >>= 8; + } + return toHexString(value, length); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = alphabet[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } + +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/IERC721.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. + */ + function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/introspection/ERC165.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/introspection/IERC165.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Enumerable is IERC721 { + + /** + * @dev Returns the total amount of tokens stored by the contract. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns a token ID owned by `owner` at a given `index` of its token list. + * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); + + /** + * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. + * Use along with {totalSupply} to enumerate all tokens. + */ + function tokenByIndex(uint256 index) external view returns (uint256); +} + + diff --git a/ethabi/code/0xa82f3a61f002f83eba7d184c50bb2a8b359ca1ce.yml b/ethabi/code/0xa82f3a61f002f83eba7d184c50bb2a8b359ca1ce.yml new file mode 100644 index 0000000..597ce8b --- /dev/null +++ b/ethabi/code/0xa82f3a61f002f83eba7d184c50bb2a8b359ca1ce.yml @@ -0,0 +1,12 @@ +--- +ContractName: CryptoPhunks +CompilerVersion: v0.8.4+commit.c7e474f2 +OptimizationUsed: '1' +Runs: '500' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: '' +Proxy: '0' +Implementation: '' +SwarmSource: '' diff --git a/ethabi/code/0xad8474ba5a7f6abc52708f171f57fefc5cdc8c1c.sol b/ethabi/code/0xad8474ba5a7f6abc52708f171f57fefc5cdc8c1c.sol new file mode 100644 index 0000000..84ef22d --- /dev/null +++ b/ethabi/code/0xad8474ba5a7f6abc52708f171f57fefc5cdc8c1c.sol @@ -0,0 +1,2746 @@ +/////////////////////////////////////////// +// File: /var/app/current/contracts/Indelible.sol + + + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.4; + + import "erc721a/contracts/ERC721A.sol"; + import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; + import "@openzeppelin/contracts/access/Ownable.sol"; + import "@openzeppelin/contracts/utils/Base64.sol"; + import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; + import "@openzeppelin/contracts/utils/Address.sol"; + import "./SSTORE2.sol"; + import "./DynamicBuffer.sol"; + import "./HelperLib.sol"; + + contract Indelible is ERC721A, ReentrancyGuard, Ownable { + using HelperLib for uint; + using DynamicBuffer for bytes; + + struct LinkedTraitDTO { + uint[] traitA; + uint[] traitB; + } + + struct TraitDTO { + string name; + string mimetype; + bytes data; + bool useExistingData; + uint existingDataIndex; + } + + struct Trait { + string name; + string mimetype; + } + + struct ContractData { + string name; + string description; + string image; + string banner; + string website; + uint royalties; + string royaltiesRecipient; + } + + mapping(uint => address[]) internal _traitDataPointers; + mapping(uint => mapping(uint => Trait)) internal _traitDetails; + mapping(uint => bool) internal _renderTokenOffChain; + mapping(uint => mapping(uint => uint[])) internal _linkedTraits; + + uint private constant DEVELOPER_FEE = 250; // of 10,000 = 2.5% + uint private constant NUM_LAYERS = 8; + uint private constant MAX_BATCH_MINT = 20; + uint[][NUM_LAYERS] private TIERS; + string[] private LAYER_NAMES = [unicode"Mouth Accessory", unicode"Neck Accessory", unicode"Eye Accessory", unicode"Earring", unicode"Headgear", unicode"Face Spot", unicode"Base", unicode"Background"]; + bool private shouldWrapSVG = true; + string private backgroundColor = "transparent"; + + bool public isContractSealed; + uint public constant maxSupply = 4500; + uint public maxPerAddress = 20; + uint public publicMintPrice = 0.030 ether; + string public baseURI = ""; + bool public isPublicMintActive; + + bytes32 private merkleRoot; + uint public allowListPrice = 0.000 ether; + uint public maxPerAllowList = 1; + bool public isAllowListActive; + + ContractData public contractData = ContractData(unicode"Mad Camels", unicode"Fully on-chain NFT collection of 4500 items.", "https://indeliblelabs-prod.s3.us-east-2.amazonaws.com/profile/00a7b751-03a5-4541-9c1a-19d303368d0f", "https://indeliblelabs-prod.s3.us-east-2.amazonaws.com/banner/00a7b751-03a5-4541-9c1a-19d303368d0f", "https://madcamels.com", 600, "0xfDf474098aCDaEC5BF8b4F7798b3E64Da0d60f57"); + + constructor() ERC721A(unicode"Mad Camels", unicode"CAMEL") { + TIERS[0] = [99,369,475,1146,1159,1252]; +TIERS[1] = [578,902,942,2078]; +TIERS[2] = [26,40,72,78,79,92,117,138,239,248,305,316,338,513,541,635,723]; +TIERS[3] = [745,855,1324,1576]; +TIERS[4] = [18,28,32,33,39,44,45,60,66,68,111,114,119,121,130,134,161,168,181,182,187,201,228,239,276,287,295,301,311,321]; +TIERS[5] = [170,210,4120]; +TIERS[6] = [1,61,119,152,210,612,1224,2121]; +TIERS[7] = [66,431,530,1063,1198,1212]; + } + + modifier whenMintActive() { + require(isMintActive(), "Minting is not active"); + _; + } + + modifier whenUnsealed() { + require(!isContractSealed, "Contract is sealed"); + _; + } + + receive() external payable { + require(isPublicMintActive, "Public minting is not active"); + handleMint(msg.value / publicMintPrice); + } + + function rarityGen(uint _randinput, uint _rarityTier) + internal + view + returns (uint) + { + uint currentLowerBound = 0; + for (uint i = 0; i < TIERS[_rarityTier].length; i++) { + uint thisPercentage = TIERS[_rarityTier][i]; + if ( + _randinput >= currentLowerBound && + _randinput < currentLowerBound + thisPercentage + ) return i; + currentLowerBound = currentLowerBound + thisPercentage; + } + + revert(); + } + + function entropyForExtraData() internal view returns (uint24) { + uint randomNumber = uint( + keccak256( + abi.encodePacked( + tx.gasprice, + block.number, + block.timestamp, + block.difficulty, + blockhash(block.number - 1), + msg.sender + ) + ) + ); + return uint24(randomNumber); + } + + function stringCompare(string memory a, string memory b) internal pure returns (bool) { + return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b)); + } + + function tokensAreDuplicates(uint tokenIdA, uint tokenIdB) public view returns (bool) { + return stringCompare( + tokenIdToHash(tokenIdA), + tokenIdToHash(tokenIdB) + ); + } + + function reRollDuplicate( + uint tokenIdA, + uint tokenIdB + ) public whenUnsealed { + require(tokensAreDuplicates(tokenIdA, tokenIdB), "All tokens must be duplicates"); + + uint largerTokenId = tokenIdA > tokenIdB ? tokenIdA : tokenIdB; + + if (msg.sender != owner()) { + require(msg.sender == ownerOf(largerTokenId), "Only the token owner or contract owner can re-roll"); + } + + _initializeOwnershipAt(largerTokenId); + if (_exists(largerTokenId + 1)) { + _initializeOwnershipAt(largerTokenId + 1); + } + + _setExtraDataAt(largerTokenId, entropyForExtraData()); + } + + function _extraData( + address from, + address to, + uint24 previousExtraData + ) internal view virtual override returns (uint24) { + return from == address(0) ? entropyForExtraData() : previousExtraData; + } + + function getTokenSeed(uint _tokenId) internal view returns (uint24) { + return _ownershipOf(_tokenId).extraData; + } + + function tokenIdToHash( + uint _tokenId + ) public view returns (string memory) { + require(_exists(_tokenId), "Invalid token"); + // This will generate a NUM_LAYERS * 3 character string. + bytes memory hashBytes = DynamicBuffer.allocate(NUM_LAYERS * 4); + + uint[] memory hash = new uint[](NUM_LAYERS); + bool[] memory modifiedLayers = new bool[](NUM_LAYERS); + + for (uint i = 0; i < NUM_LAYERS; i++) { + uint traitIndex = hash[i]; + if (modifiedLayers[i] == false) { + uint _randinput = uint( + uint( + keccak256( + abi.encodePacked( + getTokenSeed(_tokenId), + _tokenId, + _tokenId + i + ) + ) + ) % maxSupply + ); + + traitIndex = rarityGen(_randinput, i); + hash[i] = traitIndex; + } + + if (_linkedTraits[i][traitIndex].length > 0) { + hash[_linkedTraits[i][traitIndex][0]] = _linkedTraits[i][traitIndex][1]; + modifiedLayers[_linkedTraits[i][traitIndex][0]] = true; + } + } + + for (uint i = 0; i < hash.length; i++) { + if (hash[i] < 10) { + hashBytes.appendSafe("00"); + } else if (hash[i] < 100) { + hashBytes.appendSafe("0"); + } + if (hash[i] > 999) { + hashBytes.appendSafe("999"); + } else { + hashBytes.appendSafe(bytes(_toString(hash[i]))); + } + } + + return string(hashBytes); + } + + function handleMint(uint256 _count) internal whenMintActive returns (uint256) { + uint256 totalMinted = _totalMinted(); + require(_count > 0, "Invalid token count"); + require(totalMinted + _count <= maxSupply, "All tokens are gone"); + + + if (isPublicMintActive) { + if (msg.sender != owner()) { + require(_numberMinted(msg.sender) + _count <= maxPerAddress, "Exceeded max mints allowed"); + } + require(msg.sender == tx.origin, "EOAs only"); + require(_count * publicMintPrice == msg.value, "Incorrect amount of ether sent"); + } + + uint256 batchCount = _count / MAX_BATCH_MINT; + uint256 remainder = _count % MAX_BATCH_MINT; + + for (uint256 i = 0; i < batchCount; i++) { + _mint(msg.sender, MAX_BATCH_MINT); + } + + if (remainder > 0) { + _mint(msg.sender, remainder); + } + + return totalMinted; + } + + function mint(uint256 _count, bytes32[] calldata merkleProof) + external + payable + nonReentrant + whenMintActive + returns (uint) + { + + if (!isPublicMintActive) { + if (msg.sender != owner()) { + require(onAllowList(msg.sender, merkleProof), "Not on allow list"); + require(_numberMinted(msg.sender) + _count <= maxPerAllowList, "Exceeded max mints allowed"); + } + require(_count * allowListPrice == msg.value, "Incorrect amount of ether sent"); + } + + uint256 totalMinted = handleMint(_count); + + return totalMinted; + } + + function isMintActive() public view returns (bool) { + return _totalMinted() < maxSupply && (isPublicMintActive || isAllowListActive); + } + + function hashToSVG(string memory _hash) + public + view + returns (string memory) + { + uint thisTraitIndex; + + bytes memory svgBytes = DynamicBuffer.allocate(1024 * 128); + svgBytes.appendSafe('' + ) + ); + + return string( + abi.encodePacked( + "data:image/svg+xml;base64,", + Base64.encode(svgBytes) + ) + ); + } + + function hashToMetadata(string memory _hash) + public + view + returns (string memory) + { + bytes memory metadataBytes = DynamicBuffer.allocate(1024 * 128); + metadataBytes.appendSafe("["); + + for (uint i = 0; i < NUM_LAYERS; i++) { + uint thisTraitIndex = HelperLib.parseInt( + HelperLib._substring(_hash, (i * 3), (i * 3) + 3) + ); + metadataBytes.appendSafe( + abi.encodePacked( + '{"trait_type":"', + LAYER_NAMES[i], + '","value":"', + _traitDetails[i][thisTraitIndex].name, + '"}' + ) + ); + + if (i == NUM_LAYERS - 1) { + metadataBytes.appendSafe("]"); + } else { + metadataBytes.appendSafe(","); + } + } + + return string(metadataBytes); + } + + + function onAllowList(address addr, bytes32[] calldata merkleProof) public view returns (bool) { + return MerkleProof.verify(merkleProof, merkleRoot, keccak256(abi.encodePacked(addr))); + } + + + function tokenURI(uint _tokenId) + public + view + override + returns (string memory) + { + require(_exists(_tokenId), "Invalid token"); + require(_traitDataPointers[0].length > 0, "Traits have not been added"); + + string memory tokenHash = tokenIdToHash(_tokenId); + + bytes memory jsonBytes = DynamicBuffer.allocate(1024 * 128); + jsonBytes.appendSafe(unicode"{\"name\":\"Mad Camels #"); + + jsonBytes.appendSafe( + abi.encodePacked( + _toString(_tokenId), + "\",\"description\":\"", + contractData.description, + "\"," + ) + ); + + if (bytes(baseURI).length > 0 && _renderTokenOffChain[_tokenId]) { + jsonBytes.appendSafe( + abi.encodePacked( + '"image":"', + baseURI, + _toString(_tokenId), + "?dna=", + tokenHash, + '&network=mainnet",' + ) + ); + } else { + string memory svgCode = ""; + if (shouldWrapSVG) { + string memory svgString = hashToSVG(tokenHash); + svgCode = string( + abi.encodePacked( + "data:image/svg+xml;base64,", + Base64.encode( + abi.encodePacked( + '' + ) + ) + ) + ); + jsonBytes.appendSafe( + abi.encodePacked( + '"svg_image_data":"', + svgString, + '",' + ) + ); + } else { + svgCode = hashToSVG(tokenHash); + } + + jsonBytes.appendSafe( + abi.encodePacked( + '"image_data":"', + svgCode, + '",' + ) + ); + } + + jsonBytes.appendSafe( + abi.encodePacked( + '"attributes":', + hashToMetadata(tokenHash), + "}" + ) + ); + + return string( + abi.encodePacked( + "data:application/json;base64,", + Base64.encode(jsonBytes) + ) + ); + } + + function contractURI() + public + view + returns (string memory) + { + return string( + abi.encodePacked( + "data:application/json;base64,", + Base64.encode( + abi.encodePacked( + '{"name":"', + contractData.name, + '","description":"', + contractData.description, + '","image":"', + contractData.image, + '","banner":"', + contractData.banner, + '","external_link":"', + contractData.website, + '","seller_fee_basis_points":', + _toString(contractData.royalties), + ',"fee_recipient":"', + contractData.royaltiesRecipient, + '"}' + ) + ) + ) + ); + } + + function tokenIdToSVG(uint _tokenId) + public + view + returns (string memory) + { + return hashToSVG(tokenIdToHash(_tokenId)); + } + + function traitDetails(uint _layerIndex, uint _traitIndex) + public + view + returns (Trait memory) + { + return _traitDetails[_layerIndex][_traitIndex]; + } + + function traitData(uint _layerIndex, uint _traitIndex) + public + view + returns (string memory) + { + return string(SSTORE2.read(_traitDataPointers[_layerIndex][_traitIndex])); + } + + function getLinkedTraits(uint _layerIndex, uint _traitIndex) + public + view + returns (uint[] memory) + { + return _linkedTraits[_layerIndex][_traitIndex]; + } + + function addLayer(uint _layerIndex, TraitDTO[] memory traits) + public + onlyOwner + whenUnsealed + { + require(TIERS[_layerIndex].length == traits.length, "Traits size does not match tiers for this index"); + address[] memory dataPointers = new address[](traits.length); + for (uint i = 0; i < traits.length; i++) { + if (traits[i].useExistingData) { + dataPointers[i] = dataPointers[traits[i].existingDataIndex]; + } else { + dataPointers[i] = SSTORE2.write(traits[i].data); + } + _traitDetails[_layerIndex][i] = Trait(traits[i].name, traits[i].mimetype); + } + _traitDataPointers[_layerIndex] = dataPointers; + return; + } + + function addTrait(uint _layerIndex, uint _traitIndex, TraitDTO memory trait) + public + onlyOwner + whenUnsealed + { + _traitDetails[_layerIndex][_traitIndex] = Trait(trait.name, trait.mimetype); + address[] memory dataPointers = _traitDataPointers[_layerIndex]; + if (trait.useExistingData) { + dataPointers[_traitIndex] = dataPointers[trait.existingDataIndex]; + } else { + dataPointers[_traitIndex] = SSTORE2.write(trait.data); + } + _traitDataPointers[_layerIndex] = dataPointers; + return; + } + + function setLinkedTraits(LinkedTraitDTO[] memory linkedTraits) + public + onlyOwner + whenUnsealed + { + for (uint i = 0; i < linkedTraits.length; i++) { + _linkedTraits[linkedTraits[i].traitA[0]][linkedTraits[i].traitA[1]] = [linkedTraits[i].traitB[0],linkedTraits[i].traitB[1]]; + } + } + + function setContractData(ContractData memory _contractData) external onlyOwner whenUnsealed { + contractData = _contractData; + } + + function setMaxPerAddress(uint _maxPerAddress) external onlyOwner { + maxPerAddress = _maxPerAddress; + } + + function setBaseURI(string memory _baseURI) external onlyOwner { + baseURI = _baseURI; + } + + function setBackgroundColor(string memory _backgroundColor) external onlyOwner whenUnsealed { + backgroundColor = _backgroundColor; + } + + function setRenderOfTokenId(uint _tokenId, bool _renderOffChain) external { + require(msg.sender == ownerOf(_tokenId), "Only the token owner can set the render method"); + _renderTokenOffChain[_tokenId] = _renderOffChain; + } + + + function setMerkleRoot(bytes32 newMerkleRoot) external onlyOwner { + merkleRoot = newMerkleRoot; + } + + function setMaxPerAllowList(uint _maxPerAllowList) external onlyOwner { + maxPerAllowList = _maxPerAllowList; + } + + function setAllowListPrice(uint _allowListPrice) external onlyOwner { + allowListPrice = _allowListPrice; + } + + function toggleAllowListMint() external onlyOwner { + isAllowListActive = !isAllowListActive; + } + + + function toggleWrapSVG() external onlyOwner { + shouldWrapSVG = !shouldWrapSVG; + } + + function togglePublicMint() external onlyOwner { + isPublicMintActive = !isPublicMintActive; + } + + function sealContract() external whenUnsealed onlyOwner { + isContractSealed = true; + } + + function withdraw() external onlyOwner nonReentrant { + uint balance = address(this).balance; + uint amount = (balance * (10000 - DEVELOPER_FEE)) / 10000; + + address payable receiver = payable(owner()); + address payable dev = payable(0xEA208Da933C43857683C04BC76e3FD331D7bfdf7); + + Address.sendValue(receiver, amount); + Address.sendValue(dev, balance - amount); + } + } + + +/////////////////////////////////////////// +// File: /var/app/current/contracts/DynamicBuffer.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) + +pragma solidity >=0.8.0; + +/// @title DynamicBuffer +/// @author David Huber (@cxkoda) and Simon Fremaux (@dievardump). See also +/// https://raw.githubusercontent.com/dievardump/solidity-dynamic-buffer +/// @notice This library is used to allocate a big amount of container memory +// which will be subsequently filled without needing to reallocate +/// memory. +/// @dev First, allocate memory. +/// Then use `buffer.appendUnchecked(theBytes)` or `appendSafe()` if +/// bounds checking is required. +library DynamicBuffer { + /// @notice Allocates container space for the DynamicBuffer + /// @param capacity The intended max amount of bytes in the buffer + /// @return buffer The memory location of the buffer + /// @dev Allocates `capacity + 0x60` bytes of space + /// The buffer array starts at the first container data position, + /// (i.e. `buffer = container + 0x20`) + function allocate(uint256 capacity) + internal + pure + returns (bytes memory buffer) + { + assembly { + // Get next-free memory address + let container := mload(0x40) + + // Allocate memory by setting a new next-free address + { + // Add 2 x 32 bytes in size for the two length fields + // Add 32 bytes safety space for 32B chunked copy + let size := add(capacity, 0x60) + let newNextFree := add(container, size) + mstore(0x40, newNextFree) + } + + // Set the correct container length + { + let length := add(capacity, 0x40) + mstore(container, length) + } + + // The buffer starts at idx 1 in the container (0 is length) + buffer := add(container, 0x20) + + // Init content with length 0 + mstore(buffer, 0) + } + + return buffer; + } + + /// @notice Appends data to buffer, and update buffer length + /// @param buffer the buffer to append the data to + /// @param data the data to append + /// @dev Does not perform out-of-bound checks (container capacity) + /// for efficiency. + function appendUnchecked(bytes memory buffer, bytes memory data) + internal + pure + { + assembly { + let length := mload(data) + for { + data := add(data, 0x20) + let dataEnd := add(data, length) + let copyTo := add(buffer, add(mload(buffer), 0x20)) + } lt(data, dataEnd) { + data := add(data, 0x20) + copyTo := add(copyTo, 0x20) + } { + // Copy 32B chunks from data to buffer. + // This may read over data array boundaries and copy invalid + // bytes, which doesn't matter in the end since we will + // later set the correct buffer length, and have allocated an + // additional word to avoid buffer overflow. + mstore(copyTo, mload(data)) + } + + // Update buffer length + mstore(buffer, add(mload(buffer), length)) + } + } + + /// @notice Appends data to buffer, and update buffer length + /// @param buffer the buffer to append the data to + /// @param data the data to append + /// @dev Performs out-of-bound checks and calls `appendUnchecked`. + function appendSafe(bytes memory buffer, bytes memory data) internal pure { + uint256 capacity; + uint256 length; + assembly { + capacity := sub(mload(sub(buffer, 0x20)), 0x40) + length := mload(buffer) + } + + require( + length + data.length <= capacity, + "DynamicBuffer: Appending out of bounds." + ); + appendUnchecked(buffer, data); + } +} + +/////////////////////////////////////////// +// File: /var/app/current/contracts/HelperLib.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.14; + +library HelperLib { + function parseInt(string memory _a) + internal + pure + returns (uint8 _parsedInt) + { + bytes memory bresult = bytes(_a); + uint8 mint = 0; + for (uint8 i = 0; i < bresult.length; i++) { + if ( + (uint8(uint8(bresult[i])) >= 48) && + (uint8(uint8(bresult[i])) <= 57) + ) { + mint *= 10; + mint += uint8(bresult[i]) - 48; + } + } + return mint; + } + + function _substring( + string memory str, + uint256 startIndex, + uint256 endIndex + ) internal pure returns (string memory) { + bytes memory strBytes = bytes(str); + bytes memory result = new bytes(endIndex - startIndex); + for (uint256 i = startIndex; i < endIndex; i++) { + result[i - startIndex] = strBytes[i]; + } + return string(result); + } +} + +/////////////////////////////////////////// +// File: /var/app/current/contracts/SSTORE2.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./utils/Bytecode.sol"; + +/** + @title A key-value storage with auto-generated keys for storing chunks of data with a lower write & read cost. + @author Agustin Aguilar + + Readme: https://github.com/0xsequence/sstore2#readme +*/ +library SSTORE2 { + error WriteError(); + + /** + @notice Stores `_data` and returns `pointer` as key for later retrieval + @dev The pointer is a contract address with `_data` as code + @param _data to be written + @return pointer Pointer to the written `_data` + */ + function write(bytes memory _data) internal returns (address pointer) { + // Append 00 to _data so contract can't be called + // Build init code + bytes memory code = Bytecode.creationCodeFor( + abi.encodePacked( + hex'00', + _data + ) + ); + + // Deploy contract using create + assembly { pointer := create(0, add(code, 32), mload(code)) } + + // Address MUST be non-zero + if (pointer == address(0)) revert WriteError(); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @return data read from `_pointer` contract + */ + function read(address _pointer) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, 1, type(uint256).max); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @param _start number of bytes to skip + @return data read from `_pointer` contract + */ + function read(address _pointer, uint256 _start) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, _start + 1, type(uint256).max); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @param _start number of bytes to skip + @param _end index before which to end extraction + @return data read from `_pointer` contract + */ + function read(address _pointer, uint256 _start, uint256 _end) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, _start + 1, _end + 1); + } +} + +/////////////////////////////////////////// +// File: /var/app/current/contracts/utils/Bytecode.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + + +library Bytecode { + error InvalidCodeAtRange(uint256 _size, uint256 _start, uint256 _end); + + /** + @notice Generate a creation code that results on a contract with `_code` as bytecode + @param _code The returning value of the resulting `creationCode` + @return creationCode (constructor) for new contract + */ + function creationCodeFor(bytes memory _code) internal pure returns (bytes memory) { + /* + 0x00 0x63 0x63XXXXXX PUSH4 _code.length size + 0x01 0x80 0x80 DUP1 size size + 0x02 0x60 0x600e PUSH1 14 14 size size + 0x03 0x60 0x6000 PUSH1 00 0 14 size size + 0x04 0x39 0x39 CODECOPY size + 0x05 0x60 0x6000 PUSH1 00 0 size + 0x06 0xf3 0xf3 RETURN + + */ + + return abi.encodePacked( + hex"63", + uint32(_code.length), + hex"80_60_0E_60_00_39_60_00_F3", + _code + ); + } + + /** + @notice Returns the size of the code on a given address + @param _addr Address that may or may not contain code + @return size of the code on the given `_addr` + */ + function codeSize(address _addr) internal view returns (uint256 size) { + assembly { size := extcodesize(_addr) } + } + + /** + @notice Returns the code of a given address + @dev It will fail if `_end < _start` + @param _addr Address that may or may not contain code + @param _start number of bytes of code to skip on read + @param _end index before which to end extraction + @return oCode read from `_addr` deployed bytecode + + Forked from: https://gist.github.com/KardanovIR/fe98661df9338c842b4a30306d507fbd + */ + function codeAt(address _addr, uint256 _start, uint256 _end) internal view returns (bytes memory oCode) { + uint256 csize = codeSize(_addr); + if (csize == 0) return bytes(""); + + if (_start > csize) return bytes(""); + if (_end < _start) revert InvalidCodeAtRange(csize, _start, _end); + + unchecked { + uint256 reqSize = _end - _start; + uint256 maxSize = csize - _start; + + uint256 size = maxSize < reqSize ? maxSize : reqSize; + + assembly { + // allocate output byte array - this could also be done without assembly + // by using o_code = new bytes(size) + oCode := mload(0x40) + // new "memory end" including padding + mstore(0x40, add(oCode, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + // store length in memory + mstore(oCode, size) + // actually retrieve the code, this needs assembly + extcodecopy(_addr, add(oCode, 0x20), _start, size) + } + } + } +} + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/access/Ownable.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor() { + _transferOwnership(_msgSender()); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/security/ReentrancyGuard.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor() { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and making it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) + +pragma solidity ^0.8.1; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + * + * [IMPORTANT] + * ==== + * You shouldn't rely on `isContract` to protect against flash loan attacks! + * + * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets + * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract + * constructor. + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize/address.code.length, which returns 0 + // for contracts in construction, since the code is only stored at the end + // of the constructor execution. + + return account.code.length > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Base64.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (utils/Base64.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides a set of functions to operate with Base64 strings. + * + * _Available since v4.5._ + */ +library Base64 { + /** + * @dev Base64 Encoding/Decoding Table + */ + string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** + * @dev Converts a `bytes` to its Bytes64 `string` representation. + */ + function encode(bytes memory data) internal pure returns (string memory) { + /** + * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence + * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol + */ + if (data.length == 0) return ""; + + // Loads the table into memory + string memory table = _TABLE; + + // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter + // and split into 4 numbers of 6 bits. + // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up + // - `data.length + 2` -> Round up + // - `/ 3` -> Number of 3-bytes chunks + // - `4 *` -> 4 characters for each chunk + string memory result = new string(4 * ((data.length + 2) / 3)); + + assembly { + // Prepare the lookup table (skip the first "length" byte) + let tablePtr := add(table, 1) + + // Prepare result pointer, jump over length + let resultPtr := add(result, 32) + + // Run over the input, 3 bytes at a time + for { + let dataPtr := data + let endPtr := add(data, mload(data)) + } lt(dataPtr, endPtr) { + + } { + // Advance 3 bytes + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + + // To write each character, shift the 3 bytes (18 bits) chunk + // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) + // and apply logical AND with 0x3F which is the number of + // the previous character in the ASCII table prior to the Base64 Table + // The result is then added to the table to get the character to write, + // and finally write it in the result pointer but with a left shift + // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits + + mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + } + + // When data `bytes` is not exactly 3 bytes long + // it is padded with `=` characters at the end + switch mod(mload(data), 3) + case 1 { + mstore8(sub(resultPtr, 1), 0x3d) + mstore8(sub(resultPtr, 2), 0x3d) + } + case 2 { + mstore8(sub(resultPtr, 1), 0x3d) + } + } + + return result; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/cryptography/MerkleProof.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (utils/cryptography/MerkleProof.sol) + +pragma solidity ^0.8.0; + +/** + * @dev These functions deal with verification of Merkle Trees proofs. + * + * The proofs can be generated using the JavaScript library + * https://github.com/miguelmota/merkletreejs[merkletreejs]. + * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled. + * + * See `test/utils/cryptography/MerkleProof.test.js` for some examples. + * + * WARNING: You should avoid using leaf values that are 64 bytes long prior to + * hashing, or use a hash function other than keccak256 for hashing leaves. + * This is because the concatenation of a sorted pair of internal nodes in + * the merkle tree could be reinterpreted as a leaf value. + */ +library MerkleProof { + /** + * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree + * defined by `root`. For this, a `proof` must be provided, containing + * sibling hashes on the branch from the leaf to the root of the tree. Each + * pair of leaves and each pair of pre-images are assumed to be sorted. + */ + function verify( + bytes32[] memory proof, + bytes32 root, + bytes32 leaf + ) internal pure returns (bool) { + return processProof(proof, leaf) == root; + } + + /** + * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up + * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt + * hash matches the root of the tree. When processing the proof, the pairs + * of leafs & pre-images are assumed to be sorted. + * + * _Available since v4.4._ + */ + function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + bytes32 proofElement = proof[i]; + if (computedHash <= proofElement) { + // Hash(current computed hash + current element of the proof) + computedHash = _efficientHash(computedHash, proofElement); + } else { + // Hash(current element of the proof + current computed hash) + computedHash = _efficientHash(proofElement, computedHash); + } + } + return computedHash; + } + + function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { + assembly { + mstore(0x00, a) + mstore(0x20, b) + value := keccak256(0x00, 0x40) + } + } +} + + +/////////////////////////////////////////// +// File: erc721a/contracts/ERC721A.sol + +// SPDX-License-Identifier: MIT +// ERC721A Contracts v4.1.0 +// Creator: Chiru Labs + +pragma solidity ^0.8.4; + +import './IERC721A.sol'; + +/** + * @dev ERC721 token receiver interface. + */ +interface ERC721A__IERC721Receiver { + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, + * including the Metadata extension. Built to optimize for lower gas during batch mints. + * + * Assumes serials are sequentially minted starting at `_startTokenId()` + * (defaults to 0, e.g. 0, 1, 2, 3..). + * + * Assumes that an owner cannot have more than 2**64 - 1 (max value of uint64) of supply. + * + * Assumes that the maximum token id cannot exceed 2**256 - 1 (max value of uint256). + */ +contract ERC721A is IERC721A { + // Mask of an entry in packed address data. + uint256 private constant BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1; + + // The bit position of `numberMinted` in packed address data. + uint256 private constant BITPOS_NUMBER_MINTED = 64; + + // The bit position of `numberBurned` in packed address data. + uint256 private constant BITPOS_NUMBER_BURNED = 128; + + // The bit position of `aux` in packed address data. + uint256 private constant BITPOS_AUX = 192; + + // Mask of all 256 bits in packed address data except the 64 bits for `aux`. + uint256 private constant BITMASK_AUX_COMPLEMENT = (1 << 192) - 1; + + // The bit position of `startTimestamp` in packed ownership. + uint256 private constant BITPOS_START_TIMESTAMP = 160; + + // The bit mask of the `burned` bit in packed ownership. + uint256 private constant BITMASK_BURNED = 1 << 224; + + // The bit position of the `nextInitialized` bit in packed ownership. + uint256 private constant BITPOS_NEXT_INITIALIZED = 225; + + // The bit mask of the `nextInitialized` bit in packed ownership. + uint256 private constant BITMASK_NEXT_INITIALIZED = 1 << 225; + + // The bit position of `extraData` in packed ownership. + uint256 private constant BITPOS_EXTRA_DATA = 232; + + // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`. + uint256 private constant BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1; + + // The mask of the lower 160 bits for addresses. + uint256 private constant BITMASK_ADDRESS = (1 << 160) - 1; + + // The maximum `quantity` that can be minted with `_mintERC2309`. + // This limit is to prevent overflows on the address data entries. + // For a limit of 5000, a total of 3.689e15 calls to `_mintERC2309` + // is required to cause an overflow, which is unrealistic. + uint256 private constant MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000; + + // The tokenId of the next token to be minted. + uint256 private _currentIndex; + + // The number of tokens burned. + uint256 private _burnCounter; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to ownership details + // An empty struct value does not necessarily mean the token is unowned. + // See `_packedOwnershipOf` implementation for details. + // + // Bits Layout: + // - [0..159] `addr` + // - [160..223] `startTimestamp` + // - [224] `burned` + // - [225] `nextInitialized` + // - [232..255] `extraData` + mapping(uint256 => uint256) private _packedOwnerships; + + // Mapping owner address to address data. + // + // Bits Layout: + // - [0..63] `balance` + // - [64..127] `numberMinted` + // - [128..191] `numberBurned` + // - [192..255] `aux` + mapping(address => uint256) private _packedAddressData; + + // Mapping from token ID to approved address. + mapping(uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + _currentIndex = _startTokenId(); + } + + /** + * @dev Returns the starting token ID. + * To change the starting token ID, please override this function. + */ + function _startTokenId() internal view virtual returns (uint256) { + return 0; + } + + /** + * @dev Returns the next token ID to be minted. + */ + function _nextTokenId() internal view returns (uint256) { + return _currentIndex; + } + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see `_totalMinted`. + */ + function totalSupply() public view override returns (uint256) { + // Counter underflow is impossible as _burnCounter cannot be incremented + // more than `_currentIndex - _startTokenId()` times. + unchecked { + return _currentIndex - _burnCounter - _startTokenId(); + } + } + + /** + * @dev Returns the total amount of tokens minted in the contract. + */ + function _totalMinted() internal view returns (uint256) { + // Counter underflow is impossible as _currentIndex does not decrement, + // and it is initialized to `_startTokenId()` + unchecked { + return _currentIndex - _startTokenId(); + } + } + + /** + * @dev Returns the total number of tokens burned. + */ + function _totalBurned() internal view returns (uint256) { + return _burnCounter; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + // The interface IDs are constants representing the first 4 bytes of the XOR of + // all function selectors in the interface. See: https://eips.ethereum.org/EIPS/eip-165 + // e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)` + return + interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165. + interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721. + interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata. + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view override returns (uint256) { + if (owner == address(0)) revert BalanceQueryForZeroAddress(); + return _packedAddressData[owner] & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the number of tokens minted by `owner`. + */ + function _numberMinted(address owner) internal view returns (uint256) { + return (_packedAddressData[owner] >> BITPOS_NUMBER_MINTED) & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the number of tokens burned by or on behalf of `owner`. + */ + function _numberBurned(address owner) internal view returns (uint256) { + return (_packedAddressData[owner] >> BITPOS_NUMBER_BURNED) & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). + */ + function _getAux(address owner) internal view returns (uint64) { + return uint64(_packedAddressData[owner] >> BITPOS_AUX); + } + + /** + * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). + * If there are multiple variables, please pack them into a uint64. + */ + function _setAux(address owner, uint64 aux) internal { + uint256 packed = _packedAddressData[owner]; + uint256 auxCasted; + // Cast `aux` with assembly to avoid redundant masking. + assembly { + auxCasted := aux + } + packed = (packed & BITMASK_AUX_COMPLEMENT) | (auxCasted << BITPOS_AUX); + _packedAddressData[owner] = packed; + } + + /** + * Returns the packed ownership data of `tokenId`. + */ + function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) { + uint256 curr = tokenId; + + unchecked { + if (_startTokenId() <= curr) + if (curr < _currentIndex) { + uint256 packed = _packedOwnerships[curr]; + // If not burned. + if (packed & BITMASK_BURNED == 0) { + // Invariant: + // There will always be an ownership that has an address and is not burned + // before an ownership that does not have an address and is not burned. + // Hence, curr will not underflow. + // + // We can directly compare the packed value. + // If the address is zero, packed is zero. + while (packed == 0) { + packed = _packedOwnerships[--curr]; + } + return packed; + } + } + } + revert OwnerQueryForNonexistentToken(); + } + + /** + * Returns the unpacked `TokenOwnership` struct from `packed`. + */ + function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) { + ownership.addr = address(uint160(packed)); + ownership.startTimestamp = uint64(packed >> BITPOS_START_TIMESTAMP); + ownership.burned = packed & BITMASK_BURNED != 0; + ownership.extraData = uint24(packed >> BITPOS_EXTRA_DATA); + } + + /** + * Returns the unpacked `TokenOwnership` struct at `index`. + */ + function _ownershipAt(uint256 index) internal view returns (TokenOwnership memory) { + return _unpackedOwnership(_packedOwnerships[index]); + } + + /** + * @dev Initializes the ownership slot minted at `index` for efficiency purposes. + */ + function _initializeOwnershipAt(uint256 index) internal { + if (_packedOwnerships[index] == 0) { + _packedOwnerships[index] = _packedOwnershipOf(index); + } + } + + /** + * Gas spent here starts off proportional to the maximum mint batch size. + * It gradually moves to O(1) as tokens get transferred around in the collection over time. + */ + function _ownershipOf(uint256 tokenId) internal view returns (TokenOwnership memory) { + return _unpackedOwnership(_packedOwnershipOf(tokenId)); + } + + /** + * @dev Packs ownership data into a single uint256. + */ + function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) { + assembly { + // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. + owner := and(owner, BITMASK_ADDRESS) + // `owner | (block.timestamp << BITPOS_START_TIMESTAMP) | flags`. + result := or(owner, or(shl(BITPOS_START_TIMESTAMP, timestamp()), flags)) + } + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view override returns (address) { + return address(uint160(_packedOwnershipOf(tokenId))); + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + if (!_exists(tokenId)) revert URIQueryForNonexistentToken(); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : ''; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, it can be overridden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ''; + } + + /** + * @dev Returns the `nextInitialized` flag set if `quantity` equals 1. + */ + function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) { + // For branchless setting of the `nextInitialized` flag. + assembly { + // `(quantity == 1) << BITPOS_NEXT_INITIALIZED`. + result := shl(BITPOS_NEXT_INITIALIZED, eq(quantity, 1)) + } + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public override { + address owner = ownerOf(tokenId); + + if (_msgSenderERC721A() != owner) + if (!isApprovedForAll(owner, _msgSenderERC721A())) { + revert ApprovalCallerNotOwnerNorApproved(); + } + + _tokenApprovals[tokenId] = to; + emit Approval(owner, to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view override returns (address) { + if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken(); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + if (operator == _msgSenderERC721A()) revert ApproveToCaller(); + + _operatorApprovals[_msgSenderERC721A()][operator] = approved; + emit ApprovalForAll(_msgSenderERC721A(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + safeTransferFrom(from, to, tokenId, ''); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) public virtual override { + transferFrom(from, to, tokenId); + if (to.code.length != 0) + if (!_checkContractOnERC721Received(from, to, tokenId, _data)) { + revert TransferToNonERC721ReceiverImplementer(); + } + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + */ + function _exists(uint256 tokenId) internal view returns (bool) { + return + _startTokenId() <= tokenId && + tokenId < _currentIndex && // If within bounds, + _packedOwnerships[tokenId] & BITMASK_BURNED == 0; // and not burned. + } + + /** + * @dev Equivalent to `_safeMint(to, quantity, '')`. + */ + function _safeMint(address to, uint256 quantity) internal { + _safeMint(to, quantity, ''); + } + + /** + * @dev Safely mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called for each safe transfer. + * - `quantity` must be greater than 0. + * + * See {_mint}. + * + * Emits a {Transfer} event for each mint. + */ + function _safeMint( + address to, + uint256 quantity, + bytes memory _data + ) internal { + _mint(to, quantity); + + unchecked { + if (to.code.length != 0) { + uint256 end = _currentIndex; + uint256 index = end - quantity; + do { + if (!_checkContractOnERC721Received(address(0), to, index++, _data)) { + revert TransferToNonERC721ReceiverImplementer(); + } + } while (index < end); + // Reentrancy protection. + if (_currentIndex != end) revert(); + } + } + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {Transfer} event for each mint. + */ + function _mint(address to, uint256 quantity) internal { + uint256 startTokenId = _currentIndex; + if (to == address(0)) revert MintToZeroAddress(); + if (quantity == 0) revert MintZeroQuantity(); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are incredibly unrealistic. + // `balance` and `numberMinted` have a maximum limit of 2**64. + // `tokenId` has a maximum limit of 2**256. + unchecked { + // Updates: + // - `balance += quantity`. + // - `numberMinted += quantity`. + // + // We can directly add to the `balance` and `numberMinted`. + _packedAddressData[to] += quantity * ((1 << BITPOS_NUMBER_MINTED) | 1); + + // Updates: + // - `address` to the owner. + // - `startTimestamp` to the timestamp of minting. + // - `burned` to `false`. + // - `nextInitialized` to `quantity == 1`. + _packedOwnerships[startTokenId] = _packOwnershipData( + to, + _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) + ); + + uint256 tokenId = startTokenId; + uint256 end = startTokenId + quantity; + do { + emit Transfer(address(0), to, tokenId++); + } while (tokenId < end); + + _currentIndex = end; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * This function is intended for efficient minting only during contract creation. + * + * It emits only one {ConsecutiveTransfer} as defined in + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309), + * instead of a sequence of {Transfer} event(s). + * + * Calling this function outside of contract creation WILL make your contract + * non-compliant with the ERC721 standard. + * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309 + * {ConsecutiveTransfer} event is only permissible during contract creation. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {ConsecutiveTransfer} event. + */ + function _mintERC2309(address to, uint256 quantity) internal { + uint256 startTokenId = _currentIndex; + if (to == address(0)) revert MintToZeroAddress(); + if (quantity == 0) revert MintZeroQuantity(); + if (quantity > MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit(); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are unrealistic due to the above check for `quantity` to be below the limit. + unchecked { + // Updates: + // - `balance += quantity`. + // - `numberMinted += quantity`. + // + // We can directly add to the `balance` and `numberMinted`. + _packedAddressData[to] += quantity * ((1 << BITPOS_NUMBER_MINTED) | 1); + + // Updates: + // - `address` to the owner. + // - `startTimestamp` to the timestamp of minting. + // - `burned` to `false`. + // - `nextInitialized` to `quantity == 1`. + _packedOwnerships[startTokenId] = _packOwnershipData( + to, + _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) + ); + + emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to); + + _currentIndex = startTokenId + quantity; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Returns the storage slot and value for the approved address of `tokenId`. + */ + function _getApprovedAddress(uint256 tokenId) + private + view + returns (uint256 approvedAddressSlot, address approvedAddress) + { + mapping(uint256 => address) storage tokenApprovalsPtr = _tokenApprovals; + // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId]`. + assembly { + // Compute the slot. + mstore(0x00, tokenId) + mstore(0x20, tokenApprovalsPtr.slot) + approvedAddressSlot := keccak256(0x00, 0x40) + // Load the slot's value from storage. + approvedAddress := sload(approvedAddressSlot) + } + } + + /** + * @dev Returns whether the `approvedAddress` is equals to `from` or `msgSender`. + */ + function _isOwnerOrApproved( + address approvedAddress, + address from, + address msgSender + ) private pure returns (bool result) { + assembly { + // Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean. + from := and(from, BITMASK_ADDRESS) + // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean. + msgSender := and(msgSender, BITMASK_ADDRESS) + // `msgSender == from || msgSender == approvedAddress`. + result := or(eq(msgSender, from), eq(msgSender, approvedAddress)) + } + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); + + if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner(); + + (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedAddress(tokenId); + + // The nested ifs save around 20+ gas over a compound boolean condition. + if (!_isOwnerOrApproved(approvedAddress, from, _msgSenderERC721A())) + if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved(); + + if (to == address(0)) revert TransferToZeroAddress(); + + _beforeTokenTransfers(from, to, tokenId, 1); + + // Clear approvals from the previous owner. + assembly { + if approvedAddress { + // This is equivalent to `delete _tokenApprovals[tokenId]`. + sstore(approvedAddressSlot, 0) + } + } + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as tokenId would have to be 2**256. + unchecked { + // We can directly increment and decrement the balances. + --_packedAddressData[from]; // Updates: `balance -= 1`. + ++_packedAddressData[to]; // Updates: `balance += 1`. + + // Updates: + // - `address` to the next owner. + // - `startTimestamp` to the timestamp of transfering. + // - `burned` to `false`. + // - `nextInitialized` to `true`. + _packedOwnerships[tokenId] = _packOwnershipData( + to, + BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked) + ); + + // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . + if (prevOwnershipPacked & BITMASK_NEXT_INITIALIZED == 0) { + uint256 nextTokenId = tokenId + 1; + // If the next slot's address is zero and not burned (i.e. packed value is zero). + if (_packedOwnerships[nextTokenId] == 0) { + // If the next slot is within bounds. + if (nextTokenId != _currentIndex) { + // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. + _packedOwnerships[nextTokenId] = prevOwnershipPacked; + } + } + } + } + + emit Transfer(from, to, tokenId); + _afterTokenTransfers(from, to, tokenId, 1); + } + + /** + * @dev Equivalent to `_burn(tokenId, false)`. + */ + function _burn(uint256 tokenId) internal virtual { + _burn(tokenId, false); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId, bool approvalCheck) internal virtual { + uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); + + address from = address(uint160(prevOwnershipPacked)); + + (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedAddress(tokenId); + + if (approvalCheck) { + // The nested ifs save around 20+ gas over a compound boolean condition. + if (!_isOwnerOrApproved(approvedAddress, from, _msgSenderERC721A())) + if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved(); + } + + _beforeTokenTransfers(from, address(0), tokenId, 1); + + // Clear approvals from the previous owner. + assembly { + if approvedAddress { + // This is equivalent to `delete _tokenApprovals[tokenId]`. + sstore(approvedAddressSlot, 0) + } + } + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. + unchecked { + // Updates: + // - `balance -= 1`. + // - `numberBurned += 1`. + // + // We can directly decrement the balance, and increment the number burned. + // This is equivalent to `packed -= 1; packed += 1 << BITPOS_NUMBER_BURNED;`. + _packedAddressData[from] += (1 << BITPOS_NUMBER_BURNED) - 1; + + // Updates: + // - `address` to the last owner. + // - `startTimestamp` to the timestamp of burning. + // - `burned` to `true`. + // - `nextInitialized` to `true`. + _packedOwnerships[tokenId] = _packOwnershipData( + from, + (BITMASK_BURNED | BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked) + ); + + // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . + if (prevOwnershipPacked & BITMASK_NEXT_INITIALIZED == 0) { + uint256 nextTokenId = tokenId + 1; + // If the next slot's address is zero and not burned (i.e. packed value is zero). + if (_packedOwnerships[nextTokenId] == 0) { + // If the next slot is within bounds. + if (nextTokenId != _currentIndex) { + // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. + _packedOwnerships[nextTokenId] = prevOwnershipPacked; + } + } + } + } + + emit Transfer(from, address(0), tokenId); + _afterTokenTransfers(from, address(0), tokenId, 1); + + // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times. + unchecked { + _burnCounter++; + } + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkContractOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) private returns (bool) { + try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns ( + bytes4 retval + ) { + return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert TransferToNonERC721ReceiverImplementer(); + } else { + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } + + /** + * @dev Directly sets the extra data for the ownership data `index`. + */ + function _setExtraDataAt(uint256 index, uint24 extraData) internal { + uint256 packed = _packedOwnerships[index]; + if (packed == 0) revert OwnershipNotInitializedForExtraData(); + uint256 extraDataCasted; + // Cast `extraData` with assembly to avoid redundant masking. + assembly { + extraDataCasted := extraData + } + packed = (packed & BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << BITPOS_EXTRA_DATA); + _packedOwnerships[index] = packed; + } + + /** + * @dev Returns the next extra data for the packed ownership data. + * The returned result is shifted into position. + */ + function _nextExtraData( + address from, + address to, + uint256 prevOwnershipPacked + ) private view returns (uint256) { + uint24 extraData = uint24(prevOwnershipPacked >> BITPOS_EXTRA_DATA); + return uint256(_extraData(from, to, extraData)) << BITPOS_EXTRA_DATA; + } + + /** + * @dev Called during each token transfer to set the 24bit `extraData` field. + * Intended to be overridden by the cosumer contract. + * + * `previousExtraData` - the value of `extraData` before transfer. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _extraData( + address from, + address to, + uint24 previousExtraData + ) internal view virtual returns (uint24) {} + + /** + * @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. + * This includes minting. + * And also called before burning one token. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _beforeTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Hook that is called after a set of serially-ordered token ids have been transferred. + * This includes minting. + * And also called after one token has been burned. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been + * transferred to `to`. + * - When `from` is zero, `tokenId` has been minted for `to`. + * - When `to` is zero, `tokenId` has been burned by `from`. + * - `from` and `to` are never both zero. + */ + function _afterTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Returns the message sender (defaults to `msg.sender`). + * + * If you are writing GSN compatible contracts, you need to override this function. + */ + function _msgSenderERC721A() internal view virtual returns (address) { + return msg.sender; + } + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function _toString(uint256 value) internal pure returns (string memory ptr) { + assembly { + // The maximum value of a uint256 contains 78 digits (1 byte per digit), + // but we allocate 128 bytes to keep the free memory pointer 32-byte word aliged. + // We will need 1 32-byte word to store the length, + // and 3 32-byte words to store a maximum of 78 digits. Total: 32 + 3 * 32 = 128. + ptr := add(mload(0x40), 128) + // Update the free memory pointer to allocate. + mstore(0x40, ptr) + + // Cache the end of the memory to calculate the length later. + let end := ptr + + // We write the string from the rightmost digit to the leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + // Costs a bit more than early returning for the zero case, + // but cheaper in terms of deployment and overall runtime costs. + for { + // Initialize and perform the first pass without check. + let temp := value + // Move the pointer 1 byte leftwards to point to an empty character slot. + ptr := sub(ptr, 1) + // Write the character to the pointer. 48 is the ASCII index of '0'. + mstore8(ptr, add(48, mod(temp, 10))) + temp := div(temp, 10) + } temp { + // Keep dividing `temp` until zero. + temp := div(temp, 10) + } { + // Body of the for loop. + ptr := sub(ptr, 1) + mstore8(ptr, add(48, mod(temp, 10))) + } + + let length := sub(end, ptr) + // Move the pointer 32 bytes leftwards to make room for the length. + ptr := sub(ptr, 32) + // Store the length. + mstore(ptr, length) + } + } +} + + +/////////////////////////////////////////// +// File: erc721a/contracts/IERC721A.sol + +// SPDX-License-Identifier: MIT +// ERC721A Contracts v4.1.0 +// Creator: Chiru Labs + +pragma solidity ^0.8.4; + +/** + * @dev Interface of an ERC721A compliant contract. + */ +interface IERC721A { + /** + * The caller must own the token or be an approved operator. + */ + error ApprovalCallerNotOwnerNorApproved(); + + /** + * The token does not exist. + */ + error ApprovalQueryForNonexistentToken(); + + /** + * The caller cannot approve to their own address. + */ + error ApproveToCaller(); + + /** + * Cannot query the balance for the zero address. + */ + error BalanceQueryForZeroAddress(); + + /** + * Cannot mint to the zero address. + */ + error MintToZeroAddress(); + + /** + * The quantity of tokens minted must be more than zero. + */ + error MintZeroQuantity(); + + /** + * The token does not exist. + */ + error OwnerQueryForNonexistentToken(); + + /** + * The caller must own the token or be an approved operator. + */ + error TransferCallerNotOwnerNorApproved(); + + /** + * The token must be owned by `from`. + */ + error TransferFromIncorrectOwner(); + + /** + * Cannot safely transfer to a contract that does not implement the ERC721Receiver interface. + */ + error TransferToNonERC721ReceiverImplementer(); + + /** + * Cannot transfer to the zero address. + */ + error TransferToZeroAddress(); + + /** + * The token does not exist. + */ + error URIQueryForNonexistentToken(); + + /** + * The `quantity` minted with ERC2309 exceeds the safety limit. + */ + error MintERC2309QuantityExceedsLimit(); + + /** + * The `extraData` cannot be set on an unintialized ownership slot. + */ + error OwnershipNotInitializedForExtraData(); + + struct TokenOwnership { + // The address of the owner. + address addr; + // Keeps track of the start time of ownership with minimal overhead for tokenomics. + uint64 startTimestamp; + // Whether the token has been burned. + bool burned; + // Arbitrary data similar to `startTimestamp` that can be set through `_extraData`. + uint24 extraData; + } + + /** + * @dev Returns the total amount of tokens stored by the contract. + * + * Burned tokens are calculated here, use `_totalMinted()` if you want to count just minted tokens. + */ + function totalSupply() external view returns (uint256); + + // ============================== + // IERC165 + // ============================== + + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); + + // ============================== + // IERC721 + // ============================== + + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + // ============================== + // IERC721Metadata + // ============================== + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); + + // ============================== + // IERC2309 + // ============================== + + /** + * @dev Emitted when tokens in `fromTokenId` to `toTokenId` (inclusive) is transferred from `from` to `to`, + * as defined in the ERC2309 standard. See `_mintERC2309` for more details. + */ + event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); +} + + diff --git a/ethabi/code/0xad8474ba5a7f6abc52708f171f57fefc5cdc8c1c.yml b/ethabi/code/0xad8474ba5a7f6abc52708f171f57fefc5cdc8c1c.yml new file mode 100644 index 0000000..72651d9 --- /dev/null +++ b/ethabi/code/0xad8474ba5a7f6abc52708f171f57fefc5cdc8c1c.yml @@ -0,0 +1,12 @@ +--- +ContractName: Indelible +CompilerVersion: v0.8.14+commit.80d49f37 +OptimizationUsed: '1' +Runs: '200' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: MIT +Proxy: '0' +Implementation: '' +SwarmSource: '' diff --git a/ethabi/code/0xaf9ce4b327a3b690abea6f78eccbfefffbea9fdf.sol b/ethabi/code/0xaf9ce4b327a3b690abea6f78eccbfefffbea9fdf.sol new file mode 100644 index 0000000..f3dbbbc --- /dev/null +++ b/ethabi/code/0xaf9ce4b327a3b690abea6f78eccbfefffbea9fdf.sol @@ -0,0 +1,680 @@ +/////////////////////////////////////////// +// File: @rari-capital/solmate/src/tokens/ERC721.sol + +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Modern, minimalist, and gas efficient ERC-721 implementation. +/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol) +/// @dev Note that balanceOf does not revert if passed the zero address, in defiance of the ERC. +abstract contract ERC721 { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 indexed id); + + event Approval(address indexed owner, address indexed spender, uint256 indexed id); + + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /*/////////////////////////////////////////////////////////////// + METADATA STORAGE/LOGIC + //////////////////////////////////////////////////////////////*/ + + string public name; + + string public symbol; + + function tokenURI(uint256 id) public view virtual returns (string memory); + + /*/////////////////////////////////////////////////////////////// + ERC721 STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(address => uint256) public balanceOf; + + mapping(uint256 => address) public ownerOf; + + mapping(uint256 => address) public getApproved; + + mapping(address => mapping(address => bool)) public isApprovedForAll; + + /*/////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor(string memory _name, string memory _symbol) { + name = _name; + symbol = _symbol; + } + + /*/////////////////////////////////////////////////////////////// + ERC721 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 id) public virtual { + address owner = ownerOf[id]; + + require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED"); + + getApproved[id] = spender; + + emit Approval(owner, spender, id); + } + + function setApprovalForAll(address operator, bool approved) public virtual { + isApprovedForAll[msg.sender][operator] = approved; + + emit ApprovalForAll(msg.sender, operator, approved); + } + + function transferFrom( + address from, + address to, + uint256 id + ) public virtual { + require(from == ownerOf[id], "WRONG_FROM"); + + require(to != address(0), "INVALID_RECIPIENT"); + + require( + msg.sender == from || msg.sender == getApproved[id] || isApprovedForAll[from][msg.sender], + "NOT_AUTHORIZED" + ); + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + unchecked { + balanceOf[from]--; + + balanceOf[to]++; + } + + ownerOf[id] = to; + + delete getApproved[id]; + + emit Transfer(from, to, id); + } + + function safeTransferFrom( + address from, + address to, + uint256 id + ) public virtual { + transferFrom(from, to, id); + + require( + to.code.length == 0 || + ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") == + ERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + function safeTransferFrom( + address from, + address to, + uint256 id, + bytes memory data + ) public virtual { + transferFrom(from, to, id); + + require( + to.code.length == 0 || + ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) == + ERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + /*/////////////////////////////////////////////////////////////// + ERC165 LOGIC + //////////////////////////////////////////////////////////////*/ + + function supportsInterface(bytes4 interfaceId) public pure virtual returns (bool) { + return + interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 + interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721 + interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata + } + + /*/////////////////////////////////////////////////////////////// + INTERNAL MINT/BURN LOGIC + //////////////////////////////////////////////////////////////*/ + + function _mint(address to, uint256 id) internal virtual { + require(to != address(0), "INVALID_RECIPIENT"); + + require(ownerOf[id] == address(0), "ALREADY_MINTED"); + + // Counter overflow is incredibly unrealistic. + unchecked { + balanceOf[to]++; + } + + ownerOf[id] = to; + + emit Transfer(address(0), to, id); + } + + function _burn(uint256 id) internal virtual { + address owner = ownerOf[id]; + + require(ownerOf[id] != address(0), "NOT_MINTED"); + + // Ownership check above ensures no underflow. + unchecked { + balanceOf[owner]--; + } + + delete ownerOf[id]; + + delete getApproved[id]; + + emit Transfer(owner, address(0), id); + } + + /*/////////////////////////////////////////////////////////////// + INTERNAL SAFE MINT LOGIC + //////////////////////////////////////////////////////////////*/ + + function _safeMint(address to, uint256 id) internal virtual { + _mint(to, id); + + require( + to.code.length == 0 || + ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") == + ERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + function _safeMint( + address to, + uint256 id, + bytes memory data + ) internal virtual { + _mint(to, id); + + require( + to.code.length == 0 || + ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) == + ERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } +} + +/// @notice A generic interface for a contract which properly accepts ERC721 tokens. +/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol) +interface ERC721TokenReceiver { + function onERC721Received( + address operator, + address from, + uint256 id, + bytes calldata data + ) external returns (bytes4); +} + + +/////////////////////////////////////////// +// File: contracts/SyntheticPunks.sol + + +// ______ __ __ __ __ ______ __ __ ______ ______ __ ______ ______ __ __ __ __ __ __ ______ +// /\ ___\ /\ \_\ \ /\ "-.\ \ /\__ _\ /\ \_\ \ /\ ___\ /\__ _\ /\ \ /\ ___\ /\ == \ /\ \/\ \ /\ "-.\ \ /\ \/ / /\ ___\ +// \ \___ \ \ \____ \ \ \ \-. \ \/_/\ \/ \ \ __ \ \ \ __\ \/_/\ \/ \ \ \ \ \ \____ \ \ _-/ \ \ \_\ \ \ \ \-. \ \ \ _"-. \ \___ \ +// \/\_____\ \/\_____\ \ \_\\"\_\ \ \_\ \ \_\ \_\ \ \_____\ \ \_\ \ \_\ \ \_____\ \ \_\ \ \_____\ \ \_\\"\_\ \ \_\ \_\ \/\_____\ +// \/_____/ \/_____/ \/_/ \/_/ \/_/ \/_/\/_/ \/_____/ \/_/ \/_/ \/_____/ \/_/ \/_____/ \/_/ \/_/ \/_/\/_/ \/_____/ + + +// ................................................................................ +// .....................................,,,........................................ +// ...............................,,,,,,,,,,,,,,,.................................. +// ............................,7777777777777777777,............................... +// .........................,,,,7777777777777777777,,,,............................ +// ......................,,,,777~~~~~~~~~~~~~~~~~~~777,,,.......................... +// ....................,,,,,:777,,,,,,,,,,,,,,,,,,,III:,,,,,....................... +// ..................,,,,=III~~~,,,,,,,,,,,,,,,,,,,~~~III=,,,,..................... +// .................,,,,,=III:::::::::::::::::::::::::III=,,,,,.................... +// ................,,,777777777777777777777777777777777777777,,,................... +// ...............,,,,777777777777777777777777777777777777777,,,................... +// ................,,,777777777777777777777777777777777777777,,,................... +// ................,,,777777777777777777777777777777777777777,,,................... +// ................,,,===?II?=~~~~~~~~~~~~~~~~~~~~~~~~777+~~~,,,................... +// ................,,,,,,?III::,,,,,,,,,,,,,,,,,,,,,::777=,,,,,.................... +// .................,,,,,IIII,,,,,,,,,,,,,,,,,,,,,,,,,777=,,,,,.................... +// .................,,,,,I77I,,,,,..............,,,,,,777=,,,,..................... +// .................,,777===~,,,,................,,,,,777=,,,...................... +// .................,,777~,,,,,,..................,,,,777=,,....................... +// .................,,777~,,,,,,777.............7II,,,777=,,....................... +// .................,,777~,,,,,,777,............777,,,777=,,....................... +// .................,,777?777,,,===,............===,,,777=,,....................... +// .................,,777?777,,,.................,,,,,777=,,....................... +// .................,,=+=+777,,,.................,,,,,777=,,....................... +// ..................,,,,+777,,,.................,,,,,777=,,....................... +// ..................,,,,+777,,,.........=777....,,,,,777=,,....................... +// ...................,,,=777,,,.........+777..,,,,,,,777=,,....................... +// ...................,,,+777,,,,.......,~++=,,,,,,,,,777=,,....................... +// ....................,,+777,,,,.....,,,,,,,,,,,,,,,,777=,,....................... +// .....................,=777,,,,,,,,,I777777777,,,,,,777=,........................ +// .....................,+777,,,,,,,,,I777777777,,,,,,777=,........................ +// .....................,=+++~~~,,,,,,=+++++++++,,,~~~+++~......................... +// ......................,,,:777,,,,,,,,,,,,,,,,,,,777:,,.......................... +// ......................,,,:777,,,:::,,,,,,,,,,:::III:,........................... +// ......................,,,:777,,,777:,,,,,,,,:777,,,............................. +// ......................,,,:777,,,777~,,,,,,,,:777,,,............................. +// ......................,,,:777,,,,,,III?77?777,,,,............................... +// ......................,,,:777,,,,,,III?77?77I,,,,............................... +// .......................,,:777,,,,,,,,,:77?,,,,,................................. +// .......................,,,777,,,,,,,,,:77?,,,,.................................. +// .........................,???,,,,,,,,,:??=,,,................................... +// ............................,.........,,,.,..................................... +// ................................................................................ + +//SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.0; + +import "@rari-capital/solmate/src/tokens/ERC721.sol"; +import "./interfaces/ISyntheticPunksAssets.sol"; + +abstract contract ReverseRecords { + function getNames(address[] calldata addresses) external view virtual returns (string[] memory r); +} + +contract SyntheticPunks is ERC721 { + + ISyntheticPunksAssets public assets; + uint256 public immutable claimPrice = 0.02 ether; + address public immutable withdrawAddress; + address immutable ensReverseAddress; + string public constant claimMessage = "Message to claim Synthetic Punk"; + + mapping(address => bool) public claimed; + + enum Gender { Male, Female } + + constructor( + string memory _name, + string memory _symbol, + address _assetsAddress, + address _withdrawAddress, + address _ensReverseAddress + ) ERC721(_name, _symbol) { + assets = ISyntheticPunksAssets(_assetsAddress); + withdrawAddress = _withdrawAddress; + ensReverseAddress = _ensReverseAddress; + } + + function claim() public payable { + require(msg.value >= claimPrice, "Insufficient payment"); + _safeMint(msg.sender, getTokenID(msg.sender)); + claimed[msg.sender] = true; + uint256 refund = msg.value - claimPrice; + if (refund > 0) { + payable(msg.sender).transfer(refund); + } + } + + function claimOther(address _signer, bytes memory _signature) public payable { + require(msg.value >= claimPrice, "Insufficient payment"); + require(verify(_signer, claimMessage, _signature), "Invalid signature"); + + _safeMint(msg.sender, getTokenID(_signer)); + claimed[_signer] = true; + uint256 refund = msg.value - claimPrice; + if (refund > 0) { + payable(_signer).transfer(refund); + } + } + + + + function withdraw() public { + payable(withdrawAddress).transfer(address(this).balance); + } + + function _tokenURI(address _address) public view returns (string memory) { + return tokenURI(getTokenID(_address)); + } + + function getTokenID(address _address) public pure returns (uint256) { + return uint256(uint160(_address)); + } + + function getAddress(uint256 id) public pure returns (address) { + return address(uint160(id)); + } + + function tokenURI(uint256 id) public view override returns (string memory) { + uint256[] memory layers = getAttributes(id); + string memory punkSVG = generatePunkSVG(layers); + + address userAddress = getAddress(id); + string memory ensName = reverseName(userAddress); + string memory addressOrENS = bytes(ensName).length == 0 ? truncateAddress(userAddress) : ensName; + string memory addressFullorENS = bytes(ensName).length == 0 ? toString(userAddress) : ensName; + + string memory json = base64(bytes(abi.encodePacked('{"name": "', 'Synthetic CryptoPunk for ', addressOrENS, '", "description": "This is a unique Punk claimed by ', addressFullorENS,'.", "image": "data:image/svg+xml;base64,', base64(bytes(punkSVG)), '"}'))); + + return string(abi.encodePacked('data:application/json;base64,', json)); + } + + // Entropy 0 + function getGender(uint256 id) public view returns (Gender) { + return randomUint(id, 0) % 2 == 0 ? Gender.Male : Gender.Female; + } + + // Entropy 1,2-9 + function getAttributeCategories(uint256 id) public view returns (uint256[] memory) { + uint256[4][9] memory spritesheetRanges = assets.spritesheetRanges(); + uint256 checks = 2 + randomUint(id, 1) % (spritesheetRanges.length - 3); // Number of bytes to check + uint256[] memory attributes = new uint256[](checks); + uint256 length = 0; + for (uint256 i; i < checks; i++) { + uint256 newAttribute = randomUint(id, 2+i) % (spritesheetRanges.length - 2) + 1; // Skip base category + + bool added = contains(attributes, newAttribute); + + if (added) { + continue; + } + + if (getGender(id) == Gender.Female) { + if (!(spritesheetRanges[newAttribute][3] - spritesheetRanges[newAttribute][1] == 0)) { + attributes[length] = newAttribute; + length++; + } + } else { + if (!(spritesheetRanges[newAttribute][2] - spritesheetRanges[newAttribute][0] == 0)) { + attributes[length] = newAttribute; + length++; + } + } + } + + uint256[] memory attributesResized = new uint256[](length+1); + attributesResized[0] = 0; + for (uint256 i; i < length; i++) { + attributesResized[i+1] = attributes[i]; + } + + return attributesResized; + } + + // Entropy 10 + function getAttribute(uint256 id, uint256 _attributeId) public view returns (uint256) { + uint256[4] memory ranges = assets.spritesheetRanges()[_attributeId]; + Gender gender = getGender(id); + if (gender == Gender.Female) { + return ranges[1] + randomUint(id, 10+_attributeId) % (ranges[3] - ranges[1]); + } else { + return ranges[0] + randomUint(id, 10+_attributeId) % (ranges[2] - ranges[0]); + } + } + + function _getAttributes(address _address) public view returns (uint256[] memory) { + return getAttributes(getTokenID(_address)); + } + + function getAttributes(uint256 id) public view returns (uint256[] memory) { + uint256[] memory attributeCategories = getAttributeCategories(id); + uint256[] memory layers = new uint256[](attributeCategories.length); + for (uint256 i = 0; i < attributeCategories.length; i++) { + layers[i] = getAttribute(id, attributeCategories[i]); + } + return layers; + } + + function generatePunkSVG(uint256[] memory layers) public view returns (string memory) { + string memory start1 = ''; + string memory end = ''; + string memory layersSVG = ''; + + // Render in order + for (uint256 i = 0; i < assets.spritesheetRanges().length; i++) { + for (uint256 j = 0; j < layers.length; j++) { + if (assets.spritesheetRanges()[i][0] <= layers[j] && layers[j] < assets.spritesheetRanges()[i][3]) { // if layer is in range + uint256 id = layers[j]; + uint256 x = (id % 24) * 24; + uint256 y = (id / 24) * 24; + layersSVG = string(abi.encodePacked(layersSVG, '')); + break; + } + } + } + + return string(abi.encodePacked(start1, assets.spritesheetImageData(), start3, layersSVG, end)) ; + } + + function reverseName(address _address) internal view returns (string memory name) { + if (address(0) == ensReverseAddress) { + return name; + } + ReverseRecords ens = ReverseRecords(ensReverseAddress); + address[] memory t = new address[](1); + t[0] = _address; + name = ens.getNames(t)[0]; + } + + function contains(uint256[] memory arr, uint256 element) internal pure returns (bool) { + for (uint256 i = 0; i < arr.length; i++) { + if (arr[i] == element) { + return true; + } + } + return false; + } + + function randomUint(uint256 seed, uint256 offset) public view returns (uint256) { + require(offset < 32, "Offset out of bounds"); + bytes32 entropy = keccak256(abi.encodePacked(address(this), seed)); + bytes32 mask = bytes32(0xff << (offset * 8)); + uint256 out = uint256((entropy & mask) >> (offset * 8)); + return out; + } + + function truncateAddress(address _address) internal pure returns (string memory) { + string memory addressString = toString(_address); + bytes memory addressBytes = bytes(addressString); + bytes memory str = new bytes(13); + uint count = 0; + for (uint i = 0; i < 6; i++) { + str[count++] = addressBytes[i]; + } + for (uint256 i = 0; i < 3; i++) { + str[count++] = "."; + } + for (uint i = addressBytes.length-4; i < addressBytes.length; i++) { + str[count++] = addressBytes[i]; + } + + return string(str); + } + + function toString(address account) internal pure returns(string memory) { + return toString(abi.encodePacked(account)); + } + + function toString(bytes32 value) internal pure returns(string memory) { + return toString(abi.encodePacked(value)); + } + + function toString(bytes memory data) internal pure returns(string memory) { + bytes memory alphabet = "0123456789abcdef"; + + bytes memory str = new bytes(2 + data.length * 2); + str[0] = "0"; + str[1] = "x"; + for (uint i = 0; i < data.length; i++) { + str[2+i*2] = alphabet[uint(uint8(data[i] >> 4))]; + str[3+i*2] = alphabet[uint(uint8(data[i] & 0x0f))]; + } + return string(str); + } + + function toString(uint256 n) + internal + pure + returns (string memory nstr) + { + uint256 MAX_UINT256_STRING_LENGTH = 78; + uint8 ASCII_DIGIT_OFFSET = 48; + if (n == 0) { + return "0"; + } + // Overallocate memory + nstr = new string(MAX_UINT256_STRING_LENGTH); + uint256 k = MAX_UINT256_STRING_LENGTH; + // Populate string from right to left (lsb to msb). + while (n != 0) { + assembly { + let char := add( + ASCII_DIGIT_OFFSET, + mod(n, 10) + ) + mstore(add(nstr, k), char) + k := sub(k, 1) + n := div(n, 10) + } + } + assembly { + // Shift pointer over to actual start of string. + nstr := add(nstr, k) + // Store actual string length. + mstore(nstr, sub(MAX_UINT256_STRING_LENGTH, k)) + } + return nstr; + } + + /// @notice Encodes some bytes to the base64 representation + function base64(bytes memory data) internal pure returns (string memory) { + bytes memory TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + uint256 len = data.length; + if (len == 0) return ""; + + // multiply by 4/3 rounded up + uint256 encodedLen = 4 * ((len + 2) / 3); + + // Add some extra buffer at the end + bytes memory result = new bytes(encodedLen + 32); + + bytes memory table = TABLE; + + assembly { + let tablePtr := add(table, 1) + let resultPtr := add(result, 32) + + for { + let i := 0 + } lt(i, len) { + + } { + i := add(i, 3) + let input := and(mload(add(data, i)), 0xffffff) + + let out := mload(add(tablePtr, and(shr(18, input), 0x3F))) + out := shl(8, out) + out := add(out, and(mload(add(tablePtr, and(shr(12, input), 0x3F))), 0xFF)) + out := shl(8, out) + out := add(out, and(mload(add(tablePtr, and(shr(6, input), 0x3F))), 0xFF)) + out := shl(8, out) + out := add(out, and(mload(add(tablePtr, and(input, 0x3F))), 0xFF)) + out := shl(224, out) + + mstore(resultPtr, out) + + resultPtr := add(resultPtr, 4) + } + + switch mod(len, 3) + case 1 { + mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) + } + case 2 { + mstore(sub(resultPtr, 1), shl(248, 0x3d)) + } + + mstore(result, encodedLen) + } + + return string(result); + } + + // ECDSA + + function getMessageHash( + string memory _message + ) public pure returns (bytes32) { + return keccak256(abi.encodePacked(_message)); + } + + function getEthSignedMessageHash(bytes32 _messageHash) + public + pure + returns (bytes32) + { + return + keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash) + ); + } + + function verify( + address _signer, + string memory _message, + bytes memory signature + ) public pure returns (bool) { + bytes32 messageHash = getMessageHash(_message); + bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash); + + return recoverSigner(ethSignedMessageHash, signature) == _signer; + } + + function recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) + public + pure + returns (address) + { + (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature); + + return ecrecover(_ethSignedMessageHash, v, r, s); + } + + function splitSignature(bytes memory sig) + public + pure + returns ( + bytes32 r, + bytes32 s, + uint8 v + ) + { + require(sig.length == 65, "invalid signature length"); + + assembly { + // first 32 bytes, after the length prefix + r := mload(add(sig, 32)) + // second 32 bytes + s := mload(add(sig, 64)) + // final byte (first byte of the next 32 bytes) + v := byte(0, mload(add(sig, 96))) + } + } +} + +/////////////////////////////////////////// +// File: contracts/interfaces/ISyntheticPunksAssets.sol + +//SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.0; + +interface ISyntheticPunksAssets { + function spritesheetImageData() external view returns (string memory); + function spritesheetRanges() external view returns (uint256[4][9] memory); + function attributesContentURI() external view returns (string memory); +} + diff --git a/ethabi/code/0xaf9ce4b327a3b690abea6f78eccbfefffbea9fdf.yml b/ethabi/code/0xaf9ce4b327a3b690abea6f78eccbfefffbea9fdf.yml new file mode 100644 index 0000000..93ac1d1 --- /dev/null +++ b/ethabi/code/0xaf9ce4b327a3b690abea6f78eccbfefffbea9fdf.yml @@ -0,0 +1,12 @@ +--- +ContractName: SyntheticPunks +CompilerVersion: v0.8.0+commit.c7dfd78e +OptimizationUsed: '0' +Runs: '200' +ConstructorArguments: 00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000852ac0a51c27670751499360935a739e11533fe0000000000000000000000000f5a1635d136f53d3518f38b163ccccdaead78eba0000000000000000000000003671ae578e63fdf66ad4f3e12cc0c0d71ac7510c000000000000000000000000000000000000000000000000000000000000001553796e7468657469632043727970746f50756e6b730000000000000000000000000000000000000000000000000000000000000000000000000000000000000c7343525950544f50554e4b530000000000000000000000000000000000000000 +EVMVersion: Default +Library: '' +LicenseType: GNU GPLv3 +Proxy: '0' +Implementation: '' +SwarmSource: '' diff --git a/ethabi/code/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb.sol b/ethabi/code/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb.sol new file mode 100644 index 0000000..4da49c2 --- /dev/null +++ b/ethabi/code/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb.sol @@ -0,0 +1,246 @@ +pragma solidity ^0.4.8; +contract CryptoPunksMarket { + + // You can use this hash to verify the image file containing all the punks + string public imageHash = "ac39af4793119ee46bbff351d8cb6b5f23da60222126add4268e261199a2921b"; + + address owner; + + string public standard = 'CryptoPunks'; + string public name; + string public symbol; + uint8 public decimals; + uint256 public totalSupply; + + uint public nextPunkIndexToAssign = 0; + + bool public allPunksAssigned = false; + uint public punksRemainingToAssign = 0; + + //mapping (address => uint) public addressToPunkIndex; + mapping (uint => address) public punkIndexToAddress; + + /* This creates an array with all balances */ + mapping (address => uint256) public balanceOf; + + struct Offer { + bool isForSale; + uint punkIndex; + address seller; + uint minValue; // in ether + address onlySellTo; // specify to sell only to a specific person + } + + struct Bid { + bool hasBid; + uint punkIndex; + address bidder; + uint value; + } + + // A record of punks that are offered for sale at a specific minimum value, and perhaps to a specific person + mapping (uint => Offer) public punksOfferedForSale; + + // A record of the highest punk bid + mapping (uint => Bid) public punkBids; + + mapping (address => uint) public pendingWithdrawals; + + event Assign(address indexed to, uint256 punkIndex); + event Transfer(address indexed from, address indexed to, uint256 value); + event PunkTransfer(address indexed from, address indexed to, uint256 punkIndex); + event PunkOffered(uint indexed punkIndex, uint minValue, address indexed toAddress); + event PunkBidEntered(uint indexed punkIndex, uint value, address indexed fromAddress); + event PunkBidWithdrawn(uint indexed punkIndex, uint value, address indexed fromAddress); + event PunkBought(uint indexed punkIndex, uint value, address indexed fromAddress, address indexed toAddress); + event PunkNoLongerForSale(uint indexed punkIndex); + + /* Initializes contract with initial supply tokens to the creator of the contract */ + function CryptoPunksMarket() payable { + // balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens + owner = msg.sender; + totalSupply = 10000; // Update total supply + punksRemainingToAssign = totalSupply; + name = "CRYPTOPUNKS"; // Set the name for display purposes + symbol = "Ͼ"; // Set the symbol for display purposes + decimals = 0; // Amount of decimals for display purposes + } + + function setInitialOwner(address to, uint punkIndex) { + if (msg.sender != owner) throw; + if (allPunksAssigned) throw; + if (punkIndex >= 10000) throw; + if (punkIndexToAddress[punkIndex] != to) { + if (punkIndexToAddress[punkIndex] != 0x0) { + balanceOf[punkIndexToAddress[punkIndex]]--; + } else { + punksRemainingToAssign--; + } + punkIndexToAddress[punkIndex] = to; + balanceOf[to]++; + Assign(to, punkIndex); + } + } + + function setInitialOwners(address[] addresses, uint[] indices) { + if (msg.sender != owner) throw; + uint n = addresses.length; + for (uint i = 0; i < n; i++) { + setInitialOwner(addresses[i], indices[i]); + } + } + + function allInitialOwnersAssigned() { + if (msg.sender != owner) throw; + allPunksAssigned = true; + } + + function getPunk(uint punkIndex) { + if (!allPunksAssigned) throw; + if (punksRemainingToAssign == 0) throw; + if (punkIndexToAddress[punkIndex] != 0x0) throw; + if (punkIndex >= 10000) throw; + punkIndexToAddress[punkIndex] = msg.sender; + balanceOf[msg.sender]++; + punksRemainingToAssign--; + Assign(msg.sender, punkIndex); + } + + // Transfer ownership of a punk to another user without requiring payment + function transferPunk(address to, uint punkIndex) { + if (!allPunksAssigned) throw; + if (punkIndexToAddress[punkIndex] != msg.sender) throw; + if (punkIndex >= 10000) throw; + if (punksOfferedForSale[punkIndex].isForSale) { + punkNoLongerForSale(punkIndex); + } + punkIndexToAddress[punkIndex] = to; + balanceOf[msg.sender]--; + balanceOf[to]++; + Transfer(msg.sender, to, 1); + PunkTransfer(msg.sender, to, punkIndex); + // Check for the case where there is a bid from the new owner and refund it. + // Any other bid can stay in place. + Bid bid = punkBids[punkIndex]; + if (bid.bidder == to) { + // Kill bid and refund value + pendingWithdrawals[to] += bid.value; + punkBids[punkIndex] = Bid(false, punkIndex, 0x0, 0); + } + } + + function punkNoLongerForSale(uint punkIndex) { + if (!allPunksAssigned) throw; + if (punkIndexToAddress[punkIndex] != msg.sender) throw; + if (punkIndex >= 10000) throw; + punksOfferedForSale[punkIndex] = Offer(false, punkIndex, msg.sender, 0, 0x0); + PunkNoLongerForSale(punkIndex); + } + + function offerPunkForSale(uint punkIndex, uint minSalePriceInWei) { + if (!allPunksAssigned) throw; + if (punkIndexToAddress[punkIndex] != msg.sender) throw; + if (punkIndex >= 10000) throw; + punksOfferedForSale[punkIndex] = Offer(true, punkIndex, msg.sender, minSalePriceInWei, 0x0); + PunkOffered(punkIndex, minSalePriceInWei, 0x0); + } + + function offerPunkForSaleToAddress(uint punkIndex, uint minSalePriceInWei, address toAddress) { + if (!allPunksAssigned) throw; + if (punkIndexToAddress[punkIndex] != msg.sender) throw; + if (punkIndex >= 10000) throw; + punksOfferedForSale[punkIndex] = Offer(true, punkIndex, msg.sender, minSalePriceInWei, toAddress); + PunkOffered(punkIndex, minSalePriceInWei, toAddress); + } + + function buyPunk(uint punkIndex) payable { + if (!allPunksAssigned) throw; + Offer offer = punksOfferedForSale[punkIndex]; + if (punkIndex >= 10000) throw; + if (!offer.isForSale) throw; // punk not actually for sale + if (offer.onlySellTo != 0x0 && offer.onlySellTo != msg.sender) throw; // punk not supposed to be sold to this user + if (msg.value < offer.minValue) throw; // Didn't send enough ETH + if (offer.seller != punkIndexToAddress[punkIndex]) throw; // Seller no longer owner of punk + + address seller = offer.seller; + + punkIndexToAddress[punkIndex] = msg.sender; + balanceOf[seller]--; + balanceOf[msg.sender]++; + Transfer(seller, msg.sender, 1); + + punkNoLongerForSale(punkIndex); + pendingWithdrawals[seller] += msg.value; + PunkBought(punkIndex, msg.value, seller, msg.sender); + + // Check for the case where there is a bid from the new owner and refund it. + // Any other bid can stay in place. + Bid bid = punkBids[punkIndex]; + if (bid.bidder == msg.sender) { + // Kill bid and refund value + pendingWithdrawals[msg.sender] += bid.value; + punkBids[punkIndex] = Bid(false, punkIndex, 0x0, 0); + } + } + + function withdraw() { + if (!allPunksAssigned) throw; + uint amount = pendingWithdrawals[msg.sender]; + // Remember to zero the pending refund before + // sending to prevent re-entrancy attacks + pendingWithdrawals[msg.sender] = 0; + msg.sender.transfer(amount); + } + + function enterBidForPunk(uint punkIndex) payable { + if (punkIndex >= 10000) throw; + if (!allPunksAssigned) throw; + if (punkIndexToAddress[punkIndex] == 0x0) throw; + if (punkIndexToAddress[punkIndex] == msg.sender) throw; + if (msg.value == 0) throw; + Bid existing = punkBids[punkIndex]; + if (msg.value <= existing.value) throw; + if (existing.value > 0) { + // Refund the failing bid + pendingWithdrawals[existing.bidder] += existing.value; + } + punkBids[punkIndex] = Bid(true, punkIndex, msg.sender, msg.value); + PunkBidEntered(punkIndex, msg.value, msg.sender); + } + + function acceptBidForPunk(uint punkIndex, uint minPrice) { + if (punkIndex >= 10000) throw; + if (!allPunksAssigned) throw; + if (punkIndexToAddress[punkIndex] != msg.sender) throw; + address seller = msg.sender; + Bid bid = punkBids[punkIndex]; + if (bid.value == 0) throw; + if (bid.value < minPrice) throw; + + punkIndexToAddress[punkIndex] = bid.bidder; + balanceOf[seller]--; + balanceOf[bid.bidder]++; + Transfer(seller, bid.bidder, 1); + + punksOfferedForSale[punkIndex] = Offer(false, punkIndex, bid.bidder, 0, 0x0); + uint amount = bid.value; + punkBids[punkIndex] = Bid(false, punkIndex, 0x0, 0); + pendingWithdrawals[seller] += amount; + PunkBought(punkIndex, bid.value, seller, bid.bidder); + } + + function withdrawBidForPunk(uint punkIndex) { + if (punkIndex >= 10000) throw; + if (!allPunksAssigned) throw; + if (punkIndexToAddress[punkIndex] == 0x0) throw; + if (punkIndexToAddress[punkIndex] == msg.sender) throw; + Bid bid = punkBids[punkIndex]; + if (bid.bidder != msg.sender) throw; + PunkBidWithdrawn(punkIndex, bid.value, msg.sender); + uint amount = bid.value; + punkBids[punkIndex] = Bid(false, punkIndex, 0x0, 0); + // Refund the bid money + msg.sender.transfer(amount); + } + +} \ No newline at end of file diff --git a/ethabi/code/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb.yml b/ethabi/code/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb.yml new file mode 100644 index 0000000..e500a6d --- /dev/null +++ b/ethabi/code/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb.yml @@ -0,0 +1,12 @@ +--- +ContractName: CryptoPunksMarket +CompilerVersion: v0.4.11+commit.68ef5810 +OptimizationUsed: '1' +Runs: '200' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: '' +Proxy: '0' +Implementation: '' +SwarmSource: bzzr://e876fd2bb43babdd65d8ea9d7f8fb4a2de975957026c8b91057b2e1417ff38a2 diff --git a/ethabi/code/0xc3f733ca98e0dad0386979eb96fb1722a1a05e69.sol b/ethabi/code/0xc3f733ca98e0dad0386979eb96fb1722a1a05e69.sol new file mode 100644 index 0000000..e3824d9 --- /dev/null +++ b/ethabi/code/0xc3f733ca98e0dad0386979eb96fb1722a1a05e69.sol @@ -0,0 +1,3335 @@ +/////////////////////////////////////////// +// File: MoonCatAcclimator.sol + +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.7.3; + +import "./openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/ERC721Holder.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/utils/Pausable.sol"; +import "./IERC998.sol"; +import "./MoonCatOrderLookup.sol"; + +// ## ## +// ## ## ## ## +// ##.. ###### ..## +// #### #### +// ## ## +// ## () () ## +// ## ## +// ## \ ## / ## +// ## \/ \/ ## +// ## ## +// ############## +// +// #AcclimatedMoonCatsGlow +// https://mooncat.community/ + + +/** + * @title MoonCat​Acclimator + * @notice Accepts an original MoonCat and wraps it to present an ERC721- and ERC998-compliant asset + * @notice Accepts a MoonCat wrapped with the older wrapping contract (at 0x7C40c3...) and re-wraps them + * @notice Ownable by an admin address. Rights of the Owner are to pause and unpause the contract, and update metadata URL + */ +contract MoonCatAcclimator is + ERC721, + ERC721Holder, + Ownable, + Pausable, + IERC998ERC721TopDown, + IERC998ERC721TopDownEnumerable +{ + bytes32 private constant ERC998_MAGIC_VALUE = 0x00000000000000000000000000000000000000000000000000000000cd740db5; + bytes4 private constant _INTERFACE_ID_ERC998ERC721TopDown = 0x1efdf36a; + + MoonCatOrderLookup public rescueOrderLookup; + + MoonCatRescue MCR = MoonCatRescue(0x60cd862c9C687A9dE49aecdC3A99b74A4fc54aB6); + MoonCatsWrapped OLD_MCRW = MoonCatsWrapped(0x7C40c393DC0f283F318791d746d894DdD3693572); + + constructor(string memory baseURI) + ERC721(unicode"Acclimated​MoonCats", unicode"?") + Ownable() + { + _registerInterface(_INTERFACE_ID_ERC998ERC721TopDown); + rescueOrderLookup = new MoonCatOrderLookup(); + setBaseURI(baseURI); + _pause(); // Start in a paused state + } + + function pause() public whenNotPaused onlyOwner { + _pause(); + } + function unpause() public whenPaused onlyOwner { + _unpause(); + } + + /** + * @dev Emitted when `catId` token is wrapped into `tokenId`, owned by `owner`. + */ + event MoonCatAcclimated( + uint256 tokenId, + address indexed owner + ); + + /** + * @dev Emitted when `catId` token is unwrapped from `tokenId`, owned by `owner`. + */ + event MoonCatDeacclimated( + uint256 tokenId, + address indexed owner + ); + + /** + * @dev returns tokenId of newly minted wrapped MoonCat + * + * Requirements: + * + * - Do not need to check if _msgSender() is MoonCat owner as the wrapped token is assigned to owner (even if that's not _msgSender()) + * - Owner needs to call makeAdoptionOfferToAddress() in moonCatRescue first. + * Emits a {Transfer} ERC721 event. + * @param _rescueOrder the minting order of the MoonCat to wrap + * @return the ID (rescue order) of the minted token + */ + function wrap(uint256 _rescueOrder) public returns (uint256) { + bytes5 catId = MCR.rescueOrder(_rescueOrder); + address _owner = MCR.catOwners(catId); + MCR.acceptAdoptionOffer(catId); + return _wrap(_owner, _rescueOrder); + } + + /** + * @dev returns tokenId of newly minted wrapped MoonCat + * + * This method must not allow an adoption offer specifically to the new Wrapper address to be buy-able by anyone, + * because that is how the real owner sets up a manual wrapping of the MoonCat (where they don't really intend to sell). + * + * Requirements: + * + * - MoonCat at `_rescueOrder` must be offered for sale to any address. + * - Must have active makeAdoptionOffer() in moonCatRescue contract. + * Emits a {Transfer} and {MoonCatAcclimated} event. + * @param _rescueOrder the minting order of the MoonCat to wrap + * @return the ID (rescue order) of the minted token + */ + function buyAndWrap(uint256 _rescueOrder) public payable returns (uint256) { + bytes5 catId = MCR.rescueOrder(_rescueOrder); + (bool exists, , , , address onlyOfferTo) = MCR.adoptionOffers(catId); + require( + onlyOfferTo == address(0) && exists, + "That MoonCat is not for sale" + ); + MCR.acceptAdoptionOffer{value: msg.value}(catId); + return _wrap(_msgSender(), _rescueOrder); + } + + /** + * @dev returns tokenId of burned unwrapped MoonCat + * + * Requirements: + * + * - msgSender() must be owner. + * Emits a {Transfer} and {MoonCatDeacclimated} event. + * @param _tokenId the minting order of the MoonCat to unwrap + * @return the ID (rescue order) of the burned token + */ + function unwrap(uint256 _tokenId) public returns (uint256) { + require(ownerOf(_tokenId) == _msgSender(), "Not your MoonCat!"); + require( + super._exists(_tokenId), + "That MoonCat is not wrapped in this contract" + ); + bytes5 catId = MCR.rescueOrder(_tokenId); + MCR.giveCat(catId, ownerOf(_tokenId)); + _burn(_tokenId); + emit MoonCatDeacclimated(_tokenId, _msgSender()); + return _tokenId; + } + + /** + * @dev wraps MoonCat that was safeTransferFrom() the old MoonCat wrapper directly in one transaction + * + * Requirements: + * - Owner of old wrapped MoonCat must include the rescueOrder in the calldata as a bytes32 + * Emits a {Transfer} and {MoonCatAcclimated} event. + * @param _to the address that is to be the owner of the newly-wrapped token + * @param _oldTokenID the ID of the token in the other wrapping contract + * @param _rescueOrder the minting order of the MoonCat being wrapped + * @return the ID (rescue order) of the minted token + */ + function _wrapOnSafeTransferFromReceipt( + address _to, + uint256 _oldTokenID, + uint256 _rescueOrder + ) internal returns (uint256) { + if ( + MCR.rescueOrder(_rescueOrder) != + OLD_MCRW._tokenIDToCatID(_oldTokenID) + ) { + // Look up rescue order in Lookup contract + require( + rescueOrderLookup.oldTokenIdExists(_oldTokenID), + "Unable to determine proper rescueOrder for this old token ID" + ); + _rescueOrder = rescueOrderLookup.oldTokenIdToRescueOrder( + _oldTokenID + ); + require( + MCR.rescueOrder(_rescueOrder) == + OLD_MCRW._tokenIDToCatID(_oldTokenID), + "_oldTokenID and _rescueOrder do not match same catID" + ); + } + OLD_MCRW.unwrap(_oldTokenID); + return _wrap(_to, _rescueOrder); + } + + /** + * @dev wraps an unwrapped MoonCat + * + * notes: + * Emits a {Transfer} and {MoonCatAcclimated} event. + * @param _owner the address that should be the new owner of the newly-created token + * @param _tokenId the ID of the token to create (rescue order of the MoonCat) + * @return the ID (rescue order) of the minted token + */ + function _wrap(address _owner, uint256 _tokenId) + internal + returns (uint256) + { + require(!paused(), "Attempted wrap while paused"); + _mint(_owner, _tokenId); + emit MoonCatAcclimated(_tokenId, _msgSender()); + return _tokenId; + } + + /** + * @dev Always returns `IERC721Receiver.onERC721Received.selector` + * + * This function handles both automatic rewrapping of old-wrapped MoonCats, and assigning ERC721 tokens as "child assets" + * of MoonCats already wrapped with this contract. + * + * If the incoming token is an old-wrapped Mooncat, the `_data` variable is structured as + * the first 32 bytes are the rescue order of the transferred MoonCat, subsequent 20 bytes + * are the new owner's address. If the rescue order is not supplied, the `_oldTokenId` is + * looked up in the {MoonCatOrderLookup} contract. If a new owner's address is not + * supplied, the new owner will be assigned as the `_from` sender. + * Emits a {Transfer} and {MoonCatAcclimated} event. + * + * If the incoming token is any other type of ERC721, the `_data` variable is structured as + * the first 32 bytes are the token ID (rescue order) of the MoonCat that is to receive that assest. + * Emits a {ReceivedChild} event. + * + * @param _operator the _msgSender of the transaction + * @param _from the address of the former owner of the incoming token + * @param _oldTokenId the ID of the incoming token + * @param _data additional metdata + */ + function onERC721Received( + address _operator, + address _from, + uint256 _oldTokenId, + bytes calldata _data + ) public override(ERC721Holder, IERC998ERC721TopDown) returns (bytes4) { + // Using msg.sender here instead of _operator because we want to know the most recent transaction source, + // not the start of the chain + if (msg.sender == address(0x7C40c393DC0f283F318791d746d894DdD3693572)) { + // This is a Wrapped MoonCat incoming. Don't make it a child, instead unwrap and re-wrap it + + // Who should own this MoonCat after wrapping? + address _to = + (_data.length >= 32 + 20 && bytesToAddress(_data, 32) != address(0)) + ? bytesToAddress(_data, 32) + : _from; + require( + _to != address(0) && _to != address(this), + "Invalid destination owner specified" + ); + + _wrapOnSafeTransferFromReceipt( + _to, + _oldTokenId, + (_data.length >= 32) ? toUint256(_data, 0) : 0 + ); + return ERC721Holder.onERC721Received(_operator, _from, _oldTokenId, _data); + } + + // Otherwise, handle as ERC998 Child incoming + require(_data.length > 0, "_data must contain the uint256 tokenId to transfer the child token to"); + // convert up to 32 bytes of_data to uint256, owner NFT tokenId passed as uint in bytes + uint256 tokenId; + assembly {tokenId := calldataload(164)} + if (_data.length < 32) { + tokenId = tokenId >> 256 - _data.length * 8; + } + _receiveChild(_from, tokenId, msg.sender, _oldTokenId); + require(ERC721(msg.sender).ownerOf(_oldTokenId) != address(0), "Child token not owned"); + return ERC721Holder.onERC721Received(_operator, _from, _oldTokenId, _data); + } + + /** + * @dev sets the base URI + * + * notes: + * - only callable by the contract owner + */ + function setBaseURI(string memory _newBaseURI) public onlyOwner { + _setBaseURI(_newBaseURI); + } + + /** + * @dev See {IERC721-balanceOf}. + * This contract returns the locally-wrapped token count as well as old-wrapped MoonCats + * that are mapped in the {MoonCatOrderLookup} contract. + */ + function balanceOf(address _owner) public view override returns (uint256) { + return + super.balanceOf(_owner) + + rescueOrderLookup.entriesPerAddress(_owner); + } + + /** + * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. + * This contract enumerates the locally-wrapped token count as well as old-wrapped MoonCats + * that are mapped in the {MoonCatOrderLookup} contract. + */ + function tokenOfOwnerByIndex(address _owner, uint256 _index) + public + view + override + returns (uint256) + { + uint256 localBalance = super.balanceOf(_owner); + if (_index < localBalance) { + // This index is in the range of tokens owned by that address here in this contract + return super.tokenOfOwnerByIndex(_owner, _index); + } + + // Looking to enumerate a token that's mapped to the old wrapping contract + uint16 countFound = 0; + for (uint256 i = 0; i < OLD_MCRW.balanceOf(_owner); i++) { + uint256 oldTokenId = OLD_MCRW.tokenOfOwnerByIndex(_owner, i); + if (rescueOrderLookup.oldTokenIdExists(oldTokenId)) { + countFound++; + if (countFound == _index - localBalance + 1) { + return + rescueOrderLookup.oldTokenIdToRescueOrder(oldTokenId); + } + } + } + revert("Cannot find token ID for that index"); + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 _tokenId) public view override returns (address) { + if (super._exists(_tokenId)) { + return super.ownerOf(_tokenId); + } + + // Check other wrapper + + // First see if we're dealing with the MoonCat that was the zeroth-wrapped MoonCat in other wrapper + bytes5 thisMoonCatID = MCR.rescueOrder(_tokenId); + if (thisMoonCatID == OLD_MCRW._tokenIDToCatID(0)) { + return OLD_MCRW.ownerOf(0); + } + uint256 otherID = OLD_MCRW._catIDToTokenID(thisMoonCatID); + // We're not dealing with the zeroth-wrapped MoonCat, so a zero here is an indication they don't exist + require(otherID > 0, "That MoonCat is not wrapped"); + return OLD_MCRW.ownerOf(otherID); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address _owner, address _operator) + public + view + virtual + override + returns (bool) + { + return + rescueOrderLookup.entriesPerAddress(_owner) == 0 + ? super.isApprovedForAll(_owner, _operator) + : super.isApprovedForAll(_owner, _operator) && + OLD_MCRW.isApprovedForAll(_owner, address(this)); + } + + /** + * @dev See {ERC721-_isApprovedOrOwner}. + */ + function _isApprovedOrOwner(address _spender, uint256 _tokenId) + internal + view + override + returns (bool) + { + require( + _exists(_tokenId), + "ERC721: operator query for nonexistent token" + ); + // Differs here from OpenZeppelin standard: + // Calls `ownerOf` instead of `ERC721.ownerOf` + address _owner = ownerOf(_tokenId); + return (_spender == _owner || + getApproved(_tokenId) == _spender || + ERC721.isApprovedForAll(_owner, _spender)); + } + + /** + * @dev See {ERC721-approve}. + */ + function approve(address _to, uint256 _tokenId) public override { + address _owner = ownerOf(_tokenId); + require(_to != _owner, "ERC721: approval to current owner"); + // Differs here from OpenZeppelin standard: + // Calls `isApprovedForAll` instead of `ERC721.isApprovedForAll` + require( + _msgSender() == _owner || isApprovedForAll(_owner, _msgSender()), + "ERC721: approve caller is not owner nor approved for all" + ); + + _approve(_to, _tokenId); + } + + /** + * @dev rewrap several MoonCats from the old wrapper at once + * Owner needs to call setApprovalForAll in old wrapper first. + * @param _rescueOrders an array of MoonCats, identified by rescue order, to rewrap + * @param _oldTokenIds an array holding the corresponding token ID + * in the old wrapper for each MoonCat to be rewrapped + */ + function batchReWrap( + uint256[] memory _rescueOrders, + uint256[] memory _oldTokenIds + ) public { + for (uint16 i = 0; i < _rescueOrders.length; i++) { + address _owner = OLD_MCRW.ownerOf(_oldTokenIds[i]); + OLD_MCRW.safeTransferFrom( + _owner, + address(this), + _oldTokenIds[i], + abi.encodePacked( + uintToBytes(_rescueOrders[i]), + addressToBytes(_owner) + ) + ); + } + } + + /** + * @dev Take a list of unwrapped MoonCat rescue orders and wrap them. + * @param _rescueOrders an array of MoonCats, identified by rescue order, to rewrap + */ + function batchWrap(uint256[] memory _rescueOrders) public { + for (uint16 i = 0; i < _rescueOrders.length; i++) { + wrap(_rescueOrders[i]); + } + } + + /** + * @dev Take a list of MoonCats wrapped in this contract and unwrap them. + * @param _rescueOrders an array of MoonCats, identified by rescue order, to unwrap + */ + function batchUnwrap(uint256[] memory _rescueOrders) public { + for (uint16 i = 0; i < _rescueOrders.length; i++) { + unwrap(_rescueOrders[i]); + } + } + + /** + * @dev See {ERC721-_transfer}. + * If the token being transferred exists in this contract, the standard ERC721 logic is used. + * If the token does not exist in this contract, look it up in the old wrapping contract, + * and attempt to wrap-then-transfer it. + */ + function _transfer( + address _from, + address _to, + uint256 _tokenId + ) internal override { + if (super._exists(_tokenId)) { + return super._transfer(_from, _to, _tokenId); + } + + require(_to != address(0), "ERC721: transfer to the zero address"); + + if (_to == address(this)) { + // Sending the token to be owned by this contract? That's not what they meant; make it owned by the original owner after re-wrapping + _to = _from; + } + uint256 oldTokenId = + OLD_MCRW._catIDToTokenID(MCR.rescueOrder(_tokenId)); + OLD_MCRW.safeTransferFrom( + _from, + address(this), + oldTokenId, + abi.encodePacked(uintToBytes(_tokenId), addressToBytes(_to)) + ); + rescueOrderLookup.removeEntry(oldTokenId); + } + + /** + * @dev See {ERC721-_exists}. + * If the token being queried exists in this contract, the standard ERC721 logic is used. + * If the token does not exist in this contract, look it up in the old wrapping contract, + * and see if it exists there. + */ + function _exists(uint256 _tokenId) internal view override returns (bool) { + if (super._exists(_tokenId)) { + return true; + } + + // Check if exists in old wrapping contract + bytes5 realMoonCatZero = OLD_MCRW._tokenIDToCatID(0); + bytes5 thisMoonCatID = MCR.rescueOrder(_tokenId); + if (thisMoonCatID == realMoonCatZero) { + return true; + } + + return OLD_MCRW._catIDToTokenID(thisMoonCatID) != 0; + } + + ///// ERC998 ///// + using EnumerableSet for EnumerableSet.UintSet; + using EnumerableSet for EnumerableSet.AddressSet; + + /// @dev mapping of local token IDs, and which addresses they own children at. + /// tokenId => child contract + mapping(uint256 => EnumerableSet.AddressSet) private childContracts; + + /// @dev mapping of local token IDs, addresses they own children at, and IDs of the specific child tokens + /// tokenId => (child address => array of child tokens) + mapping(uint256 => mapping(address => EnumerableSet.UintSet)) private childTokens; + + /// @dev mapping of addresses of child tokens, the specific child token IDs, and which local token owns them + /// child address => childId => tokenId + mapping(address => mapping(uint256 => uint256)) internal childTokenOwner; + uint8 constant TOKEN_OWNER_OFFSET = 10; + + /** + * @dev a token has been transferred to this contract mark which local token is to now own it + * Emits a {ReceivedChild} event. + * + * @param _from the address who sent the token to this contract + * @param _tokenId the local token ID that is to be the parent + * @param _childContract the address of the child token's contract + * @param _childTokenId the ID value of teh incoming child token + */ + function _receiveChild(address _from, uint256 _tokenId, address _childContract, uint256 _childTokenId) private { + require(!paused(), "Child received while paused"); + require(super._exists(_tokenId), "That MoonCat is not wrapped in this contract"); + require(childTokens[_tokenId][_childContract].contains(_childTokenId) == false, "Cannot receive child token because it has already been received"); + childContracts[_tokenId].add(_childContract); + childTokens[_tokenId][_childContract].add(_childTokenId); + childTokenOwner[_childContract][_childTokenId] = _tokenId + TOKEN_OWNER_OFFSET; + emit ReceivedChild(_from, _tokenId, _childContract, _childTokenId); + } + + /** + * @dev See {IERC998ERC721TopDown-getChild}. + */ + function getChild( + address _from, + uint256 _tokenId, + address _childContract, + uint256 _childTokenId + ) public override { + _receiveChild(_from, _tokenId, _childContract, _childTokenId); + IERC721(_childContract).transferFrom(_from, address(this), _childTokenId); + } + + /** + * @dev Given a child address/ID that is owned by some token in this contract, return that owning token's owner + * @param _childContract the address of the child asset being queried + * @param _childTokenId the specific ID of the child asset being queried + * @return parentTokenOwner the address of the owner of that child's parent asset + * @return parentTokenId the local token ID that is the parent of that child asset + */ + function _ownerOfChild(address _childContract, uint256 _childTokenId) internal view returns (address parentTokenOwner, uint256 parentTokenId) { + parentTokenId = childTokenOwner[_childContract][_childTokenId]; + require(parentTokenId > 0, "That child is not owned by a token in this contract"); + return (ownerOf(parentTokenId - TOKEN_OWNER_OFFSET), parentTokenId - TOKEN_OWNER_OFFSET); + } + + /** + * @dev See {IERC998ERC721TopDown-ownerOfChild}. + */ + function ownerOfChild(address _childContract, uint256 _childTokenId) + public + override + view + returns (bytes32 parentTokenOwner, uint256 parentTokenId) + { + parentTokenId = childTokenOwner[_childContract][_childTokenId]; + require(parentTokenId > 0, "That child is not owned by a token in this contract"); + return (ERC998_MAGIC_VALUE << 224 | bytes32(uint256(ownerOf(parentTokenId - TOKEN_OWNER_OFFSET))), parentTokenId - TOKEN_OWNER_OFFSET); + } + + /** + * @dev See {IERC998ERC721TopDown-rootOwnerOf}. + */ + function rootOwnerOf(uint256 _tokenId) + public + override + view + returns (bytes32 rootOwner) + { + return rootOwnerOfChild(address(0), _tokenId); + } + + /** + * @dev See {IERC998ERC721TopDown-rootOwnerOfChild}. + */ + function rootOwnerOfChild(address _childContract, uint256 _childTokenId) + public + override + view + returns (bytes32 rootOwner) + { + address rootOwnerAddress; + if (_childContract != address(0)) { + (rootOwnerAddress, _childTokenId) = _ownerOfChild(_childContract, _childTokenId); + } else { + rootOwnerAddress = ownerOf(_childTokenId); + } + // Case 1: Token owner is this contract and token. + while (rootOwnerAddress == address(this)) { + (rootOwnerAddress, _childTokenId) = _ownerOfChild(rootOwnerAddress, _childTokenId); + } + + (bool callSuccess, bytes memory data) = rootOwnerAddress.staticcall(abi.encodeWithSelector(0xed81cdda, address(this), _childTokenId)); + if (data.length != 0) { + rootOwner = abi.decode(data, (bytes32)); + } + + if(callSuccess == true && rootOwner >> 224 == ERC998_MAGIC_VALUE) { + // Case 2: Token owner is other top-down composable + return rootOwner; + } + else { + // Case 3: Token owner is other contract + // Or + // Case 4: Token owner is user + return ERC998_MAGIC_VALUE << 224 | bytes32(uint256(rootOwnerAddress)); + } + } + + /** + * @dev remove internal records linking a given child to a given parent + * @param _tokenId the local token ID that is the parent of the child asset + * @param _childContract the address of the child asset to remove + * @param _childTokenId the specific ID representing the child asset to be removed + */ + function _removeChild(uint256 _tokenId, address _childContract, uint256 _childTokenId) private { + require( + childTokens[_tokenId][_childContract].contains(_childTokenId), + "Child token not owned by token" + ); + + // remove child token + childTokens[_tokenId][_childContract].remove(_childTokenId); + delete childTokenOwner[_childContract][_childTokenId]; + + // remove contract + if (childTokens[_tokenId][_childContract].length() == 0) { + childContracts[_tokenId].remove(_childContract); + } + } + + /** + * @dev check permissions are correct for a transfer of a child asset + * @param _fromTokenId the local ID of the token that is the parent + * @param _to the address this child token is being transferred to + * @param _childContract the address of the child asset's contract + * @param _childTokenId the specific ID for the child asset being transferred + */ + function _checkTransferChild( + uint256 _fromTokenId, + address _to, + address _childContract, + uint256 _childTokenId + ) private view { + require(!paused(), "Child transfer while paused"); + uint256 tokenId = childTokenOwner[_childContract][_childTokenId]; + require(tokenId > 0, "Child asset is not owned by a token in this contract"); + tokenId -= TOKEN_OWNER_OFFSET; + require(tokenId == _fromTokenId, "That MoonCat does not own that asset"); + require(_to != address(0), "Transfer to zero address"); + address rootOwner = address(uint160(uint256(rootOwnerOf(_fromTokenId)))); + require( + _msgSender() == rootOwner || getApproved(_fromTokenId) == _msgSender() || ERC721.isApprovedForAll(rootOwner, _msgSender()), + "Not allowed to transfer child assets of that MoonCat" + ); + } + + /** + * @dev See {IERC998ERC721TopDown-safeTransferChild}. + */ + function safeTransferChild( + uint256 _fromTokenId, + address _to, + address _childContract, + uint256 _childTokenId + ) public override { + _checkTransferChild(_fromTokenId, _to, _childContract, _childTokenId); + _removeChild(_fromTokenId, _childContract, _childTokenId); + ERC721(_childContract).safeTransferFrom(address(this), _to, _childTokenId); + emit TransferChild(_fromTokenId, _to, _childContract, _childTokenId); + } + + /** + * @dev See {IERC998ERC721TopDown-safeTransferChild}. + */ + function safeTransferChild( + uint256 _fromTokenId, + address _to, + address _childContract, + uint256 _childTokenId, + bytes calldata _data + ) public override { + _checkTransferChild(_fromTokenId, _to, _childContract, _childTokenId); + _removeChild(_fromTokenId, _childContract, _childTokenId); + ERC721(_childContract).safeTransferFrom(address(this), _to, _childTokenId, _data); + emit TransferChild(_fromTokenId, _to, _childContract, _childTokenId); + } + + /** + * @dev See {IERC998ERC721TopDown-transferChild}. + */ + function transferChild( + uint256 _fromTokenId, + address _to, + address _childContract, + uint256 _childTokenId + ) public override { + _checkTransferChild(_fromTokenId, _to, _childContract, _childTokenId); + _removeChild(_fromTokenId, _childContract, _childTokenId); + //this is here to be compatible with cryptokitties and other old contracts that require being owner and approved + // before transferring. + //does not work with current standard which does not allow approving self, so we must let it fail in that case. + //0x095ea7b3 == "approve(address,uint256)" + (bool success, bytes memory data) = _childContract.call(abi.encodeWithSelector(0x095ea7b3, this, _childTokenId)); + require( + success && (data.length == 0 || abi.decode(data, (bool))), + 'Failed to Approve' + ); + ERC721(_childContract).transferFrom(address(this), _to, _childTokenId); + emit TransferChild(_fromTokenId, _to, _childContract, _childTokenId); + } + + /** + * @dev See {IERC998ERC721TopDown-transferChildToParent}. + */ + function transferChildToParent( + uint256 _fromTokenId, + address _toContract, + uint256 _toTokenId, + address _childContract, + uint256 _childTokenId, + bytes calldata _data + ) public override { + _checkTransferChild(_fromTokenId, _toContract, _childContract, _childTokenId); + _removeChild(_fromTokenId, _childContract, _childTokenId); + IERC998ERC721BottomUp(_childContract).transferToParent(address(this), _toContract, _toTokenId, _childTokenId, _data); + emit TransferChild(_fromTokenId, _toContract, _childContract, _childTokenId); + } + + ///// ERC998 Enumerable + + /** + * @dev See {IERC998ERC721TopDownEnumerable-totalChildContracts}. + */ + function totalChildContracts(uint256 _tokenId) + external + override + view + returns (uint256) + { + return childContracts[_tokenId].length(); + } + + /** + * @dev See {IERC998ERC721TopDownEnumerable-childContractByIndex}. + */ + function childContractByIndex(uint256 _tokenId, uint256 _index) + external + override + view + returns (address childContract) + { + return childContracts[_tokenId].at(_index); + } + + /** + * @dev See {IERC998ERC721TopDownEnumerable-totalChildTokens}. + */ + function totalChildTokens(uint256 _tokenId, address _childContract) external override view returns (uint256) { + return childTokens[_tokenId][_childContract].length(); + } + + /** + * @dev See {IERC998ERC721TopDownEnumerable-childTokenByIndex}. + */ + function childTokenByIndex(uint256 _tokenId, address _childContract, uint256 _index) external override view returns (uint256 childTokenId) { + return childTokens[_tokenId][_childContract].at(_index); + } +} + +// UTILITIES + +/** + * @dev converts bytes (which is at least 32 bytes long) to uint256 + */ +function toUint256(bytes memory _bytes, uint256 _start) pure returns (uint256) { + require(_start + 32 >= _start, "toUint256_overflow"); + require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); + uint256 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0x20), _start)) + } + + return tempUint; +} + +/** + * @dev converts uint256 to a bytes(32) object + */ +function uintToBytes(uint256 x) pure returns (bytes memory b) { + b = new bytes(32); + assembly { + mstore(add(b, 32), x) + } +} + +/** + * @dev converts bytes (which is at least 20 bytes long) to address + */ +function bytesToAddress(bytes memory bys, uint256 _start) + pure + returns (address addr) +{ + assembly { + addr := mload(add(add(bys, 20), _start)) + } +} + +/** + * @dev converts address to a bytes(32) object + */ +function addressToBytes(address a) pure returns (bytes memory) { + return abi.encodePacked(a); +} + + +/////////////////////////////////////////// +// File: openzeppelin/contracts/token/ERC721/ERC721.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +import "@openzeppelin/contracts/utils/Context.sol"; +import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/IERC721Metadata.sol"; +import "@openzeppelin/contracts/token/ERC721/IERC721Enumerable.sol"; +import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; +import "@openzeppelin/contracts/introspection/ERC165.sol"; +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; +import "@openzeppelin/contracts/utils/EnumerableSet.sol"; +import "@openzeppelin/contracts/utils/EnumerableMap.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; + +/** + * @title ERC721 Non-Fungible Token Standard basic implementation + * @dev see https://eips.ethereum.org/EIPS/eip-721 + */ +contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable { + using SafeMath for uint256; + using Address for address; + using EnumerableSet for EnumerableSet.UintSet; + using EnumerableMap for EnumerableMap.UintToAddressMap; + using Strings for uint256; + + // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` + // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` + bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; + + // Mapping from holder address to their (enumerable) set of owned tokens + mapping (address => EnumerableSet.UintSet) private _holderTokens; + + // Enumerable mapping from token ids to their owners + EnumerableMap.UintToAddressMap private _tokenOwners; + + // Mapping from token ID to approved address + mapping (uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping (address => mapping (address => bool)) private _operatorApprovals; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Optional mapping for token URIs + mapping (uint256 => string) private _tokenURIs; + + // Base URI + string private _baseURI; + + /* + * bytes4(keccak256('balanceOf(address)')) == 0x70a08231 + * bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e + * bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3 + * bytes4(keccak256('getApproved(uint256)')) == 0x081812fc + * bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465 + * bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5 + * bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd + * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e + * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde + * + * => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^ + * 0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd + */ + bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd; + + /* + * bytes4(keccak256('name()')) == 0x06fdde03 + * bytes4(keccak256('symbol()')) == 0x95d89b41 + * bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd + * + * => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f + */ + bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f; + + /* + * bytes4(keccak256('totalSupply()')) == 0x18160ddd + * bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59 + * bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7 + * + * => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63 + */ + bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63; + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + constructor (string memory name_, string memory symbol_) public { + _name = name_; + _symbol = symbol_; + + // register the supported interfaces to conform to ERC721 via ERC165 + _registerInterface(_INTERFACE_ID_ERC721); + _registerInterface(_INTERFACE_ID_ERC721_METADATA); + _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view virtual override returns (uint256) { + require(owner != address(0), "ERC721: balance query for the zero address"); + return _holderTokens[owner].length(); + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view virtual override returns (address) { + return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token"); + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); + + string memory _tokenURI = _tokenURIs[tokenId]; + string memory base = baseURI(); + + // If there is no base URI, return the token URI. + if (bytes(base).length == 0) { + return _tokenURI; + } + // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked). + if (bytes(_tokenURI).length > 0) { + return string(abi.encodePacked(base, _tokenURI)); + } + // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI. + return string(abi.encodePacked(base, tokenId.toString())); + } + + /** + * @dev Returns the base URI set via {_setBaseURI}. This will be + * automatically added as a prefix in {tokenURI} to each token's URI, or + * to the token ID if no specific URI is set for that token ID. + */ + function baseURI() public view virtual returns (string memory) { + return _baseURI; + } + + /** + * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { + return _holderTokens[owner].at(index); + } + + /** + * @dev Return an array of all tokens this + * CUSTOM FUNCTION, NOT IN OPENZEPPELIN TEMPLATE + */ + function tokensIdsByOwner(address owner) public view returns (uint256[] memory) { + uint256[] memory tokens = new uint256[](_holderTokens[owner].length()); + for (uint i = 0; i < _holderTokens[owner].length(); i++) { + tokens[i] = _holderTokens[owner].at(i); + } + return tokens; + } + + /** + * @dev See {IERC721Enumerable-totalSupply}. + */ + function totalSupply() public view virtual override returns (uint256) { + // _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds + return _tokenOwners.length(); + } + + /** + * @dev See {IERC721Enumerable-tokenByIndex}. + */ + function tokenByIndex(uint256 index) public view virtual override returns (uint256) { + (uint256 tokenId, ) = _tokenOwners.at(index); + return tokenId; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public virtual override { + address owner = ERC721.ownerOf(tokenId); + require(to != owner, "ERC721: approval to current owner"); + + require(_msgSender() == owner || ERC721.isApprovedForAll(owner, _msgSender()), + "ERC721: approve caller is not owner nor approved for all" + ); + + _approve(to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view virtual override returns (address) { + require(_exists(tokenId), "ERC721: approved query for nonexistent token"); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + require(operator != _msgSender(), "ERC721: approve to caller"); + + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom(address from, address to, uint256 tokenId) public virtual override { + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + + _transfer(from, to, tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { + safeTransferFrom(from, to, tokenId, ""); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override { + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + _safeTransfer(from, to, tokenId, _data); + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * `_data` is additional data, it has no specified format and it is sent in call to `to`. + * + * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. + * implement alternative mechanisms to perform token transfer, such as signature-based. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual { + _transfer(from, to, tokenId); + require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + * and stop existing when they are burned (`_burn`). + */ + function _exists(uint256 tokenId) internal view virtual returns (bool) { + return _tokenOwners.contains(tokenId); + } + + /** + * @dev Returns whether `spender` is allowed to manage `tokenId`. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { + require(_exists(tokenId), "ERC721: operator query for nonexistent token"); + address owner = ERC721.ownerOf(tokenId); + return (spender == owner || getApproved(tokenId) == spender || ERC721.isApprovedForAll(owner, spender)); + } + + /** + * @dev Safely mints `tokenId` and transfers it to `to`. + * + * Requirements: + d* + * - `tokenId` must not exist. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeMint(address to, uint256 tokenId) internal virtual { + _safeMint(to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual { + _mint(to, tokenId); + require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Mints `tokenId` and transfers it to `to`. + * + * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * Emits a {Transfer} event. + */ + function _mint(address to, uint256 tokenId) internal virtual { + require(to != address(0), "ERC721: mint to the zero address"); + // DIFFERENT FROM OPENZEPPELIN STANDARD + // Calls `ERC721._exists` rather than `_exists` + require(!ERC721._exists(tokenId), "ERC721: token already minted"); + + _beforeTokenTransfer(address(0), to, tokenId); + + _holderTokens[to].add(tokenId); + + _tokenOwners.set(tokenId, to); + + emit Transfer(address(0), to, tokenId); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId) internal virtual { + address owner = ERC721.ownerOf(tokenId); // internal owner + + _beforeTokenTransfer(owner, address(0), tokenId); + + // Clear approvals + _approve(address(0), tokenId); + + // Clear metadata (if any) + if (bytes(_tokenURIs[tokenId]).length != 0) { + delete _tokenURIs[tokenId]; + } + + _holderTokens[owner].remove(tokenId); + + _tokenOwners.remove(tokenId); + + emit Transfer(owner, address(0), tokenId); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer(address from, address to, uint256 tokenId) internal virtual { + require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); // internal owner + require(to != address(0), "ERC721: transfer to the zero address"); + + _beforeTokenTransfer(from, to, tokenId); + + // Clear approvals from the previous owner + _approve(address(0), tokenId); + + _holderTokens[from].remove(tokenId); + _holderTokens[to].add(tokenId); + + _tokenOwners.set(tokenId, to); + + emit Transfer(from, to, tokenId); + } + + /** + * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { + require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token"); + _tokenURIs[tokenId] = _tokenURI; + } + + /** + * @dev Internal function to set the base URI for all token IDs. It is + * automatically added as a prefix to the value returned in {tokenURI}, + * or to the token ID if {tokenURI} is empty. + */ + function _setBaseURI(string memory baseURI_) internal virtual { + _baseURI = baseURI_; + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * The call is not executed if the target address is not a contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) + private returns (bool) + { + if (!to.isContract()) { + return true; + } + bytes memory returndata = to.functionCall(abi.encodeWithSelector( + IERC721Receiver(to).onERC721Received.selector, + _msgSender(), + from, + tokenId, + _data + ), "ERC721: transfer to non ERC721Receiver implementer"); + bytes4 retval = abi.decode(returndata, (bytes4)); + return (retval == _ERC721_RECEIVED); + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * Emits an {Approval} event. + */ + function _approve(address to, uint256 tokenId) internal virtual { + _tokenApprovals[tokenId] = to; + // DIFFERENT FROM OPENZEPPELIN STANDARD + // Calls `ownerOf` rather than `ERC721.ownerOf` + emit Approval(ownerOf(tokenId), to, tokenId); + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, ``from``'s `tokenId` will be burned. + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { } +} + + +/////////////////////////////////////////// +// File: MoonCatOrderLookup.sol + +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.7.3; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "./IMoonCatRescue.sol"; +import "./IMoonCatsWrapped.sol"; + +/** + * @title MoonCat Order Lookup + * @notice A space to have an on-chain record mapping token IDs for OLD_MCRW to their original "rescue order" IDs + * @dev This contract exists because there is no MoonCat ID => Rescue ID function + * on the original MoonCatRescue contract. The only way to tell a given MoonCat's + * rescue order if you don't know it is to iterate through the whole `rescueOrder` + * array. Looping through that whole array in a smart contract would be + * prohibitively high gas-usage, and so this alternative is needed. + */ +contract MoonCatOrderLookup is Ownable { + + MoonCatRescue MCR = MoonCatRescue(0x60cd862c9C687A9dE49aecdC3A99b74A4fc54aB6); + MoonCatsWrapped OLD_MCRW = MoonCatsWrapped(0x7C40c393DC0f283F318791d746d894DdD3693572); + + uint256[25600] private _oldTokenIdToRescueOrder; + uint8 constant VALUE_OFFSET = 10; + + constructor() Ownable() {} + + /** + * @dev Submit a batch of token IDs, and their associated rescue orders + * This is the primary method for the utility of the contract. Anyone + * can submit this pairing information (not just the owners of the token) + * and the information can be submitted in batches. + * + * Submitting pairs of token IDs with their rescue orders is verified with + * the original MoonCatRescue contract before recording. + * + * Within the private array holding this information, a VALUE_OFFSET is used + * to differentiate between "not set" and "set to zero" (because Solidity + * has no concept of "null" or "undefined"). Because the maximum value of the + * rescue ordering can only be 25,600, we can safely shift the stored values + * up, and not hit the uint256 limit. + */ + function submitRescueOrder( + uint256[] memory oldTokenIds, + uint16[] memory rescueOrders + ) public { + for (uint256 i = 0; i < oldTokenIds.length; i++) { + require( + MCR.rescueOrder(rescueOrders[i]) == OLD_MCRW._tokenIDToCatID(oldTokenIds[i]), + "Pair does not match!" + ); + _oldTokenIdToRescueOrder[oldTokenIds[i]] = rescueOrders[i] + VALUE_OFFSET; + } + } + + /** + * @dev verify a given old token ID is mapped yet or not + * + * This function can use just a zero-check because internally all values are + * stored with a VALUE_OFFSET added onto them (e.g. storing an actual zero + * is saved as 0 + VALUE_OFFSET = 10, internally), so anything set to an + * actual zero means "unset". + */ + function _exists(uint256 oldTokenId) internal view returns (bool) { + return _oldTokenIdToRescueOrder[oldTokenId] != 0; + } + + /** + * @dev public function to verify whether a given old token ID is mapped or not + */ + function oldTokenIdExists(uint256 oldTokenId) public view returns(bool) { + return _exists(oldTokenId); + } + + /** + * @dev given an old token ID, return the rescue order of that MoonCat + * + * Throws an error if that particular token ID does not have a recorded + * mapping to a rescue order. + */ + function oldTokenIdToRescueOrder(uint256 oldTokenId) public view returns(uint256) { + require(_exists(oldTokenId), "That token ID is not mapped yet"); + return _oldTokenIdToRescueOrder[oldTokenId] - VALUE_OFFSET; + } + + /** + * @dev remove a mapping from the data structure + * + * This allows reclaiming some gas, so as part of the re-wrapping process, + * this gets called by the Acclimator contract, to recoup some gas for the + * MoonCat owner. + */ + function removeEntry(uint256 _oldTokenId) public onlyOwner { + delete _oldTokenIdToRescueOrder[_oldTokenId]; + } + + /** + * @dev for a given address, iterate through all the tokens they own in the + * old wrapping contract, and for each of them, determine how many are mapped + * in this lookup contract. + * + * This method is used by the Acclimator `balanceOf` and `tokenOfOwnerByIndex` + * to be able to enumerate old-wrapped MoonCats as if they were already + * re-wrapped in the Acclimator contract. + */ + function entriesPerAddress(address _owner) public view returns (uint256) { + uint256 countMapped = 0; + for (uint256 i = 0; i < OLD_MCRW.balanceOf(_owner); i++) { + uint256 oldTokenId = OLD_MCRW.tokenOfOwnerByIndex(_owner, i); + if (_exists(oldTokenId)) { + countMapped++; + } + } + return countMapped; + } +} + + +/////////////////////////////////////////// +// File: IERC998.sol + +pragma solidity ^0.7.3; + +/** + * @title ERC998ERC721 Top-Down Composable Non-Fungible Token + * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-998.md + * Note: the ERC-165 identifier for this interface is 0x1efdf36a + */ +interface IERC998ERC721TopDown { + /** + * @dev This emits when a token receives a child token. + * @param _from The prior owner of the token. + * @param _toTokenId The token that receives the child token. + */ + event ReceivedChild( + address indexed _from, + uint256 indexed _toTokenId, + address indexed _childContract, + uint256 _childTokenId + ); + + /** + * @dev This emits when a child token is transferred from a token to an address. + * @param _fromTokenId The parent token that the child token is being transferred from. + * @param _to The new owner address of the child token. + */ + event TransferChild( + uint256 indexed _fromTokenId, + address indexed _to, + address indexed _childContract, + uint256 _childTokenId + ); + + /** + * @notice Get the root owner of tokenId. + * @param _tokenId The token to query for a root owner address + * @return rootOwner The root owner at the top of tree of tokens and ERC998 magic value. + */ + function rootOwnerOf(uint256 _tokenId) + external + view + returns (bytes32 rootOwner); + + /** + * @notice Get the root owner of a child token. + * @param _childContract The contract address of the child token. + * @param _childTokenId The tokenId of the child. + * @return rootOwner The root owner at the top of tree of tokens and ERC998 magic value. + */ + function rootOwnerOfChild(address _childContract, uint256 _childTokenId) + external + view + returns (bytes32 rootOwner); + + /** + * @notice Get the parent tokenId of a child token. + * @param _childContract The contract address of the child token. + * @param _childTokenId The tokenId of the child. + * @return parentTokenOwner The parent address of the parent token and ERC998 magic value + * @return parentTokenId The parent tokenId of _tokenId + */ + function ownerOfChild(address _childContract, uint256 _childTokenId) + external + view + returns (bytes32 parentTokenOwner, uint256 parentTokenId); + + /** + * @notice A token receives a child token + * @param _operator The address that caused the transfer. + * @param _from The owner of the child token. + * @param _childTokenId The token that is being transferred to the parent. + * @param _data Up to the first 32 bytes contains an integer which is the receiving parent tokenId. + */ + function onERC721Received( + address _operator, + address _from, + uint256 _childTokenId, + bytes calldata _data + ) external returns (bytes4); + + /** + * @notice Transfer child token from top-down composable to address. + * @param _fromTokenId The owning token to transfer from. + * @param _to The address that receives the child token + * @param _childContract The ERC721 contract of the child token. + * @param _childTokenId The tokenId of the token that is being transferred. + */ + function transferChild( + uint256 _fromTokenId, + address _to, + address _childContract, + uint256 _childTokenId + ) external; + + /** + * @notice Transfer child token from top-down composable to address. + * @param _fromTokenId The owning token to transfer from. + * @param _to The address that receives the child token + * @param _childContract The ERC721 contract of the child token. + * @param _childTokenId The tokenId of the token that is being transferred. + */ + function safeTransferChild( + uint256 _fromTokenId, + address _to, + address _childContract, + uint256 _childTokenId + ) external; + + /** + * @notice Transfer child token from top-down composable to address. + * @param _fromTokenId The owning token to transfer from. + * @param _to The address that receives the child token + * @param _childContract The ERC721 contract of the child token. + * @param _childTokenId The tokenId of the token that is being transferred. + * @param _data Additional data with no specified format + */ + function safeTransferChild( + uint256 _fromTokenId, + address _to, + address _childContract, + uint256 _childTokenId, + bytes calldata _data + ) external; + + /** + * @notice Transfer bottom-up composable child token from top-down composable to other ERC721 token. + * @param _fromTokenId The owning token to transfer from. + * @param _toContract The ERC721 contract of the receiving token + * @param _toTokenId The receiving token + * @param _childContract The bottom-up composable contract of the child token. + * @param _childTokenId The token that is being transferred. + * @param _data Additional data with no specified format + */ + function transferChildToParent( + uint256 _fromTokenId, + address _toContract, + uint256 _toTokenId, + address _childContract, + uint256 _childTokenId, + bytes calldata _data + ) external; + + /** + * @notice Get a child token from an ERC721 contract. + * @param _from The address that owns the child token. + * @param _tokenId The token that becomes the parent owner + * @param _childContract The ERC721 contract of the child token + * @param _childTokenId The tokenId of the child token + */ + function getChild( + address _from, + uint256 _tokenId, + address _childContract, + uint256 _childTokenId + ) external; +} + +/** + * @dev The ERC-165 identifier for this interface is 0xa344afe4 + */ +interface IERC998ERC721TopDownEnumerable { + /** + * @notice Get the total number of child contracts with tokens that are owned by tokenId. + * @param _tokenId The parent token of child tokens in child contracts + * @return uint256 The total number of child contracts with tokens owned by tokenId. + */ + function totalChildContracts(uint256 _tokenId) + external + view + returns (uint256); + + /** + * @notice Get child contract by tokenId and index + * @param _tokenId The parent token of child tokens in child contract + * @param _index The index position of the child contract + * @return childContract The contract found at the tokenId and index. + */ + function childContractByIndex(uint256 _tokenId, uint256 _index) + external + view + returns (address childContract); + + /** + * @notice Get the total number of child tokens owned by tokenId that exist in a child contract. + * @param _tokenId The parent token of child tokens + * @param _childContract The child contract containing the child tokens + * @return uint256 The total number of child tokens found in child contract that are owned by tokenId. + */ + function totalChildTokens(uint256 _tokenId, address _childContract) + external + view + returns (uint256); + + /** + * @notice Get child token owned by tokenId, in child contract, at index position + * @param _tokenId The parent token of the child token + * @param _childContract The child contract of the child token + * @param _index The index position of the child token. + * @return childTokenId The child tokenId for the parent token, child token and index + */ + function childTokenByIndex( + uint256 _tokenId, + address _childContract, + uint256 _index + ) external view returns (uint256 childTokenId); +} + +interface IERC998ERC721BottomUp { + /** + * @notice Transfer token from owner address to a token + * @param _from The owner address + * @param _toContract The ERC721 contract of the receiving token + * @param _toTokenId The receiving token + * @param _data Additional data with no specified format + */ + function transferToParent( + address _from, + address _toContract, + uint256 _toTokenId, + uint256 _tokenId, + bytes calldata _data + ) external; +} + +/////////////////////////////////////////// +// File: IMoonCatRescue.sol + +pragma solidity ^0.7.3; +interface MoonCatRescue { + function getCatDetails(bytes5 catId) + external + view + returns ( + bytes5 id, + address owner, + bytes32 name, + address onlyOfferTo, + uint256 offerPrice, + address requester, + uint256 requestPrice + ); + + function rescueOrder(uint256 _rescueOrder) + external + view + returns (bytes5 catId); + + function acceptAdoptionOffer(bytes5 catId) external payable; + + function acceptAdoptionRequest(bytes5 catId) external; + + function adoptionRequests(bytes5 _catId) + external + view + returns ( + bool exists, + bytes5 catId, + address requester, + uint256 price + ); + + function adoptionOffers(bytes5 _catId) + external + view + returns ( + bool exists, + bytes5 catId, + address seller, + uint256 price, + address offerOnlyTo + ); + + function giveCat(bytes5 catId, address to) external; + + function catOwners(bytes5) external view returns (address); + + function makeAdoptionOfferToAddress(bytes5 catId, uint256 price, address to) external; + + function makeAdoptionOffer(bytes5 catId, uint256 price) external; + + function withdraw() external; +} + + +/////////////////////////////////////////// +// File: IMoonCatsWrapped.sol + +pragma solidity ^0.7.3; +interface MoonCatsWrapped { + + /** + * @dev in the original contract, this is a public map property, so is + * using the default getter action, which does NOT check for "exists"; + * if this returns a zero, it might be referencing token ID #0, or it might + * be meaning "that MoonCat ID is not wrapped in this contract". + */ + function _catIDToTokenID(bytes5 catId) external pure + returns (uint256); + + /** + * @dev in the original contract, this is a public map property, so is + * using the default getter action, which does NOT check for "exists". + * However, no MoonCat has an ID of `0x0000000000`, so if this returns + * all zeroes, it means "that token ID does not exist in this contract". + */ + function _tokenIDToCatID(uint256 _tokenID) external pure + returns (bytes5 catId); + + function safeTransferFrom(address from, address to, uint256 tokenId) external; + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) external; + function balanceOf(address owner) external view returns (uint256 balance); + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); + function wrap(bytes5 catId) external; + function unwrap(uint256 tokenID) external; + function ownerOf(uint256 tokenID) external view returns(address); + function setApprovalForAll(address operator, bool _approved) external; + function isApprovedForAll(address owner, address operator) external view returns (bool); + function approve(address to, uint256 tokenId) external; +} + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with GSN meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address payable) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes memory) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/access/Ownable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +import "../utils/Context.sol"; +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor () internal { + address msgSender = _msgSender(); + _owner = msgSender; + emit OwnershipTransferred(address(0), msgSender); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Pausable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +import "./Context.sol"; + +/** + * @dev Contract module which allows children to implement an emergency stop + * mechanism that can be triggered by an authorized account. + * + * This module is used through inheritance. It will make available the + * modifiers `whenNotPaused` and `whenPaused`, which can be applied to + * the functions of your contract. Note that they will not be pausable by + * simply including this module, only once the modifiers are put in place. + */ +abstract contract Pausable is Context { + /** + * @dev Emitted when the pause is triggered by `account`. + */ + event Paused(address account); + + /** + * @dev Emitted when the pause is lifted by `account`. + */ + event Unpaused(address account); + + bool private _paused; + + /** + * @dev Initializes the contract in unpaused state. + */ + constructor () internal { + _paused = false; + } + + /** + * @dev Returns true if the contract is paused, and false otherwise. + */ + function paused() public view virtual returns (bool) { + return _paused; + } + + /** + * @dev Modifier to make a function callable only when the contract is not paused. + * + * Requirements: + * + * - The contract must not be paused. + */ + modifier whenNotPaused() { + require(!paused(), "Pausable: paused"); + _; + } + + /** + * @dev Modifier to make a function callable only when the contract is paused. + * + * Requirements: + * + * - The contract must be paused. + */ + modifier whenPaused() { + require(paused(), "Pausable: not paused"); + _; + } + + /** + * @dev Triggers stopped state. + * + * Requirements: + * + * - The contract must not be paused. + */ + function _pause() internal virtual whenNotPaused { + _paused = true; + emit Paused(_msgSender()); + } + + /** + * @dev Returns to normal state. + * + * Requirements: + * + * - The contract must be paused. + */ + function _unpause() internal virtual whenPaused { + _paused = false; + emit Unpaused(_msgSender()); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/IERC721.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +import "../../introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/IERC721Metadata.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +import "./IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/IERC721Enumerable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +import "./IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Enumerable is IERC721 { + + /** + * @dev Returns the total amount of tokens stored by the contract. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns a token ID owned by `owner` at a given `index` of its token list. + * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); + + /** + * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. + * Use along with {totalSupply} to enumerate all tokens. + */ + function tokenByIndex(uint256 index) external view returns (uint256); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. + */ + function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/ERC721Holder.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +import "./IERC721Receiver.sol"; + + /** + * @dev Implementation of the {IERC721Receiver} interface. + * + * Accepts all token transfers. + * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. + */ +contract ERC721Holder is IERC721Receiver { + + /** + * @dev See {IERC721Receiver-onERC721Received}. + * + * Always returns `IERC721Receiver.onERC721Received.selector`. + */ + function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) { + return this.onERC721Received.selector; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/introspection/ERC165.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts may inherit from this and call {_registerInterface} to declare + * their support of an interface. + */ +abstract contract ERC165 is IERC165 { + /* + * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 + */ + bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; + + /** + * @dev Mapping of interface ids to whether or not it's supported. + */ + mapping(bytes4 => bool) private _supportedInterfaces; + + constructor () internal { + // Derived contracts need only register support for their own interfaces, + // we register support for ERC165 itself here + _registerInterface(_INTERFACE_ID_ERC165); + } + + /** + * @dev See {IERC165-supportsInterface}. + * + * Time complexity O(1), guaranteed to always use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return _supportedInterfaces[interfaceId]; + } + + /** + * @dev Registers the contract as an implementer of the interface defined by + * `interfaceId`. Support of the actual ERC165 interface is automatic and + * registering its interface id is not required. + * + * See {IERC165-supportsInterface}. + * + * Requirements: + * + * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). + */ + function _registerInterface(bytes4 interfaceId) internal virtual { + require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); + _supportedInterfaces[interfaceId] = true; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/introspection/IERC165.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the substraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b > a) return (false, 0); + return (true, a - b); + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a / b); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + if (b == 0) return (false, 0); + return (true, a % b); + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0) return 0; + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: division by zero"); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b > 0, "SafeMath: modulo by zero"); + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + return a - b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryDiv}. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + return a % b; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.2 <0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/EnumerableSet.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Library for managing + * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive + * types. + * + * Sets have the following properties: + * + * - Elements are added, removed, and checked for existence in constant time + * (O(1)). + * - Elements are enumerated in O(n). No guarantees are made on the ordering. + * + * ``` + * contract Example { + * // Add the library methods + * using EnumerableSet for EnumerableSet.AddressSet; + * + * // Declare a set state variable + * EnumerableSet.AddressSet private mySet; + * } + * ``` + * + * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) + * and `uint256` (`UintSet`) are supported. + */ +library EnumerableSet { + // To implement this library for multiple types with as little code + // repetition as possible, we write it in terms of a generic Set type with + // bytes32 values. + // The Set implementation uses private functions, and user-facing + // implementations (such as AddressSet) are just wrappers around the + // underlying Set. + // This means that we can only create new EnumerableSets for types that fit + // in bytes32. + + struct Set { + // Storage of set values + bytes32[] _values; + + // Position of the value in the `values` array, plus 1 because index 0 + // means a value is not in the set. + mapping (bytes32 => uint256) _indexes; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function _add(Set storage set, bytes32 value) private returns (bool) { + if (!_contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + set._indexes[value] = set._values.length; + return true; + } else { + return false; + } + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function _remove(Set storage set, bytes32 value) private returns (bool) { + // We read and store the value's index to prevent multiple reads from the same storage slot + uint256 valueIndex = set._indexes[value]; + + if (valueIndex != 0) { // Equivalent to contains(set, value) + // To delete an element from the _values array in O(1), we swap the element to delete with the last one in + // the array, and then remove the last element (sometimes called as 'swap and pop'). + // This modifies the order of the array, as noted in {at}. + + uint256 toDeleteIndex = valueIndex - 1; + uint256 lastIndex = set._values.length - 1; + + // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs + // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. + + bytes32 lastvalue = set._values[lastIndex]; + + // Move the last value to the index where the value to delete is + set._values[toDeleteIndex] = lastvalue; + // Update the index for the moved value + set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based + + // Delete the slot where the moved value was stored + set._values.pop(); + + // Delete the index for the deleted slot + delete set._indexes[value]; + + return true; + } else { + return false; + } + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function _contains(Set storage set, bytes32 value) private view returns (bool) { + return set._indexes[value] != 0; + } + + /** + * @dev Returns the number of values on the set. O(1). + */ + function _length(Set storage set) private view returns (uint256) { + return set._values.length; + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function _at(Set storage set, uint256 index) private view returns (bytes32) { + require(set._values.length > index, "EnumerableSet: index out of bounds"); + return set._values[index]; + } + + // Bytes32Set + + struct Bytes32Set { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _add(set._inner, value); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _remove(set._inner, value); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { + return _contains(set._inner, value); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(Bytes32Set storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { + return _at(set._inner, index); + } + + // AddressSet + + struct AddressSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(AddressSet storage set, address value) internal returns (bool) { + return _add(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(AddressSet storage set, address value) internal returns (bool) { + return _remove(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(AddressSet storage set, address value) internal view returns (bool) { + return _contains(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(AddressSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(AddressSet storage set, uint256 index) internal view returns (address) { + return address(uint160(uint256(_at(set._inner, index)))); + } + + + // UintSet + + struct UintSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(UintSet storage set, uint256 value) internal returns (bool) { + return _add(set._inner, bytes32(value)); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(UintSet storage set, uint256 value) internal returns (bool) { + return _remove(set._inner, bytes32(value)); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(UintSet storage set, uint256 value) internal view returns (bool) { + return _contains(set._inner, bytes32(value)); + } + + /** + * @dev Returns the number of values on the set. O(1). + */ + function length(UintSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintSet storage set, uint256 index) internal view returns (uint256) { + return uint256(_at(set._inner, index)); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/EnumerableMap.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev Library for managing an enumerable variant of Solidity's + * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] + * type. + * + * Maps have the following properties: + * + * - Entries are added, removed, and checked for existence in constant time + * (O(1)). + * - Entries are enumerated in O(n). No guarantees are made on the ordering. + * + * ``` + * contract Example { + * // Add the library methods + * using EnumerableMap for EnumerableMap.UintToAddressMap; + * + * // Declare a set state variable + * EnumerableMap.UintToAddressMap private myMap; + * } + * ``` + * + * As of v3.0.0, only maps of type `uint256 -> address` (`UintToAddressMap`) are + * supported. + */ +library EnumerableMap { + // To implement this library for multiple types with as little code + // repetition as possible, we write it in terms of a generic Map type with + // bytes32 keys and values. + // The Map implementation uses private functions, and user-facing + // implementations (such as Uint256ToAddressMap) are just wrappers around + // the underlying Map. + // This means that we can only create new EnumerableMaps for types that fit + // in bytes32. + + struct MapEntry { + bytes32 _key; + bytes32 _value; + } + + struct Map { + // Storage of map keys and values + MapEntry[] _entries; + + // Position of the entry defined by a key in the `entries` array, plus 1 + // because index 0 means a key is not in the map. + mapping (bytes32 => uint256) _indexes; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function _set(Map storage map, bytes32 key, bytes32 value) private returns (bool) { + // We read and store the key's index to prevent multiple reads from the same storage slot + uint256 keyIndex = map._indexes[key]; + + if (keyIndex == 0) { // Equivalent to !contains(map, key) + map._entries.push(MapEntry({ _key: key, _value: value })); + // The entry is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + map._indexes[key] = map._entries.length; + return true; + } else { + map._entries[keyIndex - 1]._value = value; + return false; + } + } + + /** + * @dev Removes a key-value pair from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function _remove(Map storage map, bytes32 key) private returns (bool) { + // We read and store the key's index to prevent multiple reads from the same storage slot + uint256 keyIndex = map._indexes[key]; + + if (keyIndex != 0) { // Equivalent to contains(map, key) + // To delete a key-value pair from the _entries array in O(1), we swap the entry to delete with the last one + // in the array, and then remove the last entry (sometimes called as 'swap and pop'). + // This modifies the order of the array, as noted in {at}. + + uint256 toDeleteIndex = keyIndex - 1; + uint256 lastIndex = map._entries.length - 1; + + // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs + // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. + + MapEntry storage lastEntry = map._entries[lastIndex]; + + // Move the last entry to the index where the entry to delete is + map._entries[toDeleteIndex] = lastEntry; + // Update the index for the moved entry + map._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based + + // Delete the slot where the moved entry was stored + map._entries.pop(); + + // Delete the index for the deleted slot + delete map._indexes[key]; + + return true; + } else { + return false; + } + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function _contains(Map storage map, bytes32 key) private view returns (bool) { + return map._indexes[key] != 0; + } + + /** + * @dev Returns the number of key-value pairs in the map. O(1). + */ + function _length(Map storage map) private view returns (uint256) { + return map._entries.length; + } + + /** + * @dev Returns the key-value pair stored at position `index` in the map. O(1). + * + * Note that there are no guarantees on the ordering of entries inside the + * array, and it may change when more entries are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function _at(Map storage map, uint256 index) private view returns (bytes32, bytes32) { + require(map._entries.length > index, "EnumerableMap: index out of bounds"); + + MapEntry storage entry = map._entries[index]; + return (entry._key, entry._value); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function _tryGet(Map storage map, bytes32 key) private view returns (bool, bytes32) { + uint256 keyIndex = map._indexes[key]; + if (keyIndex == 0) return (false, 0); // Equivalent to contains(map, key) + return (true, map._entries[keyIndex - 1]._value); // All indexes are 1-based + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function _get(Map storage map, bytes32 key) private view returns (bytes32) { + uint256 keyIndex = map._indexes[key]; + require(keyIndex != 0, "EnumerableMap: nonexistent key"); // Equivalent to contains(map, key) + return map._entries[keyIndex - 1]._value; // All indexes are 1-based + } + + /** + * @dev Same as {_get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {_tryGet}. + */ + function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) { + uint256 keyIndex = map._indexes[key]; + require(keyIndex != 0, errorMessage); // Equivalent to contains(map, key) + return map._entries[keyIndex - 1]._value; // All indexes are 1-based + } + + // UintToAddressMap + + struct UintToAddressMap { + Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) { + return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value)))); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { + return _remove(map._inner, bytes32(key)); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { + return _contains(map._inner, bytes32(key)); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(UintToAddressMap storage map) internal view returns (uint256) { + return _length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the set. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { + (bytes32 key, bytes32 value) = _at(map._inner, index); + return (uint256(key), address(uint160(uint256(value)))); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + * + * _Available since v3.4._ + */ + function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) { + (bool success, bytes32 value) = _tryGet(map._inner, bytes32(key)); + return (success, address(uint160(uint256(value)))); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { + return address(uint160(uint256(_get(map._inner, bytes32(key))))); + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) { + return address(uint160(uint256(_get(map._inner, bytes32(key), errorMessage)))); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Strings.sol + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +/** + * @dev String operations. + */ +library Strings { + /** + * @dev Converts a `uint256` to its ASCII `string` representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + // Inspired by OraclizeAPI's implementation - MIT licence + // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol + + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + uint256 index = digits - 1; + temp = value; + while (temp != 0) { + buffer[index--] = bytes1(uint8(48 + temp % 10)); + temp /= 10; + } + return string(buffer); + } +} + + diff --git a/ethabi/code/0xc3f733ca98e0dad0386979eb96fb1722a1a05e69.yml b/ethabi/code/0xc3f733ca98e0dad0386979eb96fb1722a1a05e69.yml new file mode 100644 index 0000000..529330c --- /dev/null +++ b/ethabi/code/0xc3f733ca98e0dad0386979eb96fb1722a1a05e69.yml @@ -0,0 +1,12 @@ +--- +ContractName: MoonCatAcclimator +CompilerVersion: v0.7.3+commit.9bfce1f6 +OptimizationUsed: '1' +Runs: '200' +ConstructorArguments: '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002568747470733a2f2f6170692e6d6f6f6e6361742e636f6d6d756e6974792f7472616974732f000000000000000000000000000000000000000000000000000000' +EVMVersion: Default +Library: '' +LicenseType: GNU GPLv3 +Proxy: '0' +Implementation: '' +SwarmSource: ipfs://967d8a62f01db6229c1e4a60a677bd1f9686db8d0dceaf3e976bd7b2dac9a009 diff --git a/ethabi/code/0xd12882c8b5d1bccca57c994c6af7d96355590dbd.sol b/ethabi/code/0xd12882c8b5d1bccca57c994c6af7d96355590dbd.sol new file mode 100644 index 0000000..25c09dd --- /dev/null +++ b/ethabi/code/0xd12882c8b5d1bccca57c994c6af7d96355590dbd.sol @@ -0,0 +1,1202 @@ +// File: @openzeppelin/contracts/utils/Strings.sol + + + +pragma solidity ^0.8.0; + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + // Inspired by OraclizeAPI's implementation - MIT licence + // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol + + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + while (value != 0) { + digits -= 1; + buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); + value /= 10; + } + return string(buffer); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + if (value == 0) { + return "0x00"; + } + uint256 temp = value; + uint256 length = 0; + while (temp != 0) { + length++; + temp >>= 8; + } + return toHexString(value, length); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _HEX_SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } +} + +// File: @openzeppelin/contracts/utils/Address.sol + + + +pragma solidity ^0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + assembly { + size := extcodesize(account) + } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/utils/Context.sol + + + +pragma solidity ^0.8.0; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + +// File: @openzeppelin/contracts/access/Ownable.sol + + + +pragma solidity ^0.8.0; + + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor() { + _setOwner(_msgSender()); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _setOwner(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _setOwner(newOwner); + } + + function _setOwner(address newOwner) private { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} + +// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol + + + +pragma solidity ^0.8.0; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. + */ + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + +// File: @openzeppelin/contracts/utils/introspection/IERC165.sol + + + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// File: @openzeppelin/contracts/utils/introspection/ERC165.sol + + + +pragma solidity ^0.8.0; + + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + +// File: @openzeppelin/contracts/token/ERC721/IERC721.sol + + + +pragma solidity ^0.8.0; + + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external; +} + +// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol + + + +pragma solidity ^0.8.0; + + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Enumerable is IERC721 { + /** + * @dev Returns the total amount of tokens stored by the contract. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns a token ID owned by `owner` at a given `index` of its token list. + * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); + + /** + * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. + * Use along with {totalSupply} to enumerate all tokens. + */ + function tokenByIndex(uint256 index) external view returns (uint256); +} + +// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol + + + +pragma solidity ^0.8.0; + + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} + +// File: contracts/V4Punks.sol + + +// Creator: Shadowy Coder + +pragma solidity ^0.8.0; + + + + + + + + + + +/** +██╗░░░██╗░░██╗██╗██████╗░██╗░░░██╗███╗░░██╗██╗░░██╗░██████╗ +██║░░░██║░██╔╝██║██╔══██╗██║░░░██║████╗░██║██║░██╔╝██╔════╝ +╚██╗░██╔╝██╔╝░██║██████╔╝██║░░░██║██╔██╗██║█████═╝░╚█████╗░ +░╚████╔╝░███████║██╔═══╝░██║░░░██║██║╚████║██╔═██╗░░╚═══██╗ +░░╚██╔╝░░╚════██║██║░░░░░╚██████╔╝██║░╚███║██║░╚██╗██████╔╝ +░░░╚═╝░░░░░░░░╚═╝╚═╝░░░░░░╚═════╝░╚═╝░░╚══╝╚═╝░░╚═╝╚═════╝░ +**/ + +contract V4Punks is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable, Ownable { + using Address for address; + using Strings for uint256; + + struct TokenOwnership { + address addr; + uint64 startTimestamp; + } + + struct AddressData { + uint128 balance; + uint128 numberMinted; + } + + uint256 internal currentIndex = 0; + + // mint price + uint256 public _price = 20000000000000000; + + // Token name + string private _name; + + address private _owner = msg.sender; + + // Token symbol + string private _symbol; + + // Base URI + string private _baseURIextended; + + // Mapping from token ID to ownership details + // An empty struct value does not necessarily mean the token is unowned. See ownershipOf implementation for details. + mapping(uint256 => TokenOwnership) internal _ownerships; + + // Mapping owner address to address data + mapping(address => AddressData) private _addressData; + + // Mapping from token ID to approved address + mapping(uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + _baseURIextended = 'ipfs://QmWXe2zguRBbgu7kq5nU7MtKGN8A5CzFzh4EAzX1Ehu9WT/'; + } + + /** + * @dev See {IERC721Enumerable-totalSupply}. + */ + function totalSupply() public view override returns (uint256) { + return currentIndex; + } + + /** + * @dev See {IERC721Enumerable-tokenByIndex}. + */ + function tokenByIndex(uint256 index) public view override returns (uint256) { + require(index < totalSupply(), 'ERC721A: global index out of bounds'); + return index; + } + + /** + * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. + * This read function is O(totalSupply). If calling from a separate contract, be sure to test gas first. + * It may also degrade with extremely large collection sizes (e.g >> 10000), test for your use case. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) public view override returns (uint256) { + require(index < balanceOf(owner), 'ERC721A: owner index out of bounds'); + uint256 numMintedSoFar = totalSupply(); + uint256 tokenIdsIdx = 0; + address currOwnershipAddr = address(0); + for (uint256 i = 0; i < numMintedSoFar; i++) { + TokenOwnership memory ownership = _ownerships[i]; + if (ownership.addr != address(0)) { + currOwnershipAddr = ownership.addr; + } + if (currOwnershipAddr == owner) { + if (tokenIdsIdx == index) { + return i; + } + tokenIdsIdx++; + } + } + revert('ERC721A: unable to get token of owner by index'); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId || + interfaceId == type(IERC721Enumerable).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view override returns (uint256) { + require(owner != address(0), 'ERC721A: balance query for the zero address'); + return uint256(_addressData[owner].balance); + } + + function _numberMinted(address owner) internal view returns (uint256) { + require(owner != address(0), 'ERC721A: number minted query for the zero address'); + return uint256(_addressData[owner].numberMinted); + } + + /** + * Gas spent here starts off proportional to the maximum mint batch size. + * It gradually moves to O(1) as tokens get transferred around in the collection over time. + */ + function ownershipOf(uint256 tokenId) internal view returns (TokenOwnership memory) { + require(_exists(tokenId), 'ERC721A: owner query for nonexistent token'); + + for (uint256 curr = tokenId; ; curr--) { + TokenOwnership memory ownership = _ownerships[curr]; + if (ownership.addr != address(0)) { + return ownership; + } + } + + revert('ERC721A: unable to determine the owner of token'); + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view override returns (address) { + return ownershipOf(tokenId).addr; + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + require(_exists(tokenId), 'ERC721Metadata: URI query for nonexistent token'); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString(), '.json')) : ''; + } + + /** + * @dev Set the baseURI + */ + function setBaseURI(string memory baseURI_) external onlyOwner() { + _baseURIextended = baseURI_; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, can be overriden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return _baseURIextended; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public override { + address owner = V4Punks.ownerOf(tokenId); + require(to != owner, 'ERC721A: approval to current owner'); + + require( + _msgSender() == owner || isApprovedForAll(owner, _msgSender()), + 'ERC721A: approve caller is not owner nor approved for all' + ); + + _approve(to, tokenId, owner); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view override returns (address) { + require(_exists(tokenId), 'ERC721A: approved query for nonexistent token'); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public override { + require(operator != _msgSender(), 'ERC721A: approve to caller'); + + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) public override { + _transfer(from, to, tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) public override { + safeTransferFrom(from, to, tokenId, ''); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) public override { + _transfer(from, to, tokenId); + require( + _checkOnERC721Received(from, to, tokenId, _data), + 'ERC721A: transfer to non ERC721Receiver implementer' + ); + } + + function setPrice(uint256 newPrice) external { + require(msg.sender == _owner); + _price = newPrice; + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + */ + function _exists(uint256 tokenId) internal view returns (bool) { + return tokenId < currentIndex; + } + + function reserveBulk(address[] memory to) external { + require(msg.sender == _owner); + for (uint i = 0; i < to.length;i++) { + _safeMint(to[i], 1); + } + } + + function reserve(address to, uint256 quantity) external { + require(msg.sender == _owner); + require(currentIndex + quantity <= 10000); + _safeMint(to, quantity); + } + + function mint(address to, uint256 quantity) external payable { + require(quantity <= 30 && quantity > 0); + require(_price * quantity == msg.value); + require(currentIndex + quantity <= 10000); + payable(_owner).transfer(msg.value); + _safeMint(to, quantity); + } + + function _safeMint(address to, uint256 quantity) internal { + _safeMint(to, quantity, ''); + } + + /** + * @dev Safely mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called for each safe transfer. + * - `quantity` must be greater than 0. + * + * Emits a {Transfer} event. + */ + function _safeMint( + address to, + uint256 quantity, + bytes memory _data + ) internal { + _mint(to, quantity, _data, true); + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {Transfer} event. + */ + function _mint( + address to, + uint256 quantity, + bytes memory _data, + bool safe + ) internal { + uint256 startTokenId = currentIndex; + require(to != address(0), 'ERC721A: mint to the zero address'); + // We know if the first token in the batch doesn't exist, the other ones don't as well, because of serial ordering. + require(!_exists(startTokenId), 'ERC721A: token already minted'); + require(quantity > 0, 'ERC721A: quantity must be greater than 0'); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + _addressData[to].balance += uint128(quantity); + _addressData[to].numberMinted += uint128(quantity); + + _ownerships[startTokenId].addr = to; + _ownerships[startTokenId].startTimestamp = uint64(block.timestamp); + + uint256 updatedIndex = startTokenId; + + for (uint256 i = 0; i < quantity; i++) { + emit Transfer(address(0), to, updatedIndex); + if (safe) { + require( + _checkOnERC721Received(address(0), to, updatedIndex, _data), + 'ERC721A: transfer to non ERC721Receiver implementer' + ); + } + updatedIndex++; + } + + currentIndex = updatedIndex; + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer( + address from, + address to, + uint256 tokenId + ) private { + TokenOwnership memory prevOwnership = ownershipOf(tokenId); + + bool isApprovedOrOwner = (_msgSender() == prevOwnership.addr || + getApproved(tokenId) == _msgSender() || + isApprovedForAll(prevOwnership.addr, _msgSender())); + + require(isApprovedOrOwner, 'ERC721A: transfer caller is not owner nor approved'); + + require(prevOwnership.addr == from, 'ERC721A: transfer from incorrect owner'); + require(to != address(0), 'ERC721A: transfer to the zero address'); + + _beforeTokenTransfers(from, to, tokenId, 1); + + // Clear approvals from the previous owner + _approve(address(0), tokenId, prevOwnership.addr); + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + unchecked { + _addressData[from].balance -= 1; + _addressData[to].balance += 1; + } + + _ownerships[tokenId].addr = to; + _ownerships[tokenId].startTimestamp = uint64(block.timestamp); + + // If the ownership slot of tokenId+1 is not explicitly set, that means the transfer initiator owns it. + // Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls. + uint256 nextTokenId = tokenId + 1; + if (_ownerships[nextTokenId].addr == address(0)) { + if (_exists(nextTokenId)) { + _ownerships[nextTokenId].addr = prevOwnership.addr; + _ownerships[nextTokenId].startTimestamp = prevOwnership.startTimestamp; + } + } + + emit Transfer(from, to, tokenId); + _afterTokenTransfers(from, to, tokenId, 1); + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * Emits a {Approval} event. + */ + function _approve( + address to, + uint256 tokenId, + address owner + ) private { + _tokenApprovals[tokenId] = to; + emit Approval(owner, to, tokenId); + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * The call is not executed if the target address is not a contract. + * + * @param from address representing the previous ownefr of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) private returns (bool) { + if (to.isContract()) { + try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { + return retval == IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert('ERC721A: transfer to non ERC721Receiver implementer'); + } else { + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } else { + return true; + } + } + + /** + * @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. This includes minting. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + */ + function _beforeTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Hook that is called after a set of serially-ordered token ids have been transferred. This includes + * minting. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero. + * - `from` and `to` are never both zero. + */ + function _afterTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} +} \ No newline at end of file diff --git a/ethabi/code/0xd12882c8b5d1bccca57c994c6af7d96355590dbd.yml b/ethabi/code/0xd12882c8b5d1bccca57c994c6af7d96355590dbd.yml new file mode 100644 index 0000000..1ddda3b --- /dev/null +++ b/ethabi/code/0xd12882c8b5d1bccca57c994c6af7d96355590dbd.yml @@ -0,0 +1,12 @@ +--- +ContractName: V4Punks +CompilerVersion: v0.8.7+commit.e28d00a7 +OptimizationUsed: '0' +Runs: '200' +ConstructorArguments: '00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000e43727970746f70756e6b732056340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006563450554e4b0000000000000000000000000000000000000000000000000000' +EVMVersion: Default +Library: '' +LicenseType: MIT +Proxy: '0' +Implementation: '' +SwarmSource: ipfs://ba29399ef93fbba5679ab6d7e1271dc9e4b55965fcc08b7019bf373c2312e264 diff --git a/ethabi/code/0xd33c078c2486b7be0f7b4dda9b14f35163b949e0.sol b/ethabi/code/0xd33c078c2486b7be0f7b4dda9b14f35163b949e0.sol new file mode 100644 index 0000000..1488b73 --- /dev/null +++ b/ethabi/code/0xd33c078c2486b7be0f7b4dda9b14f35163b949e0.sol @@ -0,0 +1,1152 @@ +/////////////////////////////////////////// +// File: contracts/V3Punks.sol + +// SPDX-License-Identifier: MIT +// Creator: Chiru Labs + +pragma solidity ^0.8.0; + +import '@openzeppelin/contracts/token/ERC721/IERC721.sol'; +import '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol'; +import '@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol'; +import '@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol'; +import '@openzeppelin/contracts/utils/Address.sol'; +import '@openzeppelin/contracts/utils/Context.sol'; +import '@openzeppelin/contracts/utils/Strings.sol'; +import '@openzeppelin/contracts/utils/introspection/ERC165.sol'; + +/** +* +\ \ / /\_____ \ \______ \ | \ \ | |/ _| / _____/ + \ Y / _(__ < | ___/ | / | \| < \_____ \ + \ / / \ | | | | / | \ | \ / \ + \___/ /______ / |____| |______/\____|__ /____|__ \/_______ / + \/ \/ \/ \/ +* +**/ +contract V3Punks is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable { + using Address for address; + using Strings for uint256; + + struct TokenOwnership { + address addr; + uint64 startTimestamp; + } + + struct AddressData { + uint128 balance; + uint128 numberMinted; + } + + uint256 internal currentIndex = 0; + + // mint price + uint256 public _price = 20000000000000000; + + // Token name + string private _name; + + address private _owner = msg.sender; + + // Token symbol + string private _symbol; + + // Mapping from token ID to ownership details + // An empty struct value does not necessarily mean the token is unowned. See ownershipOf implementation for details. + mapping(uint256 => TokenOwnership) internal _ownerships; + + // Mapping owner address to address data + mapping(address => AddressData) private _addressData; + + // Mapping from token ID to approved address + mapping(uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev See {IERC721Enumerable-totalSupply}. + */ + function totalSupply() public view override returns (uint256) { + return currentIndex; + } + + /** + * @dev See {IERC721Enumerable-tokenByIndex}. + */ + function tokenByIndex(uint256 index) public view override returns (uint256) { + require(index < totalSupply(), 'ERC721A: global index out of bounds'); + return index; + } + + /** + * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. + * This read function is O(totalSupply). If calling from a separate contract, be sure to test gas first. + * It may also degrade with extremely large collection sizes (e.g >> 10000), test for your use case. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) public view override returns (uint256) { + require(index < balanceOf(owner), 'ERC721A: owner index out of bounds'); + uint256 numMintedSoFar = totalSupply(); + uint256 tokenIdsIdx = 0; + address currOwnershipAddr = address(0); + for (uint256 i = 0; i < numMintedSoFar; i++) { + TokenOwnership memory ownership = _ownerships[i]; + if (ownership.addr != address(0)) { + currOwnershipAddr = ownership.addr; + } + if (currOwnershipAddr == owner) { + if (tokenIdsIdx == index) { + return i; + } + tokenIdsIdx++; + } + } + revert('ERC721A: unable to get token of owner by index'); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId || + interfaceId == type(IERC721Enumerable).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view override returns (uint256) { + require(owner != address(0), 'ERC721A: balance query for the zero address'); + return uint256(_addressData[owner].balance); + } + + function _numberMinted(address owner) internal view returns (uint256) { + require(owner != address(0), 'ERC721A: number minted query for the zero address'); + return uint256(_addressData[owner].numberMinted); + } + + /** + * Gas spent here starts off proportional to the maximum mint batch size. + * It gradually moves to O(1) as tokens get transferred around in the collection over time. + */ + function ownershipOf(uint256 tokenId) internal view returns (TokenOwnership memory) { + require(_exists(tokenId), 'ERC721A: owner query for nonexistent token'); + + for (uint256 curr = tokenId; ; curr--) { + TokenOwnership memory ownership = _ownerships[curr]; + if (ownership.addr != address(0)) { + return ownership; + } + } + + revert('ERC721A: unable to determine the owner of token'); + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view override returns (address) { + return ownershipOf(tokenId).addr; + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + require(_exists(tokenId), 'ERC721Metadata: URI query for nonexistent token'); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString(), '.json')) : ''; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, can be overriden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return 'ipfs://QmWGvf6hiVrfXRPySTQn12jNQa98QiHq4BoK4r2ftk38eW/'; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public override { + address owner = V3Punks.ownerOf(tokenId); + require(to != owner, 'ERC721A: approval to current owner'); + + require( + _msgSender() == owner || isApprovedForAll(owner, _msgSender()), + 'ERC721A: approve caller is not owner nor approved for all' + ); + + _approve(to, tokenId, owner); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view override returns (address) { + require(_exists(tokenId), 'ERC721A: approved query for nonexistent token'); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public override { + require(operator != _msgSender(), 'ERC721A: approve to caller'); + + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) public override { + _transfer(from, to, tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) public override { + safeTransferFrom(from, to, tokenId, ''); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) public override { + _transfer(from, to, tokenId); + require( + _checkOnERC721Received(from, to, tokenId, _data), + 'ERC721A: transfer to non ERC721Receiver implementer' + ); + } + + function setPrice(uint256 newPrice) external { + require(msg.sender == _owner); + _price = newPrice; + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + */ + function _exists(uint256 tokenId) internal view returns (bool) { + return tokenId < currentIndex; + } + + function reserveBulk(address[] memory to) external { + require(msg.sender == _owner); + for (uint i = 0; i < to.length;i++) { + _safeMint(to[i], 1); + } + } + + function reserve(address to, uint256 quantity) external { + require(msg.sender == _owner); + require(currentIndex + quantity <= 10000); + _safeMint(to, quantity); + } + + function mint(address to, uint256 quantity) external payable { + require(quantity <= 30 && quantity > 0); + require(_price * quantity == msg.value); + require(currentIndex + quantity <= 10000); + payable(_owner).transfer(msg.value); + _safeMint(to, quantity); + } + + function _safeMint(address to, uint256 quantity) internal { + _safeMint(to, quantity, ''); + } + + /** + * @dev Safely mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called for each safe transfer. + * - `quantity` must be greater than 0. + * + * Emits a {Transfer} event. + */ + function _safeMint( + address to, + uint256 quantity, + bytes memory _data + ) internal { + _mint(to, quantity, _data, true); + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {Transfer} event. + */ + function _mint( + address to, + uint256 quantity, + bytes memory _data, + bool safe + ) internal { + uint256 startTokenId = currentIndex; + require(to != address(0), 'ERC721A: mint to the zero address'); + // We know if the first token in the batch doesn't exist, the other ones don't as well, because of serial ordering. + require(!_exists(startTokenId), 'ERC721A: token already minted'); + require(quantity > 0, 'ERC721A: quantity must be greater than 0'); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + _addressData[to].balance += uint128(quantity); + _addressData[to].numberMinted += uint128(quantity); + + _ownerships[startTokenId].addr = to; + _ownerships[startTokenId].startTimestamp = uint64(block.timestamp); + + uint256 updatedIndex = startTokenId; + + for (uint256 i = 0; i < quantity; i++) { + emit Transfer(address(0), to, updatedIndex); + if (safe) { + require( + _checkOnERC721Received(address(0), to, updatedIndex, _data), + 'ERC721A: transfer to non ERC721Receiver implementer' + ); + } + updatedIndex++; + } + + currentIndex = updatedIndex; + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer( + address from, + address to, + uint256 tokenId + ) private { + TokenOwnership memory prevOwnership = ownershipOf(tokenId); + + bool isApprovedOrOwner = (_msgSender() == prevOwnership.addr || + getApproved(tokenId) == _msgSender() || + isApprovedForAll(prevOwnership.addr, _msgSender())); + + require(isApprovedOrOwner, 'ERC721A: transfer caller is not owner nor approved'); + + require(prevOwnership.addr == from, 'ERC721A: transfer from incorrect owner'); + require(to != address(0), 'ERC721A: transfer to the zero address'); + + _beforeTokenTransfers(from, to, tokenId, 1); + + // Clear approvals from the previous owner + _approve(address(0), tokenId, prevOwnership.addr); + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + unchecked { + _addressData[from].balance -= 1; + _addressData[to].balance += 1; + } + + _ownerships[tokenId].addr = to; + _ownerships[tokenId].startTimestamp = uint64(block.timestamp); + + // If the ownership slot of tokenId+1 is not explicitly set, that means the transfer initiator owns it. + // Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls. + uint256 nextTokenId = tokenId + 1; + if (_ownerships[nextTokenId].addr == address(0)) { + if (_exists(nextTokenId)) { + _ownerships[nextTokenId].addr = prevOwnership.addr; + _ownerships[nextTokenId].startTimestamp = prevOwnership.startTimestamp; + } + } + + emit Transfer(from, to, tokenId); + _afterTokenTransfers(from, to, tokenId, 1); + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * Emits a {Approval} event. + */ + function _approve( + address to, + uint256 tokenId, + address owner + ) private { + _tokenApprovals[tokenId] = to; + emit Approval(owner, to, tokenId); + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * The call is not executed if the target address is not a contract. + * + * @param from address representing the previous ownefr of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) private returns (bool) { + if (to.isContract()) { + try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { + return retval == IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert('ERC721A: transfer to non ERC721Receiver implementer'); + } else { + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } else { + return true; + } + } + + /** + * @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. This includes minting. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + */ + function _beforeTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Hook that is called after a set of serially-ordered token ids have been transferred. This includes + * minting. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero. + * - `from` and `to` are never both zero. + */ + function _afterTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/IERC721.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol) + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external; +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol) + +pragma solidity ^0.8.0; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. + */ + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Enumerable.sol) + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Enumerable is IERC721 { + /** + * @dev Returns the total amount of tokens stored by the contract. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns a token ID owned by `owner` at a given `index` of its token list. + * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); + + /** + * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. + * Use along with {totalSupply} to enumerate all tokens. + */ + function tokenByIndex(uint256 index) external view returns (uint256); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Address.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + assembly { + size := extcodesize(account) + } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Strings.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol) + +pragma solidity ^0.8.0; + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + // Inspired by OraclizeAPI's implementation - MIT licence + // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol + + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + while (value != 0) { + digits -= 1; + buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); + value /= 10; + } + return string(buffer); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + if (value == 0) { + return "0x00"; + } + uint256 temp = value; + uint256 length = 0; + while (temp != 0) { + length++; + temp >>= 8; + } + return toHexString(value, length); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _HEX_SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/introspection/ERC165.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/introspection/IERC165.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + + diff --git a/ethabi/code/0xd33c078c2486b7be0f7b4dda9b14f35163b949e0.yml b/ethabi/code/0xd33c078c2486b7be0f7b4dda9b14f35163b949e0.yml new file mode 100644 index 0000000..e426767 --- /dev/null +++ b/ethabi/code/0xd33c078c2486b7be0f7b4dda9b14f35163b949e0.yml @@ -0,0 +1,12 @@ +--- +ContractName: V3Punks +CompilerVersion: v0.8.0+commit.c7dfd78e +OptimizationUsed: '1' +Runs: '1000' +ConstructorArguments: '00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000e43727970746f70756e6b732056330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006563350554e4b0000000000000000000000000000000000000000000000000000' +EVMVersion: Default +Library: '' +LicenseType: '' +Proxy: '0' +Implementation: '' +SwarmSource: '' diff --git a/ethabi/code/0xe5a5520b798c5f67ca1b0657b932656df02595ad.sol b/ethabi/code/0xe5a5520b798c5f67ca1b0657b932656df02595ad.sol new file mode 100644 index 0000000..981d554 --- /dev/null +++ b/ethabi/code/0xe5a5520b798c5f67ca1b0657b932656df02595ad.sol @@ -0,0 +1,2752 @@ +/////////////////////////////////////////// +// File: /Users/michael/indeliblelabs/indeliblelabs-app/contracts/Indelible.sol + + + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.4; + + import "erc721a/contracts/ERC721A.sol"; + import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; + import "@openzeppelin/contracts/access/Ownable.sol"; + import "@openzeppelin/contracts/utils/Base64.sol"; + import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; + import "@openzeppelin/contracts/utils/Address.sol"; + import "./SSTORE2.sol"; + import "./DynamicBuffer.sol"; + import "./HelperLib.sol"; + + contract Indelible is ERC721A, ReentrancyGuard, Ownable { + using HelperLib for uint; + using DynamicBuffer for bytes; + + struct LinkedTraitDTO { + uint[] traitA; + uint[] traitB; + } + + struct TraitDTO { + string name; + string mimetype; + bytes data; + bool useExistingData; + uint existingDataIndex; + } + + struct Trait { + string name; + string mimetype; + } + + struct ContractData { + string name; + string description; + string image; + string banner; + string website; + uint royalties; + string royaltiesRecipient; + } + + mapping(uint => address[]) internal _traitDataPointers; + mapping(uint => mapping(uint => Trait)) internal _traitDetails; + mapping(uint => bool) internal _renderTokenOffChain; + mapping(uint => mapping(uint => uint[])) internal _linkedTraits; + + uint private constant DEVELOPER_FEE = 250; // of 10,000 = 2.5% + uint private constant NUM_LAYERS = 14; + uint private constant MAX_BATCH_MINT = 20; + uint[][NUM_LAYERS] private TIERS; + string[] private LAYER_NAMES = [unicode"Glitch", unicode"Nose", unicode"Earring", unicode"Mouth", unicode"Eyes", unicode"Beard", unicode"Rosy cheeks", unicode"Head", unicode"Neck", unicode"Clothes", unicode"Fur", unicode"Background", unicode"Soul", unicode"FLEX"]; + bool private shouldWrapSVG = true; + string private backgroundColor = "transparent"; + + bool public isContractSealed; + uint public constant maxSupply = 10000; + uint public maxPerAddress = 5; + uint public publicMintPrice = 0.020 ether; + string public baseURI = ""; + bool public isPublicMintActive; + + bytes32 private merkleRoot; + uint public allowListPrice = 0.000 ether; + uint public maxPerAllowList = 1; + bool public isAllowListActive; + + ContractData public contractData = ContractData(unicode"PUNK APE YACHT CLUB", unicode"A little bit of punk, a little bit of BAYC, 1000% awesome. No discord, no promises - for the art and culture! CC0 and onchain. OLD SKOOL STEALTH MINT. FREE MINT allowlist open for 2 hours. Chain Runners, MyFF, Proof of Pepe, WomenOnChain, Crypto Marcs and OKC can all access the FREE MINT allowlist. Then mints at 0.02ETH. Pamp it.", "https://indeliblelabs-prod.s3.us-east-2.amazonaws.com/profile/e54bd01c-ca92-4c08-a22a-5fd1e37ec55e", "https://indeliblelabs-prod.s3.us-east-2.amazonaws.com/banner/e54bd01c-ca92-4c08-a22a-5fd1e37ec55e", "https://medium.com/@punkapeyachtclub/a-lil-bit-of-punk-a-lil-bit-of-bayc-1000-awesome-20b23b2b6c88", 600, "0x549c01f812E609b80548c9837b2DaCB0CB0ADc64"); + + constructor() ERC721A(unicode"PUNK APE YACHT CLUB", unicode"PUNKAYC") { + TIERS[0] = [8,9992]; +TIERS[1] = [300,9700]; +TIERS[2] = [150,250,450,450,850,900,6950]; +TIERS[3] = [50,80,90,100,195,200,207,212,280,286,320,578,584,589,1175,1190,1278,1286,1300]; +TIERS[4] = [20,50,100,150,160,260,277,300,300,300,300,300,333,400,400,400,400,500,500,500,550,600,600,700,800,800]; +TIERS[5] = [100,150,250,9500]; +TIERS[6] = [150,9850]; +TIERS[7] = [50,80,80,100,115,150,150,150,180,220,250,255,280,280,280,280,300,300,300,300,300,300,400,400,400,400,400,400,400,410,410,420,420,420,420]; +TIERS[8] = [200,300,500,9000]; +TIERS[9] = [10,100,150,200,200,200,200,200,300,300,300,300,300,400,400,400,400,500,500,500,550,600,600,2390]; +TIERS[10] = [20,100,120,150,200,250,280,300,400,450,500,500,500,530,650,650,1100,1100,1100,1100]; +TIERS[11] = [1200,1200,1200,1200,1300,1300,1300,1300]; +TIERS[12] = [600,1700,1700,2000,2000,2000]; +TIERS[13] = [1,10,20,50,100,200,300,350,400,500,8069]; + } + + modifier whenMintActive() { + require(isMintActive(), "Minting is not active"); + _; + } + + modifier whenUnsealed() { + require(!isContractSealed, "Contract is sealed"); + _; + } + + receive() external payable { + require(isPublicMintActive, "Public minting is not active"); + handleMint(msg.value / publicMintPrice); + } + + function rarityGen(uint _randinput, uint _rarityTier) + internal + view + returns (uint) + { + uint currentLowerBound = 0; + for (uint i = 0; i < TIERS[_rarityTier].length; i++) { + uint thisPercentage = TIERS[_rarityTier][i]; + if ( + _randinput >= currentLowerBound && + _randinput < currentLowerBound + thisPercentage + ) return i; + currentLowerBound = currentLowerBound + thisPercentage; + } + + revert(); + } + + function entropyForExtraData() internal view returns (uint24) { + uint randomNumber = uint( + keccak256( + abi.encodePacked( + tx.gasprice, + block.number, + block.timestamp, + block.difficulty, + blockhash(block.number - 1), + msg.sender + ) + ) + ); + return uint24(randomNumber); + } + + function stringCompare(string memory a, string memory b) internal pure returns (bool) { + return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b)); + } + + function tokensAreDuplicates(uint tokenIdA, uint tokenIdB) public view returns (bool) { + return stringCompare( + tokenIdToHash(tokenIdA), + tokenIdToHash(tokenIdB) + ); + } + + function reRollDuplicate( + uint tokenIdA, + uint tokenIdB + ) public whenUnsealed { + require(tokensAreDuplicates(tokenIdA, tokenIdB), "All tokens must be duplicates"); + + uint largerTokenId = tokenIdA > tokenIdB ? tokenIdA : tokenIdB; + + if (msg.sender != owner()) { + require(msg.sender == ownerOf(largerTokenId), "Only the token owner or contract owner can re-roll"); + } + + _initializeOwnershipAt(largerTokenId); + if (_exists(largerTokenId + 1)) { + _initializeOwnershipAt(largerTokenId + 1); + } + + _setExtraDataAt(largerTokenId, entropyForExtraData()); + } + + function _extraData( + address from, + address to, + uint24 previousExtraData + ) internal view virtual override returns (uint24) { + return from == address(0) ? entropyForExtraData() : previousExtraData; + } + + function getTokenSeed(uint _tokenId) internal view returns (uint24) { + return _ownershipOf(_tokenId).extraData; + } + + function tokenIdToHash( + uint _tokenId + ) public view returns (string memory) { + require(_exists(_tokenId), "Invalid token"); + // This will generate a NUM_LAYERS * 3 character string. + bytes memory hashBytes = DynamicBuffer.allocate(NUM_LAYERS * 4); + + uint[] memory hash = new uint[](NUM_LAYERS); + bool[] memory modifiedLayers = new bool[](NUM_LAYERS); + + for (uint i = 0; i < NUM_LAYERS; i++) { + uint traitIndex = hash[i]; + if (modifiedLayers[i] == false) { + uint _randinput = uint( + uint( + keccak256( + abi.encodePacked( + getTokenSeed(_tokenId), + _tokenId, + _tokenId + i + ) + ) + ) % maxSupply + ); + + traitIndex = rarityGen(_randinput, i); + hash[i] = traitIndex; + } + + if (_linkedTraits[i][traitIndex].length > 0) { + hash[_linkedTraits[i][traitIndex][0]] = _linkedTraits[i][traitIndex][1]; + modifiedLayers[_linkedTraits[i][traitIndex][0]] = true; + } + } + + for (uint i = 0; i < hash.length; i++) { + if (hash[i] < 10) { + hashBytes.appendSafe("00"); + } else if (hash[i] < 100) { + hashBytes.appendSafe("0"); + } + if (hash[i] > 999) { + hashBytes.appendSafe("999"); + } else { + hashBytes.appendSafe(bytes(_toString(hash[i]))); + } + } + + return string(hashBytes); + } + + function handleMint(uint256 _count) internal whenMintActive returns (uint256) { + uint256 totalMinted = _totalMinted(); + require(_count > 0, "Invalid token count"); + require(totalMinted + _count <= maxSupply, "All tokens are gone"); + + + if (isPublicMintActive) { + if (msg.sender != owner()) { + require(_numberMinted(msg.sender) + _count <= maxPerAddress, "Exceeded max mints allowed"); + } + require(msg.sender == tx.origin, "EOAs only"); + require(_count * publicMintPrice == msg.value, "Incorrect amount of ether sent"); + } + + uint256 batchCount = _count / MAX_BATCH_MINT; + uint256 remainder = _count % MAX_BATCH_MINT; + + for (uint256 i = 0; i < batchCount; i++) { + _mint(msg.sender, MAX_BATCH_MINT); + } + + if (remainder > 0) { + _mint(msg.sender, remainder); + } + + return totalMinted; + } + + function mint(uint256 _count, bytes32[] calldata merkleProof) + external + payable + nonReentrant + whenMintActive + returns (uint) + { + + if (!isPublicMintActive) { + if (msg.sender != owner()) { + require(onAllowList(msg.sender, merkleProof), "Not on allow list"); + require(_numberMinted(msg.sender) + _count <= maxPerAllowList, "Exceeded max mints allowed"); + } + require(_count * allowListPrice == msg.value, "Incorrect amount of ether sent"); + } + + uint256 totalMinted = handleMint(_count); + + return totalMinted; + } + + function isMintActive() public view returns (bool) { + return _totalMinted() < maxSupply && (isPublicMintActive || isAllowListActive); + } + + function hashToSVG(string memory _hash) + public + view + returns (string memory) + { + uint thisTraitIndex; + + bytes memory svgBytes = DynamicBuffer.allocate(1024 * 128); + svgBytes.appendSafe('' + ) + ); + + return string( + abi.encodePacked( + "data:image/svg+xml;base64,", + Base64.encode(svgBytes) + ) + ); + } + + function hashToMetadata(string memory _hash) + public + view + returns (string memory) + { + bytes memory metadataBytes = DynamicBuffer.allocate(1024 * 128); + metadataBytes.appendSafe("["); + + for (uint i = 0; i < NUM_LAYERS; i++) { + uint thisTraitIndex = HelperLib.parseInt( + HelperLib._substring(_hash, (i * 3), (i * 3) + 3) + ); + metadataBytes.appendSafe( + abi.encodePacked( + '{"trait_type":"', + LAYER_NAMES[i], + '","value":"', + _traitDetails[i][thisTraitIndex].name, + '"}' + ) + ); + + if (i == NUM_LAYERS - 1) { + metadataBytes.appendSafe("]"); + } else { + metadataBytes.appendSafe(","); + } + } + + return string(metadataBytes); + } + + + function onAllowList(address addr, bytes32[] calldata merkleProof) public view returns (bool) { + return MerkleProof.verify(merkleProof, merkleRoot, keccak256(abi.encodePacked(addr))); + } + + + function tokenURI(uint _tokenId) + public + view + override + returns (string memory) + { + require(_exists(_tokenId), "Invalid token"); + require(_traitDataPointers[0].length > 0, "Traits have not been added"); + + string memory tokenHash = tokenIdToHash(_tokenId); + + bytes memory jsonBytes = DynamicBuffer.allocate(1024 * 128); + jsonBytes.appendSafe(unicode"{\"name\":\"PUNK APE YACHT CLUB #"); + + jsonBytes.appendSafe( + abi.encodePacked( + _toString(_tokenId), + "\",\"description\":\"", + contractData.description, + "\"," + ) + ); + + if (bytes(baseURI).length > 0 && _renderTokenOffChain[_tokenId]) { + jsonBytes.appendSafe( + abi.encodePacked( + '"image":"', + baseURI, + _toString(_tokenId), + "?dna=", + tokenHash, + '&network=mainnet",' + ) + ); + } else { + string memory svgCode = ""; + if (shouldWrapSVG) { + string memory svgString = hashToSVG(tokenHash); + svgCode = string( + abi.encodePacked( + "data:image/svg+xml;base64,", + Base64.encode( + abi.encodePacked( + '' + ) + ) + ) + ); + jsonBytes.appendSafe( + abi.encodePacked( + '"svg_image_data":"', + svgString, + '",' + ) + ); + } else { + svgCode = hashToSVG(tokenHash); + } + + jsonBytes.appendSafe( + abi.encodePacked( + '"image_data":"', + svgCode, + '",' + ) + ); + } + + jsonBytes.appendSafe( + abi.encodePacked( + '"attributes":', + hashToMetadata(tokenHash), + "}" + ) + ); + + return string( + abi.encodePacked( + "data:application/json;base64,", + Base64.encode(jsonBytes) + ) + ); + } + + function contractURI() + public + view + returns (string memory) + { + return string( + abi.encodePacked( + "data:application/json;base64,", + Base64.encode( + abi.encodePacked( + '{"name":"', + contractData.name, + '","description":"', + contractData.description, + '","image":"', + contractData.image, + '","banner":"', + contractData.banner, + '","external_link":"', + contractData.website, + '","seller_fee_basis_points":', + _toString(contractData.royalties), + ',"fee_recipient":"', + contractData.royaltiesRecipient, + '"}' + ) + ) + ) + ); + } + + function tokenIdToSVG(uint _tokenId) + public + view + returns (string memory) + { + return hashToSVG(tokenIdToHash(_tokenId)); + } + + function traitDetails(uint _layerIndex, uint _traitIndex) + public + view + returns (Trait memory) + { + return _traitDetails[_layerIndex][_traitIndex]; + } + + function traitData(uint _layerIndex, uint _traitIndex) + public + view + returns (string memory) + { + return string(SSTORE2.read(_traitDataPointers[_layerIndex][_traitIndex])); + } + + function getLinkedTraits(uint _layerIndex, uint _traitIndex) + public + view + returns (uint[] memory) + { + return _linkedTraits[_layerIndex][_traitIndex]; + } + + function addLayer(uint _layerIndex, TraitDTO[] memory traits) + public + onlyOwner + whenUnsealed + { + require(TIERS[_layerIndex].length == traits.length, "Traits size does not match tiers for this index"); + address[] memory dataPointers = new address[](traits.length); + for (uint i = 0; i < traits.length; i++) { + if (traits[i].useExistingData) { + dataPointers[i] = dataPointers[traits[i].existingDataIndex]; + } else { + dataPointers[i] = SSTORE2.write(traits[i].data); + } + _traitDetails[_layerIndex][i] = Trait(traits[i].name, traits[i].mimetype); + } + _traitDataPointers[_layerIndex] = dataPointers; + return; + } + + function addTrait(uint _layerIndex, uint _traitIndex, TraitDTO memory trait) + public + onlyOwner + whenUnsealed + { + _traitDetails[_layerIndex][_traitIndex] = Trait(trait.name, trait.mimetype); + address[] memory dataPointers = _traitDataPointers[_layerIndex]; + if (trait.useExistingData) { + dataPointers[_traitIndex] = dataPointers[trait.existingDataIndex]; + } else { + dataPointers[_traitIndex] = SSTORE2.write(trait.data); + } + _traitDataPointers[_layerIndex] = dataPointers; + return; + } + + function setLinkedTraits(LinkedTraitDTO[] memory linkedTraits) + public + onlyOwner + whenUnsealed + { + for (uint i = 0; i < linkedTraits.length; i++) { + _linkedTraits[linkedTraits[i].traitA[0]][linkedTraits[i].traitA[1]] = [linkedTraits[i].traitB[0],linkedTraits[i].traitB[1]]; + } + } + + function setContractData(ContractData memory _contractData) external onlyOwner whenUnsealed { + contractData = _contractData; + } + + function setMaxPerAddress(uint _maxPerAddress) external onlyOwner { + maxPerAddress = _maxPerAddress; + } + + function setBaseURI(string memory _baseURI) external onlyOwner { + baseURI = _baseURI; + } + + function setBackgroundColor(string memory _backgroundColor) external onlyOwner whenUnsealed { + backgroundColor = _backgroundColor; + } + + function setRenderOfTokenId(uint _tokenId, bool _renderOffChain) external { + require(msg.sender == ownerOf(_tokenId), "Only the token owner can set the render method"); + _renderTokenOffChain[_tokenId] = _renderOffChain; + } + + + function setMerkleRoot(bytes32 newMerkleRoot) external onlyOwner { + merkleRoot = newMerkleRoot; + } + + function setMaxPerAllowList(uint _maxPerAllowList) external onlyOwner { + maxPerAllowList = _maxPerAllowList; + } + + function setAllowListPrice(uint _allowListPrice) external onlyOwner { + allowListPrice = _allowListPrice; + } + + function toggleAllowListMint() external onlyOwner { + isAllowListActive = !isAllowListActive; + } + + + function toggleWrapSVG() external onlyOwner { + shouldWrapSVG = !shouldWrapSVG; + } + + function togglePublicMint() external onlyOwner { + isPublicMintActive = !isPublicMintActive; + } + + function sealContract() external whenUnsealed onlyOwner { + isContractSealed = true; + } + + function withdraw() external onlyOwner nonReentrant { + uint balance = address(this).balance; + uint amount = (balance * (10000 - DEVELOPER_FEE)) / 10000; + + address payable receiver = payable(owner()); + address payable dev = payable(0xEA208Da933C43857683C04BC76e3FD331D7bfdf7); + + Address.sendValue(receiver, amount); + Address.sendValue(dev, balance - amount); + } + } + + +/////////////////////////////////////////// +// File: /Users/michael/indeliblelabs/indeliblelabs-app/contracts/DynamicBuffer.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) + +pragma solidity >=0.8.0; + +/// @title DynamicBuffer +/// @author David Huber (@cxkoda) and Simon Fremaux (@dievardump). See also +/// https://raw.githubusercontent.com/dievardump/solidity-dynamic-buffer +/// @notice This library is used to allocate a big amount of container memory +// which will be subsequently filled without needing to reallocate +/// memory. +/// @dev First, allocate memory. +/// Then use `buffer.appendUnchecked(theBytes)` or `appendSafe()` if +/// bounds checking is required. +library DynamicBuffer { + /// @notice Allocates container space for the DynamicBuffer + /// @param capacity The intended max amount of bytes in the buffer + /// @return buffer The memory location of the buffer + /// @dev Allocates `capacity + 0x60` bytes of space + /// The buffer array starts at the first container data position, + /// (i.e. `buffer = container + 0x20`) + function allocate(uint256 capacity) + internal + pure + returns (bytes memory buffer) + { + assembly { + // Get next-free memory address + let container := mload(0x40) + + // Allocate memory by setting a new next-free address + { + // Add 2 x 32 bytes in size for the two length fields + // Add 32 bytes safety space for 32B chunked copy + let size := add(capacity, 0x60) + let newNextFree := add(container, size) + mstore(0x40, newNextFree) + } + + // Set the correct container length + { + let length := add(capacity, 0x40) + mstore(container, length) + } + + // The buffer starts at idx 1 in the container (0 is length) + buffer := add(container, 0x20) + + // Init content with length 0 + mstore(buffer, 0) + } + + return buffer; + } + + /// @notice Appends data to buffer, and update buffer length + /// @param buffer the buffer to append the data to + /// @param data the data to append + /// @dev Does not perform out-of-bound checks (container capacity) + /// for efficiency. + function appendUnchecked(bytes memory buffer, bytes memory data) + internal + pure + { + assembly { + let length := mload(data) + for { + data := add(data, 0x20) + let dataEnd := add(data, length) + let copyTo := add(buffer, add(mload(buffer), 0x20)) + } lt(data, dataEnd) { + data := add(data, 0x20) + copyTo := add(copyTo, 0x20) + } { + // Copy 32B chunks from data to buffer. + // This may read over data array boundaries and copy invalid + // bytes, which doesn't matter in the end since we will + // later set the correct buffer length, and have allocated an + // additional word to avoid buffer overflow. + mstore(copyTo, mload(data)) + } + + // Update buffer length + mstore(buffer, add(mload(buffer), length)) + } + } + + /// @notice Appends data to buffer, and update buffer length + /// @param buffer the buffer to append the data to + /// @param data the data to append + /// @dev Performs out-of-bound checks and calls `appendUnchecked`. + function appendSafe(bytes memory buffer, bytes memory data) internal pure { + uint256 capacity; + uint256 length; + assembly { + capacity := sub(mload(sub(buffer, 0x20)), 0x40) + length := mload(buffer) + } + + require( + length + data.length <= capacity, + "DynamicBuffer: Appending out of bounds." + ); + appendUnchecked(buffer, data); + } +} + +/////////////////////////////////////////// +// File: /Users/michael/indeliblelabs/indeliblelabs-app/contracts/HelperLib.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.14; + +library HelperLib { + function parseInt(string memory _a) + internal + pure + returns (uint8 _parsedInt) + { + bytes memory bresult = bytes(_a); + uint8 mint = 0; + for (uint8 i = 0; i < bresult.length; i++) { + if ( + (uint8(uint8(bresult[i])) >= 48) && + (uint8(uint8(bresult[i])) <= 57) + ) { + mint *= 10; + mint += uint8(bresult[i]) - 48; + } + } + return mint; + } + + function _substring( + string memory str, + uint256 startIndex, + uint256 endIndex + ) internal pure returns (string memory) { + bytes memory strBytes = bytes(str); + bytes memory result = new bytes(endIndex - startIndex); + for (uint256 i = startIndex; i < endIndex; i++) { + result[i - startIndex] = strBytes[i]; + } + return string(result); + } +} + +/////////////////////////////////////////// +// File: /Users/michael/indeliblelabs/indeliblelabs-app/contracts/SSTORE2.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./utils/Bytecode.sol"; + +/** + @title A key-value storage with auto-generated keys for storing chunks of data with a lower write & read cost. + @author Agustin Aguilar + + Readme: https://github.com/0xsequence/sstore2#readme +*/ +library SSTORE2 { + error WriteError(); + + /** + @notice Stores `_data` and returns `pointer` as key for later retrieval + @dev The pointer is a contract address with `_data` as code + @param _data to be written + @return pointer Pointer to the written `_data` + */ + function write(bytes memory _data) internal returns (address pointer) { + // Append 00 to _data so contract can't be called + // Build init code + bytes memory code = Bytecode.creationCodeFor( + abi.encodePacked( + hex'00', + _data + ) + ); + + // Deploy contract using create + assembly { pointer := create(0, add(code, 32), mload(code)) } + + // Address MUST be non-zero + if (pointer == address(0)) revert WriteError(); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @return data read from `_pointer` contract + */ + function read(address _pointer) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, 1, type(uint256).max); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @param _start number of bytes to skip + @return data read from `_pointer` contract + */ + function read(address _pointer, uint256 _start) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, _start + 1, type(uint256).max); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @param _start number of bytes to skip + @param _end index before which to end extraction + @return data read from `_pointer` contract + */ + function read(address _pointer, uint256 _start, uint256 _end) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, _start + 1, _end + 1); + } +} + +/////////////////////////////////////////// +// File: /Users/michael/indeliblelabs/indeliblelabs-app/contracts/utils/Bytecode.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + + +library Bytecode { + error InvalidCodeAtRange(uint256 _size, uint256 _start, uint256 _end); + + /** + @notice Generate a creation code that results on a contract with `_code` as bytecode + @param _code The returning value of the resulting `creationCode` + @return creationCode (constructor) for new contract + */ + function creationCodeFor(bytes memory _code) internal pure returns (bytes memory) { + /* + 0x00 0x63 0x63XXXXXX PUSH4 _code.length size + 0x01 0x80 0x80 DUP1 size size + 0x02 0x60 0x600e PUSH1 14 14 size size + 0x03 0x60 0x6000 PUSH1 00 0 14 size size + 0x04 0x39 0x39 CODECOPY size + 0x05 0x60 0x6000 PUSH1 00 0 size + 0x06 0xf3 0xf3 RETURN + + */ + + return abi.encodePacked( + hex"63", + uint32(_code.length), + hex"80_60_0E_60_00_39_60_00_F3", + _code + ); + } + + /** + @notice Returns the size of the code on a given address + @param _addr Address that may or may not contain code + @return size of the code on the given `_addr` + */ + function codeSize(address _addr) internal view returns (uint256 size) { + assembly { size := extcodesize(_addr) } + } + + /** + @notice Returns the code of a given address + @dev It will fail if `_end < _start` + @param _addr Address that may or may not contain code + @param _start number of bytes of code to skip on read + @param _end index before which to end extraction + @return oCode read from `_addr` deployed bytecode + + Forked from: https://gist.github.com/KardanovIR/fe98661df9338c842b4a30306d507fbd + */ + function codeAt(address _addr, uint256 _start, uint256 _end) internal view returns (bytes memory oCode) { + uint256 csize = codeSize(_addr); + if (csize == 0) return bytes(""); + + if (_start > csize) return bytes(""); + if (_end < _start) revert InvalidCodeAtRange(csize, _start, _end); + + unchecked { + uint256 reqSize = _end - _start; + uint256 maxSize = csize - _start; + + uint256 size = maxSize < reqSize ? maxSize : reqSize; + + assembly { + // allocate output byte array - this could also be done without assembly + // by using o_code = new bytes(size) + oCode := mload(0x40) + // new "memory end" including padding + mstore(0x40, add(oCode, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + // store length in memory + mstore(oCode, size) + // actually retrieve the code, this needs assembly + extcodecopy(_addr, add(oCode, 0x20), _start, size) + } + } + } +} + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/access/Ownable.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor() { + _transferOwnership(_msgSender()); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/security/ReentrancyGuard.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor() { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and making it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) + +pragma solidity ^0.8.1; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + * + * [IMPORTANT] + * ==== + * You shouldn't rely on `isContract` to protect against flash loan attacks! + * + * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets + * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract + * constructor. + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize/address.code.length, which returns 0 + // for contracts in construction, since the code is only stored at the end + // of the constructor execution. + + return account.code.length > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Base64.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (utils/Base64.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides a set of functions to operate with Base64 strings. + * + * _Available since v4.5._ + */ +library Base64 { + /** + * @dev Base64 Encoding/Decoding Table + */ + string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** + * @dev Converts a `bytes` to its Bytes64 `string` representation. + */ + function encode(bytes memory data) internal pure returns (string memory) { + /** + * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence + * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol + */ + if (data.length == 0) return ""; + + // Loads the table into memory + string memory table = _TABLE; + + // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter + // and split into 4 numbers of 6 bits. + // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up + // - `data.length + 2` -> Round up + // - `/ 3` -> Number of 3-bytes chunks + // - `4 *` -> 4 characters for each chunk + string memory result = new string(4 * ((data.length + 2) / 3)); + + assembly { + // Prepare the lookup table (skip the first "length" byte) + let tablePtr := add(table, 1) + + // Prepare result pointer, jump over length + let resultPtr := add(result, 32) + + // Run over the input, 3 bytes at a time + for { + let dataPtr := data + let endPtr := add(data, mload(data)) + } lt(dataPtr, endPtr) { + + } { + // Advance 3 bytes + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + + // To write each character, shift the 3 bytes (18 bits) chunk + // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) + // and apply logical AND with 0x3F which is the number of + // the previous character in the ASCII table prior to the Base64 Table + // The result is then added to the table to get the character to write, + // and finally write it in the result pointer but with a left shift + // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits + + mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + } + + // When data `bytes` is not exactly 3 bytes long + // it is padded with `=` characters at the end + switch mod(mload(data), 3) + case 1 { + mstore8(sub(resultPtr, 1), 0x3d) + mstore8(sub(resultPtr, 2), 0x3d) + } + case 2 { + mstore8(sub(resultPtr, 1), 0x3d) + } + } + + return result; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/cryptography/MerkleProof.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (utils/cryptography/MerkleProof.sol) + +pragma solidity ^0.8.0; + +/** + * @dev These functions deal with verification of Merkle Trees proofs. + * + * The proofs can be generated using the JavaScript library + * https://github.com/miguelmota/merkletreejs[merkletreejs]. + * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled. + * + * See `test/utils/cryptography/MerkleProof.test.js` for some examples. + * + * WARNING: You should avoid using leaf values that are 64 bytes long prior to + * hashing, or use a hash function other than keccak256 for hashing leaves. + * This is because the concatenation of a sorted pair of internal nodes in + * the merkle tree could be reinterpreted as a leaf value. + */ +library MerkleProof { + /** + * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree + * defined by `root`. For this, a `proof` must be provided, containing + * sibling hashes on the branch from the leaf to the root of the tree. Each + * pair of leaves and each pair of pre-images are assumed to be sorted. + */ + function verify( + bytes32[] memory proof, + bytes32 root, + bytes32 leaf + ) internal pure returns (bool) { + return processProof(proof, leaf) == root; + } + + /** + * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up + * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt + * hash matches the root of the tree. When processing the proof, the pairs + * of leafs & pre-images are assumed to be sorted. + * + * _Available since v4.4._ + */ + function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + bytes32 proofElement = proof[i]; + if (computedHash <= proofElement) { + // Hash(current computed hash + current element of the proof) + computedHash = _efficientHash(computedHash, proofElement); + } else { + // Hash(current element of the proof + current computed hash) + computedHash = _efficientHash(proofElement, computedHash); + } + } + return computedHash; + } + + function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { + assembly { + mstore(0x00, a) + mstore(0x20, b) + value := keccak256(0x00, 0x40) + } + } +} + + +/////////////////////////////////////////// +// File: erc721a/contracts/ERC721A.sol + +// SPDX-License-Identifier: MIT +// ERC721A Contracts v4.1.0 +// Creator: Chiru Labs + +pragma solidity ^0.8.4; + +import './IERC721A.sol'; + +/** + * @dev ERC721 token receiver interface. + */ +interface ERC721A__IERC721Receiver { + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, + * including the Metadata extension. Built to optimize for lower gas during batch mints. + * + * Assumes serials are sequentially minted starting at `_startTokenId()` + * (defaults to 0, e.g. 0, 1, 2, 3..). + * + * Assumes that an owner cannot have more than 2**64 - 1 (max value of uint64) of supply. + * + * Assumes that the maximum token id cannot exceed 2**256 - 1 (max value of uint256). + */ +contract ERC721A is IERC721A { + // Mask of an entry in packed address data. + uint256 private constant BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1; + + // The bit position of `numberMinted` in packed address data. + uint256 private constant BITPOS_NUMBER_MINTED = 64; + + // The bit position of `numberBurned` in packed address data. + uint256 private constant BITPOS_NUMBER_BURNED = 128; + + // The bit position of `aux` in packed address data. + uint256 private constant BITPOS_AUX = 192; + + // Mask of all 256 bits in packed address data except the 64 bits for `aux`. + uint256 private constant BITMASK_AUX_COMPLEMENT = (1 << 192) - 1; + + // The bit position of `startTimestamp` in packed ownership. + uint256 private constant BITPOS_START_TIMESTAMP = 160; + + // The bit mask of the `burned` bit in packed ownership. + uint256 private constant BITMASK_BURNED = 1 << 224; + + // The bit position of the `nextInitialized` bit in packed ownership. + uint256 private constant BITPOS_NEXT_INITIALIZED = 225; + + // The bit mask of the `nextInitialized` bit in packed ownership. + uint256 private constant BITMASK_NEXT_INITIALIZED = 1 << 225; + + // The bit position of `extraData` in packed ownership. + uint256 private constant BITPOS_EXTRA_DATA = 232; + + // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`. + uint256 private constant BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1; + + // The mask of the lower 160 bits for addresses. + uint256 private constant BITMASK_ADDRESS = (1 << 160) - 1; + + // The maximum `quantity` that can be minted with `_mintERC2309`. + // This limit is to prevent overflows on the address data entries. + // For a limit of 5000, a total of 3.689e15 calls to `_mintERC2309` + // is required to cause an overflow, which is unrealistic. + uint256 private constant MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000; + + // The tokenId of the next token to be minted. + uint256 private _currentIndex; + + // The number of tokens burned. + uint256 private _burnCounter; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to ownership details + // An empty struct value does not necessarily mean the token is unowned. + // See `_packedOwnershipOf` implementation for details. + // + // Bits Layout: + // - [0..159] `addr` + // - [160..223] `startTimestamp` + // - [224] `burned` + // - [225] `nextInitialized` + // - [232..255] `extraData` + mapping(uint256 => uint256) private _packedOwnerships; + + // Mapping owner address to address data. + // + // Bits Layout: + // - [0..63] `balance` + // - [64..127] `numberMinted` + // - [128..191] `numberBurned` + // - [192..255] `aux` + mapping(address => uint256) private _packedAddressData; + + // Mapping from token ID to approved address. + mapping(uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + _currentIndex = _startTokenId(); + } + + /** + * @dev Returns the starting token ID. + * To change the starting token ID, please override this function. + */ + function _startTokenId() internal view virtual returns (uint256) { + return 0; + } + + /** + * @dev Returns the next token ID to be minted. + */ + function _nextTokenId() internal view returns (uint256) { + return _currentIndex; + } + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see `_totalMinted`. + */ + function totalSupply() public view override returns (uint256) { + // Counter underflow is impossible as _burnCounter cannot be incremented + // more than `_currentIndex - _startTokenId()` times. + unchecked { + return _currentIndex - _burnCounter - _startTokenId(); + } + } + + /** + * @dev Returns the total amount of tokens minted in the contract. + */ + function _totalMinted() internal view returns (uint256) { + // Counter underflow is impossible as _currentIndex does not decrement, + // and it is initialized to `_startTokenId()` + unchecked { + return _currentIndex - _startTokenId(); + } + } + + /** + * @dev Returns the total number of tokens burned. + */ + function _totalBurned() internal view returns (uint256) { + return _burnCounter; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + // The interface IDs are constants representing the first 4 bytes of the XOR of + // all function selectors in the interface. See: https://eips.ethereum.org/EIPS/eip-165 + // e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)` + return + interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165. + interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721. + interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata. + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view override returns (uint256) { + if (owner == address(0)) revert BalanceQueryForZeroAddress(); + return _packedAddressData[owner] & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the number of tokens minted by `owner`. + */ + function _numberMinted(address owner) internal view returns (uint256) { + return (_packedAddressData[owner] >> BITPOS_NUMBER_MINTED) & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the number of tokens burned by or on behalf of `owner`. + */ + function _numberBurned(address owner) internal view returns (uint256) { + return (_packedAddressData[owner] >> BITPOS_NUMBER_BURNED) & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). + */ + function _getAux(address owner) internal view returns (uint64) { + return uint64(_packedAddressData[owner] >> BITPOS_AUX); + } + + /** + * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). + * If there are multiple variables, please pack them into a uint64. + */ + function _setAux(address owner, uint64 aux) internal { + uint256 packed = _packedAddressData[owner]; + uint256 auxCasted; + // Cast `aux` with assembly to avoid redundant masking. + assembly { + auxCasted := aux + } + packed = (packed & BITMASK_AUX_COMPLEMENT) | (auxCasted << BITPOS_AUX); + _packedAddressData[owner] = packed; + } + + /** + * Returns the packed ownership data of `tokenId`. + */ + function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) { + uint256 curr = tokenId; + + unchecked { + if (_startTokenId() <= curr) + if (curr < _currentIndex) { + uint256 packed = _packedOwnerships[curr]; + // If not burned. + if (packed & BITMASK_BURNED == 0) { + // Invariant: + // There will always be an ownership that has an address and is not burned + // before an ownership that does not have an address and is not burned. + // Hence, curr will not underflow. + // + // We can directly compare the packed value. + // If the address is zero, packed is zero. + while (packed == 0) { + packed = _packedOwnerships[--curr]; + } + return packed; + } + } + } + revert OwnerQueryForNonexistentToken(); + } + + /** + * Returns the unpacked `TokenOwnership` struct from `packed`. + */ + function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) { + ownership.addr = address(uint160(packed)); + ownership.startTimestamp = uint64(packed >> BITPOS_START_TIMESTAMP); + ownership.burned = packed & BITMASK_BURNED != 0; + ownership.extraData = uint24(packed >> BITPOS_EXTRA_DATA); + } + + /** + * Returns the unpacked `TokenOwnership` struct at `index`. + */ + function _ownershipAt(uint256 index) internal view returns (TokenOwnership memory) { + return _unpackedOwnership(_packedOwnerships[index]); + } + + /** + * @dev Initializes the ownership slot minted at `index` for efficiency purposes. + */ + function _initializeOwnershipAt(uint256 index) internal { + if (_packedOwnerships[index] == 0) { + _packedOwnerships[index] = _packedOwnershipOf(index); + } + } + + /** + * Gas spent here starts off proportional to the maximum mint batch size. + * It gradually moves to O(1) as tokens get transferred around in the collection over time. + */ + function _ownershipOf(uint256 tokenId) internal view returns (TokenOwnership memory) { + return _unpackedOwnership(_packedOwnershipOf(tokenId)); + } + + /** + * @dev Packs ownership data into a single uint256. + */ + function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) { + assembly { + // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. + owner := and(owner, BITMASK_ADDRESS) + // `owner | (block.timestamp << BITPOS_START_TIMESTAMP) | flags`. + result := or(owner, or(shl(BITPOS_START_TIMESTAMP, timestamp()), flags)) + } + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view override returns (address) { + return address(uint160(_packedOwnershipOf(tokenId))); + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + if (!_exists(tokenId)) revert URIQueryForNonexistentToken(); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : ''; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, it can be overridden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ''; + } + + /** + * @dev Returns the `nextInitialized` flag set if `quantity` equals 1. + */ + function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) { + // For branchless setting of the `nextInitialized` flag. + assembly { + // `(quantity == 1) << BITPOS_NEXT_INITIALIZED`. + result := shl(BITPOS_NEXT_INITIALIZED, eq(quantity, 1)) + } + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public override { + address owner = ownerOf(tokenId); + + if (_msgSenderERC721A() != owner) + if (!isApprovedForAll(owner, _msgSenderERC721A())) { + revert ApprovalCallerNotOwnerNorApproved(); + } + + _tokenApprovals[tokenId] = to; + emit Approval(owner, to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view override returns (address) { + if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken(); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + if (operator == _msgSenderERC721A()) revert ApproveToCaller(); + + _operatorApprovals[_msgSenderERC721A()][operator] = approved; + emit ApprovalForAll(_msgSenderERC721A(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + safeTransferFrom(from, to, tokenId, ''); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) public virtual override { + transferFrom(from, to, tokenId); + if (to.code.length != 0) + if (!_checkContractOnERC721Received(from, to, tokenId, _data)) { + revert TransferToNonERC721ReceiverImplementer(); + } + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + */ + function _exists(uint256 tokenId) internal view returns (bool) { + return + _startTokenId() <= tokenId && + tokenId < _currentIndex && // If within bounds, + _packedOwnerships[tokenId] & BITMASK_BURNED == 0; // and not burned. + } + + /** + * @dev Equivalent to `_safeMint(to, quantity, '')`. + */ + function _safeMint(address to, uint256 quantity) internal { + _safeMint(to, quantity, ''); + } + + /** + * @dev Safely mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called for each safe transfer. + * - `quantity` must be greater than 0. + * + * See {_mint}. + * + * Emits a {Transfer} event for each mint. + */ + function _safeMint( + address to, + uint256 quantity, + bytes memory _data + ) internal { + _mint(to, quantity); + + unchecked { + if (to.code.length != 0) { + uint256 end = _currentIndex; + uint256 index = end - quantity; + do { + if (!_checkContractOnERC721Received(address(0), to, index++, _data)) { + revert TransferToNonERC721ReceiverImplementer(); + } + } while (index < end); + // Reentrancy protection. + if (_currentIndex != end) revert(); + } + } + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {Transfer} event for each mint. + */ + function _mint(address to, uint256 quantity) internal { + uint256 startTokenId = _currentIndex; + if (to == address(0)) revert MintToZeroAddress(); + if (quantity == 0) revert MintZeroQuantity(); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are incredibly unrealistic. + // `balance` and `numberMinted` have a maximum limit of 2**64. + // `tokenId` has a maximum limit of 2**256. + unchecked { + // Updates: + // - `balance += quantity`. + // - `numberMinted += quantity`. + // + // We can directly add to the `balance` and `numberMinted`. + _packedAddressData[to] += quantity * ((1 << BITPOS_NUMBER_MINTED) | 1); + + // Updates: + // - `address` to the owner. + // - `startTimestamp` to the timestamp of minting. + // - `burned` to `false`. + // - `nextInitialized` to `quantity == 1`. + _packedOwnerships[startTokenId] = _packOwnershipData( + to, + _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) + ); + + uint256 tokenId = startTokenId; + uint256 end = startTokenId + quantity; + do { + emit Transfer(address(0), to, tokenId++); + } while (tokenId < end); + + _currentIndex = end; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * This function is intended for efficient minting only during contract creation. + * + * It emits only one {ConsecutiveTransfer} as defined in + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309), + * instead of a sequence of {Transfer} event(s). + * + * Calling this function outside of contract creation WILL make your contract + * non-compliant with the ERC721 standard. + * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309 + * {ConsecutiveTransfer} event is only permissible during contract creation. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {ConsecutiveTransfer} event. + */ + function _mintERC2309(address to, uint256 quantity) internal { + uint256 startTokenId = _currentIndex; + if (to == address(0)) revert MintToZeroAddress(); + if (quantity == 0) revert MintZeroQuantity(); + if (quantity > MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit(); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are unrealistic due to the above check for `quantity` to be below the limit. + unchecked { + // Updates: + // - `balance += quantity`. + // - `numberMinted += quantity`. + // + // We can directly add to the `balance` and `numberMinted`. + _packedAddressData[to] += quantity * ((1 << BITPOS_NUMBER_MINTED) | 1); + + // Updates: + // - `address` to the owner. + // - `startTimestamp` to the timestamp of minting. + // - `burned` to `false`. + // - `nextInitialized` to `quantity == 1`. + _packedOwnerships[startTokenId] = _packOwnershipData( + to, + _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) + ); + + emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to); + + _currentIndex = startTokenId + quantity; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Returns the storage slot and value for the approved address of `tokenId`. + */ + function _getApprovedAddress(uint256 tokenId) + private + view + returns (uint256 approvedAddressSlot, address approvedAddress) + { + mapping(uint256 => address) storage tokenApprovalsPtr = _tokenApprovals; + // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId]`. + assembly { + // Compute the slot. + mstore(0x00, tokenId) + mstore(0x20, tokenApprovalsPtr.slot) + approvedAddressSlot := keccak256(0x00, 0x40) + // Load the slot's value from storage. + approvedAddress := sload(approvedAddressSlot) + } + } + + /** + * @dev Returns whether the `approvedAddress` is equals to `from` or `msgSender`. + */ + function _isOwnerOrApproved( + address approvedAddress, + address from, + address msgSender + ) private pure returns (bool result) { + assembly { + // Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean. + from := and(from, BITMASK_ADDRESS) + // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean. + msgSender := and(msgSender, BITMASK_ADDRESS) + // `msgSender == from || msgSender == approvedAddress`. + result := or(eq(msgSender, from), eq(msgSender, approvedAddress)) + } + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); + + if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner(); + + (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedAddress(tokenId); + + // The nested ifs save around 20+ gas over a compound boolean condition. + if (!_isOwnerOrApproved(approvedAddress, from, _msgSenderERC721A())) + if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved(); + + if (to == address(0)) revert TransferToZeroAddress(); + + _beforeTokenTransfers(from, to, tokenId, 1); + + // Clear approvals from the previous owner. + assembly { + if approvedAddress { + // This is equivalent to `delete _tokenApprovals[tokenId]`. + sstore(approvedAddressSlot, 0) + } + } + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as tokenId would have to be 2**256. + unchecked { + // We can directly increment and decrement the balances. + --_packedAddressData[from]; // Updates: `balance -= 1`. + ++_packedAddressData[to]; // Updates: `balance += 1`. + + // Updates: + // - `address` to the next owner. + // - `startTimestamp` to the timestamp of transfering. + // - `burned` to `false`. + // - `nextInitialized` to `true`. + _packedOwnerships[tokenId] = _packOwnershipData( + to, + BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked) + ); + + // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . + if (prevOwnershipPacked & BITMASK_NEXT_INITIALIZED == 0) { + uint256 nextTokenId = tokenId + 1; + // If the next slot's address is zero and not burned (i.e. packed value is zero). + if (_packedOwnerships[nextTokenId] == 0) { + // If the next slot is within bounds. + if (nextTokenId != _currentIndex) { + // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. + _packedOwnerships[nextTokenId] = prevOwnershipPacked; + } + } + } + } + + emit Transfer(from, to, tokenId); + _afterTokenTransfers(from, to, tokenId, 1); + } + + /** + * @dev Equivalent to `_burn(tokenId, false)`. + */ + function _burn(uint256 tokenId) internal virtual { + _burn(tokenId, false); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId, bool approvalCheck) internal virtual { + uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); + + address from = address(uint160(prevOwnershipPacked)); + + (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedAddress(tokenId); + + if (approvalCheck) { + // The nested ifs save around 20+ gas over a compound boolean condition. + if (!_isOwnerOrApproved(approvedAddress, from, _msgSenderERC721A())) + if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved(); + } + + _beforeTokenTransfers(from, address(0), tokenId, 1); + + // Clear approvals from the previous owner. + assembly { + if approvedAddress { + // This is equivalent to `delete _tokenApprovals[tokenId]`. + sstore(approvedAddressSlot, 0) + } + } + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. + unchecked { + // Updates: + // - `balance -= 1`. + // - `numberBurned += 1`. + // + // We can directly decrement the balance, and increment the number burned. + // This is equivalent to `packed -= 1; packed += 1 << BITPOS_NUMBER_BURNED;`. + _packedAddressData[from] += (1 << BITPOS_NUMBER_BURNED) - 1; + + // Updates: + // - `address` to the last owner. + // - `startTimestamp` to the timestamp of burning. + // - `burned` to `true`. + // - `nextInitialized` to `true`. + _packedOwnerships[tokenId] = _packOwnershipData( + from, + (BITMASK_BURNED | BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked) + ); + + // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . + if (prevOwnershipPacked & BITMASK_NEXT_INITIALIZED == 0) { + uint256 nextTokenId = tokenId + 1; + // If the next slot's address is zero and not burned (i.e. packed value is zero). + if (_packedOwnerships[nextTokenId] == 0) { + // If the next slot is within bounds. + if (nextTokenId != _currentIndex) { + // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. + _packedOwnerships[nextTokenId] = prevOwnershipPacked; + } + } + } + } + + emit Transfer(from, address(0), tokenId); + _afterTokenTransfers(from, address(0), tokenId, 1); + + // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times. + unchecked { + _burnCounter++; + } + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkContractOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) private returns (bool) { + try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns ( + bytes4 retval + ) { + return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert TransferToNonERC721ReceiverImplementer(); + } else { + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } + + /** + * @dev Directly sets the extra data for the ownership data `index`. + */ + function _setExtraDataAt(uint256 index, uint24 extraData) internal { + uint256 packed = _packedOwnerships[index]; + if (packed == 0) revert OwnershipNotInitializedForExtraData(); + uint256 extraDataCasted; + // Cast `extraData` with assembly to avoid redundant masking. + assembly { + extraDataCasted := extraData + } + packed = (packed & BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << BITPOS_EXTRA_DATA); + _packedOwnerships[index] = packed; + } + + /** + * @dev Returns the next extra data for the packed ownership data. + * The returned result is shifted into position. + */ + function _nextExtraData( + address from, + address to, + uint256 prevOwnershipPacked + ) private view returns (uint256) { + uint24 extraData = uint24(prevOwnershipPacked >> BITPOS_EXTRA_DATA); + return uint256(_extraData(from, to, extraData)) << BITPOS_EXTRA_DATA; + } + + /** + * @dev Called during each token transfer to set the 24bit `extraData` field. + * Intended to be overridden by the cosumer contract. + * + * `previousExtraData` - the value of `extraData` before transfer. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _extraData( + address from, + address to, + uint24 previousExtraData + ) internal view virtual returns (uint24) {} + + /** + * @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. + * This includes minting. + * And also called before burning one token. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _beforeTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Hook that is called after a set of serially-ordered token ids have been transferred. + * This includes minting. + * And also called after one token has been burned. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been + * transferred to `to`. + * - When `from` is zero, `tokenId` has been minted for `to`. + * - When `to` is zero, `tokenId` has been burned by `from`. + * - `from` and `to` are never both zero. + */ + function _afterTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Returns the message sender (defaults to `msg.sender`). + * + * If you are writing GSN compatible contracts, you need to override this function. + */ + function _msgSenderERC721A() internal view virtual returns (address) { + return msg.sender; + } + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function _toString(uint256 value) internal pure returns (string memory ptr) { + assembly { + // The maximum value of a uint256 contains 78 digits (1 byte per digit), + // but we allocate 128 bytes to keep the free memory pointer 32-byte word aliged. + // We will need 1 32-byte word to store the length, + // and 3 32-byte words to store a maximum of 78 digits. Total: 32 + 3 * 32 = 128. + ptr := add(mload(0x40), 128) + // Update the free memory pointer to allocate. + mstore(0x40, ptr) + + // Cache the end of the memory to calculate the length later. + let end := ptr + + // We write the string from the rightmost digit to the leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + // Costs a bit more than early returning for the zero case, + // but cheaper in terms of deployment and overall runtime costs. + for { + // Initialize and perform the first pass without check. + let temp := value + // Move the pointer 1 byte leftwards to point to an empty character slot. + ptr := sub(ptr, 1) + // Write the character to the pointer. 48 is the ASCII index of '0'. + mstore8(ptr, add(48, mod(temp, 10))) + temp := div(temp, 10) + } temp { + // Keep dividing `temp` until zero. + temp := div(temp, 10) + } { + // Body of the for loop. + ptr := sub(ptr, 1) + mstore8(ptr, add(48, mod(temp, 10))) + } + + let length := sub(end, ptr) + // Move the pointer 32 bytes leftwards to make room for the length. + ptr := sub(ptr, 32) + // Store the length. + mstore(ptr, length) + } + } +} + + +/////////////////////////////////////////// +// File: erc721a/contracts/IERC721A.sol + +// SPDX-License-Identifier: MIT +// ERC721A Contracts v4.1.0 +// Creator: Chiru Labs + +pragma solidity ^0.8.4; + +/** + * @dev Interface of an ERC721A compliant contract. + */ +interface IERC721A { + /** + * The caller must own the token or be an approved operator. + */ + error ApprovalCallerNotOwnerNorApproved(); + + /** + * The token does not exist. + */ + error ApprovalQueryForNonexistentToken(); + + /** + * The caller cannot approve to their own address. + */ + error ApproveToCaller(); + + /** + * Cannot query the balance for the zero address. + */ + error BalanceQueryForZeroAddress(); + + /** + * Cannot mint to the zero address. + */ + error MintToZeroAddress(); + + /** + * The quantity of tokens minted must be more than zero. + */ + error MintZeroQuantity(); + + /** + * The token does not exist. + */ + error OwnerQueryForNonexistentToken(); + + /** + * The caller must own the token or be an approved operator. + */ + error TransferCallerNotOwnerNorApproved(); + + /** + * The token must be owned by `from`. + */ + error TransferFromIncorrectOwner(); + + /** + * Cannot safely transfer to a contract that does not implement the ERC721Receiver interface. + */ + error TransferToNonERC721ReceiverImplementer(); + + /** + * Cannot transfer to the zero address. + */ + error TransferToZeroAddress(); + + /** + * The token does not exist. + */ + error URIQueryForNonexistentToken(); + + /** + * The `quantity` minted with ERC2309 exceeds the safety limit. + */ + error MintERC2309QuantityExceedsLimit(); + + /** + * The `extraData` cannot be set on an unintialized ownership slot. + */ + error OwnershipNotInitializedForExtraData(); + + struct TokenOwnership { + // The address of the owner. + address addr; + // Keeps track of the start time of ownership with minimal overhead for tokenomics. + uint64 startTimestamp; + // Whether the token has been burned. + bool burned; + // Arbitrary data similar to `startTimestamp` that can be set through `_extraData`. + uint24 extraData; + } + + /** + * @dev Returns the total amount of tokens stored by the contract. + * + * Burned tokens are calculated here, use `_totalMinted()` if you want to count just minted tokens. + */ + function totalSupply() external view returns (uint256); + + // ============================== + // IERC165 + // ============================== + + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); + + // ============================== + // IERC721 + // ============================== + + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + // ============================== + // IERC721Metadata + // ============================== + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); + + // ============================== + // IERC2309 + // ============================== + + /** + * @dev Emitted when tokens in `fromTokenId` to `toTokenId` (inclusive) is transferred from `from` to `to`, + * as defined in the ERC2309 standard. See `_mintERC2309` for more details. + */ + event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); +} + + diff --git a/ethabi/code/0xe5a5520b798c5f67ca1b0657b932656df02595ad.yml b/ethabi/code/0xe5a5520b798c5f67ca1b0657b932656df02595ad.yml new file mode 100644 index 0000000..72651d9 --- /dev/null +++ b/ethabi/code/0xe5a5520b798c5f67ca1b0657b932656df02595ad.yml @@ -0,0 +1,12 @@ +--- +ContractName: Indelible +CompilerVersion: v0.8.14+commit.80d49f37 +OptimizationUsed: '1' +Runs: '200' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: MIT +Proxy: '0' +Implementation: '' +SwarmSource: '' diff --git a/ethabi/code/0xe9b91d537c3aa5a3fa87275fbd2e4feaaed69bd0.sol b/ethabi/code/0xe9b91d537c3aa5a3fa87275fbd2e4feaaed69bd0.sol new file mode 100644 index 0000000..dfb618b --- /dev/null +++ b/ethabi/code/0xe9b91d537c3aa5a3fa87275fbd2e4feaaed69bd0.sol @@ -0,0 +1,2455 @@ +/////////////////////////////////////////// +// File: /var/app/current/contracts/IndelibleERC721A.sol + + + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.4; + + import "erc721a/contracts/ERC721A.sol"; + import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; + import "@openzeppelin/contracts/access/Ownable.sol"; + import "@openzeppelin/contracts/utils/Base64.sol"; + import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; + import "./SSTORE2.sol"; + import "./DynamicBuffer.sol"; + import "./HelperLib.sol"; + + + interface IOnChainKevin { + function balanceOf(address owner) external view returns (uint256); + } + + + contract IndelibleERC721A is ERC721A, ReentrancyGuard, Ownable { + using HelperLib for uint256; + using DynamicBuffer for bytes; + + struct TraitDTO { + string name; + string mimetype; + bytes data; + } + + struct Trait { + string name; + string mimetype; + } + + struct ContractData { + string name; + string description; + string image; + string banner; + string website; + uint256 royalties; + string royaltiesRecipient; + } + + mapping(uint256 => address[]) internal _traitDataPointers; + mapping(uint256 => mapping(uint256 => Trait)) internal _traitDetails; + mapping(uint256 => bool) internal _renderTokenOffChain; + + uint256 private constant NUM_LAYERS = 12; + uint256 private constant MAX_BATCH_MINT = 20; + uint256[][NUM_LAYERS] private TIERS; + string[] private LAYER_NAMES = [unicode"1/1", unicode"Mouth", unicode"Eyes", unicode"Lips", unicode"Facial Hair", unicode"Head", unicode"Neck", unicode"Nose", unicode"Ear", unicode"Emotion", unicode"Face", unicode"Marc Type"]; + bool private shouldWrapSVG = true; + string private backgroundColor = "transparent"; + + bool public isContractSealed; + uint256 public constant maxSupply = 5000; + uint256 public maxPerAddress = 5; + uint256 public publicMintPrice = 0.020 ether; + string public baseURI = ""; + bool public isPublicMintActive; + + bytes32 private merkleRoot; + uint256 public allowListPrice = 0.0 ether; + uint256 public maxPerAllowList = 2; + bool public isAllowListActive; + address public ockAddress = 0x17B19C70bfcA098da3f2eFeF6e7FA3a1C42F5429; + + ContractData public contractData = ContractData(unicode"Crypto Marcs", unicode"A collection of 5k CryptoMarcs fully On-Chain - Seizing the memes of production", "https://indeliblelabs-prod.s3.us-east-2.amazonaws.com/profile/3be32837-f589-480e-a7c1-104f875fc59e", "https://indeliblelabs-prod.s3.us-east-2.amazonaws.com/banner/3be32837-f589-480e-a7c1-104f875fc59e", "cryptomarcs.xyz", 500, "0xdf12DBA344515c98F866af1436245438cd7D8566"); + + constructor() ERC721A(unicode"Crypto Marcs", unicode"MARCS") { + TIERS[0] = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4979]; +TIERS[1] = [75,115,120,141,193,272,439,3645]; +TIERS[2] = [20,48,64,74,84,88,88,89,90,102,104,108,111,136,138,142,150,168,176,188,190,214,2428]; +TIERS[3] = [94,188,196,330,4192]; +TIERS[4] = [32,106,113,114,114,116,120,128,130,131,136,149,176,180,196,322,505,2232]; +TIERS[5] = [16,16,16,45,47,49,55,61,63,63,66,68,68,69,71,73,74,80,86,88,94,95,99,99,111,112,118,120,142,164,169,190,194,198,222,382,420,897]; +TIERS[6] = [31,46,66,86,99,100,111,115,123,133,138,163,169,180,189,190,214,244,256,266,2081]; +TIERS[7] = [190,322,4488]; +TIERS[8] = [146,199,421,1066,3168]; +TIERS[9] = [334,432,4234]; +TIERS[10] = [44,87,113,125,127,148,162,168,190,225,230,253,1063,2065]; +TIERS[11] = [16,24,64,99,99,99,128,1044,1126,1146,1155]; + } + + modifier whenMintActive() { + require(isMintActive(), "Minting is not active"); + _; + } + + modifier whenUnsealed() { + require(!isContractSealed, "Contract is sealed"); + _; + } + + function rarityGen(uint256 _randinput, uint256 _rarityTier) + internal + view + returns (uint256) + { + uint256 currentLowerBound = 0; + for (uint256 i = 0; i < TIERS[_rarityTier].length; i++) { + uint256 thisPercentage = TIERS[_rarityTier][i]; + if ( + _randinput >= currentLowerBound && + _randinput < currentLowerBound + thisPercentage + ) return i; + currentLowerBound = currentLowerBound + thisPercentage; + } + + revert(); + } + + function entropyForExtraData() internal view returns (uint24) { + uint256 randomNumber = uint256( + keccak256( + abi.encodePacked( + tx.gasprice, + block.number, + block.timestamp, + block.difficulty, + blockhash(block.number - 1), + msg.sender + ) + ) + ); + return uint24(randomNumber); + } + + function stringCompare(string memory a, string memory b) internal pure returns (bool) { + return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b)); + } + + function tokensAreDuplicates(uint tokenId1, uint tokenId2) public view returns (bool) { + return stringCompare( + tokenIdToHash(tokenId1), + tokenIdToHash(tokenId2) + ); + } + + function reRollDuplicates( + uint[] memory groupA, + uint[] memory groupB + ) public whenUnsealed { + for (uint i; i < groupA.length; ++i) { + uint tokenId1 = groupA[i]; + uint tokenId2 = groupB[i]; + + require(tokensAreDuplicates(tokenId1, tokenId2), "All tokens must be duplicates"); + + uint largerTokenId = tokenId1 > tokenId2 ? tokenId1 : tokenId2; + + _initializeOwnershipAt(largerTokenId); + if (_exists(largerTokenId + 1)) { + _initializeOwnershipAt(largerTokenId + 1); + } + + _setExtraDataAt(largerTokenId, entropyForExtraData()); + } + } + + function _extraData( + address from, + address to, + uint24 previousExtraData + ) internal view virtual override returns (uint24) { + return from == address(0) ? entropyForExtraData() : previousExtraData; + } + + function getTokenSeed(uint256 _tokenId) internal view returns (uint24) { + return _ownershipOf(_tokenId).extraData; + } + + function tokenIdToHash( + uint256 _tokenId + ) public view returns (string memory) { + require(_exists(_tokenId), "Invalid token"); + // This will generate a NUM_LAYERS * 3 character string. + bytes memory hashBytes = DynamicBuffer.allocate(NUM_LAYERS * 4); + + for (uint256 i = 0; i < NUM_LAYERS; i++) { + uint256 _randinput = uint256( + uint256( + keccak256( + abi.encodePacked( + getTokenSeed(_tokenId), + _tokenId, + _tokenId + i + ) + ) + ) % maxSupply + ); + + uint256 rarity = rarityGen(_randinput, i); + + if (rarity < 10) { + hashBytes.appendSafe("00"); + } else if (rarity < 100) { + hashBytes.appendSafe("0"); + } + if (rarity > 999) { + hashBytes.appendSafe("999"); + } else { + hashBytes.appendSafe(bytes(_toString(rarity))); + } + } + + return string(hashBytes); + } + + function mint(uint64 _count, bytes32[] calldata merkleProof) + external + payable + nonReentrant + whenMintActive + returns (uint256) + { + uint256 totalMinted = _totalMinted(); + require(_count > 0, "Invalid token count"); + require(totalMinted + _count <= maxSupply, "All tokens are gone"); + + if (isPublicMintActive) { + require(_count * publicMintPrice == msg.value, "Incorrect amount of ether sent"); + require(_numberMinted(msg.sender) + _count <= maxPerAddress, "Exceeded max mints allowed"); + } else { + require(_count * allowListPrice == msg.value, "Incorrect amount of ether sent"); + IOnChainKevin ockContract = IOnChainKevin(ockAddress); + require(onAllowList(msg.sender, merkleProof) || ockContract.balanceOf(msg.sender) > 0, "Not on allow list"); + require(_numberMinted(msg.sender) + _count <= maxPerAllowList, "Exceeded max mints allowed"); + } + + + uint256 batchCount = _count / MAX_BATCH_MINT; + uint256 remainder = _count % MAX_BATCH_MINT; + + for (uint256 i = 0; i < batchCount; i++) { + _mint(msg.sender, MAX_BATCH_MINT); + } + + if (remainder > 0) { + _mint(msg.sender, remainder); + } + + return totalMinted; + } + + function isMintActive() public view returns (bool) { + return _totalMinted() < maxSupply && (isPublicMintActive || isAllowListActive); + } + + function hashToSVG(string memory _hash) + public + view + returns (string memory) + { + uint256 thisTraitIndex; + + bytes memory svgBytes = DynamicBuffer.allocate(1024 * 128); + svgBytes.appendSafe('' + ) + ); + + return string( + abi.encodePacked( + "data:image/svg+xml;base64,", + Base64.encode(svgBytes) + ) + ); + } + + function hashToMetadata(string memory _hash) + public + view + returns (string memory) + { + bytes memory metadataBytes = DynamicBuffer.allocate(1024 * 128); + metadataBytes.appendSafe("["); + + for (uint256 i = 0; i < NUM_LAYERS; i++) { + uint256 thisTraitIndex = HelperLib.parseInt( + HelperLib._substring(_hash, (i * 3), (i * 3) + 3) + ); + metadataBytes.appendSafe( + abi.encodePacked( + '{"trait_type":"', + LAYER_NAMES[i], + '","value":"', + _traitDetails[i][thisTraitIndex].name, + '"}' + ) + ); + + if (i == NUM_LAYERS - 1) { + metadataBytes.appendSafe("]"); + } else { + metadataBytes.appendSafe(","); + } + } + + return string(metadataBytes); + } + + + function onAllowList(address addr, bytes32[] calldata merkleProof) public view returns (bool) { + return MerkleProof.verify(merkleProof, merkleRoot, keccak256(abi.encodePacked(addr))); + } + + + function tokenURI(uint256 _tokenId) + public + view + override + returns (string memory) + { + require(_exists(_tokenId), "Invalid token"); + require(_traitDataPointers[0].length > 0, "Traits have not been added"); + + string memory tokenHash = tokenIdToHash(_tokenId); + + bytes memory jsonBytes = DynamicBuffer.allocate(1024 * 128); + jsonBytes.appendSafe(unicode"{\"name\":\"Crypto Marcs #"); + + jsonBytes.appendSafe( + abi.encodePacked( + _toString(_tokenId), + "\",\"description\":\"", + contractData.description, + "\"," + ) + ); + + if (bytes(baseURI).length > 0 && _renderTokenOffChain[_tokenId]) { + jsonBytes.appendSafe( + abi.encodePacked( + '"image":"', + baseURI, + _toString(_tokenId), + "?dna=", + tokenHash, + '&network=mainnet",' + ) + ); + } else { + string memory svgCode = ""; + if (shouldWrapSVG) { + string memory svgString = hashToSVG(tokenHash); + svgCode = string( + abi.encodePacked( + "data:image/svg+xml;base64,", + Base64.encode( + abi.encodePacked( + '' + ) + ) + ) + ); + jsonBytes.appendSafe( + abi.encodePacked( + '"svg_image_data":"', + svgString, + '",' + ) + ); + } else { + svgCode = hashToSVG(tokenHash); + } + + jsonBytes.appendSafe( + abi.encodePacked( + '"image_data":"', + svgCode, + '",' + ) + ); + } + + jsonBytes.appendSafe( + abi.encodePacked( + '"attributes":', + hashToMetadata(tokenHash), + "}" + ) + ); + + return string( + abi.encodePacked( + "data:application/json;base64,", + Base64.encode(jsonBytes) + ) + ); + } + + function contractURI() + public + view + returns (string memory) + { + return string( + abi.encodePacked( + "data:application/json;base64,", + Base64.encode( + abi.encodePacked( + '{"name":"', + contractData.name, + '","description":"', + contractData.description, + '","image":"', + contractData.image, + '","banner":"', + contractData.banner, + '","external_link":"', + contractData.website, + '","seller_fee_basis_points":', + _toString(contractData.royalties), + ',"fee_recipient":"', + contractData.royaltiesRecipient, + '"}' + ) + ) + ) + ); + } + + function tokenIdToSVG(uint256 _tokenId) + public + view + returns (string memory) + { + return hashToSVG(tokenIdToHash(_tokenId)); + } + + function traitDetails(uint256 _layerIndex, uint256 _traitIndex) + public + view + returns (Trait memory) + { + return _traitDetails[_layerIndex][_traitIndex]; + } + + function traitData(uint256 _layerIndex, uint256 _traitIndex) + public + view + returns (string memory) + { + return string(SSTORE2.read(_traitDataPointers[_layerIndex][_traitIndex])); + } + + function addLayer(uint256 _layerIndex, TraitDTO[] memory traits) + public + onlyOwner + whenUnsealed + { + require(TIERS[_layerIndex].length == traits.length, "Traits size does not match tiers for this index"); + address[] memory dataPointers = new address[](traits.length); + for (uint256 i = 0; i < traits.length; i++) { + dataPointers[i] = SSTORE2.write(traits[i].data); + _traitDetails[_layerIndex][i] = Trait(traits[i].name, traits[i].mimetype); + } + _traitDataPointers[_layerIndex] = dataPointers; + return; + } + + function addTrait(uint256 _layerIndex, uint256 _traitIndex, TraitDTO memory trait) + public + onlyOwner + whenUnsealed + { + _traitDetails[_layerIndex][_traitIndex] = Trait(trait.name, trait.mimetype); + address[] memory dataPointers = _traitDataPointers[_layerIndex]; + dataPointers[_traitIndex] = SSTORE2.write(trait.data); + _traitDataPointers[_layerIndex] = dataPointers; + return; + } + + function setContractData(ContractData memory _contractData) external onlyOwner whenUnsealed { + contractData = _contractData; + } + + function setMaxPerAddress(uint256 _maxPerAddress) external onlyOwner { + maxPerAddress = _maxPerAddress; + } + + function setBaseURI(string memory _baseURI) external onlyOwner { + baseURI = _baseURI; + } + + function setBackgroundColor(string memory _backgroundColor) external onlyOwner whenUnsealed { + backgroundColor = _backgroundColor; + } + + function setRenderOfTokenId(uint256 _tokenId, bool _renderOffChain) external { + require(msg.sender == ownerOf(_tokenId), "Only the token owner can set the render method"); + _renderTokenOffChain[_tokenId] = _renderOffChain; + } + + + function setMerkleRoot(bytes32 newMerkleRoot) external onlyOwner { + merkleRoot = newMerkleRoot; + } + + function setMaxPerAllowList(uint256 _maxPerAllowList) external onlyOwner { + maxPerAllowList = _maxPerAllowList; + } + + function toggleAllowListMint() external onlyOwner { + isAllowListActive = !isAllowListActive; + } + + + + + function toggleWrapSVG() external onlyOwner { + shouldWrapSVG = !shouldWrapSVG; + } + + function togglePublicMint() external onlyOwner { + isPublicMintActive = !isPublicMintActive; + } + + function sealContract() external whenUnsealed onlyOwner { + isContractSealed = true; + } + + function withdraw() external onlyOwner nonReentrant { + (bool success,) = msg.sender.call{value : address(this).balance}(""); + require(success, "Withdrawal failed"); + } + } + + +/////////////////////////////////////////// +// File: /var/app/current/contracts/DynamicBuffer.sol + +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) + +pragma solidity >=0.8.0; + +/// @title DynamicBuffer +/// @author David Huber (@cxkoda) and Simon Fremaux (@dievardump). See also +/// https://raw.githubusercontent.com/dievardump/solidity-dynamic-buffer +/// @notice This library is used to allocate a big amount of container memory +// which will be subsequently filled without needing to reallocate +/// memory. +/// @dev First, allocate memory. +/// Then use `buffer.appendUnchecked(theBytes)` or `appendSafe()` if +/// bounds checking is required. +library DynamicBuffer { + /// @notice Allocates container space for the DynamicBuffer + /// @param capacity The intended max amount of bytes in the buffer + /// @return buffer The memory location of the buffer + /// @dev Allocates `capacity + 0x60` bytes of space + /// The buffer array starts at the first container data position, + /// (i.e. `buffer = container + 0x20`) + function allocate(uint256 capacity) + internal + pure + returns (bytes memory buffer) + { + assembly { + // Get next-free memory address + let container := mload(0x40) + + // Allocate memory by setting a new next-free address + { + // Add 2 x 32 bytes in size for the two length fields + // Add 32 bytes safety space for 32B chunked copy + let size := add(capacity, 0x60) + let newNextFree := add(container, size) + mstore(0x40, newNextFree) + } + + // Set the correct container length + { + let length := add(capacity, 0x40) + mstore(container, length) + } + + // The buffer starts at idx 1 in the container (0 is length) + buffer := add(container, 0x20) + + // Init content with length 0 + mstore(buffer, 0) + } + + return buffer; + } + + /// @notice Appends data to buffer, and update buffer length + /// @param buffer the buffer to append the data to + /// @param data the data to append + /// @dev Does not perform out-of-bound checks (container capacity) + /// for efficiency. + function appendUnchecked(bytes memory buffer, bytes memory data) + internal + pure + { + assembly { + let length := mload(data) + for { + data := add(data, 0x20) + let dataEnd := add(data, length) + let copyTo := add(buffer, add(mload(buffer), 0x20)) + } lt(data, dataEnd) { + data := add(data, 0x20) + copyTo := add(copyTo, 0x20) + } { + // Copy 32B chunks from data to buffer. + // This may read over data array boundaries and copy invalid + // bytes, which doesn't matter in the end since we will + // later set the correct buffer length, and have allocated an + // additional word to avoid buffer overflow. + mstore(copyTo, mload(data)) + } + + // Update buffer length + mstore(buffer, add(mload(buffer), length)) + } + } + + /// @notice Appends data to buffer, and update buffer length + /// @param buffer the buffer to append the data to + /// @param data the data to append + /// @dev Performs out-of-bound checks and calls `appendUnchecked`. + function appendSafe(bytes memory buffer, bytes memory data) internal pure { + uint256 capacity; + uint256 length; + assembly { + capacity := sub(mload(sub(buffer, 0x20)), 0x40) + length := mload(buffer) + } + + require( + length + data.length <= capacity, + "DynamicBuffer: Appending out of bounds." + ); + appendUnchecked(buffer, data); + } +} + +/////////////////////////////////////////// +// File: /var/app/current/contracts/HelperLib.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.14; + +library HelperLib { + function parseInt(string memory _a) + internal + pure + returns (uint8 _parsedInt) + { + bytes memory bresult = bytes(_a); + uint8 mint = 0; + for (uint8 i = 0; i < bresult.length; i++) { + if ( + (uint8(uint8(bresult[i])) >= 48) && + (uint8(uint8(bresult[i])) <= 57) + ) { + mint *= 10; + mint += uint8(bresult[i]) - 48; + } + } + return mint; + } + + function _substring( + string memory str, + uint256 startIndex, + uint256 endIndex + ) internal pure returns (string memory) { + bytes memory strBytes = bytes(str); + bytes memory result = new bytes(endIndex - startIndex); + for (uint256 i = startIndex; i < endIndex; i++) { + result[i - startIndex] = strBytes[i]; + } + return string(result); + } +} + +/////////////////////////////////////////// +// File: /var/app/current/contracts/SSTORE2.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./utils/Bytecode.sol"; + +/** + @title A key-value storage with auto-generated keys for storing chunks of data with a lower write & read cost. + @author Agustin Aguilar + + Readme: https://github.com/0xsequence/sstore2#readme +*/ +library SSTORE2 { + error WriteError(); + + /** + @notice Stores `_data` and returns `pointer` as key for later retrieval + @dev The pointer is a contract address with `_data` as code + @param _data to be written + @return pointer Pointer to the written `_data` + */ + function write(bytes memory _data) internal returns (address pointer) { + // Append 00 to _data so contract can't be called + // Build init code + bytes memory code = Bytecode.creationCodeFor( + abi.encodePacked( + hex'00', + _data + ) + ); + + // Deploy contract using create + assembly { pointer := create(0, add(code, 32), mload(code)) } + + // Address MUST be non-zero + if (pointer == address(0)) revert WriteError(); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @return data read from `_pointer` contract + */ + function read(address _pointer) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, 1, type(uint256).max); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @param _start number of bytes to skip + @return data read from `_pointer` contract + */ + function read(address _pointer, uint256 _start) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, _start + 1, type(uint256).max); + } + + /** + @notice Reads the contents of the `_pointer` code as data, skips the first byte + @dev The function is intended for reading pointers generated by `write` + @param _pointer to be read + @param _start number of bytes to skip + @param _end index before which to end extraction + @return data read from `_pointer` contract + */ + function read(address _pointer, uint256 _start, uint256 _end) internal view returns (bytes memory) { + return Bytecode.codeAt(_pointer, _start + 1, _end + 1); + } +} + +/////////////////////////////////////////// +// File: /var/app/current/contracts/utils/Bytecode.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + + +library Bytecode { + error InvalidCodeAtRange(uint256 _size, uint256 _start, uint256 _end); + + /** + @notice Generate a creation code that results on a contract with `_code` as bytecode + @param _code The returning value of the resulting `creationCode` + @return creationCode (constructor) for new contract + */ + function creationCodeFor(bytes memory _code) internal pure returns (bytes memory) { + /* + 0x00 0x63 0x63XXXXXX PUSH4 _code.length size + 0x01 0x80 0x80 DUP1 size size + 0x02 0x60 0x600e PUSH1 14 14 size size + 0x03 0x60 0x6000 PUSH1 00 0 14 size size + 0x04 0x39 0x39 CODECOPY size + 0x05 0x60 0x6000 PUSH1 00 0 size + 0x06 0xf3 0xf3 RETURN + + */ + + return abi.encodePacked( + hex"63", + uint32(_code.length), + hex"80_60_0E_60_00_39_60_00_F3", + _code + ); + } + + /** + @notice Returns the size of the code on a given address + @param _addr Address that may or may not contain code + @return size of the code on the given `_addr` + */ + function codeSize(address _addr) internal view returns (uint256 size) { + assembly { size := extcodesize(_addr) } + } + + /** + @notice Returns the code of a given address + @dev It will fail if `_end < _start` + @param _addr Address that may or may not contain code + @param _start number of bytes of code to skip on read + @param _end index before which to end extraction + @return oCode read from `_addr` deployed bytecode + + Forked from: https://gist.github.com/KardanovIR/fe98661df9338c842b4a30306d507fbd + */ + function codeAt(address _addr, uint256 _start, uint256 _end) internal view returns (bytes memory oCode) { + uint256 csize = codeSize(_addr); + if (csize == 0) return bytes(""); + + if (_start > csize) return bytes(""); + if (_end < _start) revert InvalidCodeAtRange(csize, _start, _end); + + unchecked { + uint256 reqSize = _end - _start; + uint256 maxSize = csize - _start; + + uint256 size = maxSize < reqSize ? maxSize : reqSize; + + assembly { + // allocate output byte array - this could also be done without assembly + // by using o_code = new bytes(size) + oCode := mload(0x40) + // new "memory end" including padding + mstore(0x40, add(oCode, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + // store length in memory + mstore(oCode, size) + // actually retrieve the code, this needs assembly + extcodecopy(_addr, add(oCode, 0x20), _start, size) + } + } + } +} + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/access/Ownable.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor() { + _transferOwnership(_msgSender()); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/security/ReentrancyGuard.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor() { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and making it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Base64.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (utils/Base64.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides a set of functions to operate with Base64 strings. + * + * _Available since v4.5._ + */ +library Base64 { + /** + * @dev Base64 Encoding/Decoding Table + */ + string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** + * @dev Converts a `bytes` to its Bytes64 `string` representation. + */ + function encode(bytes memory data) internal pure returns (string memory) { + /** + * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence + * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol + */ + if (data.length == 0) return ""; + + // Loads the table into memory + string memory table = _TABLE; + + // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter + // and split into 4 numbers of 6 bits. + // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up + // - `data.length + 2` -> Round up + // - `/ 3` -> Number of 3-bytes chunks + // - `4 *` -> 4 characters for each chunk + string memory result = new string(4 * ((data.length + 2) / 3)); + + assembly { + // Prepare the lookup table (skip the first "length" byte) + let tablePtr := add(table, 1) + + // Prepare result pointer, jump over length + let resultPtr := add(result, 32) + + // Run over the input, 3 bytes at a time + for { + let dataPtr := data + let endPtr := add(data, mload(data)) + } lt(dataPtr, endPtr) { + + } { + // Advance 3 bytes + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + + // To write each character, shift the 3 bytes (18 bits) chunk + // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) + // and apply logical AND with 0x3F which is the number of + // the previous character in the ASCII table prior to the Base64 Table + // The result is then added to the table to get the character to write, + // and finally write it in the result pointer but with a left shift + // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits + + mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + } + + // When data `bytes` is not exactly 3 bytes long + // it is padded with `=` characters at the end + switch mod(mload(data), 3) + case 1 { + mstore8(sub(resultPtr, 1), 0x3d) + mstore8(sub(resultPtr, 2), 0x3d) + } + case 2 { + mstore8(sub(resultPtr, 1), 0x3d) + } + } + + return result; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/cryptography/MerkleProof.sol + +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (utils/cryptography/MerkleProof.sol) + +pragma solidity ^0.8.0; + +/** + * @dev These functions deal with verification of Merkle Trees proofs. + * + * The proofs can be generated using the JavaScript library + * https://github.com/miguelmota/merkletreejs[merkletreejs]. + * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled. + * + * See `test/utils/cryptography/MerkleProof.test.js` for some examples. + * + * WARNING: You should avoid using leaf values that are 64 bytes long prior to + * hashing, or use a hash function other than keccak256 for hashing leaves. + * This is because the concatenation of a sorted pair of internal nodes in + * the merkle tree could be reinterpreted as a leaf value. + */ +library MerkleProof { + /** + * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree + * defined by `root`. For this, a `proof` must be provided, containing + * sibling hashes on the branch from the leaf to the root of the tree. Each + * pair of leaves and each pair of pre-images are assumed to be sorted. + */ + function verify( + bytes32[] memory proof, + bytes32 root, + bytes32 leaf + ) internal pure returns (bool) { + return processProof(proof, leaf) == root; + } + + /** + * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up + * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt + * hash matches the root of the tree. When processing the proof, the pairs + * of leafs & pre-images are assumed to be sorted. + * + * _Available since v4.4._ + */ + function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + bytes32 proofElement = proof[i]; + if (computedHash <= proofElement) { + // Hash(current computed hash + current element of the proof) + computedHash = _efficientHash(computedHash, proofElement); + } else { + // Hash(current element of the proof + current computed hash) + computedHash = _efficientHash(proofElement, computedHash); + } + } + return computedHash; + } + + function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { + assembly { + mstore(0x00, a) + mstore(0x20, b) + value := keccak256(0x00, 0x40) + } + } +} + + +/////////////////////////////////////////// +// File: erc721a/contracts/ERC721A.sol + +// SPDX-License-Identifier: MIT +// ERC721A Contracts v4.1.0 +// Creator: Chiru Labs + +pragma solidity ^0.8.4; + +import './IERC721A.sol'; + +/** + * @dev ERC721 token receiver interface. + */ +interface ERC721A__IERC721Receiver { + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, + * including the Metadata extension. Built to optimize for lower gas during batch mints. + * + * Assumes serials are sequentially minted starting at `_startTokenId()` + * (defaults to 0, e.g. 0, 1, 2, 3..). + * + * Assumes that an owner cannot have more than 2**64 - 1 (max value of uint64) of supply. + * + * Assumes that the maximum token id cannot exceed 2**256 - 1 (max value of uint256). + */ +contract ERC721A is IERC721A { + // Mask of an entry in packed address data. + uint256 private constant BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1; + + // The bit position of `numberMinted` in packed address data. + uint256 private constant BITPOS_NUMBER_MINTED = 64; + + // The bit position of `numberBurned` in packed address data. + uint256 private constant BITPOS_NUMBER_BURNED = 128; + + // The bit position of `aux` in packed address data. + uint256 private constant BITPOS_AUX = 192; + + // Mask of all 256 bits in packed address data except the 64 bits for `aux`. + uint256 private constant BITMASK_AUX_COMPLEMENT = (1 << 192) - 1; + + // The bit position of `startTimestamp` in packed ownership. + uint256 private constant BITPOS_START_TIMESTAMP = 160; + + // The bit mask of the `burned` bit in packed ownership. + uint256 private constant BITMASK_BURNED = 1 << 224; + + // The bit position of the `nextInitialized` bit in packed ownership. + uint256 private constant BITPOS_NEXT_INITIALIZED = 225; + + // The bit mask of the `nextInitialized` bit in packed ownership. + uint256 private constant BITMASK_NEXT_INITIALIZED = 1 << 225; + + // The bit position of `extraData` in packed ownership. + uint256 private constant BITPOS_EXTRA_DATA = 232; + + // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`. + uint256 private constant BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1; + + // The mask of the lower 160 bits for addresses. + uint256 private constant BITMASK_ADDRESS = (1 << 160) - 1; + + // The maximum `quantity` that can be minted with `_mintERC2309`. + // This limit is to prevent overflows on the address data entries. + // For a limit of 5000, a total of 3.689e15 calls to `_mintERC2309` + // is required to cause an overflow, which is unrealistic. + uint256 private constant MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000; + + // The tokenId of the next token to be minted. + uint256 private _currentIndex; + + // The number of tokens burned. + uint256 private _burnCounter; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to ownership details + // An empty struct value does not necessarily mean the token is unowned. + // See `_packedOwnershipOf` implementation for details. + // + // Bits Layout: + // - [0..159] `addr` + // - [160..223] `startTimestamp` + // - [224] `burned` + // - [225] `nextInitialized` + // - [232..255] `extraData` + mapping(uint256 => uint256) private _packedOwnerships; + + // Mapping owner address to address data. + // + // Bits Layout: + // - [0..63] `balance` + // - [64..127] `numberMinted` + // - [128..191] `numberBurned` + // - [192..255] `aux` + mapping(address => uint256) private _packedAddressData; + + // Mapping from token ID to approved address. + mapping(uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + _currentIndex = _startTokenId(); + } + + /** + * @dev Returns the starting token ID. + * To change the starting token ID, please override this function. + */ + function _startTokenId() internal view virtual returns (uint256) { + return 0; + } + + /** + * @dev Returns the next token ID to be minted. + */ + function _nextTokenId() internal view returns (uint256) { + return _currentIndex; + } + + /** + * @dev Returns the total number of tokens in existence. + * Burned tokens will reduce the count. + * To get the total number of tokens minted, please see `_totalMinted`. + */ + function totalSupply() public view override returns (uint256) { + // Counter underflow is impossible as _burnCounter cannot be incremented + // more than `_currentIndex - _startTokenId()` times. + unchecked { + return _currentIndex - _burnCounter - _startTokenId(); + } + } + + /** + * @dev Returns the total amount of tokens minted in the contract. + */ + function _totalMinted() internal view returns (uint256) { + // Counter underflow is impossible as _currentIndex does not decrement, + // and it is initialized to `_startTokenId()` + unchecked { + return _currentIndex - _startTokenId(); + } + } + + /** + * @dev Returns the total number of tokens burned. + */ + function _totalBurned() internal view returns (uint256) { + return _burnCounter; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + // The interface IDs are constants representing the first 4 bytes of the XOR of + // all function selectors in the interface. See: https://eips.ethereum.org/EIPS/eip-165 + // e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)` + return + interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165. + interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721. + interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata. + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view override returns (uint256) { + if (owner == address(0)) revert BalanceQueryForZeroAddress(); + return _packedAddressData[owner] & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the number of tokens minted by `owner`. + */ + function _numberMinted(address owner) internal view returns (uint256) { + return (_packedAddressData[owner] >> BITPOS_NUMBER_MINTED) & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the number of tokens burned by or on behalf of `owner`. + */ + function _numberBurned(address owner) internal view returns (uint256) { + return (_packedAddressData[owner] >> BITPOS_NUMBER_BURNED) & BITMASK_ADDRESS_DATA_ENTRY; + } + + /** + * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). + */ + function _getAux(address owner) internal view returns (uint64) { + return uint64(_packedAddressData[owner] >> BITPOS_AUX); + } + + /** + * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). + * If there are multiple variables, please pack them into a uint64. + */ + function _setAux(address owner, uint64 aux) internal { + uint256 packed = _packedAddressData[owner]; + uint256 auxCasted; + // Cast `aux` with assembly to avoid redundant masking. + assembly { + auxCasted := aux + } + packed = (packed & BITMASK_AUX_COMPLEMENT) | (auxCasted << BITPOS_AUX); + _packedAddressData[owner] = packed; + } + + /** + * Returns the packed ownership data of `tokenId`. + */ + function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) { + uint256 curr = tokenId; + + unchecked { + if (_startTokenId() <= curr) + if (curr < _currentIndex) { + uint256 packed = _packedOwnerships[curr]; + // If not burned. + if (packed & BITMASK_BURNED == 0) { + // Invariant: + // There will always be an ownership that has an address and is not burned + // before an ownership that does not have an address and is not burned. + // Hence, curr will not underflow. + // + // We can directly compare the packed value. + // If the address is zero, packed is zero. + while (packed == 0) { + packed = _packedOwnerships[--curr]; + } + return packed; + } + } + } + revert OwnerQueryForNonexistentToken(); + } + + /** + * Returns the unpacked `TokenOwnership` struct from `packed`. + */ + function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) { + ownership.addr = address(uint160(packed)); + ownership.startTimestamp = uint64(packed >> BITPOS_START_TIMESTAMP); + ownership.burned = packed & BITMASK_BURNED != 0; + ownership.extraData = uint24(packed >> BITPOS_EXTRA_DATA); + } + + /** + * Returns the unpacked `TokenOwnership` struct at `index`. + */ + function _ownershipAt(uint256 index) internal view returns (TokenOwnership memory) { + return _unpackedOwnership(_packedOwnerships[index]); + } + + /** + * @dev Initializes the ownership slot minted at `index` for efficiency purposes. + */ + function _initializeOwnershipAt(uint256 index) internal { + if (_packedOwnerships[index] == 0) { + _packedOwnerships[index] = _packedOwnershipOf(index); + } + } + + /** + * Gas spent here starts off proportional to the maximum mint batch size. + * It gradually moves to O(1) as tokens get transferred around in the collection over time. + */ + function _ownershipOf(uint256 tokenId) internal view returns (TokenOwnership memory) { + return _unpackedOwnership(_packedOwnershipOf(tokenId)); + } + + /** + * @dev Packs ownership data into a single uint256. + */ + function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) { + assembly { + // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. + owner := and(owner, BITMASK_ADDRESS) + // `owner | (block.timestamp << BITPOS_START_TIMESTAMP) | flags`. + result := or(owner, or(shl(BITPOS_START_TIMESTAMP, timestamp()), flags)) + } + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view override returns (address) { + return address(uint160(_packedOwnershipOf(tokenId))); + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + if (!_exists(tokenId)) revert URIQueryForNonexistentToken(); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : ''; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, it can be overridden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ''; + } + + /** + * @dev Returns the `nextInitialized` flag set if `quantity` equals 1. + */ + function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) { + // For branchless setting of the `nextInitialized` flag. + assembly { + // `(quantity == 1) << BITPOS_NEXT_INITIALIZED`. + result := shl(BITPOS_NEXT_INITIALIZED, eq(quantity, 1)) + } + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public override { + address owner = ownerOf(tokenId); + + if (_msgSenderERC721A() != owner) + if (!isApprovedForAll(owner, _msgSenderERC721A())) { + revert ApprovalCallerNotOwnerNorApproved(); + } + + _tokenApprovals[tokenId] = to; + emit Approval(owner, to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view override returns (address) { + if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken(); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + if (operator == _msgSenderERC721A()) revert ApproveToCaller(); + + _operatorApprovals[_msgSenderERC721A()][operator] = approved; + emit ApprovalForAll(_msgSenderERC721A(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + safeTransferFrom(from, to, tokenId, ''); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) public virtual override { + transferFrom(from, to, tokenId); + if (to.code.length != 0) + if (!_checkContractOnERC721Received(from, to, tokenId, _data)) { + revert TransferToNonERC721ReceiverImplementer(); + } + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + */ + function _exists(uint256 tokenId) internal view returns (bool) { + return + _startTokenId() <= tokenId && + tokenId < _currentIndex && // If within bounds, + _packedOwnerships[tokenId] & BITMASK_BURNED == 0; // and not burned. + } + + /** + * @dev Equivalent to `_safeMint(to, quantity, '')`. + */ + function _safeMint(address to, uint256 quantity) internal { + _safeMint(to, quantity, ''); + } + + /** + * @dev Safely mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement + * {IERC721Receiver-onERC721Received}, which is called for each safe transfer. + * - `quantity` must be greater than 0. + * + * See {_mint}. + * + * Emits a {Transfer} event for each mint. + */ + function _safeMint( + address to, + uint256 quantity, + bytes memory _data + ) internal { + _mint(to, quantity); + + unchecked { + if (to.code.length != 0) { + uint256 end = _currentIndex; + uint256 index = end - quantity; + do { + if (!_checkContractOnERC721Received(address(0), to, index++, _data)) { + revert TransferToNonERC721ReceiverImplementer(); + } + } while (index < end); + // Reentrancy protection. + if (_currentIndex != end) revert(); + } + } + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {Transfer} event for each mint. + */ + function _mint(address to, uint256 quantity) internal { + uint256 startTokenId = _currentIndex; + if (to == address(0)) revert MintToZeroAddress(); + if (quantity == 0) revert MintZeroQuantity(); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are incredibly unrealistic. + // `balance` and `numberMinted` have a maximum limit of 2**64. + // `tokenId` has a maximum limit of 2**256. + unchecked { + // Updates: + // - `balance += quantity`. + // - `numberMinted += quantity`. + // + // We can directly add to the `balance` and `numberMinted`. + _packedAddressData[to] += quantity * ((1 << BITPOS_NUMBER_MINTED) | 1); + + // Updates: + // - `address` to the owner. + // - `startTimestamp` to the timestamp of minting. + // - `burned` to `false`. + // - `nextInitialized` to `quantity == 1`. + _packedOwnerships[startTokenId] = _packOwnershipData( + to, + _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) + ); + + uint256 tokenId = startTokenId; + uint256 end = startTokenId + quantity; + do { + emit Transfer(address(0), to, tokenId++); + } while (tokenId < end); + + _currentIndex = end; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Mints `quantity` tokens and transfers them to `to`. + * + * This function is intended for efficient minting only during contract creation. + * + * It emits only one {ConsecutiveTransfer} as defined in + * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309), + * instead of a sequence of {Transfer} event(s). + * + * Calling this function outside of contract creation WILL make your contract + * non-compliant with the ERC721 standard. + * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309 + * {ConsecutiveTransfer} event is only permissible during contract creation. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `quantity` must be greater than 0. + * + * Emits a {ConsecutiveTransfer} event. + */ + function _mintERC2309(address to, uint256 quantity) internal { + uint256 startTokenId = _currentIndex; + if (to == address(0)) revert MintToZeroAddress(); + if (quantity == 0) revert MintZeroQuantity(); + if (quantity > MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit(); + + _beforeTokenTransfers(address(0), to, startTokenId, quantity); + + // Overflows are unrealistic due to the above check for `quantity` to be below the limit. + unchecked { + // Updates: + // - `balance += quantity`. + // - `numberMinted += quantity`. + // + // We can directly add to the `balance` and `numberMinted`. + _packedAddressData[to] += quantity * ((1 << BITPOS_NUMBER_MINTED) | 1); + + // Updates: + // - `address` to the owner. + // - `startTimestamp` to the timestamp of minting. + // - `burned` to `false`. + // - `nextInitialized` to `quantity == 1`. + _packedOwnerships[startTokenId] = _packOwnershipData( + to, + _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) + ); + + emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to); + + _currentIndex = startTokenId + quantity; + } + _afterTokenTransfers(address(0), to, startTokenId, quantity); + } + + /** + * @dev Returns the storage slot and value for the approved address of `tokenId`. + */ + function _getApprovedAddress(uint256 tokenId) + private + view + returns (uint256 approvedAddressSlot, address approvedAddress) + { + mapping(uint256 => address) storage tokenApprovalsPtr = _tokenApprovals; + // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId]`. + assembly { + // Compute the slot. + mstore(0x00, tokenId) + mstore(0x20, tokenApprovalsPtr.slot) + approvedAddressSlot := keccak256(0x00, 0x40) + // Load the slot's value from storage. + approvedAddress := sload(approvedAddressSlot) + } + } + + /** + * @dev Returns whether the `approvedAddress` is equals to `from` or `msgSender`. + */ + function _isOwnerOrApproved( + address approvedAddress, + address from, + address msgSender + ) private pure returns (bool result) { + assembly { + // Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean. + from := and(from, BITMASK_ADDRESS) + // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean. + msgSender := and(msgSender, BITMASK_ADDRESS) + // `msgSender == from || msgSender == approvedAddress`. + result := or(eq(msgSender, from), eq(msgSender, approvedAddress)) + } + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); + + if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner(); + + (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedAddress(tokenId); + + // The nested ifs save around 20+ gas over a compound boolean condition. + if (!_isOwnerOrApproved(approvedAddress, from, _msgSenderERC721A())) + if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved(); + + if (to == address(0)) revert TransferToZeroAddress(); + + _beforeTokenTransfers(from, to, tokenId, 1); + + // Clear approvals from the previous owner. + assembly { + if approvedAddress { + // This is equivalent to `delete _tokenApprovals[tokenId]`. + sstore(approvedAddressSlot, 0) + } + } + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as tokenId would have to be 2**256. + unchecked { + // We can directly increment and decrement the balances. + --_packedAddressData[from]; // Updates: `balance -= 1`. + ++_packedAddressData[to]; // Updates: `balance += 1`. + + // Updates: + // - `address` to the next owner. + // - `startTimestamp` to the timestamp of transfering. + // - `burned` to `false`. + // - `nextInitialized` to `true`. + _packedOwnerships[tokenId] = _packOwnershipData( + to, + BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked) + ); + + // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . + if (prevOwnershipPacked & BITMASK_NEXT_INITIALIZED == 0) { + uint256 nextTokenId = tokenId + 1; + // If the next slot's address is zero and not burned (i.e. packed value is zero). + if (_packedOwnerships[nextTokenId] == 0) { + // If the next slot is within bounds. + if (nextTokenId != _currentIndex) { + // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. + _packedOwnerships[nextTokenId] = prevOwnershipPacked; + } + } + } + } + + emit Transfer(from, to, tokenId); + _afterTokenTransfers(from, to, tokenId, 1); + } + + /** + * @dev Equivalent to `_burn(tokenId, false)`. + */ + function _burn(uint256 tokenId) internal virtual { + _burn(tokenId, false); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId, bool approvalCheck) internal virtual { + uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); + + address from = address(uint160(prevOwnershipPacked)); + + (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedAddress(tokenId); + + if (approvalCheck) { + // The nested ifs save around 20+ gas over a compound boolean condition. + if (!_isOwnerOrApproved(approvedAddress, from, _msgSenderERC721A())) + if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved(); + } + + _beforeTokenTransfers(from, address(0), tokenId, 1); + + // Clear approvals from the previous owner. + assembly { + if approvedAddress { + // This is equivalent to `delete _tokenApprovals[tokenId]`. + sstore(approvedAddressSlot, 0) + } + } + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. + unchecked { + // Updates: + // - `balance -= 1`. + // - `numberBurned += 1`. + // + // We can directly decrement the balance, and increment the number burned. + // This is equivalent to `packed -= 1; packed += 1 << BITPOS_NUMBER_BURNED;`. + _packedAddressData[from] += (1 << BITPOS_NUMBER_BURNED) - 1; + + // Updates: + // - `address` to the last owner. + // - `startTimestamp` to the timestamp of burning. + // - `burned` to `true`. + // - `nextInitialized` to `true`. + _packedOwnerships[tokenId] = _packOwnershipData( + from, + (BITMASK_BURNED | BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked) + ); + + // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . + if (prevOwnershipPacked & BITMASK_NEXT_INITIALIZED == 0) { + uint256 nextTokenId = tokenId + 1; + // If the next slot's address is zero and not burned (i.e. packed value is zero). + if (_packedOwnerships[nextTokenId] == 0) { + // If the next slot is within bounds. + if (nextTokenId != _currentIndex) { + // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. + _packedOwnerships[nextTokenId] = prevOwnershipPacked; + } + } + } + } + + emit Transfer(from, address(0), tokenId); + _afterTokenTransfers(from, address(0), tokenId, 1); + + // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times. + unchecked { + _burnCounter++; + } + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkContractOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory _data + ) private returns (bool) { + try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns ( + bytes4 retval + ) { + return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert TransferToNonERC721ReceiverImplementer(); + } else { + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } + + /** + * @dev Directly sets the extra data for the ownership data `index`. + */ + function _setExtraDataAt(uint256 index, uint24 extraData) internal { + uint256 packed = _packedOwnerships[index]; + if (packed == 0) revert OwnershipNotInitializedForExtraData(); + uint256 extraDataCasted; + // Cast `extraData` with assembly to avoid redundant masking. + assembly { + extraDataCasted := extraData + } + packed = (packed & BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << BITPOS_EXTRA_DATA); + _packedOwnerships[index] = packed; + } + + /** + * @dev Returns the next extra data for the packed ownership data. + * The returned result is shifted into position. + */ + function _nextExtraData( + address from, + address to, + uint256 prevOwnershipPacked + ) private view returns (uint256) { + uint24 extraData = uint24(prevOwnershipPacked >> BITPOS_EXTRA_DATA); + return uint256(_extraData(from, to, extraData)) << BITPOS_EXTRA_DATA; + } + + /** + * @dev Called during each token transfer to set the 24bit `extraData` field. + * Intended to be overridden by the cosumer contract. + * + * `previousExtraData` - the value of `extraData` before transfer. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _extraData( + address from, + address to, + uint24 previousExtraData + ) internal view virtual returns (uint24) {} + + /** + * @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. + * This includes minting. + * And also called before burning one token. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, `tokenId` will be burned by `from`. + * - `from` and `to` are never both zero. + */ + function _beforeTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Hook that is called after a set of serially-ordered token ids have been transferred. + * This includes minting. + * And also called after one token has been burned. + * + * startTokenId - the first token id to be transferred + * quantity - the amount to be transferred + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been + * transferred to `to`. + * - When `from` is zero, `tokenId` has been minted for `to`. + * - When `to` is zero, `tokenId` has been burned by `from`. + * - `from` and `to` are never both zero. + */ + function _afterTokenTransfers( + address from, + address to, + uint256 startTokenId, + uint256 quantity + ) internal virtual {} + + /** + * @dev Returns the message sender (defaults to `msg.sender`). + * + * If you are writing GSN compatible contracts, you need to override this function. + */ + function _msgSenderERC721A() internal view virtual returns (address) { + return msg.sender; + } + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function _toString(uint256 value) internal pure returns (string memory ptr) { + assembly { + // The maximum value of a uint256 contains 78 digits (1 byte per digit), + // but we allocate 128 bytes to keep the free memory pointer 32-byte word aliged. + // We will need 1 32-byte word to store the length, + // and 3 32-byte words to store a maximum of 78 digits. Total: 32 + 3 * 32 = 128. + ptr := add(mload(0x40), 128) + // Update the free memory pointer to allocate. + mstore(0x40, ptr) + + // Cache the end of the memory to calculate the length later. + let end := ptr + + // We write the string from the rightmost digit to the leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + // Costs a bit more than early returning for the zero case, + // but cheaper in terms of deployment and overall runtime costs. + for { + // Initialize and perform the first pass without check. + let temp := value + // Move the pointer 1 byte leftwards to point to an empty character slot. + ptr := sub(ptr, 1) + // Write the character to the pointer. 48 is the ASCII index of '0'. + mstore8(ptr, add(48, mod(temp, 10))) + temp := div(temp, 10) + } temp { + // Keep dividing `temp` until zero. + temp := div(temp, 10) + } { + // Body of the for loop. + ptr := sub(ptr, 1) + mstore8(ptr, add(48, mod(temp, 10))) + } + + let length := sub(end, ptr) + // Move the pointer 32 bytes leftwards to make room for the length. + ptr := sub(ptr, 32) + // Store the length. + mstore(ptr, length) + } + } +} + + +/////////////////////////////////////////// +// File: erc721a/contracts/IERC721A.sol + +// SPDX-License-Identifier: MIT +// ERC721A Contracts v4.1.0 +// Creator: Chiru Labs + +pragma solidity ^0.8.4; + +/** + * @dev Interface of an ERC721A compliant contract. + */ +interface IERC721A { + /** + * The caller must own the token or be an approved operator. + */ + error ApprovalCallerNotOwnerNorApproved(); + + /** + * The token does not exist. + */ + error ApprovalQueryForNonexistentToken(); + + /** + * The caller cannot approve to their own address. + */ + error ApproveToCaller(); + + /** + * Cannot query the balance for the zero address. + */ + error BalanceQueryForZeroAddress(); + + /** + * Cannot mint to the zero address. + */ + error MintToZeroAddress(); + + /** + * The quantity of tokens minted must be more than zero. + */ + error MintZeroQuantity(); + + /** + * The token does not exist. + */ + error OwnerQueryForNonexistentToken(); + + /** + * The caller must own the token or be an approved operator. + */ + error TransferCallerNotOwnerNorApproved(); + + /** + * The token must be owned by `from`. + */ + error TransferFromIncorrectOwner(); + + /** + * Cannot safely transfer to a contract that does not implement the ERC721Receiver interface. + */ + error TransferToNonERC721ReceiverImplementer(); + + /** + * Cannot transfer to the zero address. + */ + error TransferToZeroAddress(); + + /** + * The token does not exist. + */ + error URIQueryForNonexistentToken(); + + /** + * The `quantity` minted with ERC2309 exceeds the safety limit. + */ + error MintERC2309QuantityExceedsLimit(); + + /** + * The `extraData` cannot be set on an unintialized ownership slot. + */ + error OwnershipNotInitializedForExtraData(); + + struct TokenOwnership { + // The address of the owner. + address addr; + // Keeps track of the start time of ownership with minimal overhead for tokenomics. + uint64 startTimestamp; + // Whether the token has been burned. + bool burned; + // Arbitrary data similar to `startTimestamp` that can be set through `_extraData`. + uint24 extraData; + } + + /** + * @dev Returns the total amount of tokens stored by the contract. + * + * Burned tokens are calculated here, use `_totalMinted()` if you want to count just minted tokens. + */ + function totalSupply() external view returns (uint256); + + // ============================== + // IERC165 + // ============================== + + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); + + // ============================== + // IERC721 + // ============================== + + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId, + bytes calldata data + ) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 tokenId + ) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + // ============================== + // IERC721Metadata + // ============================== + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); + + // ============================== + // IERC2309 + // ============================== + + /** + * @dev Emitted when tokens in `fromTokenId` to `toTokenId` (inclusive) is transferred from `from` to `to`, + * as defined in the ERC2309 standard. See `_mintERC2309` for more details. + */ + event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); +} + + diff --git a/ethabi/code/0xe9b91d537c3aa5a3fa87275fbd2e4feaaed69bd0.yml b/ethabi/code/0xe9b91d537c3aa5a3fa87275fbd2e4feaaed69bd0.yml new file mode 100644 index 0000000..c6f86b6 --- /dev/null +++ b/ethabi/code/0xe9b91d537c3aa5a3fa87275fbd2e4feaaed69bd0.yml @@ -0,0 +1,12 @@ +--- +ContractName: IndelibleERC721A +CompilerVersion: v0.8.14+commit.80d49f37 +OptimizationUsed: '1' +Runs: '200' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: MIT +Proxy: '0' +Implementation: '' +SwarmSource: '' diff --git a/ethabi/code/0xf07468ead8cf26c752c676e43c814fee9c8cf402.sol b/ethabi/code/0xf07468ead8cf26c752c676e43c814fee9c8cf402.sol new file mode 100644 index 0000000..c161c8d --- /dev/null +++ b/ethabi/code/0xf07468ead8cf26c752c676e43c814fee9c8cf402.sol @@ -0,0 +1,1630 @@ +/////////////////////////////////////////// +// File: contracts/CryptoPhunksV2.sol + +// SPDX-License-Identifier: UNLICENSE +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; +import "@openzeppelin/contracts/utils/Counters.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; + +contract CryptoPhunksV2 is Ownable, ERC721Enumerable, ReentrancyGuard { + using Counters for Counters.Counter; + using Strings for uint256; + + // You can use this hash to verify the image file containing all the phunks + string public constant imageHash = + "122dab9670c21ad538dafdbb87191c4d7114c389af616c42c54556aa2211b899"; + + constructor() ERC721("CryptoPhunksV2", "PHUNK") {} + + bool public isSaleOn = false; + + bool public saleHasBeenStarted = false; + + uint256 public constant MAX_MINTABLE_AT_ONCE = 50; + + uint256[10000] private _availableTokens; + uint256 private _numAvailableTokens = 10000; + uint256 private _numFreeRollsGiven = 0; + + mapping(address => uint256) public freeRollPhunks; + + uint256 private _lastTokenIdMintedInInitialSet = 10000; + + function numTotalPhunks() public view virtual returns (uint256) { + return 10000; + } + + function freeRollMint() public nonReentrant() { + uint256 toMint = freeRollPhunks[msg.sender]; + freeRollPhunks[msg.sender] = 0; + uint256 remaining = numTotalPhunks() - totalSupply(); + if (toMint > remaining) { + toMint = remaining; + } + _mint(toMint); + } + + function getNumFreeRollPhunks(address owner) public view returns (uint256) { + return freeRollPhunks[owner]; + } + + function mint(uint256 _numToMint) public payable nonReentrant() { + require(isSaleOn, "Sale hasn't started."); + uint256 totalSupply = totalSupply(); + require( + totalSupply + _numToMint <= numTotalPhunks(), + "There aren't this many phunks left." + ); + uint256 costForMintingPhunks = getCostForMintingPhunks(_numToMint); + require( + msg.value >= costForMintingPhunks, + "Too little sent, please send more eth." + ); + if (msg.value > costForMintingPhunks) { + payable(msg.sender).transfer(msg.value - costForMintingPhunks); + } + + _mint(_numToMint); + } + + // internal minting function + function _mint(uint256 _numToMint) internal { + require(_numToMint <= MAX_MINTABLE_AT_ONCE, "Minting too many at once."); + + uint256 updatedNumAvailableTokens = _numAvailableTokens; + for (uint256 i = 0; i < _numToMint; i++) { + uint256 newTokenId = useRandomAvailableToken(_numToMint, i); + _safeMint(msg.sender, newTokenId); + updatedNumAvailableTokens--; + } + _numAvailableTokens = updatedNumAvailableTokens; + } + + function useRandomAvailableToken(uint256 _numToFetch, uint256 _i) + internal + returns (uint256) + { + uint256 randomNum = + uint256( + keccak256( + abi.encode( + msg.sender, + tx.gasprice, + block.number, + block.timestamp, + blockhash(block.number - 1), + _numToFetch, + _i + ) + ) + ); + uint256 randomIndex = randomNum % _numAvailableTokens; + return useAvailableTokenAtIndex(randomIndex); + } + + function useAvailableTokenAtIndex(uint256 indexToUse) + internal + returns (uint256) + { + uint256 valAtIndex = _availableTokens[indexToUse]; + uint256 result; + if (valAtIndex == 0) { + // This means the index itself is still an available token + result = indexToUse; + } else { + // This means the index itself is not an available token, but the val at that index is. + result = valAtIndex; + } + + uint256 lastIndex = _numAvailableTokens - 1; + if (indexToUse != lastIndex) { + // Replace the value at indexToUse, now that it's been used. + // Replace it with the data from the last index in the array, since we are going to decrease the array size afterwards. + uint256 lastValInArray = _availableTokens[lastIndex]; + if (lastValInArray == 0) { + // This means the index itself is still an available token + _availableTokens[indexToUse] = lastIndex; + } else { + // This means the index itself is not an available token, but the val at that index is. + _availableTokens[indexToUse] = lastValInArray; + } + } + + _numAvailableTokens--; + return result; + } + + function getCostForMintingPhunks(uint256 _numToMint) + public + view + returns (uint256) + { + require( + totalSupply() + _numToMint <= numTotalPhunks(), + "There aren't this many phunks left." + ); + if (_numToMint == 1) { + return 0.02 ether; + } else if (_numToMint == 3) { + return 0.05 ether; + } else if (_numToMint == 5) { + return 0.07 ether; + } else if (_numToMint == 10) { + return 0.10 ether; + } else { + revert("Unsupported mint amount"); + } + } + + function getPhunksBelongingToOwner(address _owner) + external + view + returns (uint256[] memory) + { + uint256 numPhunks = balanceOf(_owner); + if (numPhunks == 0) { + return new uint256[](0); + } else { + uint256[] memory result = new uint256[](numPhunks); + for (uint256 i = 0; i < numPhunks; i++) { + result[i] = tokenOfOwnerByIndex(_owner, i); + } + return result; + } + } + + /* + * Dev stuff. + */ + + // metadata URI + string private _baseTokenURI; + + function _baseURI() internal view virtual override returns (string memory) { + return _baseTokenURI; + } + + function tokenURI(uint256 _tokenId) + public + view + override + returns (string memory) + { + string memory base = _baseURI(); + string memory _tokenURI = Strings.toString(_tokenId); + + // If there is no base URI, return the token URI. + if (bytes(base).length == 0) { + return _tokenURI; + } + + return string(abi.encodePacked(base, _tokenURI)); + } + + // contract metadata URI for opensea + string public contractURI; + + /* + * Owner stuff + */ + + function startSale() public onlyOwner { + isSaleOn = true; + saleHasBeenStarted = true; + } + + function endSale() public onlyOwner { + isSaleOn = false; + } + + function giveFreeRoll(address receiver) public onlyOwner { + // max number of free mints we can give to the community for promotions/marketing + require(_numFreeRollsGiven < 200, "already given max number of free rolls"); + uint256 freeRolls = freeRollPhunks[receiver]; + freeRollPhunks[receiver] = freeRolls + 1; + _numFreeRollsGiven = _numFreeRollsGiven + 1; + } + + // for handing out free rolls to v1 phunk owners + // details on seeding info here: https://gist.github.com/cryptophunks/7f542feaee510e12464da3bb2a922713 + function seedFreeRolls( + address[] memory tokenOwners, + uint256[] memory numOfFreeRolls + ) public onlyOwner { + require( + !saleHasBeenStarted, + "cannot seed free rolls after sale has started" + ); + require( + tokenOwners.length == numOfFreeRolls.length, + "tokenOwners does not match numOfFreeRolls length" + ); + + // light check to make sure the proper values are being passed + require(numOfFreeRolls[0] <= 3, "cannot give more than 3 free rolls"); + + for (uint256 i = 0; i < tokenOwners.length; i++) { + freeRollPhunks[tokenOwners[i]] = numOfFreeRolls[i]; + } + } + + // for seeding the v2 contract with v1 state + // details on seeding info here: https://gist.github.com/cryptophunks/7f542feaee510e12464da3bb2a922713 + function seedInitialContractState( + address[] memory tokenOwners, + uint256[] memory tokens + ) public onlyOwner { + require( + !saleHasBeenStarted, + "cannot initial phunk mint if sale has started" + ); + require( + tokenOwners.length == tokens.length, + "tokenOwners does not match tokens length" + ); + + uint256 lastTokenIdMintedInInitialSetCopy = _lastTokenIdMintedInInitialSet; + for (uint256 i = 0; i < tokenOwners.length; i++) { + uint256 token = tokens[i]; + require( + lastTokenIdMintedInInitialSetCopy > token, + "initial phunk mints must be in decreasing order for our availableToken index to work" + ); + lastTokenIdMintedInInitialSetCopy = token; + + useAvailableTokenAtIndex(token); + _safeMint(tokenOwners[i], token); + } + _lastTokenIdMintedInInitialSet = lastTokenIdMintedInInitialSetCopy; + } + + // URIs + function setBaseURI(string memory baseURI) external onlyOwner { + _baseTokenURI = baseURI; + } + + function setContractURI(string memory _contractURI) external onlyOwner { + contractURI = _contractURI; + } + + function withdrawMoney() public payable onlyOwner { + (bool success, ) = msg.sender.call{value: address(this).balance}(""); + require(success, "Transfer failed."); + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId + ) internal virtual override(ERC721Enumerable) { + super._beforeTokenTransfer(from, to, tokenId); + } + + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(ERC721Enumerable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/access/Ownable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor () { + address msgSender = _msgSender(); + _owner = msgSender; + emit OwnershipTransferred(address(0), msgSender); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/security/ReentrancyGuard.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor () { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and make it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/ERC721.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./IERC721.sol"; +import "./IERC721Receiver.sol"; +import "./extensions/IERC721Metadata.sol"; +import "../../utils/Address.sol"; +import "../../utils/Context.sol"; +import "../../utils/Strings.sol"; +import "../../utils/introspection/ERC165.sol"; + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including + * the Metadata extension, but not including the Enumerable extension, which is available separately as + * {ERC721Enumerable}. + */ +contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { + using Address for address; + using Strings for uint256; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to owner address + mapping (uint256 => address) private _owners; + + // Mapping owner address to token count + mapping (address => uint256) private _balances; + + // Mapping from token ID to approved address + mapping (uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping (address => mapping (address => bool)) private _operatorApprovals; + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + constructor (string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IERC721).interfaceId + || interfaceId == type(IERC721Metadata).interfaceId + || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view virtual override returns (uint256) { + require(owner != address(0), "ERC721: balance query for the zero address"); + return _balances[owner]; + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view virtual override returns (address) { + address owner = _owners[tokenId]; + require(owner != address(0), "ERC721: owner query for nonexistent token"); + return owner; + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length > 0 + ? string(abi.encodePacked(baseURI, tokenId.toString())) + : ''; + } + + /** + * @dev Base URI for computing {tokenURI}. Empty by default, can be overriden + * in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ""; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public virtual override { + address owner = ERC721.ownerOf(tokenId); + require(to != owner, "ERC721: approval to current owner"); + + require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()), + "ERC721: approve caller is not owner nor approved for all" + ); + + _approve(to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view virtual override returns (address) { + require(_exists(tokenId), "ERC721: approved query for nonexistent token"); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + require(operator != _msgSender(), "ERC721: approve to caller"); + + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom(address from, address to, uint256 tokenId) public virtual override { + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + + _transfer(from, to, tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { + safeTransferFrom(from, to, tokenId, ""); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override { + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + _safeTransfer(from, to, tokenId, _data); + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * `_data` is additional data, it has no specified format and it is sent in call to `to`. + * + * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. + * implement alternative mechanisms to perform token transfer, such as signature-based. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual { + _transfer(from, to, tokenId); + require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + * and stop existing when they are burned (`_burn`). + */ + function _exists(uint256 tokenId) internal view virtual returns (bool) { + return _owners[tokenId] != address(0); + } + + /** + * @dev Returns whether `spender` is allowed to manage `tokenId`. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { + require(_exists(tokenId), "ERC721: operator query for nonexistent token"); + address owner = ERC721.ownerOf(tokenId); + return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); + } + + /** + * @dev Safely mints `tokenId` and transfers it to `to`. + * + * Requirements: + * + * - `tokenId` must not exist. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeMint(address to, uint256 tokenId) internal virtual { + _safeMint(to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual { + _mint(to, tokenId); + require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Mints `tokenId` and transfers it to `to`. + * + * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * Emits a {Transfer} event. + */ + function _mint(address to, uint256 tokenId) internal virtual { + require(to != address(0), "ERC721: mint to the zero address"); + require(!_exists(tokenId), "ERC721: token already minted"); + + _beforeTokenTransfer(address(0), to, tokenId); + + _balances[to] += 1; + _owners[tokenId] = to; + + emit Transfer(address(0), to, tokenId); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId) internal virtual { + address owner = ERC721.ownerOf(tokenId); + + _beforeTokenTransfer(owner, address(0), tokenId); + + // Clear approvals + _approve(address(0), tokenId); + + _balances[owner] -= 1; + delete _owners[tokenId]; + + emit Transfer(owner, address(0), tokenId); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer(address from, address to, uint256 tokenId) internal virtual { + require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); + require(to != address(0), "ERC721: transfer to the zero address"); + + _beforeTokenTransfer(from, to, tokenId); + + // Clear approvals from the previous owner + _approve(address(0), tokenId); + + _balances[from] -= 1; + _balances[to] += 1; + _owners[tokenId] = to; + + emit Transfer(from, to, tokenId); + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * Emits a {Approval} event. + */ + function _approve(address to, uint256 tokenId) internal virtual { + _tokenApprovals[tokenId] = to; + emit Approval(ERC721.ownerOf(tokenId), to, tokenId); + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * The call is not executed if the target address is not a contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) + private returns (bool) + { + if (to.isContract()) { + try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { + return retval == IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert("ERC721: transfer to non ERC721Receiver implementer"); + } else { + // solhint-disable-next-line no-inline-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } else { + return true; + } + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, ``from``'s `tokenId` will be burned. + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "./IERC721Enumerable.sol"; + +/** + * @dev This implements an optional extension of {ERC721} defined in the EIP that adds + * enumerability of all the token ids in the contract as well as all token ids owned by each + * account. + */ +abstract contract ERC721Enumerable is ERC721, IERC721Enumerable { + // Mapping from owner to list of owned token IDs + mapping(address => mapping(uint256 => uint256)) private _ownedTokens; + + // Mapping from token ID to index of the owner tokens list + mapping(uint256 => uint256) private _ownedTokensIndex; + + // Array with all token ids, used for enumeration + uint256[] private _allTokens; + + // Mapping from token id to position in the allTokens array + mapping(uint256 => uint256) private _allTokensIndex; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { + return interfaceId == type(IERC721Enumerable).interfaceId + || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { + require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); + return _ownedTokens[owner][index]; + } + + /** + * @dev See {IERC721Enumerable-totalSupply}. + */ + function totalSupply() public view virtual override returns (uint256) { + return _allTokens.length; + } + + /** + * @dev See {IERC721Enumerable-tokenByIndex}. + */ + function tokenByIndex(uint256 index) public view virtual override returns (uint256) { + require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds"); + return _allTokens[index]; + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, ``from``'s `tokenId` will be burned. + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override { + super._beforeTokenTransfer(from, to, tokenId); + + if (from == address(0)) { + _addTokenToAllTokensEnumeration(tokenId); + } else if (from != to) { + _removeTokenFromOwnerEnumeration(from, tokenId); + } + if (to == address(0)) { + _removeTokenFromAllTokensEnumeration(tokenId); + } else if (to != from) { + _addTokenToOwnerEnumeration(to, tokenId); + } + } + + /** + * @dev Private function to add a token to this extension's ownership-tracking data structures. + * @param to address representing the new owner of the given token ID + * @param tokenId uint256 ID of the token to be added to the tokens list of the given address + */ + function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { + uint256 length = ERC721.balanceOf(to); + _ownedTokens[to][length] = tokenId; + _ownedTokensIndex[tokenId] = length; + } + + /** + * @dev Private function to add a token to this extension's token tracking data structures. + * @param tokenId uint256 ID of the token to be added to the tokens list + */ + function _addTokenToAllTokensEnumeration(uint256 tokenId) private { + _allTokensIndex[tokenId] = _allTokens.length; + _allTokens.push(tokenId); + } + + /** + * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that + * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for + * gas optimizations e.g. when performing a transfer operation (avoiding double writes). + * This has O(1) time complexity, but alters the order of the _ownedTokens array. + * @param from address representing the previous owner of the given token ID + * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address + */ + function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { + // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and + // then delete the last slot (swap and pop). + + uint256 lastTokenIndex = ERC721.balanceOf(from) - 1; + uint256 tokenIndex = _ownedTokensIndex[tokenId]; + + // When the token to delete is the last token, the swap operation is unnecessary + if (tokenIndex != lastTokenIndex) { + uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; + + _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token + _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index + } + + // This also deletes the contents at the last position of the array + delete _ownedTokensIndex[tokenId]; + delete _ownedTokens[from][lastTokenIndex]; + } + + /** + * @dev Private function to remove a token from this extension's token tracking data structures. + * This has O(1) time complexity, but alters the order of the _allTokens array. + * @param tokenId uint256 ID of the token to be removed from the tokens list + */ + function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { + // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and + // then delete the last slot (swap and pop). + + uint256 lastTokenIndex = _allTokens.length - 1; + uint256 tokenIndex = _allTokensIndex[tokenId]; + + // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so + // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding + // an 'if' statement (like in _removeTokenFromOwnerEnumeration) + uint256 lastTokenId = _allTokens[lastTokenIndex]; + + _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token + _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index + + // This also deletes the contents at the last position of the array + delete _allTokensIndex[tokenId]; + _allTokens.pop(); + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Counters.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @title Counters + * @author Matt Condon (@shrugs) + * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number + * of elements in a mapping, issuing ERC721 ids, or counting request ids. + * + * Include with `using Counters for Counters.Counter;` + */ +library Counters { + struct Counter { + // This variable should never be directly accessed by users of the library: interactions must be restricted to + // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add + // this feature: see https://github.com/ethereum/solidity/issues/4637 + uint256 _value; // default: 0 + } + + function current(Counter storage counter) internal view returns (uint256) { + return counter._value; + } + + function increment(Counter storage counter) internal { + unchecked { + counter._value += 1; + } + } + + function decrement(Counter storage counter) internal { + uint256 value = counter._value; + require(value > 0, "Counter: decrement overflow"); + unchecked { + counter._value = value - 1; + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Strings.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant alphabet = "0123456789abcdef"; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + // Inspired by OraclizeAPI's implementation - MIT licence + // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol + + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + while (value != 0) { + digits -= 1; + buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); + value /= 10; + } + return string(buffer); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + if (value == 0) { + return "0x00"; + } + uint256 temp = value; + uint256 length = 0; + while (temp != 0) { + length++; + temp >>= 8; + } + return toHexString(value, length); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = alphabet[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } + +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Context.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/IERC721.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. + */ + function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/Address.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/introspection/ERC165.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/utils/introspection/IERC165.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + + +/////////////////////////////////////////// +// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Enumerable is IERC721 { + + /** + * @dev Returns the total amount of tokens stored by the contract. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns a token ID owned by `owner` at a given `index` of its token list. + * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); + + /** + * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. + * Use along with {totalSupply} to enumerate all tokens. + */ + function tokenByIndex(uint256 index) external view returns (uint256); +} + + diff --git a/ethabi/code/0xf07468ead8cf26c752c676e43c814fee9c8cf402.yml b/ethabi/code/0xf07468ead8cf26c752c676e43c814fee9c8cf402.yml new file mode 100644 index 0000000..43a679c --- /dev/null +++ b/ethabi/code/0xf07468ead8cf26c752c676e43c814fee9c8cf402.yml @@ -0,0 +1,12 @@ +--- +ContractName: CryptoPhunksV2 +CompilerVersion: v0.8.4+commit.c7e474f2 +OptimizationUsed: '1' +Runs: '500' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: '' +Proxy: '0' +Implementation: '' +SwarmSource: '' diff --git a/ethabi/code/0xf4a4644e818c2843ba0aabea93af6c80b5984114.sol b/ethabi/code/0xf4a4644e818c2843ba0aabea93af6c80b5984114.sol new file mode 100644 index 0000000..28f2734 --- /dev/null +++ b/ethabi/code/0xf4a4644e818c2843ba0aabea93af6c80b5984114.sol @@ -0,0 +1,1132 @@ +// SPDX-License-Identifier: GPL-3.0 + + + +// File: @openzeppelin/contracts/utils/introspection/IERC165.sol + + + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// File: @openzeppelin/contracts/token/ERC721/IERC721.sol + + + +pragma solidity ^0.8.0; + + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool _approved) external; + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; +} + +// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol + + + +pragma solidity ^0.8.0; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. + */ + function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4); +} + +// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol + + + +pragma solidity ^0.8.0; + + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} + +// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol + + + +pragma solidity ^0.8.0; + + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Enumerable is IERC721 { + + /** + * @dev Returns the total amount of tokens stored by the contract. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns a token ID owned by `owner` at a given `index` of its token list. + * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); + + /** + * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. + * Use along with {totalSupply} to enumerate all tokens. + */ + function tokenByIndex(uint256 index) external view returns (uint256); +} + +// File: @openzeppelin/contracts/utils/Address.sol + + + +pragma solidity ^0.8.0; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize, which returns 0 for contracts in + // construction, since the code is only stored at the end of the + // constructor execution. + + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + // solhint-disable-next-line avoid-low-level-calls, avoid-call-value + (bool success, ) = recipient.call{ value: amount }(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain`call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCall(target, data, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + require(isContract(target), "Address: call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.call{ value: value }(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { + require(isContract(target), "Address: static call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.staticcall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { + require(isContract(target), "Address: delegate call to non-contract"); + + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = target.delegatecall(data); + return _verifyCallResult(success, returndata, errorMessage); + } + + function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { + if (success) { + return returndata; + } else { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } + } +} + +// File: @openzeppelin/contracts/utils/Context.sol + + + +pragma solidity ^0.8.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} + +// File: @openzeppelin/contracts/utils/Strings.sol + + + +pragma solidity ^0.8.0; + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant alphabet = "0123456789abcdef"; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + // Inspired by OraclizeAPI's implementation - MIT licence + // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol + + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + while (value != 0) { + digits -= 1; + buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); + value /= 10; + } + return string(buffer); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + if (value == 0) { + return "0x00"; + } + uint256 temp = value; + uint256 length = 0; + while (temp != 0) { + length++; + temp >>= 8; + } + return toHexString(value, length); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = alphabet[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } + +} + +// File: @openzeppelin/contracts/utils/introspection/ERC165.sol + + + +pragma solidity ^0.8.0; + + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + +// File: @openzeppelin/contracts/token/ERC721/ERC721.sol + + + +pragma solidity ^0.8.0; + + + + + + + + + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including + * the Metadata extension, but not including the Enumerable extension, which is available separately as + * {ERC721Enumerable}. + */ +contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { + using Address for address; + using Strings for uint256; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to owner address + mapping (uint256 => address) private _owners; + + // Mapping owner address to token count + mapping (address => uint256) private _balances; + + // Mapping from token ID to approved address + mapping (uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping (address => mapping (address => bool)) private _operatorApprovals; + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + constructor (string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IERC721).interfaceId + || interfaceId == type(IERC721Metadata).interfaceId + || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view virtual override returns (uint256) { + require(owner != address(0), "ERC721: balance query for the zero address"); + return _balances[owner]; + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view virtual override returns (address) { + address owner = _owners[tokenId]; + require(owner != address(0), "ERC721: owner query for nonexistent token"); + return owner; + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length > 0 + ? string(abi.encodePacked(baseURI, tokenId.toString())) + : ''; + } + + /** + * @dev Base URI for computing {tokenURI}. Empty by default, can be overriden + * in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ""; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public virtual override { + address owner = ERC721.ownerOf(tokenId); + require(to != owner, "ERC721: approval to current owner"); + + require(_msgSender() == owner || ERC721.isApprovedForAll(owner, _msgSender()), + "ERC721: approve caller is not owner nor approved for all" + ); + + _approve(to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view virtual override returns (address) { + require(_exists(tokenId), "ERC721: approved query for nonexistent token"); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + require(operator != _msgSender(), "ERC721: approve to caller"); + + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom(address from, address to, uint256 tokenId) public virtual override { + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + + _transfer(from, to, tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { + safeTransferFrom(from, to, tokenId, ""); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override { + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + _safeTransfer(from, to, tokenId, _data); + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * `_data` is additional data, it has no specified format and it is sent in call to `to`. + * + * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. + * implement alternative mechanisms to perform token transfer, such as signature-based. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual { + _transfer(from, to, tokenId); + require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + * and stop existing when they are burned (`_burn`). + */ + function _exists(uint256 tokenId) internal view virtual returns (bool) { + return _owners[tokenId] != address(0); + } + + /** + * @dev Returns whether `spender` is allowed to manage `tokenId`. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { + require(_exists(tokenId), "ERC721: operator query for nonexistent token"); + address owner = ERC721.ownerOf(tokenId); + return (spender == owner || getApproved(tokenId) == spender || ERC721.isApprovedForAll(owner, spender)); + } + + /** + * @dev Safely mints `tokenId` and transfers it to `to`. + * + * Requirements: + * + * - `tokenId` must not exist. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeMint(address to, uint256 tokenId) internal virtual { + _safeMint(to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual { + _mint(to, tokenId); + require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Mints `tokenId` and transfers it to `to`. + * + * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * Emits a {Transfer} event. + */ + function _mint(address to, uint256 tokenId) internal virtual { + require(to != address(0), "ERC721: mint to the zero address"); + require(!_exists(tokenId), "ERC721: token already minted"); + + _beforeTokenTransfer(address(0), to, tokenId); + + _balances[to] += 1; + _owners[tokenId] = to; + + emit Transfer(address(0), to, tokenId); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId) internal virtual { + address owner = ERC721.ownerOf(tokenId); + + _beforeTokenTransfer(owner, address(0), tokenId); + + // Clear approvals + _approve(address(0), tokenId); + + _balances[owner] -= 1; + delete _owners[tokenId]; + + emit Transfer(owner, address(0), tokenId); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer(address from, address to, uint256 tokenId) internal virtual { + require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); + require(to != address(0), "ERC721: transfer to the zero address"); + + _beforeTokenTransfer(from, to, tokenId); + + // Clear approvals from the previous owner + _approve(address(0), tokenId); + + _balances[from] -= 1; + _balances[to] += 1; + _owners[tokenId] = to; + + emit Transfer(from, to, tokenId); + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * Emits a {Approval} event. + */ + function _approve(address to, uint256 tokenId) internal virtual { + _tokenApprovals[tokenId] = to; + emit Approval(ERC721.ownerOf(tokenId), to, tokenId); + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * The call is not executed if the target address is not a contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) + private returns (bool) + { + if (to.isContract()) { + try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { + return retval == IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert("ERC721: transfer to non ERC721Receiver implementer"); + } else { + // solhint-disable-next-line no-inline-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } else { + return true; + } + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, ``from``'s `tokenId` will be burned. + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { } +} + +// File: @openzeppelin/contracts/access/Ownable.sol + + + +pragma solidity ^0.8.0; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor () { + address msgSender = _msgSender(); + _owner = msgSender; + emit OwnershipTransferred(address(0), msgSender); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } +} + +// File: contracts/PunksV1Wrapper.sol + + + +pragma solidity ^0.8.0; + + + + +interface PunksV1Contract { + + // Events + + event Assign(address indexed to, uint256 punkIndex); + event Transfer(address indexed from, address indexed to, uint256 value); + event PunkTransfer(address indexed from, address indexed to, uint256 punkIndex); + event PunkOffered(uint indexed punkIndex, uint minValue, address indexed toAddress); + event PunkBought(uint indexed punkIndex, uint value, address indexed fromAddress, address indexed toAddress); + event PunkNoLongerForSale(uint indexed punkIndex); + + // Read contract + + function name() external view returns (string memory); + + function punksOfferedForSale(uint id) external view returns (bool isForSale, uint punkIndex, address seller, uint minValue, address onlySellTo); + + function totalSupply() external view returns (uint); + + function decimals() external view returns (uint8); + + function imageHash() external view returns (string memory); + + function nextPunkIndexToAssign() external view returns (uint); + + function punkIndexToAddress(uint id) external view returns (address); + + function standard() external view returns (string memory); + + function balanceOf(address) external view returns (uint); + + function symbol() external view returns (string memory); + + function numberOfPunksToReserve() external view returns (uint); + + function numberOfPunksReserved() external view returns (uint); + + function punksRemainingToAssign() external view returns (uint); + + function pendingWithdrawals(address) external view returns (uint); + + // Write contract + + function reservePunksForOwner(uint maxForThisRun) external; + + function withdraw() external; + + function buyPunk(uint id) external payable; + + function transferPunk(address to, uint id) external; + + function offerPunkForSaleToAddress(uint id, uint minSalePriceInWei, address to) external; + + function offerPunkForSale(uint id, uint minSalePriceInWei) external; + + function getPunk(uint id) external; + + function punkNoLongerForSale(uint id) external; + +} + +contract PunksV1Wrapper is Ownable, ERC721 { + + event Wrapped(uint indexed _punkId, address indexed owner); + event Unwrapped(uint indexed _punkId, address indexed owner); + + address payable public punkAddress = payable(0x6Ba6f2207e343923BA692e5Cae646Fb0F566DB8D); + string public _baseTokenURI; + + constructor() payable ERC721("Wrapped CryptoPunks V1", "WPUNKS1") {} + + /** + * @dev Accepts an offer from the punks contract and assigns a wrapped token to msg.sender + */ + function wrap(uint _punkId) public payable { + // Prereq: owner should call `offerPunkForSaleToAddress` with price 0 (or higher if they wish) + (bool isForSale, , address seller, uint minValue, address onlySellTo) = PunksV1Contract(punkAddress).punksOfferedForSale(_punkId); + require(isForSale == true); + require(seller == msg.sender); + require(minValue == 0); + require((onlySellTo == address(this)) || (onlySellTo == address(0x0))); + // Buy the punk + PunksV1Contract(punkAddress).buyPunk{value: msg.value}(_punkId); + // Mint a wrapped punk + _mint(msg.sender, _punkId); + Wrapped(_punkId, msg.sender); + } + + /** + * @dev Burns the wrapped token and transfers the underlying punk to the owner + **/ + function unwrap(uint256 _punkId) public { + require(_isApprovedOrOwner(msg.sender, _punkId)); + _burn(_punkId); + PunksV1Contract(punkAddress).transferPunk(msg.sender, _punkId); + Unwrapped(_punkId, msg.sender); + } + + /** + * @dev Returns a URI for a given token ID's metadata + */ + function tokenURI(uint256 _tokenId) public view override returns (string memory) { + return string(abi.encodePacked(_baseTokenURI, Strings.toString(_tokenId))); + } + + function setBaseTokenURI(string memory __baseTokenURI) public onlyOwner { + _baseTokenURI = __baseTokenURI; + } +} \ No newline at end of file diff --git a/ethabi/code/0xf4a4644e818c2843ba0aabea93af6c80b5984114.yml b/ethabi/code/0xf4a4644e818c2843ba0aabea93af6c80b5984114.yml new file mode 100644 index 0000000..14abb80 --- /dev/null +++ b/ethabi/code/0xf4a4644e818c2843ba0aabea93af6c80b5984114.yml @@ -0,0 +1,12 @@ +--- +ContractName: PunksV1Wrapper +CompilerVersion: v0.8.3+commit.8d00100c +OptimizationUsed: '0' +Runs: '200' +ConstructorArguments: '' +EVMVersion: Default +Library: '' +LicenseType: None +Proxy: '0' +Implementation: '' +SwarmSource: ipfs://fab1f2d7ff300c2ef98f8cd4a07b0e35d341c8d79866f2802c0118476c7304c8 diff --git a/ethabi/sandbox/download.rb b/ethabi/sandbox/download_abis.rb similarity index 91% rename from ethabi/sandbox/download.rb rename to ethabi/sandbox/download_abis.rb index 9904843..2615b3e 100644 --- a/ethabi/sandbox/download.rb +++ b/ethabi/sandbox/download_abis.rb @@ -3,7 +3,7 @@ # # to run use -# ruby sandbox/download.rb +# ruby sandbox/download_abis.rb $LOAD_PATH.unshift( "../etherscan-lite/lib" ) diff --git a/ethabi/sandbox/download_code.rb b/ethabi/sandbox/download_code.rb new file mode 100644 index 0000000..b0588fc --- /dev/null +++ b/ethabi/sandbox/download_code.rb @@ -0,0 +1,96 @@ +################ +# download (source) code via Etherscan + +# +# to run use +# ruby sandbox/download_code.rb + + +$LOAD_PATH.unshift( "../etherscan-lite/lib" ) +require 'ethname' +require 'etherscan-lite' + + + +def format_code( txt ) + ## {{ to { + ## and }} to } + txt = txt.strip.sub( /\A\{\{/, '{').sub( /\}\}\z/, '}' ) + + data = JSON.parse( txt ) + ## pp data + + language = data['language'] + pp language + if language != 'Solidity' + puts "!! ERROR - expected Solidity for language; got: #{language}" + exit 1 + end + + sources = data['sources'] + puts " #{sources.size} source(s)" + + buf = '' + sources.each do |name, h| + buf << "///////////////////////////////////////////\n" + buf << "// File: #{name}\n\n" + buf << h['content'] + buf << "\n\n" + end + buf +end + + + + + + +puts " #{Ethname.directory.size} (contract) address record(s)" + + +delay_in_s = 1 + +Ethname.directory.records.each_with_index do |rec,i| + puts "==> [#{i+1}] #{rec.names.join('|')} @ #{rec.addr} supports #{rec.interfaces.join('|')}..." + + outpath_code = "./code/#{rec.addr}.sol" + outpath_meta = "./code/#{rec.addr}.yml" + + if File.exist?( outpath_code ) + # already download / found in cache + else + puts " sleeping in #{delay_in_s} sec(s)..." + sleep( delay_in_s ) + + data = Etherscan.getsourcecode( address: rec.addr ) + pp data ## note: returns abi data as a json string (parse again!!) + + ## note: returns an array + if data.size != 1 + puts "!! ERROR - expected array of size 1; got #{data.size}" + exit 1 + end + + code = data[0]['SourceCode'] + + ## note: unroll multi-file format if present (starts with {{ .. }}) + code = format_code( code ) if code.start_with?( /[ \t\n\r]*\{\{/ ) + + + ## fix: use "universal new line or such ?? - why lines get duplicated??" + ## hack: use write_blob + write_blob( outpath_code, code ) + + ## remove SourceCode & ABI entries + data[0].delete('SourceCode') + data[0].delete('ABI') + puts "meta:" + pp data[0] + + ## save rest (remaining) as yml + write_text( outpath_meta, YAML.dump( data[0] )) + end +end + + +puts "bye" \ No newline at end of file diff --git a/etherscan-lite/lib/etherscan-lite/contract.rb b/etherscan-lite/lib/etherscan-lite/contract.rb index cad4896..c588b0d 100644 --- a/etherscan-lite/lib/etherscan-lite/contract.rb +++ b/etherscan-lite/lib/etherscan-lite/contract.rb @@ -33,5 +33,19 @@ def self.getabi( **kwargs ) call( getabi_url( **kwargs ) ) end + ######### + ## Get Contract Source Code for Verified Contract Source Codes + ## Returns the Solidity source code of a verified smart contract. + ## see https://docs.etherscan.io/api-endpoints/contracts#get-contract-source-code-for-verified-contract-source-codes + def self.getsourcecode_url( address: ) + src = "#{BASE}?module=contract&action=getsourcecode" + + "&address=#{address}" + + "&apikey=#{config.key}" + src + end + + def self.getsourcecode( **kwargs ) + call( getsourcecode_url( **kwargs ) ) + end +end # module Etherscan -end # module Etherscan \ No newline at end of file