// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; contract QuantumLynx is ERC721Enumerable, Ownable { using Counters for Counters.Counter; using Strings for uint256; Counters.Counter private _tokenIdCounter; struct LynxAttributes { string name; string description; string metadataURI; bool isBlessed; bool isEnchanted; bool isProtectedByBrinks; bool aiQuantumLinksInCoralReefs; } mapping(uint256 => LynxAttributes) public lynxAttributes; string private _baseTokenURI; constructor(string memory baseURI) ERC721("Quantum Lynx", "QLYNX") { _baseTokenURI = baseURI; } function mintLynx( address to, string memory name, string memory description, string memory metadataURI, bool isBlessed, bool isEnchanted, bool isProtectedByBrinks, bool aiQuantumLinksInCoralReefs ) public onlyOwner { _tokenIdCounter.increment(); uint256 tokenId = _tokenIdCounter.current(); lynxAttributes[tokenId] = LynxAttributes( name, description, metadataURI, isBlessed, isEnchanted, isProtectedByBrinks, aiQuantumLinksInCoralReefs ); _safeMint(to, tokenId); } function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); LynxAttributes memory attributes = lynxAttributes[tokenId]; string memory attributesString = string(abi.encodePacked( '{"name": "', attributes.name, '",', '"description": "', attributes.description, '",', '"image": "', _baseTokenURI, tokenId.toString(), '",', '"attributes": [', '{"trait_type": "Blessed by Archangel Michael", "value": ', attributes.isBlessed ? '"Yes"' : '"No"', '},', '{"trait_type": "Enchanted", "value": ', attributes.isEnchanted ? '"Yes"' : '"No"', '},', '{"trait_type": "Protected by BRINKS", "value": ', attributes.isProtectedByBrinks ? '"Yes"' : '"No"', '},', '{"trait_type": "AI Quantum Links in Coral Reefs", "value": ', attributes.aiQuantumLinksInCoralReefs ? '"Yes"' : '"No"', '}', ']}' )); return string(abi.encodePacked("data:application/json;base64,", Base64.encode(bytes(attributesString)))); } function setBaseURI(string memory baseURI) public onlyOwner { _baseTokenURI = baseURI; } } /// @title Base64 - Utility library for encoding/decoding base64 library Base64 { bytes internal constant TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; function encode(bytes memory data) internal pure returns (string memory) { if (data.length == 0) return ""; string memory table = string(TABLE); uint256 encodedLen = 4 * ((data.length + 2) / 3); string memory result = new string(encodedLen + 32); assembly { let tablePtr := add(table, 1) let resultPtr := add(result, 32) for { let i := 0 } lt(i, mload(data)) { i := add(i, 3) } { data := add(data, 3) let input := mload(data) mstore(resultPtr, shl(224, mload(add(tablePtr, and(shr(18, input), 0x3F))))) resultPtr := add(resultPtr, 1) mstore(resultPtr, shl(224, mload(add(tablePtr, and(shr(12, input), 0x3F))))) resultPtr := add(resultPtr, 1) mstore(resultPtr, shl(224, mload(add(tablePtr, and(shr(6, input), 0x3F))))) resultPtr := add(resultPtr, 1) mstore(resultPtr, shl(224, mload(add(tablePtr, and(input, 0x3F))))) resultPtr := add(resultPtr, 1) } mstore(result, encodedLen) } return result; } }