文件 1 的 19:Address.sol
pragma solidity ^0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
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");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
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");
}
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);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
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);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
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
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 19:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 3 的 19:Counters.sol
pragma solidity ^0.8.0;
library Counters {
struct Counter {
uint256 _value;
}
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;
}
}
文件 4 的 19:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 5 的 19:ERC721.sol
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";
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
using Address for address;
using Strings for uint256;
string private _name;
string private _symbol;
mapping(uint256 => address) private _owners;
mapping(address => uint256) private _balances;
mapping(uint256 => address) private _tokenApprovals;
mapping(address => mapping(address => bool)) private _operatorApprovals;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
function balanceOf(address owner) public view virtual override returns (uint256) {
require(owner != address(0), "ERC721: balance query for the zero address");
return _balances[owner];
}
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;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
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())) : "";
}
function _baseURI() internal view virtual returns (string memory) {
return "";
}
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);
}
function getApproved(uint256 tokenId) public view virtual override returns (address) {
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
return _tokenApprovals[tokenId];
}
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);
}
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
function transferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_transfer(from, to, tokenId);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
safeTransferFrom(from, to, tokenId, "");
}
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);
}
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");
}
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _owners[tokenId] != address(0);
}
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));
}
function _safeMint(address to, uint256 tokenId) internal virtual {
_safeMint(to, tokenId, "");
}
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"
);
}
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);
}
function _burn(uint256 tokenId) internal virtual {
address owner = ERC721.ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId);
_approve(address(0), tokenId);
_balances[owner] -= 1;
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
}
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);
_approve(address(0), tokenId);
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
}
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
}
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.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;
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual {}
}
文件 6 的 19:ERC721Enumerable.sol
pragma solidity ^0.8.0;
import "../ERC721.sol";
import "./IERC721Enumerable.sol";
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
mapping(address => mapping(uint256 => uint256)) private _ownedTokens;
mapping(uint256 => uint256) private _ownedTokensIndex;
uint256[] private _allTokens;
mapping(uint256 => uint256) private _allTokensIndex;
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
}
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];
}
function totalSupply() public view virtual override returns (uint256) {
return _allTokens.length;
}
function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
return _allTokens[index];
}
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);
}
}
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
uint256 length = ERC721.balanceOf(to);
_ownedTokens[to][length] = tokenId;
_ownedTokensIndex[tokenId] = length;
}
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
_allTokensIndex[tokenId] = _allTokens.length;
_allTokens.push(tokenId);
}
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
uint256 tokenIndex = _ownedTokensIndex[tokenId];
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastTokenId;
_ownedTokensIndex[lastTokenId] = tokenIndex;
}
delete _ownedTokensIndex[tokenId];
delete _ownedTokens[from][lastTokenIndex];
}
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
uint256 lastTokenIndex = _allTokens.length - 1;
uint256 tokenIndex = _allTokensIndex[tokenId];
uint256 lastTokenId = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastTokenId;
_allTokensIndex[lastTokenId] = tokenIndex;
delete _allTokensIndex[tokenId];
_allTokens.pop();
}
}
文件 7 的 19:GalacticFloppyDisk.sol
pragma solidity >=0.8.0 <0.9.0;
import 'base64-sol/base64.sol';
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import './SVGBuilder.sol';
import './HexStrings.sol';
import './ToColor.sol';
abstract contract NFTContract {
function balanceOf(address owner) external virtual view returns (uint256);
}
interface IERC20 {
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
}
struct CoolSoftware {
NFTContract contractInterface;
string contractName;
string softwareName;
}
struct BoringSoftware {
string softwareName;
uint256 diskCount;
uint256 diskNumber;
}
contract GalacticFloppyDisk is Ownable, ERC721Enumerable {
using Counters for Counters.Counter;
using Strings for uint256;
using Strings for uint8;
using HexStrings for uint160;
using ToColor for bytes3;
using SafeMath for uint256;
Counters.Counter private _tokenCounter;
CoolSoftware[] private coolSoftware;
uint256 public immutable AVAILABLE_SUPPLY;
uint256 public immutable MAX_PER_ADDRESS;
uint16 private immutable WACKY_THRESHHOLD;
uint16 private immutable INSECURE_THRESHHOLD;
uint16 private immutable INFECTED_THRESHHOLD;
bool private saleActive = true;
mapping(uint256 => bytes32) private genes;
event FloppyMinted(address indexed user, uint256 mintIndex);
event SaleStateFlipped(bool active);
event ContractSet(string contractName);
constructor(
string memory _NFT_NAME,
string memory _NFT_SYMBOL,
uint256 _MAX_PER_ADDRESS,
uint256 _AVAILABLE_SUPPLY,
uint16 _WACKY_THRESHHOLD,
uint16 _INSECURE_THRESHHOLD,
uint16 _INFECTED_THRESHHOLD
)
ERC721(
_NFT_NAME, _NFT_SYMBOL
)
{
MAX_PER_ADDRESS = _MAX_PER_ADDRESS;
AVAILABLE_SUPPLY = _AVAILABLE_SUPPLY;
WACKY_THRESHHOLD = _WACKY_THRESHHOLD;
INSECURE_THRESHHOLD = _INSECURE_THRESHHOLD;
INFECTED_THRESHHOLD = _INFECTED_THRESHHOLD;
}
function flipSaleState() public onlyOwner {
saleActive = !saleActive;
emit SaleStateFlipped(saleActive);
}
function setNFTContract(address contractAddress, string memory contractName, string memory softwareName) public onlyOwner {
coolSoftware.push(CoolSoftware({
contractInterface: NFTContract(contractAddress),
contractName: contractName,
softwareName: softwareName
}));
emit ContractSet(contractName);
}
function getNFTContracts() public view onlyOwner returns (CoolSoftware[] memory) {
return coolSoftware;
}
function clearNFTContracts() public onlyOwner {
delete coolSoftware;
}
function mint() external {
uint256 id = _tokenCounter.current();
uint256 _newAmountMinted = id.add(1);
uint256 _walletOwns = balanceOf(_msgSender());
uint256 _newWalletOwns = _walletOwns.add(1);
require(saleActive, "Sale must be active");
require(_newAmountMinted <= AVAILABLE_SUPPLY, "We ran out of floppies");
require(_newWalletOwns <= MAX_PER_ADDRESS, "Max floppy disks obtained");
_safeMint(msg.sender, id);
_tokenCounter.increment();
genes[id] = keccak256(abi.encodePacked(
block.timestamp,
block.difficulty,
id,
_msgSender(),
address(this)
));
emit FloppyMinted(_msgSender(), id);
}
function getColors(bytes32 gene) internal pure returns (colorSet memory) {
return colorSet({
color1: bytes3(
bytes2(gene[0]) |
bytes2(gene[1]) >> 8 |
bytes3(gene[2]) >> 16
),
color2: bytes3(
bytes2(gene[3]) |
bytes2(gene[4]) >> 8 |
bytes3(gene[5]) >> 16
),
color3: bytes3(
bytes2(gene[6]) |
bytes2(gene[7]) >> 8 |
bytes3(gene[8]) >> 16
),
color4: bytes3(
bytes2(gene[9]) |
bytes2(gene[10]) >> 8 |
bytes3(gene[11]) >> 16
),
color5: bytes3(
bytes2(gene[12]) |
bytes2(gene[13]) >> 8 |
bytes3(gene[14]) >> 16
)
});
}
function isDiskInsecure(bytes32 gene, uint256 threshhold) internal pure returns (bool) {
uint16 insecureDisk = uint16(
uint8(gene[17]) |
uint16(uint8(gene[18])) << 8
);
return insecureDisk > threshhold ? true : false;
}
function getInitialSoftware(bytes32 gene) internal pure returns (BoringSoftware[2] memory) {
string[68] memory boringSoftware = [
"WordPerfect 5.1", "Lotus 123 3.1+", "Norton Cmmndr [CRK]", "Qmodem 4.5 (DOS)", "FreePascal GO32v2",
"Wildcat BBS 4", "ACiDDraw v0.05", "mouse.com", "BIORYTHYMICATOR", "386 TeST", "GORILLAS.BAS", "WordStar",
"X-Tree Gold", "ProComm Plus", "dBase 3", "pkzip.exe", "QEMM", "Dazzle", "Norton Ghost", "Zmodem",
"IceModem", "ARJ", "LapLink3", "NeoPaint", "quickmenu III", "MS-DOS 6.22", "iMPULSE TRaCKeR",
"Commander KEEN", "GWBasic", "ALF", "ZZT", "NetHack", "Iniquity BBS", "LoRD", "Borland TurboC",
"Norton Utilities", "FoxPro", "Print Shop Pro", "Quattro Pro", "Renegade BBS", "Spinrite",
"Telegard", "Turbo Assembler", "XTree", "GALACT~1.EXE", "King's Quest 2", "Scortched Earth", "Lemmings",
"ZORK", "California Games", "Hexen", "Rise of the Triad", "Prince of Persia", "SimCity",
"Space Quest", "black cauldron", "jumpman", "battle chess", "warcraft", "ultima 5",
"nethack", "syndicate", "alone in the dark", "secret of monkey island",
"x-wing tie figther", "stronghold", "civ", "Arkanoid"
];
BoringSoftware[2] memory initialSoftware;
uint boringSoftwares = (uint8(
gene[21]
) % 2) + 1;
for (uint256 i = 0; i < boringSoftwares; i++) {
uint256 boringIdx = (uint8(gene[22 + i])) % boringSoftware.length;
uint8 diskCount = (uint8(boringIdx) % 11) + 1;
initialSoftware[i] = BoringSoftware({
softwareName: boringSoftware[boringIdx],
diskCount: diskCount,
diskNumber: (uint8(gene[23 + i]) % diskCount)+ 1
});
}
return initialSoftware;
}
function getPattern(bytes32 gene, uint256 threshhold) internal pure returns (uint8 patternId) {
uint16 wackyPattern = uint16(
uint8(gene[19]) |
uint16(uint8(gene[20])) << 8
);
return wackyPattern > threshhold ? uint8(wackyPattern % 3) + 1 : 0;
}
function getVirus(bytes32 gene, uint256 threshhold) internal pure returns (string memory virusName) {
string[18] memory viruses = [
"Michaelangelo", "Europe-92",
"Leandro", "STONED",
"DOS.Casino", "BRAiN",
"DOS.Walker", "Natas",
"911 Virus", "Hare",
"Yankee Doodle", "OneHalf",
"MkS_vir", "GhostBall",
"Elvira", "Ambulence",
"Ithaqua", "Cascade"
];
uint16 infectedDisk = uint16(
uint8(gene[15]) |
uint16(uint8(gene[16])) << 8
);
return infectedDisk > threshhold ? viruses[infectedDisk % viruses.length] : '';
}
function tokenURI(uint256 id) public view override returns (string memory) {
require(_exists(id), "not exist");
address owner = ownerOf(id);
bytes32 gene = genes[id];
uint8 pattern = getPattern(gene, WACKY_THRESHHOLD);
bool insecure = isDiskInsecure(gene, INSECURE_THRESHHOLD);
string memory virusName = getVirus(gene, INFECTED_THRESHHOLD);
colorSet memory colors = getColors(gene);
FileListing memory files = getFiles(owner, getInitialSoftware(gene), insecure, virusName);
string memory traits = getTraits(colors, files, insecure, pattern, virusName);
string memory image = Base64.encode(bytes(SVGBuilder.generateSVGofToken(colors, files, pattern)));
return
string(
abi.encodePacked(
'data:application/json;base64,',
Base64.encode(
bytes(
abi.encodePacked(
'{"name":"',
string(abi.encodePacked('Galactic Floppy #', id.toString())),
'", "description":"',
'This Floppy Is Radical!',
'", "external_url":"https://floppy.galactic.io/?token=',
id.toString(),
'", "attributes": [',
traits,
'], "owner":"',
uint160(owner).toHexString(20),
'", "image": "',
'data:image/svg+xml;base64,',
image,
'"}'
)
)
)
)
);
}
function getTraits(colorSet memory tokenColors, FileListing memory files, bool isInsecure, uint256 wackyPattern, string memory infectedWith) internal pure returns (string memory) {
string memory traits = string(abi.encodePacked(
'{"trait_type": "Disk Color", "value": "',tokenColors.color1.toColor(),'"},',
'{"trait_type": "Label Color", "value": "',tokenColors.color2.toColor(),'"}'
));
for (uint256 i = 0; i < files.boringSoftwares.length; i++) {
if (bytes(files.boringSoftwares[i]).length > 0) {
traits = string(abi.encodePacked(
traits,
",",
'{"trait_type": "',
string(abi.encodePacked("BoringFile", i.toString())),
'", "value": "',
files.boringSoftwares[i],
'"}'
));
}
}
for (uint256 i = 0; i < files.specialSoftwares.length; i++) {
if (bytes(files.specialSoftwares[i]).length > 0) {
traits = string(abi.encodePacked(
traits,
",",
'{"trait_type": "',
string(abi.encodePacked("CoolFile", i.toString())),
'", "value": "',
files.specialSoftwares[i],
'"}'
));
}
}
if (isInsecure) {
traits = string(abi.encodePacked(
traits,
",",
'{"trait_type": "Insecure Disk", "value": "true"}'
));
}
if (bytes(infectedWith).length > 0) {
traits = string(abi.encodePacked(
traits,
",",
'{"trait_type": "Has Virus", "value": "',infectedWith,'"}'
));
}
if (wackyPattern > 0) {
string memory wackyPatternName;
if (wackyPattern == 1) {
wackyPatternName = "Crosses";
} else if (wackyPattern == 2) {
wackyPatternName = "Ombre";
} else if (wackyPattern == 3) {
wackyPatternName = "Polka Dot";
}
traits = string(abi.encodePacked(
traits,
",",
'{"trait_type": "Wacky Pattern", "value": "',wackyPatternName,'"}'
));
}
return traits;
}
function getFiles(address owner, BoringSoftware[2] memory initialSoftware, bool isInsecure, string memory infectedWith) internal view returns (FileListing memory) {
uint256 fileCount;
uint256 yPos;
FileListing memory fl;
for (uint256 i = 0; i < initialSoftware.length; i++) {
yPos = fileCount * 23 + 32;
if (bytes(initialSoftware[i].softwareName).length > 0) {
fl.textElements = string(abi.encodePacked(
fl.textElements,
"<text class='t' x='49' y='",
yPos.toString(),
"'>* ",
initialSoftware[i].softwareName,
" disk ",
initialSoftware[i].diskNumber.toString(),
"/",
initialSoftware[i].diskCount.toString(),
"</text>"
));
fl.boringSoftwares[i] = initialSoftware[i].softwareName;
fileCount++;
}
}
if (isInsecure) {
yPos = fileCount * 23 + 32;
fl.textElements = string(abi.encodePacked(
fl.textElements,
"<text class='t' x='49' y='",yPos.toString(),"'>* mnemonic.txt</text>"
));
fileCount++;
}
for (uint256 i = 0; i < coolSoftware.length; i++) {
uint256 ownerBalance = coolSoftware[i].contractInterface.balanceOf(owner);
if (ownerBalance > 0) {
if (fileCount < 7) {
yPos = fileCount * 23 + 32;
fl.textElements = string(abi.encodePacked(
fl.textElements,
"<text class='t' x='49' y='",
yPos.toString(),
"'>* ",
coolSoftware[i].softwareName,
"</text>"
));
fl.specialSoftwares[i] = coolSoftware[i].softwareName;
fileCount++;
}
}
}
if (bytes(infectedWith).length > 0) {
fl.textElements = string(abi.encodePacked(
fl.textElements,
"<text x='110' y='100' style='fill: rgb(255, 100, 100); font-family: saserif; font-size: 28px; white-space: pre; font-style: italic; font-weight: bold;' stroke-width='1' stroke='#0b000099' text-anchor='middle' dominant-baseline='central' transform='rotate(-25 100 0)'><tspan>Infected with</tspan><tspan x='100' y='130'>",
infectedWith,
"!!</tspan></text>"
));
}
return fl;
}
function withdrawERC20(IERC20 token) public onlyOwner {
token.transfer(msg.sender, token.balanceOf(address(this)));
}
}
文件 8 的 19:HexStrings.sol
pragma solidity >=0.8.0 <0.9.0;
library HexStrings {
bytes16 internal constant ALPHABET = '0123456789abcdef';
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;
}
return string(buffer);
}
}
文件 9 的 19:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 10 的 19:IERC721.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
}
文件 11 的 19:IERC721Enumerable.sol
pragma solidity ^0.8.0;
import "../IERC721.sol";
interface IERC721Enumerable is IERC721 {
function totalSupply() external view returns (uint256);
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);
function tokenByIndex(uint256 index) external view returns (uint256);
}
文件 12 的 19:IERC721Metadata.sol
pragma solidity ^0.8.0;
import "../IERC721.sol";
interface IERC721Metadata is IERC721 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
}
文件 13 的 19:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 14 的 19:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_setOwner(_msgSender());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
_setOwner(address(0));
}
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);
}
}
文件 15 的 19:SVGBuilder.sol
pragma solidity >=0.8.0 <0.9.0;
import './ToColor.sol';
struct colorSet {
bytes3 color1;
bytes3 color2;
bytes3 color3;
bytes3 color4;
bytes3 color5;
}
struct FileListing {
string textElements;
string[10] boringSoftwares;
string[10] specialSoftwares;
}
library SVGBuilder {
using ToColor for bytes3;
function generateSVGofToken(colorSet memory tokenColors, FileListing memory files, uint8 wackyPattern) public pure returns (string memory) {
string memory diskFill = tokenColors.color1.toColor();
string memory svg = string(abi.encodePacked(
"<svg viewBox='0 0 322.2 332.55' xmlns='http://www.w3.org/2000/svg'><style>.t { white-space: pre; fill: rgb(51, 51, 51); font: 11px monospace; }</style><defs><linearGradient id='a' x1='80.802' x2='254.2' y1='-28.879' y2='-28.879' gradientTransform='matrix(-.99682 0 0 -2.5057 319.72 205.97)' gradientUnits='userSpaceOnUse'><stop stop-color='#878787' offset='0'/><stop stop-color='#fff' offset='.5'/><stop stop-color='#878787' offset='1'/></linearGradient>"
));
if (wackyPattern > 0) {
diskFill = "url(#b)";
if (wackyPattern == 1) {
svg = string(abi.encodePacked(
svg,
string(abi.encodePacked(
"<pattern id='b' patternUnits='userSpaceOnUse' width='20' height='20' patternTransform='scale(2) rotate(0)'><rect x='0' y='0' width='100%' height='100%' fill='",
tokenColors.color1.toColor(),
"'/><path d='M3.25 10h13.5M10 3.25v13.5' stroke-linecap='square' stroke-width='1' stroke='",
tokenColors.color3.toColor(),
"' fill='none'/></pattern>"
))
));
}
if (wackyPattern == 3) {
svg = string(abi.encodePacked(
svg,
string(abi.encodePacked(
"<pattern id='b' patternUnits='userSpaceOnUse' width='40' height='40' patternTransform='scale(2) rotate(0)'><rect x='0' y='0' width='100%' height='100%' fill='",
tokenColors.color1.toColor(),
"'/><path d='M40 45a5 5 0 110-10 5 5 0 010 10zM0 45a5 5 0 110-10 5 5 0 010 10zM0 5A5 5 0 110-5 5 5 0 010 5zm40 0a5 5 0 110-10 5 5 0 010 10z' stroke-width='2' stroke='",
tokenColors.color4.toColor(),
"' fill='none'/><path d='M20 25a5 5 0 110-10 5 5 0 010 10z' stroke-width='2' stroke='",
tokenColors.color5.toColor(),
"' fill='none'/></pattern>"
))
));
}
if (wackyPattern == 2) {
svg = string(abi.encodePacked(
svg,
string(abi.encodePacked(
"<linearGradient id='b' x1='80.802' x2='254.2' y1='-28.879' y2='-28.879' gradientTransform='matrix(-1.667037, 1.746009, -1.812309, -1.730337, 383.987524, -171.581138)' gradientUnits='userSpaceOnUse'><stop stop-color='",
tokenColors.color1.toColor(),
"' offset='0'/><stop stop-color='",
tokenColors.color4.toColor(),
"' offset='.223'/><stop stop-color='",
tokenColors.color5.toColor(),
"' offset='.451'/><stop stop-color='",
tokenColors.color2.toColor(),
"' offset='.771'/><stop stop-color='",
tokenColors.color3.toColor(),
"' offset='1'/></linearGradient>"
))
));
}
}
svg = string(abi.encodePacked(
svg,
"</defs><ellipse cx='160.95' cy='164.38' rx='158.43' ry='161.93' fill='#797474'/><ellipse cx='162.67' cy='163.34' rx='58.216' ry='59.966' fill='#897b7b' stroke='#070707' stroke-width='11.339'/><path d='m311.54 292.2h-4.2v-13.65h-8.7v13.65h-4.2l8.55 24.75z' stroke='#808080' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10' stroke-width='.9'/><path d='m311.39 23.4h-18.15v11.85h18.15z' stroke='#808080' stroke-linecap='round' stroke-miterlimit='8' stroke-width='.9'/><path d='m319.19 331.64 1.9375-1.7812 0.625-2.2501-0.3125-324.15-0.75-1.66-1.6562-1.06-315.43-0.28-2.1 1.18-1.06 1.97 0.44 289.19h2.25v13.188l-1.78-0.438v4.5l24.28 21.312 4.81 0.28175 1.5-1.3438h25.81l2.25-2.25 5.25-0.1562h173.38l-2e-3 1.5 42.624 0.3124-0.156 1.6563 38.094 0.28125zm-288.91-296.25h-18.15v-11.84h18.15z' fill='",
diskFill
));
svg = string(abi.encodePacked(
svg,
"' fill-rule='evenodd' opacity='.75' stroke='#020000'/><g transform='rotate(180 295.08 220.36)'><path d='m550.9 440.27-0.01874-184.65-1.8-2.1-240 0.3-2.1 1.5v184.95z' fill='#eaeaea' fill-rule='evenodd' stroke='#9b9b9b' stroke-width='.8'/><path d='m307.58 285.32h242.7' fill='none' stroke='",
tokenColors.color2.toColor(),
"' stroke-linejoin='round' stroke-miterlimit='10' stroke-width='1.2'/><path d='m307.58 308.42h242.7' fill='none' stroke='",
tokenColors.color2.toColor(),
"' stroke-linejoin='round' stroke-miterlimit='10' stroke-width='1.2'/><path d='m307.58 331.67h242.7' fill='none' stroke='",
tokenColors.color2.toColor(),
"' stroke-linejoin='round' stroke-miterlimit='10' stroke-width='1.2'/><path id='b' d='m307.58 355.07h242.7' fill='none' stroke='",
tokenColors.color2.toColor()
));
svg = string(abi.encodePacked(
svg,
"' stroke-linejoin='round' stroke-miterlimit='10' stroke-width='1.2'/><path d='m307.58 378.32h242.7' fill='none' stroke='",
tokenColors.color2.toColor(),
"' stroke-linejoin='round' stroke-miterlimit='10' stroke-width='1.2'/><path d='m307.58 401.57h242.7' fill='none' stroke='",
tokenColors.color2.toColor(),
"' stroke-linejoin='round' stroke-miterlimit='10' stroke-width='1.2'/><path d='m307.36 439.87h243.14v-15h-243.14z' fill='",
tokenColors.color2.toColor(),
"' stroke-width='1.0009'/></g><path d='m280.79 330.3v-106.35l-0.75-1.35-1.05-0.45h-46.5' fill='none' stroke='#808080' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10' stroke-width='.6'/><path d='m238.53 332.02v-107.97l-3.125-2.4062h-165.97l-2.75 3.0312v107.34h171.84zm-99.031-17.781h-46.375v-87h46.375z' color='#000000' fill='url(#a)' stroke-width='.3'/>"
));
svg = string(abi.encodePacked(
svg,
files.textElements,
"</svg>"
));
return svg;
}
}
文件 16 的 19:SafeMath.sol
pragma solidity ^0.8.0;
library SafeMath {
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);
}
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
文件 17 的 19:Strings.sol
pragma solidity ^0.8.0;
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
function toString(uint256 value) internal pure returns (string memory) {
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);
}
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);
}
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);
}
}
文件 18 的 19:ToColor.sol
pragma solidity >=0.8.0 <0.9.0;
library ToColor {
bytes16 internal constant ALPHABET = '0123456789abcdef';
function toColor(bytes3 value) internal pure returns (string memory) {
bytes memory buffer = new bytes(6);
for (uint256 i = 0; i < 3; i++) {
buffer[i*2+1] = ALPHABET[uint8(value[i]) & 0xf];
buffer[i*2] = ALPHABET[uint8(value[i]>>4) & 0xf];
}
return string(abi.encodePacked("#", string(buffer)));
}
}
文件 19 的 19:base64.sol
pragma solidity >=0.6.0;
library Base64 {
string internal constant TABLE_ENCODE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
bytes internal constant TABLE_DECODE = hex"0000000000000000000000000000000000000000000000000000000000000000"
hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000"
hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000"
hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000";
function encode(bytes memory data) internal pure returns (string memory) {
if (data.length == 0) return '';
string memory table = TABLE_ENCODE;
uint256 encodedLen = 4 * ((data.length + 2) / 3);
string memory result = new string(encodedLen + 32);
assembly {
mstore(result, encodedLen)
let tablePtr := add(table, 1)
let dataPtr := data
let endPtr := add(dataPtr, mload(data))
let resultPtr := add(result, 32)
for {} lt(dataPtr, endPtr) {}
{
dataPtr := add(dataPtr, 3)
let input := mload(dataPtr)
mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and(shr( 6, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and( input, 0x3F))))
resultPtr := add(resultPtr, 1)
}
switch mod(mload(data), 3)
case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) }
case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) }
}
return result;
}
function decode(string memory _data) internal pure returns (bytes memory) {
bytes memory data = bytes(_data);
if (data.length == 0) return new bytes(0);
require(data.length % 4 == 0, "invalid base64 decoder input");
bytes memory table = TABLE_DECODE;
uint256 decodedLen = (data.length / 4) * 3;
bytes memory result = new bytes(decodedLen + 32);
assembly {
let lastBytes := mload(add(data, mload(data)))
if eq(and(lastBytes, 0xFF), 0x3d) {
decodedLen := sub(decodedLen, 1)
if eq(and(lastBytes, 0xFFFF), 0x3d3d) {
decodedLen := sub(decodedLen, 1)
}
}
mstore(result, decodedLen)
let tablePtr := add(table, 1)
let dataPtr := data
let endPtr := add(dataPtr, mload(data))
let resultPtr := add(result, 32)
for {} lt(dataPtr, endPtr) {}
{
dataPtr := add(dataPtr, 4)
let input := mload(dataPtr)
let output := add(
add(
shl(18, and(mload(add(tablePtr, and(shr(24, input), 0xFF))), 0xFF)),
shl(12, and(mload(add(tablePtr, and(shr(16, input), 0xFF))), 0xFF))),
add(
shl( 6, and(mload(add(tablePtr, and(shr( 8, input), 0xFF))), 0xFF)),
and(mload(add(tablePtr, and( input , 0xFF))), 0xFF)
)
)
mstore(resultPtr, shl(232, output))
resultPtr := add(resultPtr, 3)
}
}
return result;
}
}
{
"compilationTarget": {
"contracts/GalacticFloppyDisk.sol": "GalacticFloppyDisk"
},
"evmVersion": "istanbul",
"libraries": {
"contracts/SVGBuilder.sol:SVGBuilder": "0x5610296d8bf05b992aadad6676a98db77363ca17"
},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"string","name":"_NFT_NAME","type":"string"},{"internalType":"string","name":"_NFT_SYMBOL","type":"string"},{"internalType":"uint256","name":"_MAX_PER_ADDRESS","type":"uint256"},{"internalType":"uint256","name":"_AVAILABLE_SUPPLY","type":"uint256"},{"internalType":"uint16","name":"_WACKY_THRESHHOLD","type":"uint16"},{"internalType":"uint16","name":"_INSECURE_THRESHHOLD","type":"uint16"},{"internalType":"uint16","name":"_INFECTED_THRESHHOLD","type":"uint16"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"contractName","type":"string"}],"name":"ContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"mintIndex","type":"uint256"}],"name":"FloppyMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"active","type":"bool"}],"name":"SaleStateFlipped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"AVAILABLE_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PER_ADDRESS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"clearNFTContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"flipSaleState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNFTContracts","outputs":[{"components":[{"internalType":"contract NFTContract","name":"contractInterface","type":"address"},{"internalType":"string","name":"contractName","type":"string"},{"internalType":"string","name":"softwareName","type":"string"}],"internalType":"struct CoolSoftware[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"string","name":"contractName","type":"string"},{"internalType":"string","name":"softwareName","type":"string"}],"name":"setNFTContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"}]