文件 1 的 17: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 的 17:Base64.sol
pragma solidity ^0.8.2;
library Base64 {
bytes internal constant TABLE =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
function encode(bytes memory data) internal pure returns (string memory) {
uint256 len = data.length;
if (len == 0) return "";
uint256 encodedLen = 4 * ((len + 2) / 3);
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);
}
}
文件 3 的 17:Colors.sol
pragma solidity ^0.8.2;
import "@openzeppelin/contracts/utils/Strings.sol";
library Colors {
using Strings for uint256;
struct HSL {
uint256 hue;
uint256 saturation;
uint256 lightness;
}
struct Color {
string start;
string end;
}
struct MainframeColors {
Color light;
Color medium;
Color dark;
Color bg;
}
function generateHSLColor(
string memory seed,
uint256 hMin,
uint256 hMax,
uint256 sMin,
uint256 sMax,
uint256 lMin,
uint256 lMax
) public pure returns (HSL memory) {
return
HSL(
generatePseudoRandomValue(
string(abi.encodePacked("H", seed)),
hMin,
hMax
),
generatePseudoRandomValue(
string(abi.encodePacked("S", seed)),
sMin,
sMax
),
generatePseudoRandomValue(
string(abi.encodePacked("L", seed)),
lMin,
lMax
)
);
}
function toHSLString(HSL memory hsl) public pure returns (string memory) {
return
string(
abi.encodePacked(
"hsl(",
hsl.hue.toString(),
",",
hsl.saturation.toString(),
"%,",
hsl.lightness.toString(),
"%)"
)
);
}
function generatePseudoRandomValue(
string memory seed,
uint256 from,
uint256 to
) public pure returns (uint256) {
if (to <= from) return from;
return
(uint256(keccak256(abi.encodePacked(seed))) % (to - from)) + from;
}
function generateComputerColors(string memory seed)
public
pure
returns (MainframeColors memory)
{
HSL memory lightStart = generateHSLColor(
string(abi.encodePacked(seed, "LIGHT_START")),
0,
359,
50,
70,
55,
75
);
HSL memory lightEnd = generateHSLColor(
string(abi.encodePacked(seed, "LIGHT_END")),
lightStart.hue + 359 - generatePseudoRandomValue(seed, 5, 60),
lightStart.hue + 359 + generatePseudoRandomValue(seed, 5, 60),
70,
85,
25,
45
);
HSL memory mediumStart = generateHSLColor(
string(abi.encodePacked(seed, "MEDIUM_START")),
lightStart.hue,
lightStart.hue,
lightStart.saturation,
lightStart.saturation,
35,
50
);
HSL memory mediumEnd = generateHSLColor(
string(abi.encodePacked(seed, "MEDIUM_START")),
lightEnd.hue,
lightEnd.hue,
lightEnd.saturation,
lightEnd.saturation,
35,
10
);
HSL memory darkStart = generateHSLColor(
string(abi.encodePacked(seed, "MEDIUM_START")),
0,
359,
40,
70,
13,
16
);
HSL memory darkEnd = generateHSLColor(
string(abi.encodePacked(seed, "DARKEST_END")),
darkStart.hue + 359 - generatePseudoRandomValue(seed, 5, 60),
darkStart.hue + 359 + generatePseudoRandomValue(seed, 5, 60),
darkStart.saturation,
darkStart.saturation,
3,
13
);
HSL memory BGStart = generateHSLColor(
string(abi.encodePacked(seed, "BG_START")),
0,
359,
55,
100,
45,
65
);
HSL memory BGEnd = generateHSLColor(
string(abi.encodePacked(seed, "BG_END")),
0,
359,
BGStart.saturation,
BGStart.saturation,
BGStart.lightness,
BGStart.lightness
);
return
MainframeColors(
Color(toHSLString(lightStart), toHSLString(lightEnd)),
Color(toHSLString(mediumStart), toHSLString(mediumEnd)),
Color(toHSLString(darkStart), toHSLString(darkEnd)),
Color(toHSLString(BGStart), toHSLString(BGEnd))
);
}
}
文件 4 的 17: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;
}
}
文件 5 的 17: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;
}
}
文件 6 的 17: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;
}
}
文件 7 的 17: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 {}
}
文件 8 的 17: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();
}
}
文件 9 的 17:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 10 的 17: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 的 17: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 的 17: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 的 17:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 14 的 17:Mainframes.sol
pragma solidity ^0.8.2;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
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";
import "./Base64.sol";
import "./Colors.sol";
import "./SVGFace.sol";
contract Mainframes is ERC721, ERC721Enumerable, Ownable {
using Counters for Counters.Counter;
uint256 public cost = 0.02048 ether;
uint256 public maxSupply = 2048;
Counters.Counter private _tokenIdCounter;
string public constant DESCRIPTION =
"Mainframes are a collection of 2048 randomly generated mainframes stored entirely on-chain. Each Mainframe will fit into your wallet and stay operational forever, constantly giving you retro vibes from the past.";
constructor() ERC721("Mainframes", "MFS") {
_tokenIdCounter.increment();
}
function _mint(address _to) private {
uint256 amount = _tokenIdCounter.current();
uint256 supply = totalSupply();
require(supply + amount <= maxSupply, "SOLD_OUT");
_safeMint(_to, amount);
_tokenIdCounter.increment();
}
function tokenURI(uint256 tokenId)
public
view
override
returns (string memory)
{
string memory seed = string(
abi.encodePacked(
Strings.toString(tokenId),
block.difficulty,
block.timestamp
)
);
Colors.MainframeColors memory colors = Colors.generateComputerColors(
seed
);
uint256 face = Colors.generatePseudoRandomValue(seed, 0, 200);
string memory attributes = generateAttributes(face);
string memory image = string(
abi.encodePacked(
'<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" fill="none">',
generatePaths(face),
generateDefs(colors),
"</svg>"
)
);
string memory output = Base64.encode(
bytes(
string(
abi.encodePacked(
'{"name":"Mainframe #',
Strings.toString(tokenId),
'", "attributes":',
attributes,
',"description":"',
DESCRIPTION,
'","image": "data:image/svg+xml;base64,',
Base64.encode(bytes(image)),
'"}'
)
)
)
);
output = string(
abi.encodePacked("data:application/json;base64,", output)
);
return output;
}
function generatePaths(uint256 face) internal pure returns (string memory) {
return
string(
abi.encodePacked(
'<path fill="url(#a)" d="M0 0h1024v1024H0z"/><path fill="#fff" fill-rule="evenodd" d="M232.808 240.339c0-11.311 9.169-20.48 20.48-20.48h453.205a114.895 114.895 0 0 1 114.898 114.898v9.437l51.846 44.251c14.234 12.196 23.688 28.902 23.688 47.842v111.14c0 22.997-13.635 41.537-31.031 53.441-6.429 4.4-13.605 8.093-21.326 11.005A105.455 105.455 0 0 1 808.2 807.106a20.43 20.43 0 0 1-7.289 1.336H83.336c-10.793 0-19.636-8.35-20.423-18.942a20.476 20.476 0 0 1-18.94-20.422v-37.767a20.48 20.48 0 0 1 14.003-19.429l174.832-58.277V618.01c0-3.316.804-6.548 2.304-9.437a20.396 20.396 0 0 1-2.304-9.447V240.339z" clip-rule="evenodd"/><path fill="url(#b)" d="M253.287 240.339h453.205v358.787H253.287V240.339zM253.287 618.01h453.205v169.952H253.287V618.01z"/><path fill="url(#c)" d="M773.256 267.993a94.418 94.418 0 0 0-66.764-27.654v358.787h94.418V334.757a94.42 94.42 0 0 0-27.654-66.764zM706.492 618.01h84.976a84.976 84.976 0 0 1 0 169.952h-84.976V618.01z"/><path fill="url(#d)" d="m668.724 655.777-226.603 75.534v37.767h358.787v-75.534l-132.184 49.569v-87.336z"/><path fill="url(#e)" d="M64.451 731.311h377.671v37.767H64.452v-37.767zM536.539 750.194H649.84v18.884H536.539v-18.884z"/><g fill="url(#f)"><path d="M291.054 655.777 64.451 731.312h377.671l226.603-75.535H291.054zM687.607 693.544l-151.068 56.651H649.84l151.069-56.651H687.607z"/></g><g fill="url(#g)"><path d="M668.726 278.105H291.055v283.254h377.671V278.105zM272.17 599.126h509.856v18.884H272.17v-18.884zM83.123 769.205h718.005v18.673H83.123v-18.673zM859.913 403.996l-59.001-50.356v245.465c41.733 0 75.534-23.143 75.534-51.678v-111.14c0-11.75-5.833-23.122-16.533-32.291z"/></g>',
SVGFace.pickSVGFacePath(face)
)
);
}
function generateDefs(Colors.MainframeColors memory colors)
internal
pure
returns (string memory)
{
string memory parts = string(
abi.encodePacked(
'<defs><linearGradient id="a" x1="512" x2="512" y1="0" y2="1024" gradientUnits="userSpaceOnUse"><stop stop-color="',
colors.bg.start,
'"/><stop offset="1" stop-color="',
colors.bg.end,
'"/></linearGradient><linearGradient id="b" x1="479.89" x2="479.89" y1="240.339" y2="787.962" gradientUnits="userSpaceOnUse"><stop stop-color="',
colors.light.start,
'"/><stop offset="1" stop-color="',
colors.light.end,
'"/></linearGradient><linearGradient id="c" x1="791.468" x2="791.468" y1="240.339" y2="787.962" gradientUnits="userSpaceOnUse"><stop stop-color="',
colors.medium.start,
'"/><stop offset="1" stop-color="',
colors.medium.end,
'"/></linearGradient><linearGradient id="d" x1="710" x2="665.834" y1="633" y2="782.198" gradientUnits="userSpaceOnUse"><stop stop-color="',
colors.light.start
)
);
parts = string(
abi.encodePacked(
parts,
'"/><stop offset="1" stop-color="',
colors.light.end,
'"/></linearGradient><linearGradient id="e" x1="357.146" x2="357.146" y1="720" y2="769.078" gradientUnits="userSpaceOnUse"><stop stop-color="',
colors.light.start,
'"/><stop offset="1" stop-color="',
colors.light.end,
'"/></linearGradient><linearGradient id="f" x1="432.68" x2="432.68" y1="655.777" y2="750.195" gradientUnits="userSpaceOnUse"><stop stop-color="',
colors.light.start,
'"/><stop offset="1" stop-color="',
colors.light.end,
'"/></linearGradient><linearGradient id="g" x1="479.785" x2="479.785" y1="278.105" y2="787.878" gradientUnits="userSpaceOnUse"><stop stop-color="',
colors.dark.start,
'"/><stop offset="1" stop-color="',
colors.dark.end,
'"/></linearGradient></defs>'
)
);
return parts;
}
function generateAttributes(uint256 face)
internal
pure
returns (string memory)
{
return
string(
abi.encodePacked(
"[",
'{ "trait_type": "Face",',
'"value": "',
SVGFace.pickSVGFaceName(face),
'"}',
"]"
)
);
}
function mint(address destination) public onlyOwner {
_mint(destination);
}
function mintMainframe() public payable virtual {
require(msg.value >= cost, "PRICE_NOT_MET");
_mint(msg.sender);
}
function withdraw() public payable onlyOwner {
require(payable(msg.sender).send(address(this).balance));
}
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);
}
}
文件 15 的 17: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);
}
}
文件 16 的 17:SVGFace.sol
pragma solidity ^0.8.2;
library SVGFace {
function pickSVGFaceName(uint256 face) public pure returns (string memory) {
string memory name = "";
if (face <= 50) {
name = "Happy";
} else if (face <= 90) {
name = "Joyful";
} else if (face <= 120) {
name = "Surprised";
} else if (face <= 140) {
name = "Tired";
} else if (face <= 160) {
name = "Angry";
} else if (face <= 170) {
name = "Uh-oh";
} else if (face <= 180) {
name = "Sad";
} else if (face <= 190) {
name = "Dead";
} else if (face <= 198) {
name = "Uwu";
} else if (face == 199) {
name = "BSOD";
} else {
name = "Off";
}
return string(abi.encodePacked(name));
}
function pickSVGFacePath(uint256 face) public pure returns (string memory) {
string memory path = "";
if (face <= 50) {
path = '<path fill="#fff" d="M392 334h35v71h-35v-71zM534 334h35v71h-35v-71zM391.571 440.714H356v35.572h35.571v-35.572zM569 476H392v36h177v-36zM569.428 440.714h35.571v35.572h-35.571v-35.572z"/>';
} else if (face <= 90) {
path = '<path fill="#fff" d="M427.142 334H391.57v35.571h35.572V334zM391.571 369.572H356v35.571h35.571v-35.571zM427.142 369.571l35.572.001v35.571h-35.571l-.001-35.572zM533.857 369.572h-35.572v35.571h35.572v-35.571zM392 476h35v36h107v-36h35v-35H392v35zM569.427 334h-35.572v35.571h35.572V334zM604.999 369.572l-35.572-.001.001 35.572h35.571v-35.571z"/>';
} else if (face <= 120) {
path = '<path fill="#fff" d="M391 334h35.571v35.571H391V334zM427 405h106v107H427V405zM568.857 334h-35.572v35.571h35.572V334z"/>';
} else if (face <= 140) {
path = '<path fill="#fff" d="M391 370h35.571v35.571H391V370zM426.857 440.857h106v36h-106v-36zM568.857 370h-35.572v35.571h35.572V370z"/>';
} else if (face <= 160) {
path = '<path fill="#fff" d="M356 352h35.571v35.571h35.571v35.572h-35.571v35.571H356v-35.571h35.57v-35.572H356V352zM427 459h107v35H427v-35zM569.427 387.571h-35.572v35.572h35.572v-35.572zM569.428 352h35.571v35.571h-35.572l.001-35.571zM604.999 423.143h-35.572l.001 35.571h35.571v-35.571z"/>';
} else if (face <= 170) {
path = '<path fill="#fff" d="M568.429 452h-35.572v35.571h35.572V452zM391 452.286h35.571v35.571H391v-35.571zM462.143 487.857h35.571v35.571h-35.571v-35.571z"/>';
} else if (face <= 180) {
path = '<path fill="#fff" d="M392 334h35v71h-35v-71zM356 476.286h35.571v35.571H356v-35.571zM569 334h-35v71h35v-71zM392 440h177v36H392v-36zM604.999 476.286h-35.571v35.571h35.571v-35.571z"/>';
} else if (face <= 190) {
path = '<path fill="#fff" d="M356 334h35.571v35.571H356V334zM391.571 405.143h35.571v-35.571H391.57v35.571H356v35.571h35.571v-35.571z"/><path fill="#fff" d="M427.142 405.143h35.572v35.571h-35.571l-.001-35.571zM533.857 334h-35.572v35.571h35.572V334zM498.285 405.143h35.57v-35.571h35.572v35.571h-35.57v35.571h-35.572v-35.571zM534 476H427v36h107v-36zM604.999 334h-35.571l-.001 35.572 35.572-.001V334zM569.427 405.143h35.572v35.571h-35.571l-.001-35.571zM462.714 334h-35.571l-.001 35.572 35.572-.001V334z"/>';
} else if (face <= 198) {
path = '<path fill="#fff" d="M391 334h36v71h-36v-71zM533 334h36v71h-36v-71zM426.571 440.714H391v35.572h35.571v-35.572zM497.714 476.286h-35.57v35.571h-35.572l-.001-35.571h35.572v-35.572h35.571v35.572z"/><path fill="#fff" d="M568.857 476.286h-35.571v35.571h-35.571l-.001-35.571h35.571v-35.572h35.572v35.572z"/>';
} else if (face == 199) {
path = '<path fill="#0000A3" d="M668.671 278.105H291v283.254h377.671V278.105z" class="BG"/><path fill="#AAA" d="M420 357h120v27H420z" /><path fill="#fff" d="M322 407h120v9H322v-9zM322 423h196v9H322v-9zM592 439H322v9h270v-9zM322 455h70v9h-70v-9zM540 496H420v9h120v-9z"/>';
}
return string(abi.encodePacked(path));
}
}
文件 17 的 17: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);
}
}
{
"compilationTarget": {
"contracts/Mainframes.sol": "Mainframes"
},
"evmVersion": "istanbul",
"libraries": {
"contracts/Colors.sol:Colors": "0xbb747489e67c072bea7ce59f4eff59370c60aa0a",
"contracts/SVGFace.sol:SVGFace": "0x4ad488d5ec98b857d7554d16a917e19b61de9aa9"
},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"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":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","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":"DESCRIPTION","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"cost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"destination","type":"address"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintMainframe","outputs":[],"stateMutability":"payable","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":"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":"tokenId","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":[],"name":"withdraw","outputs":[],"stateMutability":"payable","type":"function"}]