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,';
+
+ 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 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 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 MoonCatAcclimator
+ * @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"AcclimatedMoonCats", 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