// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol)pragmasolidity ^0.8.0;/**
* @dev Provides a set of functions to operate with Base64 strings.
*
* _Available since v4.5._
*/libraryBase64{
/**
* @dev Base64 Encoding/Decoding Table
*/stringinternalconstant _TABLE ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* @dev Converts a `bytes` to its Bytes64 `string` representation.
*/functionencode(bytesmemory data) internalpurereturns (stringmemory) {
/**
* Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
* https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
*/if (data.length==0) return"";
// Loads the table into memorystringmemory table = _TABLE;
// Encoding takes 3 bytes chunks of binary data from `bytes` data parameter// and split into 4 numbers of 6 bits.// The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up// - `data.length + 2` -> Round up// - `/ 3` -> Number of 3-bytes chunks// - `4 *` -> 4 characters for each chunkstringmemory result =newstring(4* ((data.length+2) /3));
/// @solidity memory-safe-assemblyassembly {
// Prepare the lookup table (skip the first "length" byte)let tablePtr :=add(table, 1)
// Prepare result pointer, jump over lengthlet resultPtr :=add(result, 32)
// Run over the input, 3 bytes at a timefor {
let dataPtr := data
let endPtr :=add(data, mload(data))
} lt(dataPtr, endPtr) {
} {
// Advance 3 bytes
dataPtr :=add(dataPtr, 3)
let input :=mload(dataPtr)
// To write each character, shift the 3 bytes (18 bits) chunk// 4 times in blocks of 6 bits for each character (18, 12, 6, 0)// and apply logical AND with 0x3F which is the number of// the previous character in the ASCII table prior to the Base64 Table// The result is then added to the table to get the character to write,// and finally write it in the result pointer but with a left shift// of 256 (1 byte) - 8 (1 ASCII char) = 248 bitsmstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr :=add(resultPtr, 1) // Advancemstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr :=add(resultPtr, 1) // Advancemstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
resultPtr :=add(resultPtr, 1) // Advancemstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
resultPtr :=add(resultPtr, 1) // Advance
}
// When data `bytes` is not exactly 3 bytes long// it is padded with `=` characters at the endswitchmod(mload(data), 3)
case1 {
mstore8(sub(resultPtr, 1), 0x3d)
mstore8(sub(resultPtr, 2), 0x3d)
}
case2 {
mstore8(sub(resultPtr, 1), 0x3d)
}
}
return result;
}
}
Contract Source Code
File 2 of 14: Context.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)pragmasolidity ^0.8.0;/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
}
Contract Source Code
File 3 of 14: ERC1155.sol
// SPDX-License-Identifier: MIT// Derived from OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol)pragmasolidity ^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";
/**
* @dev Simplified implementation of the basic standard multi-token.
* See https://eips.ethereum.org/EIPS/eip-1155
* Originally based on code by Enjin: https://github.com/enjin/erc-1155
*/contractERC1155isContext, ERC165, IERC1155, IERC1155MetadataURI{
// Mapping from token ID to account balancesmapping(uint256=>mapping(address=>uint256)) private _balances;
/**
* @dev Emitted when minting a token with a message.
*/eventMessage(addressindexedfrom, addressindexed to, uint256indexed id, string message);
/**
* @dev Custom revert errors.
*/errorInvalidToken();
errorInvalidInput();
errorInvalidDesposit();
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(ERC165, IERC165) returns (bool) {
return
interfaceId ==type(IERC1155).interfaceId||
interfaceId ==type(IERC1155MetadataURI).interfaceId||super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC1155MetadataURI-uri}.
*
* This implementation returns the same URI for *all* token types. It relies
* on the token type ID substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* Clients calling this function must replace the `\{id\}` substring with the
* actual token type ID.
*/functionuri(uint256) publicviewvirtualoverridereturns (stringmemory) {}
/**
* @dev See {IERC1155-balanceOf}.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/functionbalanceOf(address account, uint256 id) publicviewvirtualoverridereturns (uint256) {
if (account ==address(0)) return0;
return _balances[id][account];
}
/**
* @dev See {IERC1155-balanceOfBatch}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/functionbalanceOfBatch(address[] memory accounts, uint256[] memory ids)
publicviewvirtualoverridereturns (uint256[] memory)
{
require(accounts.length== ids.length, "ERC1155: accounts and ids length mismatch");
uint256[] memory batchBalances =newuint256[](accounts.length);
for (uint256 i =0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts[i], ids[i]);
}
return batchBalances;
}
/**
* @notice Infinities are never approved.
* @dev See {IERC1155-setApprovalForAll}.
*/functionsetApprovalForAll(address, bool) publicvirtualoverride{
revert("No approvals on infinities");
}
/**
* @notice Infinities are never approved.
* @dev See {IERC1155-isApprovedForAll}.
*/functionisApprovedForAll(address, address) publicviewvirtualoverridereturns (bool) {
returnfalse;
}
/**
* @dev See {IERC1155-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 id,
uint256 amount,
bytesmemory data
) publicvirtualoverride{
require(
from== _msgSender(),
"ERC1155: caller is not token owner"
);
_safeTransferFrom(from, to, id, amount, data);
}
/**
* @dev See {IERC1155-safeBatchTransferFrom}.
*/functionsafeBatchTransferFrom(addressfrom,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytesmemory data
) publicvirtualoverride{
require(
from== _msgSender(),
"ERC1155: caller is not token owner"
);
_safeBatchTransferFrom(from, to, ids, amounts, data);
}
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/function_safeTransferFrom(addressfrom,
address to,
uint256 id,
uint256 amount,
bytesmemory data
) internalvirtual{
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);
}
/**
* @dev Emits a {TransferBatch} event.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/function_safeBatchTransferFrom(addressfrom,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytesmemory data
) internalvirtual{
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);
}
/**
* @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/function_mint(address to,
uint256 id,
uint256 amount,
bytesmemory data
) internalvirtual{
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);
}
/**
* @dev Destroys `amount` tokens of token type `id` from `from`
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have at least `amount` tokens of token type `id`.
*/function_burn(addressfrom,
uint256 id,
uint256 amount
) internalvirtual{
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);
}
/**
* @dev Batched version of {_burn}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
*/function_burnBatch(addressfrom,
uint256[] memory ids,
uint256[] memory amounts
) internalvirtual{
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,
addressfrom,
address to,
uint256 id,
uint256 amount,
bytesmemory 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");
}
} catchError(stringmemory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function_doSafeBatchTransferAcceptanceCheck(address operator,
addressfrom,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytesmemory 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");
}
} catchError(stringmemory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function_isContract(address account) internalviewreturns (bool) {
return account.code.length>0;
}
}
Contract Source Code
File 4 of 14: ERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)pragmasolidity ^0.8.0;import"./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/abstractcontractERC165isIERC165{
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverridereturns (bool) {
return interfaceId ==type(IERC165).interfaceId;
}
}
Contract Source Code
File 5 of 14: IERC1155.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)pragmasolidity ^0.8.0;import"../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/interfaceIERC1155isIERC165{
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/eventTransferSingle(addressindexed operator, addressindexedfrom, addressindexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/eventTransferBatch(addressindexed operator,
addressindexedfrom,
addressindexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/eventApprovalForAll(addressindexed account, addressindexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/eventURI(string value, uint256indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/functionbalanceOf(address account, uint256 id) externalviewreturns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/functionbalanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
externalviewreturns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/functionsetApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/functionisApprovedForAll(address account, address operator) externalviewreturns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 id,
uint256 amount,
bytescalldata data
) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/functionsafeBatchTransferFrom(addressfrom,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytescalldata data
) external;
}
Contract Source Code
File 6 of 14: IERC1155MetadataURI.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)pragmasolidity ^0.8.0;import"../IERC1155.sol";
/**
* @dev Interface of the optional ERC1155MetadataExtension interface, as defined
* in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
*
* _Available since v3.1._
*/interfaceIERC1155MetadataURIisIERC1155{
/**
* @dev Returns the URI for token type `id`.
*
* If the `\{id\}` substring is present in the URI, it must be replaced by
* clients with the actual token type ID.
*/functionuri(uint256 id) externalviewreturns (stringmemory);
}
Contract Source Code
File 7 of 14: IERC1155Receiver.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)pragmasolidity ^0.8.0;import"../../utils/introspection/IERC165.sol";
/**
* @dev _Available since v3.1._
*/interfaceIERC1155ReceiverisIERC165{
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/functiononERC1155Received(address operator,
addressfrom,
uint256 id,
uint256 value,
bytescalldata data
) externalreturns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/functiononERC1155BatchReceived(address operator,
addressfrom,
uint256[] calldata ids,
uint256[] calldata values,
bytescalldata data
) externalreturns (bytes4);
}
Contract Source Code
File 8 of 14: IERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)pragmasolidity ^0.8.0;/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/interfaceIERC165{
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.20;import"./InfiniteBags.sol";
import"./Utilities.sol";
/**
@title InfiniteGenerator
@author VisualizeValue
@notice Gathers the data to render Infinity visuals.
*/libraryInfiniteGenerator{
/// @dev 16 distinct colors + void.uint8publicconstant ELEMENTS =17;
/// @dev Number of shades for each color.uint8publicconstant SHADES =4;
/// @dev Collect relevant rendering data for easy access across functions.functiontokenData(uint tokenId) publicpurereturns (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);
}
/// @dev Define the grid for a token.functiongetGrid(Token memory data) publicpurereturns (uint8) {
if (data.seed ==0) return1; // Genesis token override.uint n = Utilities.random(data.seed, 'grid', 160);
return n <1 ? 1
: n <8 ? 2
: n <32 ? 4
: 8;
}
/// @dev Define the color band size for a token.functiongetBand(Token memory data) publicpurereturns (uint8) {
// Four times the number of used elements, min 1.return Utilities.max(data.alloy * SHADES, 1);
}
/// @dev Whether to map symbols to colors.functiongetColorMap(Token memory data) publicpurereturns (bool) {
// 20% for gradients; 8% for skittles.return data.gradient >0
? Utilities.random(data.seed, 'color_map', 100) <20
: Utilities.random(data.seed, 'color_map', 100) <8;
}
/// @dev Whether color banding is continuous or random. 50/50.functiongetContinuous(Token memory data) publicpurereturns (bool) {
return Utilities.random(data.seed, 'continuous', 2) <1;
}
/// @dev Get the number of distinct elements used. 0 for Isolates.functiongetAlloy(Token memory data) publicpurereturns (uint8) {
if (data.grid ==1) return0;
uint8 n =uint8(Utilities.random(data.seed, 'alloy', 100));
return n >=56 ? 4+ n % (ELEMENTS -4) // Complete
: n >=24 ? 2// Compound
: n >=4 ? 1// Composite
: 0; // Isolate
}
/// @dev Choose a gradient for the token.functiongetGradient(Token memory data) publicpurereturns (uint8) {
if (data.grid ==1|| data.alloy ==0) return0; // No gradients for 1x1 or isolate tokensif (Utilities.random(data.seed, 'gradient', 10) <8) return0; // 80% have no gradientuint8 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)];
}
/// @dev Get the symbols for all slots on the grid.functiongetSymbols(Token memory data) publicpurereturns (Symbol[64] memory symbols) {
uint8[7] memory forms = [1, 2, 3, 4, 5, 8, 9]; // Seven distinct symbols.uint8[7] memory rotationCounts = [2, 4, 4, 2, 2, 0, 0]; // How often we rotate.
(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);
}
}
/// @dev Get shape of a given symbol of a token.functiongetFormIdx(Token memory data, uint i) publicpurereturns (uint) {
if (data.seed ==0) return5; // Genesis token is an infinity flower.uint random = Utilities.random(data.seed, string.concat('form', str(i)), 10);
if (random ==0) return0; // 10% Single Loopsuint8[3] memory common = [1, 3, 5]; // Infinitiesuint8[3] memory uncommon = [2, 4, 6]; // Loopsuint idx = Utilities.random(data.seed, string.concat('form-idx', str(i)), 3);
return random <8 ? common[idx] : uncommon[idx];
}
/// @dev Get all colors available to choose from.functionallColors() publicpurereturns (Color[68] memory colors) {
// One "Void" color with 4 shades.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];
}
// 16 distinct colors with 4 shades each.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];
}
}
}
/// @dev Get the color variations for a specific token. Compute gradients / skittles.functiongetColors(Token memory data) publicpurereturns (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]]];
// Paradoxical, i know. Opepen your eyes. All one. Common fate.if (data.light) colors[idx].rendered ='#080808';
}
}
/// @dev Get the colors to choose from for a given token.functiongetColorOptions(Token memory data) publicpurereturns (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// Increment previous by one for a continuous band.
? (options[idx -1] / SHADES +1) % ELEMENTS
// Random selection for hard shifts in color.
: 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;
}
}
}
/// @dev Compute the gradient colors for a gradient token.functiongetGradientColor(Token memory data, uint i) publicpurereturns (uint) {
uint offset;
if (data.gradient ==3|| data.gradient ==7) {
// Fix angled gradient y-shift.
offset = data.grid +1;
}
return ((offset + i) * data.gradient * data.band / data.count) % data.band;
}
/// @dev Compute colors for a skittle tokens.functiongetRandomColor(Token memory data, uint i) publicpurereturns (uint) {
uint8 max = Utilities.max(SHADES, data.band);
stringmemory key = data.alloy ==0 ? '0' : str(i);
return Utilities.random(data.seed, string.concat('random_color_', key), max);
}
/// @dev Helper to keep track of a key value store in memory.functionsetGetMap(uint[64] memory map, uint key, uint value
) publicpurereturns (uint[64] memory, uint) {
uint k = key %64;
if (map[k] ==0) {
map[k] = value;
}
return (map, map[k]);
}
/// @dev Uint to string helper.functionstr(uint n) publicpurereturns (stringmemory) {
return Utilities.uint2str(n);
}
}
Contract Source Code
File 12 of 14: InfiniteMetadata.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.20;import"@openzeppelin/contracts/utils/Base64.sol";
import"./InfiniteBags.sol";
import"./InfiniteArt.sol";
import"./Utilities.sol";
/**
@title InfiniteMetadata
@author VisualizeValue
@notice Renders ERC1155 compatible metadata for Infinity tokens.
*/libraryInfiniteMetadata{
/// @dev Render the JSON Metadata for a given Infinity token./// @param data The render data for our tokenfunctiontokenURI(
Token memory data
) publicpurereturns (stringmemory) {
bytesmemory metadata =abi.encodePacked(
'{',
'"name": "Infinity",',
unicode'"description": "∞",',
'"image": ',
'"data:image/svg+xml;base64,',
Base64.encode(abi.encodePacked(InfiniteArt.renderSVG(data))),
'",',
'"attributes": [', attributes(data), ']',
'}'
);
returnstring.concat(
"data:application/json;base64,",
Base64.encode(metadata)
);
}
/// @dev Render the JSON atributes for a given Infinity token./// @param data The check to render.functionattributes(Token memory data) publicpurereturns (stringmemory) {
returnstring.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), '')
);
}
/// @dev Get the value for the 'Light' attribute.functionlight(bool on) publicpurereturns (stringmemory) {
return on ? 'On' : 'Off';
}
/// @dev Get the value for the 'Grid' attribute.functiongrid(Token memory data) publicpurereturns (stringmemory) {
stringmemory g = Utilities.uint2str(data.grid);
returnstring.concat(g, 'x', g);
}
/// @dev Get the value for the 'Elements' attribute.functionelements(Token memory data) publicpurereturns (stringmemory) {
return data.alloy ==0 ? 'Isolate'
: data.alloy ==1 ? 'Composite'
: data.alloy ==2 ? 'Compound'
: 'Complete';
}
/// @dev Get the value for the 'Band' attribute.functionband(Token memory data) publicpurereturns (stringmemory) {
return (data.continuous || data.alloy <2) ? 'Continuous' : 'Cut';
}
/// @dev Get the value for the 'Gradient' attribute.functiongradient(Token memory data) publicpurereturns (stringmemory) {
return [
// [0, 1, 2, 3, 4, 5, _, 7, 8, 9, 10, _, _, _, _, _, 16]'None', 'Linear', 'Double Linear', 'Angled Down', 'Ordered', 'Angled Up', '', 'Angled Down', 'Linear Z',
'Angled', 'Angled Up', '', '', '', '', '', 'Double Linear Z'
][data.gradient];
}
/// @dev Get the value for the 'Symbols' attribute.functionsymbols(Token memory data) publicpurereturns (stringmemory) {
return data.mapColors ? 'Mapped' : 'Random';
}
/// @dev Generate the SVG snipped for a single attribute./// @param traitType The `trait_type` for this trait./// @param traitValue The `value` for this trait./// @param append Helper to append a comma.functiontrait(stringmemory traitType, stringmemory traitValue, stringmemory append
) publicpurereturns (stringmemory) {
returnstring(abi.encodePacked(
'{',
'"trait_type": "', traitType, '",''"value": "', traitValue, '"''}',
append
));
}
}
Contract Source Code
File 13 of 14: Infinity.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.20;import"./libraries/InfiniteArt.sol";
import"./libraries/InfiniteBags.sol";
import"./libraries/InfiniteGenerator.sol";
import"./libraries/InfiniteMetadata.sol";
import"./standards/ERC1155.sol";
/// @title Infinity token contract./// @notice Imo notable./// @author Visualize ValuecontractInfinityisERC1155{
/// @notice The name of the collection.stringpublic name ="Infinity";
/// @notice The symbol of the collection.stringpublic symbol =unicode"∞";
/// @notice The price of an infinity token.uintpublic price =0.008ether;
/// @dev VV creator account.addressprivateconstant VV =0xc8f8e2F59Dd95fF67c3d39109ecA2e2A017D4c8a;
/// @dev Instanciate the contract...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; }
}
}
/// @notice Deposit ether, receive random infinitiesreceive() externalpayable{
_generateViaDeposit(msg.sender, _randomId());
}
/// @notice Create a new infinity check and deposit 0.008 ETH for each token./// @param recipient The address that should receive the token./// @param message Mint the token with an optional message.functiongenerate(address recipient,
stringcalldata message
) publicpayable{
uint tokenId = _randomId();
_generateViaDeposit(recipient, tokenId);
_message(recipient, tokenId, message);
}
/// @notice Copy an existing infinity check owned by someone and deposit 0.008 ETH for each token./// @param source The address of an existing owner of the token./// @param recipient The address that should receive the token./// @param tokenId The token ID to mint./// @param message Mint the token with an optional message.functiongenerateExisting(address source,
address recipient,
uint tokenId,
stringcalldata message
) publicpayable{
_validateId(tokenId, source);
_generateViaDeposit(recipient, tokenId);
_message(recipient, tokenId, message);
}
/// @notice Swap an inifinity token for a new one./// @param id The token ID to burn./// @param amount The token amount to burn / recreate.functionregenerate(uint id, uint amount) public{
// Execute burn
_burn(msg.sender, id, amount);
// Mint a new token
_mint(msg.sender, _randomId(), amount, "");
}
/// @notice Destroy the token to withdraw its desposited ETH./// @param id The token ID to destroy./// @param amount The amount to degenerate (withdraws 0.008 ETH per item).functiondegenerate(uint id,
uint amount
) public{
// Execute burn
_burn(msg.sender, id, amount);
// Withdraw funds
_send(msg.sender, amount * price);
}
/// @notice Create multiple infinity check tokens and deposit 0.008 ETH in each./// @param recipients The addresses that should receive the token./// @param amounts The number of tokens to send to each recipient.functiongenerateMany(address[] calldata recipients,
uint[] calldata amounts
) publicpayable{
_checkDeposit(_totalAmount(amounts));
uint count = recipients.length;
for (uint i =0; i < count;) {
_mint(recipients[i], _randomId(), amounts[i], "");
unchecked { ++i; }
}
}
/// @notice Copy multiple infinity check tokens and deposit 0.008 ETH in each./// @param sources The addresses of existing owners of each token./// @param recipients The addresses that should receive the token./// @param tokenIds The tokenIDs to mint./// @param amounts The number of tokens to send for each token.functiongenerateManyExisting(address[] calldata sources,
address[] calldata recipients,
uint[] calldata tokenIds,
uint[] calldata amounts
) publicpayable{
_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; }
}
}
/// @notice Create multiple new infinity check tokens and deposit 0.008 ETH in each./// @param ids The existing token IDs that should be destroyed in the process./// @param degenerateAmounts The number of tokens per id to burn./// @param amounts The number of tokens per id recreate.functionregenerateMany(uint[] calldata ids,
uint[] calldata degenerateAmounts,
uint[] calldata amounts
) publicpayable{
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; }
}
}
/// @notice Degenerate multiple tokens at once./// @param ids The tokenIDs to destroy./// @param amounts The amounts to degenerate (withdraws 0.008 ETH per item).functiondegenerateMany(uint[] memory ids,
uint[] memory amounts
) public{
if (ids.length!= amounts.length) revert InvalidInput();
// Execute burn
_burnBatch(msg.sender, ids, amounts);
// Withdraw funds
_send(msg.sender, _totalAmount(amounts) * price);
}
/// @notice Render SVG of the token./// @param tokenId The token ID to render.functionsvg(uint tokenId) publicpurereturns (stringmemory) {
return InfiniteArt.renderSVG(InfiniteGenerator.tokenData(tokenId));
}
/// @notice Render the encoded token metadata-URI./// @param tokenId The token ID to get metadata for.functionuri(uint tokenId) publicpureoverridereturns (stringmemory) {
return InfiniteMetadata.tokenURI(InfiniteGenerator.tokenData(tokenId));
}
/// @notice Supply is (in)finite: (2^256 - 1)^2.functiontotalSupply() publicpurereturns (uint) { returntype(uint).max; }
functiontotalSupply(uint) publicpurereturns (uint) { returntype(uint).max; }
/// @dev Mint a token n times, based on the amount of ETH sent.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);
}
/// @dev Validate IDs to minted tokens or randomize for initial mints. Exception for VV mints.function_validateId(uint id, address source) internalview{
bool minted = balanceOf(source, id) >0;
// If it's not already minted piece, or we are not VV, revert.if(! minted &&msg.sender!= VV) revert InvalidToken();
}
/// @dev Make a random generative token ID.function_randomId() internalviewreturns (uint) {
returnuint(keccak256(abi.encodePacked(block.prevrandao, msg.sender, gasleft())));
}
/// @dev Check whether the deposited Ether is a correct {price} multipe of the token {amount}function_checkDeposit(uint amount) internal{
if (msg.value!= amount * price) revert InvalidDesposit();
}
/// @dev Get the sum of all given amountsfunction_totalAmount(uint[] memory amounts) internalpurereturns (uint amount) {
for (uint i =0; i < amounts.length; i++) {
amount += amounts[i];
}
}
/// @dev Send ETH to an addressfunction_send(address to, uint value) internal{
(bool success, ) =payable(to).call{value: value}("");
require(success, "Unable to send value, recipient may have reverted");
}
/// @dev Emit a mint message, if providedfunction_message(address recipient, uint tokenId, stringcalldata message) internal{
if (bytes(message).length>0) {
emit Message(msg.sender, recipient, tokenId, message);
}
}
}
Contract Source Code
File 14 of 14: Utilities.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.17;libraryUtilities{
/// @dev Zero-index based pseudorandom number based on one input and max boundfunctionrandom(uint256 input, uint256 _max) publicpurereturns (uint256) {
return (uint256(keccak256(abi.encodePacked(input))) % _max);
}
/// @dev Zero-index based salted pseudorandom number based on two inputs and max boundfunctionrandom(uint256 input, stringmemory salt, uint256 _max) publicpurereturns (uint256) {
return (uint256(keccak256(abi.encodePacked(input, salt))) % _max);
}
/// @dev Convert an integer to a stringfunctionuint2str(uint256 _i) publicpurereturns (stringmemory _uintAsString) {
if (_i ==0) {
return"0";
}
uint256 j = _i;
uint256 len;
while (j !=0) {
++len;
j /=10;
}
bytesmemory bstr =newbytes(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;
}
returnstring(bstr);
}
/// @dev Get the smallest non zero numberfunctionminGt0(uint8 one, uint8 two) publicpurereturns (uint8) {
return one > two
? two >0
? two
: one
: one;
}
/// @dev Get the smaller numberfunctionmin(uint8 one, uint8 two) publicpurereturns (uint8) {
return one < two ? one : two;
}
/// @dev Get the larger numberfunctionmax(uint8 one, uint8 two) publicpurereturns (uint8) {
return one > two ? one : two;
}
/// @dev Get the average between two numbersfunctionavg(uint8 one, uint8 two) publicpurereturns (uint8 result) {
unchecked {
result = (one >>1) + (two >>1) + (one & two &1);
}
}
/// @dev Get the days since another date (input is seconds)functionday(uint256from, uint256 to) publicpurereturns (uint24) {
returnuint24((to -from) /24hours+1);
}
}