编译器
0.8.20+commit.a1b79de6
文件 1 的 14:Base64.sol
pragma solidity ^0.8.0;
library Base64 {
string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
function encode(bytes memory data) internal pure returns (string memory) {
if (data.length == 0) return "";
string memory table = _TABLE;
string memory result = new string(4 * ((data.length + 2) / 3));
assembly {
let tablePtr := add(table, 1)
let resultPtr := add(result, 32)
for {
let dataPtr := data
let endPtr := add(data, mload(data))
} 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 {
mstore8(sub(resultPtr, 1), 0x3d)
mstore8(sub(resultPtr, 2), 0x3d)
}
case 2 {
mstore8(sub(resultPtr, 1), 0x3d)
}
}
return result;
}
}
文件 2 的 14: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 的 14:ERC1155.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
mapping(uint256 => mapping(address => uint256)) private _balances;
event Message(address indexed from, address indexed to, uint256 indexed id, string message);
error InvalidToken();
error InvalidInput();
error InvalidDesposit();
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
function uri(uint256) public view virtual override returns (string memory) {}
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
if (account == address(0)) return 0;
return _balances[id][account];
}
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;
}
function setApprovalForAll(address, bool) public virtual override {
revert("No approvals on infinities");
}
function isApprovedForAll(address, address) public view virtual override returns (bool) {
return false;
}
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual override {
require(
from == _msgSender(),
"ERC1155: caller is not token owner"
);
_safeTransferFrom(from, to, id, amount, data);
}
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual override {
require(
from == _msgSender(),
"ERC1155: caller is not token owner"
);
_safeBatchTransferFrom(from, to, ids, amounts, data);
}
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");
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(from, from, to, id, amount);
_doSafeTransferAcceptanceCheck(from, from, to, id, amount, data);
}
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");
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(from, from, to, ids, amounts);
_doSafeBatchTransferAcceptanceCheck(from, from, to, ids, amounts, data);
}
function _mint(
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
address operator = _msgSender();
_balances[id][to] += amount;
emit TransferSingle(operator, address(0), to, id, amount);
_doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
}
function _burn(
address from,
uint256 id,
uint256 amount
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
emit TransferSingle(_msgSender(), from, address(0), id, amount);
}
function _burnBatch(
address from,
uint256[] memory ids,
uint256[] memory amounts
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
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: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
}
emit TransferBatch(operator, from, address(0), ids, amounts);
}
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) private {
if (_isContract(to)) {
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 (_isContract(to)) {
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 _isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
}
文件 4 的 14: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 的 14:IERC1155.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC1155 is IERC165 {
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
event URI(string value, uint256 indexed id);
function balanceOf(address account, uint256 id) external view returns (uint256);
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
external
view
returns (uint256[] memory);
function setApprovalForAll(address operator, bool approved) external;
function isApprovedForAll(address account, address operator) external view returns (bool);
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) external;
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}
文件 6 的 14:IERC1155MetadataURI.sol
pragma solidity ^0.8.0;
import "../IERC1155.sol";
interface IERC1155MetadataURI is IERC1155 {
function uri(uint256 id) external view returns (string memory);
}
文件 7 的 14:IERC1155Receiver.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC1155Receiver is IERC165 {
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
文件 8 的 14:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 9 的 14:InfiniteArt.sol
pragma solidity ^0.8.20;
import "./InfiniteBags.sol";
import "./Utilities.sol";
library InfiniteArt {
function renderSVG(Token memory data) public pure returns (string memory) {
return string.concat(
'<svg viewBox="0 0 800 800" fill="none" xmlns="http://www.w3.org/2000/svg">',
renderStyle(data),
renderDefs(),
'<rect width="800" height="800" fill="var(--bg)" />',
'<g transform="scale(0.95)" transform-origin="center">',
renderGrid(),
'</g>',
renderNoise(data),
'<g transform="scale(0.95)" transform-origin="center">',
renderSymbols(data),
'</g>',
'</svg>'
);
}
function renderStyle(Token memory data) public pure returns (string memory) {
return string.concat(
'<style>',
':root {',
'--bg: ', data.background, ';',
'--gr: ', data.gridColor, ';',
'}',
'</style>'
);
}
function renderDefs() public pure returns (string memory) {
return string.concat(
'<defs>',
'<rect id="box" width="100" height="100" stroke="var(--gr)" stroke-width="3" style="paint-order: stroke;" />'
'<g id="row">', renderGridRow(), '</g>',
'<mask id="mask"><rect width="800" height="800" fill="white"/></mask>',
'<path id="loop" d="M 100 0 A 100 100, 0, 1, 1, 0 100 L 0 0 Z"/>',
'<g id="infinity">',
'<use href="#loop" />',
'<use href="#loop" transform="scale(-1,-1)" />',
'</g>',
'<filter id="noise">',
'<feTurbulence type="fractalNoise" baseFrequency="0.8" stitchTiles="stitch" numOctaves="1" seed="8"/>',
'<feColorMatrix type="saturate" values="0"/>',
'</filter>',
'</defs>'
);
}
function renderGrid() public pure returns (string memory) {
string memory grid;
for (uint256 i; i < 8; i++) {
grid = string.concat(
grid,
'<use href="#row" transform="translate(0,', str(i*100), ')" />'
);
}
return grid;
}
function renderGridRow() public pure returns (string memory) {
string memory row;
for (uint256 i; i < 8; i++) {
row = string.concat(
row,
'<use transform="translate(', str(i*100), ')" href="#box" />'
);
}
return row;
}
function renderNoise(Token memory data) public pure returns (string memory) {
return string.concat(
'<rect mask="url(#mask)" width="800" height="800" fill="black" filter="url(#noise)" ',
'style="mix-blend-mode: multiply;" opacity="', data.light ? '0.248"' : '0.8"',
'/>'
);
}
function renderSymbols(Token memory data) public pure returns (string memory) {
uint space = 800 / data.grid;
uint center = space / 4;
uint width = space / 2;
string memory symbols;
for (uint i = 0; i < data.count; i++) {
Symbol memory symbol = data.symbols[i];
uint baseStroke = symbol.isInfinity ? 8 : 4;
uint stroke = (data.grid < 8 ? baseStroke : baseStroke * 3 / 4) * data.grid / 2;
uint scale = width * 1000 / symbol.formWidth;
symbol.x = str(i % data.grid * space + center);
symbol.y = str(i / data.grid * space + center);
symbol.stroke = str(stroke);
symbol.center = str(center);
symbol.width = str(width);
symbol.scale = scale < 1000
? string.concat('0.', str(scale))
: str(scale / 1000);
symbols = string.concat(symbols, renderSymbol(symbol));
}
return symbols;
}
function renderSymbol(Symbol memory symbol) public pure returns (string memory) {
symbol.color.rendered = renderColor(symbol.color);
string memory rendered = symbol.form == 1 ? renderLoop(symbol)
: symbol.form == 2 ? renderInfinitySingle(symbol)
: symbol.form == 3 ? render90Loop(symbol)
: symbol.form == 4 ? renderInfinityPair(symbol)
: symbol.form == 5 ? render180Loop(symbol)
: symbol.form == 8 ? renderInfinityCheck(symbol)
: render360Loop(symbol);
return string.concat(
'<g transform="translate(',symbol.x,',',symbol.y,') rotate(',symbol.rotation,')" ',
'transform-origin="',symbol.center,' ',symbol.center,'" ',
'stroke-width="', symbol.stroke,
'">',
rendered,
'</g>'
);
}
function renderColor(Color memory color) public pure returns (string memory) {
if (bytes(color.rendered).length > 0) return color.rendered;
return string.concat('hsl(', str(color.h), ' ', str(color.s), '% ', str(color.l), '%)');
}
function renderLoop(Symbol memory symbol) public pure returns (string memory) {
return string.concat(
'<use href="#loop" transform="scale(', symbol.scale, ')" stroke="', symbol.color.rendered, '" />'
);
}
function render90Loop(Symbol memory symbol) public pure returns (string memory) {
return string.concat(
'<g transform="scale(', symbol.scale, ')" stroke="', symbol.color.rendered, '">',
'<use href="#loop" />',
'<use href="#loop" transform="translate(200,0) scale(-1,1)" />',
'</g>'
);
}
function render180Loop(Symbol memory symbol) public pure returns (string memory) {
return string.concat(
'<g transform="scale(', symbol.scale, ')" stroke="', symbol.color.rendered, '">',
'<use href="#loop" />',
'<use href="#loop" transform="translate(200,200) scale(-1,-1)" />',
'</g>'
);
}
function render360Loop(Symbol memory symbol) public pure returns (string memory) {
return string.concat(
'<g transform="scale(', symbol.scale, ')" stroke="', symbol.color.rendered, '">',
'<use href="#loop" />',
'<use href="#loop" transform="translate(200,0) scale(-1,1)" />',
'<use href="#loop" transform="translate(0,200) scale(1,-1)" />',
'<use href="#loop" transform="translate(200,200) scale(-1,-1)" />',
'</g>'
);
}
function renderInfinitySingle(Symbol memory symbol) public pure returns (string memory) {
return string.concat(
'<g transform="scale(', symbol.scale, ')" stroke="', symbol.color.rendered, '">',
'<g transform="translate(200,200)">'
'<use href="#infinity" />',
'</g>'
'</g>'
);
}
function renderInfinityPair(Symbol memory symbol) public pure returns (string memory) {
return string.concat(
'<g transform="scale(', symbol.scale, ')" stroke="', symbol.color.rendered, '">',
'<g transform="translate(200,200)">'
'<use href="#infinity" />',
'<use href="#infinity" transform="rotate(90)" />',
'</g>'
'</g>'
);
}
function renderInfinityCheck(Symbol memory symbol) public pure returns (string memory) {
return string.concat(
'<g transform="scale(', symbol.scale, ')" stroke="', symbol.color.rendered, '">',
'<g transform="translate(200,200)">'
'<use href="#infinity" />',
'<use href="#infinity" transform="rotate(45)" />',
'<use href="#infinity" transform="rotate(90)" />',
'<use href="#infinity" transform="rotate(135)" />',
'</g>'
'</g>'
);
}
function str(uint n) public pure returns (string memory) {
return Utilities.uint2str(n);
}
}
文件 10 的 14:InfiniteBags.sol
pragma solidity ^0.8.20;
struct Token {
uint seed;
string background;
string gridColor;
uint8 alloy;
uint8 grid;
uint8 count;
uint8 band;
uint8 gradient;
bool continuous;
bool mapColors;
bool light;
Symbol[64] symbols;
}
struct Symbol {
uint form;
uint16 formWidth;
bool isInfinity;
string rotation;
string stroke;
string center;
string scale;
string width;
string x;
string y;
uint colorIdx;
Color color;
}
struct Color {
uint16 h;
uint16 s;
uint16 l;
string rendered;
}
文件 11 的 14:InfiniteGenerator.sol
pragma solidity ^0.8.20;
import "./InfiniteBags.sol";
import "./Utilities.sol";
library InfiniteGenerator {
uint8 public constant ELEMENTS = 17;
uint8 public constant SHADES = 4;
function tokenData(uint tokenId) public pure returns (Token memory data) {
data.seed = tokenId;
data.light = tokenId % 4096 == 0 ? true : false;
data.background = data.light == true ? '#FFFFFF' : '#111111';
data.gridColor = data.light == true ? '#F5F5F5' : '#19181B';
data.grid = getGrid(data);
data.count = data.grid ** 2;
data.alloy = getAlloy(data);
data.band = getBand(data);
data.continuous = getContinuous(data);
data.gradient = getGradient(data);
data.mapColors = getColorMap(data);
data.symbols = getSymbols(data);
}
function getGrid(Token memory data) public pure returns (uint8) {
if (data.seed == 0) return 1;
uint n = Utilities.random(data.seed, 'grid', 160);
return n < 1 ? 1
: n < 8 ? 2
: n < 32 ? 4
: 8;
}
function getBand(Token memory data) public pure returns (uint8) {
return Utilities.max(data.alloy * SHADES, 1);
}
function getColorMap(Token memory data) public pure returns (bool) {
return data.gradient > 0
? Utilities.random(data.seed, 'color_map', 100) < 20
: Utilities.random(data.seed, 'color_map', 100) < 8;
}
function getContinuous(Token memory data) public pure returns (bool) {
return Utilities.random(data.seed, 'continuous', 2) < 1;
}
function getAlloy(Token memory data) public pure returns (uint8) {
if (data.grid == 1) return 0;
uint8 n = uint8(Utilities.random(data.seed, 'alloy', 100));
return n >= 56 ? 4 + n % (ELEMENTS - 4)
: n >= 24 ? 2
: n >= 4 ? 1
: 0;
}
function getGradient(Token memory data) public pure returns (uint8) {
if (data.grid == 1 || data.alloy == 0) return 0;
if (Utilities.random(data.seed, 'gradient', 10) < 8) return 0;
uint8 options = data.grid == 2 ? 2 : 7;
uint8[7] memory GRADIENTS = data.grid == 2 ? [1, 2, 0, 0, 0, 0, 0]
: data.grid == 4 ? [1, 2, 3, 4, 5, 8, 10]
: [1, 2, 4, 7, 8, 9, 16];
return GRADIENTS[Utilities.random(data.seed, 'select_gradient', options)];
}
function getSymbols(Token memory data) public pure returns (Symbol[64] memory symbols) {
uint8[7] memory forms = [1, 2, 3, 4, 5, 8, 9];
uint8[7] memory rotationCounts = [2, 4, 4, 2, 2, 0, 0];
(uint[64] memory colorIndexes, Color[64] memory colors) = getColors(data);
uint[64] memory formColorMap;
for (uint i = 0; i < data.count; i++) {
symbols[i].colorIdx = colorIndexes[i];
symbols[i].color = colors[i];
uint formIdx = getFormIdx(data, i);
uint form = forms[formIdx];
if (data.mapColors) {
(formColorMap, form) = setGetMap(formColorMap, symbols[i].colorIdx, form);
}
symbols[i].form = form;
symbols[i].isInfinity = symbols[i].form % 2 == 0;
symbols[i].formWidth = symbols[i].isInfinity ? 400 : 200;
uint rotationIncrement = symbols[i].isInfinity ? 45 : 90;
uint rotations = rotationCounts[formIdx] > 0
? Utilities.random(
data.seed,
string.concat('rotation', str(i)),
rotationCounts[formIdx]
)
: 0;
symbols[i].rotation = str(rotations * rotationIncrement);
}
}
function getFormIdx(Token memory data, uint i) public pure returns (uint) {
if (data.seed == 0) return 5;
uint random = Utilities.random(data.seed, string.concat('form', str(i)), 10);
if (random == 0) return 0;
uint8[3] memory common = [1, 3, 5];
uint8[3] memory uncommon = [2, 4, 6];
uint idx = Utilities.random(data.seed, string.concat('form-idx', str(i)), 3);
return random < 8 ? common[idx] : uncommon[idx];
}
function allColors() public pure returns (Color[68] memory colors) {
uint8[4] memory voidLums = [16, 32, 80, 96];
for (uint i = 0; i < SHADES; i++) {
colors[i].h = 270;
colors[i].s = 8;
colors[i].l = voidLums[i];
}
uint8 count = 4*4;
uint16 startHue = 256;
uint8[4] memory lums = [56, 60, 64, 72];
for (uint8 i = 0; i < 16; i++) {
uint16 hue = (startHue + 360 * i / count) % 360;
for(uint8 e = 0; e < 4; e++) {
uint8 idx = 4+i*4+e;
colors[idx].h = hue;
colors[idx].s = 88;
colors[idx].l = lums[e];
}
}
}
function getColors(Token memory data) public pure returns (
uint[64] memory colorIndexes,
Color[64] memory colors
) {
Color[68] memory all = allColors();
uint[68] memory options = getColorOptions(data);
bool reverse = Utilities.random(data.seed, 'reverse', 2) > 0;
for (uint i = 0; i < data.count; i++) {
colorIndexes[i] = (
data.gradient > 0
? getGradientColor(data, i)
: getRandomColor(data, i)
) % 68;
uint idx = reverse ? data.count - 1 - i : i;
colors[idx] = all[options[colorIndexes[i]]];
if (data.light) colors[idx].rendered = '#080808';
}
}
function getColorOptions(Token memory data) public pure returns (uint[68] memory options) {
uint count = Utilities.max(1, data.alloy);
for (uint element = 0; element < count; element++) {
uint idx = element * SHADES;
uint chosen = data.continuous && element > 0
? (options[idx - 1] / SHADES + 1) % ELEMENTS
: Utilities.random(data.seed, string.concat('element', str(element)), ELEMENTS);
uint chosenIdx = chosen * SHADES;
for (uint shade = 0; shade < SHADES; shade++) {
options[idx + shade] = chosenIdx + shade;
}
}
}
function getGradientColor(Token memory data, uint i) public pure returns (uint) {
uint offset;
if (data.gradient == 3 || data.gradient == 7) {
offset = data.grid + 1;
}
return ((offset + i) * data.gradient * data.band / data.count) % data.band;
}
function getRandomColor(Token memory data, uint i) public pure returns (uint) {
uint8 max = Utilities.max(SHADES, data.band);
string memory key = data.alloy == 0 ? '0' : str(i);
return Utilities.random(data.seed, string.concat('random_color_', key), max);
}
function setGetMap(
uint[64] memory map, uint key, uint value
) public pure returns (uint[64] memory, uint) {
uint k = key % 64;
if (map[k] == 0) {
map[k] = value;
}
return (map, map[k]);
}
function str(uint n) public pure returns (string memory) {
return Utilities.uint2str(n);
}
}
文件 12 的 14:InfiniteMetadata.sol
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/utils/Base64.sol";
import "./InfiniteBags.sol";
import "./InfiniteArt.sol";
import "./Utilities.sol";
library InfiniteMetadata {
function tokenURI(
Token memory data
) public pure returns (string memory) {
bytes memory metadata = abi.encodePacked(
'{',
'"name": "Infinity",',
unicode'"description": "∞",',
'"image": ',
'"data:image/svg+xml;base64,',
Base64.encode(abi.encodePacked(InfiniteArt.renderSVG(data))),
'",',
'"attributes": [', attributes(data), ']',
'}'
);
return string.concat(
"data:application/json;base64,",
Base64.encode(metadata)
);
}
function attributes(Token memory data) public pure returns (string memory) {
return string.concat(
trait('Light', light(data.light), ','),
trait('Grid', grid(data), ','),
data.light ? '' : trait('Elements', elements(data), ','),
data.light ? '' : trait('Gradient', gradient(data), ','),
data.light ? '' : trait('Band', band(data), ','),
trait('Symbols', symbols(data), '')
);
}
function light(bool on) public pure returns (string memory) {
return on ? 'On' : 'Off';
}
function grid(Token memory data) public pure returns (string memory) {
string memory g = Utilities.uint2str(data.grid);
return string.concat(g, 'x', g);
}
function elements(Token memory data) public pure returns (string memory) {
return data.alloy == 0 ? 'Isolate'
: data.alloy == 1 ? 'Composite'
: data.alloy == 2 ? 'Compound'
: 'Complete';
}
function band(Token memory data) public pure returns (string memory) {
return (data.continuous || data.alloy < 2) ? 'Continuous' : 'Cut';
}
function gradient(Token memory data) public pure returns (string memory) {
return [
'None', 'Linear', 'Double Linear', 'Angled Down', 'Ordered', 'Angled Up', '', 'Angled Down', 'Linear Z',
'Angled', 'Angled Up', '', '', '', '', '', 'Double Linear Z'
][data.gradient];
}
function symbols(Token memory data) public pure returns (string memory) {
return data.mapColors ? 'Mapped' : 'Random';
}
function trait(
string memory traitType, string memory traitValue, string memory append
) public pure returns (string memory) {
return string(abi.encodePacked(
'{',
'"trait_type": "', traitType, '",'
'"value": "', traitValue, '"'
'}',
append
));
}
}
文件 13 的 14:Infinity.sol
pragma solidity ^0.8.20;
import "./libraries/InfiniteArt.sol";
import "./libraries/InfiniteBags.sol";
import "./libraries/InfiniteGenerator.sol";
import "./libraries/InfiniteMetadata.sol";
import "./standards/ERC1155.sol";
contract Infinity is ERC1155 {
string public name = "Infinity";
string public symbol = unicode"∞";
uint public price = 0.008 ether;
address private constant VV = 0xc8f8e2F59Dd95fF67c3d39109ecA2e2A017D4c8a;
constructor(address[] memory genesisRecipients) ERC1155() payable {
_checkDeposit(genesisRecipients.length);
uint count = genesisRecipients.length;
for (uint i = 0; i < count;) {
_mint(genesisRecipients[i], 0, 1, "");
unchecked { ++i; }
}
}
receive() external payable {
_generateViaDeposit(msg.sender, _randomId());
}
function generate(
address recipient,
string calldata message
) public payable {
uint tokenId = _randomId();
_generateViaDeposit(recipient, tokenId);
_message(recipient, tokenId, message);
}
function generateExisting(
address source,
address recipient,
uint tokenId,
string calldata message
) public payable {
_validateId(tokenId, source);
_generateViaDeposit(recipient, tokenId);
_message(recipient, tokenId, message);
}
function regenerate(uint id, uint amount) public {
_burn(msg.sender, id, amount);
_mint(msg.sender, _randomId(), amount, "");
}
function degenerate(
uint id,
uint amount
) public {
_burn(msg.sender, id, amount);
_send(msg.sender, amount * price);
}
function generateMany(
address[] calldata recipients,
uint[] calldata amounts
) public payable {
_checkDeposit(_totalAmount(amounts));
uint count = recipients.length;
for (uint i = 0; i < count;) {
_mint(recipients[i], _randomId(), amounts[i], "");
unchecked { ++i; }
}
}
function generateManyExisting(
address[] calldata sources,
address[] calldata recipients,
uint[] calldata tokenIds,
uint[] calldata amounts
) public payable {
_checkDeposit(_totalAmount(amounts));
uint count = sources.length;
for (uint i = 0; i < count;) {
_validateId(tokenIds[i], sources[i]);
_mint(recipients[i], tokenIds[i], amounts[i], "");
unchecked { ++i; }
}
}
function regenerateMany(
uint[] calldata ids,
uint[] calldata degenerateAmounts,
uint[] calldata amounts
) public payable {
if (_totalAmount(degenerateAmounts) != _totalAmount(amounts)) revert InvalidInput();
uint count = ids.length;
for (uint i = 0; i < count;) {
_burn(msg.sender, ids[i], degenerateAmounts[i]);
_mint(msg.sender, _randomId(), amounts[i], "");
unchecked { ++i; }
}
}
function degenerateMany(
uint[] memory ids,
uint[] memory amounts
) public {
if (ids.length != amounts.length) revert InvalidInput();
_burnBatch(msg.sender, ids, amounts);
_send(msg.sender, _totalAmount(amounts) * price);
}
function svg(uint tokenId) public pure returns (string memory) {
return InfiniteArt.renderSVG(InfiniteGenerator.tokenData(tokenId));
}
function uri(uint tokenId) public pure override returns (string memory) {
return InfiniteMetadata.tokenURI(InfiniteGenerator.tokenData(tokenId));
}
function totalSupply() public pure returns (uint) { return type(uint).max; }
function totalSupply(uint) public pure returns (uint) { return type(uint).max; }
function _generateViaDeposit(address recipient, uint tokenId) internal {
uint amount = msg.value / price;
uint surplus = msg.value % price;
if (amount == 0) revert InvalidDesposit();
_mint(recipient, tokenId, amount, "");
_send(recipient, surplus);
}
function _validateId(uint id, address source) internal view {
bool minted = balanceOf(source, id) > 0;
if(! minted && msg.sender != VV) revert InvalidToken();
}
function _randomId() internal view returns (uint) {
return uint(keccak256(abi.encodePacked(block.prevrandao, msg.sender, gasleft())));
}
function _checkDeposit(uint amount) internal {
if (msg.value != amount * price) revert InvalidDesposit();
}
function _totalAmount(uint[] memory amounts) internal pure returns (uint amount) {
for (uint i = 0; i < amounts.length; i++) {
amount += amounts[i];
}
}
function _send(address to, uint value) internal {
(bool success, ) = payable(to).call{value: value}("");
require(success, "Unable to send value, recipient may have reverted");
}
function _message(address recipient, uint tokenId, string calldata message) internal {
if (bytes(message).length > 0) {
emit Message(msg.sender, recipient, tokenId, message);
}
}
}
文件 14 的 14:Utilities.sol
pragma solidity ^0.8.17;
library Utilities {
function random(uint256 input, uint256 _max) public pure returns (uint256) {
return (uint256(keccak256(abi.encodePacked(input))) % _max);
}
function random(uint256 input, string memory salt, uint256 _max) public pure returns (uint256) {
return (uint256(keccak256(abi.encodePacked(input, salt))) % _max);
}
function uint2str(uint256 _i) public pure returns (string memory _uintAsString) {
if (_i == 0) {
return "0";
}
uint256 j = _i;
uint256 len;
while (j != 0) {
++len;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint256 k = len;
while (_i != 0) {
k = k - 1;
uint8 temp = (48 + uint8(_i - (_i / 10) * 10));
bytes1 b1 = bytes1(temp);
bstr[k] = b1;
_i /= 10;
}
return string(bstr);
}
function minGt0(uint8 one, uint8 two) public pure returns (uint8) {
return one > two
? two > 0
? two
: one
: one;
}
function min(uint8 one, uint8 two) public pure returns (uint8) {
return one < two ? one : two;
}
function max(uint8 one, uint8 two) public pure returns (uint8) {
return one > two ? one : two;
}
function avg(uint8 one, uint8 two) public pure returns (uint8 result) {
unchecked {
result = (one >> 1) + (two >> 1) + (one & two & 1);
}
}
function day(uint256 from, uint256 to) public pure returns (uint24) {
return uint24((to - from) / 24 hours + 1);
}
}
{
"compilationTarget": {
"contracts/Infinity.sol": "Infinity"
},
"evmVersion": "shanghai",
"libraries": {
"contracts/libraries/InfiniteArt.sol:InfiniteArt": "0xc6b17cafcc2439ef4833fe6a073ba71438112f87",
"contracts/libraries/InfiniteGenerator.sol:InfiniteGenerator": "0xb0047233de84066b491f093380b8ca3cff4f7333",
"contracts/libraries/InfiniteMetadata.sol:InfiniteMetadata": "0x12b7f0e2f3d562b0cd012bd58e2d620bfdfe542f"
},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": []
}
[{"inputs":[{"internalType":"address[]","name":"genesisRecipients","type":"address[]"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"InvalidDesposit","type":"error"},{"inputs":[],"name":"InvalidInput","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","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":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"string","name":"message","type":"string"}],"name":"Message","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"degenerate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"degenerateMany","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"string","name":"message","type":"string"}],"name":"generate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"source","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"message","type":"string"}],"name":"generateExisting","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"generateMany","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"sources","type":"address[]"},{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"generateManyExisting","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"regenerate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"degenerateAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"regenerateMany","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bool","name":"","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":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"svg","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"stateMutability":"payable","type":"receive"}]