// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)pragmasolidity ^0.8.1;/**
* @dev Collection of functions related to the address type
*/libraryAddress{
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/functionisContract(address account) internalviewreturns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0// for contracts in construction, since the code is only stored at the end// of the constructor execution.return account.code.length>0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/functionsendValue(addresspayable 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");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/functionfunctionCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(address(this).balance>= value, "Address: insufficient balance for call");
(bool success, bytesmemory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target, bytesmemory data) internalviewreturns (bytesmemory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalviewreturns (bytesmemory) {
(bool success, bytesmemory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
(bool success, bytesmemory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/functionverifyCallResultFromTarget(address target,
bool success,
bytesmemory returndata,
stringmemory errorMessage
) internalviewreturns (bytesmemory) {
if (success) {
if (returndata.length==0) {
// only check isContract if the call was successful and the return data is empty// otherwise we already know that it was a contractrequire(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/functionverifyCallResult(bool success,
bytesmemory returndata,
stringmemory errorMessage
) internalpurereturns (bytesmemory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function_revert(bytesmemory returndata, stringmemory errorMessage) privatepure{
// Look for revert reason and bubble it up if presentif (returndata.length>0) {
// The easiest way to bubble the revert reason is using memory via assembly/// @solidity memory-safe-assemblyassembly {
let returndata_size :=mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
Contract Source Code
File 2 of 21: Array.sol
// SPDX-License-Identifier: MIT/*
* @dev Modified from original Array.sol from Clement Walter <clement0walter@gmail.com>
*/pragmasolidity ^0.8.0;errorEmptyArray();
errorGlueOutOfBounds(uint256 length);
libraryArray{
functionjoin(bytes[] memory a, bytesmemory glue) privatepurereturns (bytesmemory) {
uint256 inputPointer;
uint256 gluePointer;
assembly {
inputPointer := a
gluePointer := glue
}
return _joinReferenceType(inputPointer, gluePointer);
}
functionjoin(bytes[] memory a) internalpurereturns (bytesmemory) {
return join(a, bytes(""));
}
function_joinReferenceType(uint256 inputPointer,
uint256 gluePointer
) privatepurereturns (bytesmemory tempBytes) {
assembly {
// Get a location of some free memory and store it in tempBytes as// Solidity does for memory variables.
tempBytes :=mload(0x40)
// Skip the first 32 bytes where we will store the length of the resultlet memoryPointer :=add(tempBytes, 0x20)
// Load gluelet glueLength :=mload(gluePointer)
ifgt(glueLength, 0x20) {
revert(gluePointer, 0x20)
}
let glue :=mload(add(gluePointer, 0x20))
// Load the length (first 32 bytes)let inputLength :=mload(inputPointer)
let inputData :=add(inputPointer, 0x20)
let end :=add(inputData, mul(inputLength, 0x20))
// Initialize the length of the final stringlet stringLength :=0// Iterate over all strings (a string is itself an array).for {
let pointer := inputData
} lt(pointer, end) {
pointer :=add(pointer, 0x20)
} {
let currentStringArray :=mload(pointer)
let currentStringLength :=mload(currentStringArray)
stringLength :=add(stringLength, currentStringLength)
let currentStringBytesCount :=add(
div(currentStringLength, 0x20),
gt(mod(currentStringLength, 0x20), 0)
)
let currentPointer :=add(currentStringArray, 0x20)
for {
let copiedBytesCount :=0
} lt(copiedBytesCount, currentStringBytesCount) {
copiedBytesCount :=add(copiedBytesCount, 1)
} {
mstore(add(memoryPointer, mul(copiedBytesCount, 0x20)), mload(currentPointer))
currentPointer :=add(currentPointer, 0x20)
}
memoryPointer :=add(memoryPointer, currentStringLength)
mstore(memoryPointer, glue)
memoryPointer :=add(memoryPointer, glueLength)
}
mstore(tempBytes, add(stringLength, mul(sub(inputLength, 1), glueLength)))
mstore(0x40, and(add(memoryPointer, 31), not(31)))
}
return tempBytes;
}
}
Contract Source Code
File 3 of 21: ButerinCards.sol
//SPDX-License-Identifier: MIT/// @title JPEG Mining/// @author Xatarrer/// @notice Unauditedpragmasolidity ^0.8.0;import"./Array.sol";
import"./ButerinCardsLib.sol";
import"./ButerinCardsBackA.sol";
import"./ButerinCardsBackB.sol";
import"./ERC721Enumerable.sol";
import"./SSTORE2.sol";
import"./Ownable.sol";
import"./LibString.sol";
import"./MerkleProof.sol";
contractButerinCardsisERC721Enumerable, Ownable{
eventMined(addressindexed minerAddress,
uint256indexed uploadedKB,
uint256indexed tokenId,
uint8 phaseId,
uint16 tokenIdWithinPhase,
uint8 quoteId,
uint8 bgDirectionId,
uint8 bgPaletteId,
uint16 lastTokenIdInScan,
uint32 Nbytes,
uint8 Nicons,
uint32 seed
);
// State variablesmapping(address=>uint256) public Nmined; // Number of cards mined by an addressuint256[] public chunks; // Array of tightly pack card data and metadatastringpublic baseURLAnimation ="https://yellow-immense-spider-81.mypinata.cloud/ipfs/Qmczf1nd4uHzLxWRZ68pc2PWXBPKcRkoc39ZgQkB8X5bgy/index.html";
// Constantsstringprivateconstant _NAME ="Buterin Cards";
stringprivateconstant _SYMBOL ="VITALIK";
bytes32privateimmutable _ROOT;
uint256publicimmutable TOKEN_ID_FIRST_BLUE_CHROMINANCE; // TokenId of first blue chrominance chunkuint256publicimmutable TOKEN_ID_FIRST_RED_CHROMINANCE; // TokenId of first red chrominance chunkuint256publicimmutable N_EMPTY_BLUE_COLOR_CHUNKS;
uint256publicimmutable N_EMPTY_RED_COLOR_CHUNKS;
addresspublicimmutable JPEG_HEADER_POINTER; // Pointer to JPEG headerconstructor(bytes32 root,
stringmemory jpegHeader,
uint256 tokenIdFirstBlueChrominance,
uint256 tokenIdFirstRedChrominance,
uint256 NemptyBlueColorChunks,
uint256 NemptyRedColorChunks
) ERC721(_NAME, _SYMBOL) {
_ROOT = root;
JPEG_HEADER_POINTER = SSTORE2.write(bytes(jpegHeader));
TOKEN_ID_FIRST_BLUE_CHROMINANCE = tokenIdFirstBlueChrominance;
TOKEN_ID_FIRST_RED_CHROMINANCE = tokenIdFirstRedChrominance;
N_EMPTY_BLUE_COLOR_CHUNKS = NemptyBlueColorChunks;
N_EMPTY_RED_COLOR_CHUNKS = NemptyRedColorChunks;
}
functionsetBaseURLAnimation(stringcalldata newBaseURLAnimation) externalonlyOwner{
baseURLAnimation = newBaseURLAnimation;
}
functiontokenURI(uint256 tokenId) publicviewoverridereturns (stringmemory) {
require(_exists(tokenId), "Token does not exist");
// Retrieve chunk data
ButerinCardsLib.ChunkUnpacked memory chunk = unpackChunk(tokenId);
stringmemory cardIdStr = LibString.toString(tokenId +1);
stringmemory NiconsStr = LibString.toString(chunk.Nicons);
stringmemory NkilobytesStr = LibString.toString(chunk.Nbytes /1024);
bytes[] memory bytesSegments =newbytes[](43);
bytesSegments[0] =bytes("data:application/json;charset=UTF-8,%7B%22name%22%3A%22Buterin%20Card%20%23");
bytesSegments[1] =bytes(cardIdStr);
bytesSegments[2] =bytes(
"%22%2C%22description%22%3A%22Introducing%20the%20Buterin%20Cards%2C%20a%20unique%20on-chain%20collection%20of%202%2C015%20cards%20celebrating%20Ethereum's%20co-founder%2C%20Vitalik%20Buterin.%20Inspired%20by%20the%20iconic%20Nakamoto%20Cards%20on%20Bitcoin%2C%20the%20Buterin%20Cards%20aim%20to%20pay%20tribute%20to%20Vitalik's%20immense%20contributions%20to%20blockchain%20technology.%20%20%5Cn%5CnPermanently%20stored%20on%20the%20Ethereum%20blockchain%2C%20these%20cards%20are%20the%20result%20of%20a%20collaborative%20effort%20by%20JPEG%20miners%20who%20work%20together%20to%20upload%20each%20card's%20data%20on-chain.%20The%20face%20side%20of%20each%20card%20features%20an%20HTML%20and%20SVG-coded%20frame%20surrounding%20a%20JPEG%20image%20of%20Vitalik%20Buterin%2C%20designed%20by%20Xatarrer.%20At%20over%2010%20MB%2C%20this%20image%20holds%20the%20record%20for%20the%20largest%20stored%20JPEG%20on-chain%20at%20the%20time%20of%20minting.%20%20%5Cn%5CnAdding%20to%20the%20uniqueness%20of%20the%20cards%2C%20the%20face%20side%20background%2C%20designed%20by%20Pawe%C5%82%20Dudko%2C%20showcases%20mesmerizing%2C%20dynamically%20moving%20rays%20of%20color.%20As%20a%20fusion%20of%20profile%20picture%20(pfp)%20NFTs%20and%20generative%20art%2C%20the%20Buterin%20Cards%20possess%20randomly-selected%20attributes%20during%20minting%2C%20such%20as%20one%20of%2045%20possible%20quotes%20from%20Vitalik.%20%20%5Cn%5CnThe%20Buterin%20Cards%20are%20the%20second%20collection%20to%20utilize%20a%20technique%20called%20JPEG%20Mining.%20In%20this%20process%2C%20the%20miners%20are%20responsible%20for%20uploading%20the%20NFT%20components%2C%20including%20the%20HTML%2C%20SVG%2C%20and%20Vitalik%20JPEG.%20Using%20Progressive%20JPEG%20technology%2C%20the%20image%20is%20revealed%20as%20it%20is%20mined%2C%20and%20miners%20are%20rewarded%20with%20a%20Buterin%20Card%20for%20their%20efforts.%20%20%5Cn%5CnThe%20JPEG%20mining%20process%20of%20the%20Buterin%20Cards%20consists%20of%20six%20phases%3A%20%20%5Cn%5Cu270F%5CuFE0F%20Pencil%20Drawing%3A%20Miners%20upload%20the%20HTML%20and%20SVG%2C%20receiving%20a%20card%20with%20a%20hand-drawn%20vectorized%20SVG%20version%20of%20the%20JPEG%2C%20as%20no%20JPEG%20data%20is%20available%20yet.%20%20%5Cn%5CuD83D%5CuDD33%20Black%20%26%20White%3A%20The%20intensity%20component%20of%20the%20progressive%20JPEG%20is%20uploaded%2C%20rendering%20the%20image%20in%20pure%20black%20and%20white.%20%20%5Cn%5CuD83C%5CuDF2B%5CuFE0F%20Grey%20Shades%3A%20Additional%20bits%20for%20the%20intensity%20component%20reveal%20a%20range%20of%20grey%20tones.%20%20%5Cn%5CuD83D%5CuDFE6%20Blue%20Chroma%3A%20The%20blue%20chroma%20is%20uploaded%2C%20introducing%20blue%20and%20green%20hues%20to%20the%20JPEG.%20%20%5Cn%5CuD83D%5CuDFE5%20Red%20Chroma%3A%20The%20red%20chroma%20is%20added%2C%20infusing%20red%20and%20pink%20shades%20into%20the%20image.%20%20%5Cn%5CuD83C%5CuDF04%20In%20the%20final%20phase%2C%20the%20AC%20components%20are%20uploaded%2C%20enhancing%20the%20image%20resolution.%22%2C%22attributes%22%3A%5B%7B%22trait_type%22%3A%22Quote%20Title%22%2C%22value%22%3A%22"
);
bytesSegments[3] =bytes(ButerinCardsLib.quoteName(chunk.quoteId));
bytesSegments[4] =bytes("%22%7D%2C%7B%22trait_type%22%3A%22Phase%22%2C%22value%22%3A%22");
bytesSegments[5] =bytes(ButerinCardsLib.phaseName(chunk.phaseId));
bytesSegments[6] =bytes("%22%7D%2C%7B%22trait_type%22%3A%22Background%20Direction%22%2C%22value%22%3A%22");
bytesSegments[7] =bytes(ButerinCardsLib.bgDirection(chunk.bgDirectionId));
bytesSegments[8] =bytes("%22%7D%2C%7B%22trait_type%22%3A%22Background%20Palette%22%2C%22value%22%3A%22");
bytesSegments[9] =bytes(ButerinCardsLib.bgPalette(chunk.bgPaletteId));
bytesSegments[10] =bytes(
"%22%7D%2C%7B%22display_type%22%3A%22boost_number%22%2C%22trait_type%22%3A%22Number%20of%20Icons%22%2C%22value%22%3A"
);
bytesSegments[11] =bytes(NiconsStr);
bytesSegments[12] =bytes("%7D%2C%7B%22trait_type%22%3A%22Uploaded%20%5BKB%5D%22%2C%22value%22%3A");
bytesSegments[13] =bytes(NkilobytesStr);
bytesSegments[14] =bytes("%7D%5D%2C%22animation_url%22%3A%22");
bytesSegments[15] =bytes(baseURLAnimation);
bytesSegments[16] =bytes("?cardId=");
bytesSegments[17] =bytes(cardIdStr);
bytesSegments[18] =bytes("&phaseId=");
bytesSegments[19] =bytes(LibString.toString(chunk.phaseId));
bytesSegments[20] =bytes("&tokenIdWithinPhase=");
bytesSegments[21] =bytes(LibString.toString(chunk.tokenIdWithinPhase));
bytesSegments[22] =bytes("&kiloBytes=");
bytesSegments[23] =bytes(NkilobytesStr);
bytesSegments[24] =bytes(""eId=");
bytesSegments[25] =bytes(LibString.toString(chunk.quoteId));
bytesSegments[26] =bytes("&bgDirection=");
bytesSegments[27] =bytes(LibString.toString(chunk.bgDirectionId));
bytesSegments[28] =bytes("&bgPalette=");
bytesSegments[29] =bytes(LibString.toString(chunk.bgPaletteId));
bytesSegments[30] =bytes("&seed=");
bytesSegments[31] =bytes(LibString.toString(chunk.seed));
bytesSegments[32] =bytes("&Nicons=");
bytesSegments[33] =bytes(NiconsStr);
bytesSegments[34] =bytes("%22%2C%22image%22%3A%22");
bytesSegments[35] =bytes(ButerinCardsBackA.cardBackPiece0());
bytesSegments[36] =bytes(ButerinCardsBackA.cardBackPiece1(chunk.Nicons));
bytesSegments[37] =bytes(ButerinCardsBackB.cardBackPiece2());
bytesSegments[38] =bytes(chunk.quoteId <8 ? ".2" : "0");
bytesSegments[39] =bytes(ButerinCardsBackB.cardBackPiece3());
bytesSegments[40] =bytes(ButerinCardsLib.cardBackPiece4());
bytesSegments[41] =bytes(ButerinCardsLib.cardBackPiece5(chunk.phaseId));
bytesSegments[42] =bytes("%22%7D");
returnstring(Array.join(bytesSegments));
}
functiononchainAnimation(uint256 tokenId) publicviewreturns (stringmemory) {
require(_exists(tokenId), "Token does not exist");
// Retrieve chunk data
ButerinCardsLib.ChunkUnpacked memory chunk = unpackChunk(tokenId);
// Communicates to the miner that its card is not fully uploaded just yetif (chunk.lastTokenIdInScan >= totalSupply()) ButerinCardsLib.cardNotAvailable(chunk.lastTokenIdInScan);
uint256 NHTMLChunks = unpackChunk(0).lastTokenIdInScan +1;
uint256 NJPEGChunks;
/**
Let's fuse all the parts together:
If phaseId == 0, then
1. _HTML_BEGINNING
2. User parameters separated by commas
3...M+1. HTML scans
If phaseId > 0, then
1. _HTML_BEGINNING
2. User parameters separated by commas
3. JPEG header
4...(N+2). JPEG scans
N+4. JPEG footer
N+5...N+M+4. HTML scans
Know that
N + M = tokenId +1
*/// Create big array of bytes and copy necessary segmentsbytes[] memory bytesSegments =newbytes[](
chunk.phaseId ==0 ? chunk.lastTokenIdInScan +3 : chunk.phaseId ==1|| chunk.phaseId ==2
? chunk.lastTokenIdInScan +5
: chunk.phaseId ==3// Ads red empty chroma NOT blue empty chroma NOR red chroma
? chunk.lastTokenIdInScan +5- N_EMPTY_BLUE_COLOR_CHUNKS
: chunk.phaseId ==4// Add empty blue chroma NOT red empty chroma NOR blue chroma
? chunk.lastTokenIdInScan +5+
TOKEN_ID_FIRST_BLUE_CHROMINANCE -
TOKEN_ID_FIRST_RED_CHROMINANCE -
N_EMPTY_RED_COLOR_CHUNKS
: chunk.lastTokenIdInScan +5- N_EMPTY_BLUE_COLOR_CHUNKS - N_EMPTY_RED_COLOR_CHUNKS
);
bytesSegments[0] = htmlHeader();
uint256 ind;
if (chunk.phaseId >0) {
// JPEG header
bytesSegments[2] = SSTORE2.read(JPEG_HEADER_POINTER);
// Number JPEG chunks (includes all chromas (including empty) regardless)
NJPEGChunks = chunk.lastTokenIdInScan +1- NHTMLChunks;
bytesmemory tempChunk;
// Add JPEG chunksfor (
uint i = NHTMLChunks + N_EMPTY_BLUE_COLOR_CHUNKS + N_EMPTY_RED_COLOR_CHUNKS;
i < NHTMLChunks + NJPEGChunks;
i++
) {
if (chunk.phaseId !=4|| i < TOKEN_ID_FIRST_BLUE_CHROMINANCE) {
tempChunk = SSTORE2.read(unpackChunk(i).dataPointer);
ind = i - NHTMLChunks - N_EMPTY_BLUE_COLOR_CHUNKS - N_EMPTY_RED_COLOR_CHUNKS +3;
bytesSegments[ind] = tempChunk;
} elseif (i >= TOKEN_ID_FIRST_RED_CHROMINANCE) {
// We skip blue chroma in phase 4
tempChunk = SSTORE2.read(unpackChunk(i).dataPointer);
ind =
i -
NHTMLChunks -
N_EMPTY_BLUE_COLOR_CHUNKS -
N_EMPTY_RED_COLOR_CHUNKS +
TOKEN_ID_FIRST_BLUE_CHROMINANCE -
TOKEN_ID_FIRST_RED_CHROMINANCE +3;
bytesSegments[ind] = tempChunk;
}
}
// Add empty blue color chunks if necessaryfor (uint256 i = NHTMLChunks; i < NHTMLChunks + N_EMPTY_BLUE_COLOR_CHUNKS; i++) {
if (chunk.phaseId ==1|| chunk.phaseId ==2) {
// B&W, Grey Tones and Red Chroma phases need empty blue chroma
tempChunk = SSTORE2.read(unpackChunk(i).dataPointer);
ind = i + NJPEGChunks - NHTMLChunks - N_EMPTY_BLUE_COLOR_CHUNKS - N_EMPTY_RED_COLOR_CHUNKS +3;
bytesSegments[ind] = tempChunk;
} elseif (chunk.phaseId ==4) {
// Red Chroma phase needs empty blue chroma
tempChunk = SSTORE2.read(unpackChunk(i).dataPointer);
ind =
i +
NJPEGChunks -
NHTMLChunks -
N_EMPTY_BLUE_COLOR_CHUNKS -
N_EMPTY_RED_COLOR_CHUNKS +
TOKEN_ID_FIRST_BLUE_CHROMINANCE -
TOKEN_ID_FIRST_RED_CHROMINANCE +3;
bytesSegments[ind] = tempChunk;
}
}
// Add empty red color chunks if necessaryfor (
uint i = NHTMLChunks + N_EMPTY_BLUE_COLOR_CHUNKS;
i < NHTMLChunks + N_EMPTY_BLUE_COLOR_CHUNKS + N_EMPTY_RED_COLOR_CHUNKS;
i++
) {
if (chunk.phaseId ==1|| chunk.phaseId ==2) {
// B&W and Grey Tones phases need empty red chroma
tempChunk = SSTORE2.read(unpackChunk(i).dataPointer);
ind = i + NJPEGChunks - NHTMLChunks - N_EMPTY_BLUE_COLOR_CHUNKS - N_EMPTY_RED_COLOR_CHUNKS +3;
bytesSegments[ind] = tempChunk;
} elseif (chunk.phaseId ==3) {
// Blue Chroma phase needs empty red chroma
tempChunk = SSTORE2.read(unpackChunk(i).dataPointer);
ind = i + NJPEGChunks - NHTMLChunks -2* N_EMPTY_BLUE_COLOR_CHUNKS - N_EMPTY_RED_COLOR_CHUNKS +3;
bytesSegments[ind] = tempChunk;
}
}
// JPEG footer
bytesSegments[ind +1] = jpegFooter();
// Correct number JPEG chunks (exclude empty chroma and blue chroma if necessary)if (chunk.phaseId ==3|| chunk.phaseId ==5) NJPEGChunks -= N_EMPTY_BLUE_COLOR_CHUNKS;
if (chunk.phaseId >=4) NJPEGChunks -= N_EMPTY_RED_COLOR_CHUNKS;
if (chunk.phaseId ==4) NJPEGChunks -= TOKEN_ID_FIRST_RED_CHROMINANCE - TOKEN_ID_FIRST_BLUE_CHROMINANCE;
}
// HTML chunksfor (uint256 i =0; i < NHTMLChunks; i++) {
ind = i + NJPEGChunks + (chunk.phaseId >0 ? 4 : 2);
bytesSegments[ind] = SSTORE2.read(unpackChunk(i).dataPointer);
}
// HTML parameters
bytesSegments[1] = ButerinCardsLib.paramsHTML(tokenId, chunk);
returnstring(Array.join(bytesSegments));
}
functionunpackChunk(uint tokenId) publicviewreturns (ButerinCardsLib.ChunkUnpacked memory) {
uint chunk = chunks[tokenId];
return
ButerinCardsLib.ChunkUnpacked({
dataPointer: address(uint160(chunk)), // 20 bytes
phaseId: uint8((chunk >>160) &0x7), // 3 bits
tokenIdWithinPhase: uint16((chunk >>163) &0x7FF), // 11 bits
lastTokenIdInScan: uint16((chunk >>174) &0x7FF), // 11 bits
quoteId: uint8((chunk >>185) &0x3F), // 6 bits
bgDirectionId: uint8((chunk >>191) &0x3), // 2 bits
bgPaletteId: uint8((chunk >>193) &0xF), // 4 bits
Nicons: uint8((chunk >>197) &0x3), // 2 bits
Nbytes: uint32((chunk >>199) &0x1FFFFFF), // 25 bits
seed: uint32((chunk >>224) &0xFFFFFFFF) // 32 bits
});
}
function_packChunk(ButerinCardsLib.ChunkUnpacked memory chunk) privatepurereturns (uint) {
returnuint(uint160(chunk.dataPointer)) |
(uint(chunk.phaseId) <<160) |
(uint(chunk.tokenIdWithinPhase) <<163) |
(uint(chunk.lastTokenIdInScan) <<174) |
(uint(chunk.quoteId) <<185) |
(uint(chunk.bgDirectionId) <<191) |
(uint(chunk.bgPaletteId) <<193) |
(uint(chunk.Nicons) <<197) |
(uint(chunk.Nbytes) <<199) |
(uint(chunk.seed) <<224);
}
function_rndParams(ButerinCardsLib.ChunkUnpacked memory chunk, uint256 tokenId_) privateview{
uint256 rndUniform =uint256(
keccak256(
abi.encodePacked(block.number, block.timestamp, block.basefee, block.coinbase, msg.sender, tokenId_)
)
);
chunk.seed =uint32(rndUniform); // Uniform distribution between 0 and 2**32-1uint temp = rndUniform >>32;
chunk.bgDirectionId = temp &0x3>1 ? 2 : temp &0x1==1 ? 1 : 0; // Diagonal (2) has 0.5 probability, vertical(1) and horizontal(0) have 0.25 probability
temp = (rndUniform >>34) &0xFFFF; // Use 16 bits to approximate custom distribution between 1 and 10if (temp <0x30A4) chunk.bgPaletteId =1;
elseif (temp <0x5C29) chunk.bgPaletteId =2;
elseif (temp <0x8290) chunk.bgPaletteId =3;
elseif (temp <0xA3D8) chunk.bgPaletteId =4;
elseif (temp <0xC000) chunk.bgPaletteId =5;
elseif (temp <0xD70B) chunk.bgPaletteId =6;
elseif (temp <0xE8F6) chunk.bgPaletteId =7;
elseif (temp <0xF5C3) chunk.bgPaletteId =8;
elseif (temp <0xFD71) chunk.bgPaletteId =9;
else chunk.bgPaletteId =10;
temp = (rndUniform >>240) &0xFFFF; // Use 16 bits to approximate custom distribution between 0 and 44if (temp <0x02ba) chunk.quoteId =0;
elseif (temp <0x0597) chunk.quoteId =1;
elseif (temp <0x0897) chunk.quoteId =2;
elseif (temp <0x0bb9) chunk.quoteId =3;
elseif (temp <0x0efd) chunk.quoteId =4;
elseif (temp <0x1264) chunk.quoteId =5;
elseif (temp <0x15ed) chunk.quoteId =6;
elseif (temp <0x1999) chunk.quoteId =7;
elseif (temp <0x1d67) chunk.quoteId =8;
elseif (temp <0x2158) chunk.quoteId =9;
elseif (temp <0x256b) chunk.quoteId =10;
elseif (temp <0x29a0) chunk.quoteId =11;
elseif (temp <0x2df8) chunk.quoteId =12;
elseif (temp <0x3273) chunk.quoteId =13;
elseif (temp <0x3710) chunk.quoteId =14;
elseif (temp <0x3bcf) chunk.quoteId =15;
elseif (temp <0x40b1) chunk.quoteId =16;
elseif (temp <0x45b5) chunk.quoteId =17;
elseif (temp <0x4adb) chunk.quoteId =18;
elseif (temp <0x5024) chunk.quoteId =19;
elseif (temp <0x5590) chunk.quoteId =20;
elseif (temp <0x5b1e) chunk.quoteId =21;
elseif (temp <0x60ce) chunk.quoteId =22;
elseif (temp <0x66a1) chunk.quoteId =23;
elseif (temp <0x6c96) chunk.quoteId =24;
elseif (temp <0x72ae) chunk.quoteId =25;
elseif (temp <0x78e8) chunk.quoteId =26;
elseif (temp <0x7f45) chunk.quoteId =27;
elseif (temp <0x85c4) chunk.quoteId =28;
elseif (temp <0x8c65) chunk.quoteId =29;
elseif (temp <0x9329) chunk.quoteId =30;
elseif (temp <0x9a0f) chunk.quoteId =31;
elseif (temp <0xa118) chunk.quoteId =32;
elseif (temp <0xa843) chunk.quoteId =33;
elseif (temp <0xaf91) chunk.quoteId =34;
elseif (temp <0xb701) chunk.quoteId =35;
elseif (temp <0xbe93) chunk.quoteId =36;
elseif (temp <0xc648) chunk.quoteId =37;
elseif (temp <0xce20) chunk.quoteId =38;
elseif (temp <0xd61a) chunk.quoteId =39;
elseif (temp <0xde36) chunk.quoteId =40;
elseif (temp <0xe675) chunk.quoteId =41;
elseif (temp <0xeed6) chunk.quoteId =42;
elseif (temp <0xf759) chunk.quoteId =43;
else chunk.quoteId =44;
}
/// @param dataChunk will be a piece of HTML in UTF-8 or a piece of JPEG in base64functionmine(stringcalldata dataChunk,
uint8 phaseId,
uint16 tokenIdWithinPhase,
uint16 lastTokenIdInScan,
bytes32[] calldata proof
) external{
// Get the next tokenIdxuint256 tokenId = totalSupply();
// Check hash matches
_verifyDataChunk(dataChunk, tokenId, phaseId, tokenIdWithinPhase, lastTokenIdInScan, proof);
// Generate random color, quote and seed
ButerinCardsLib.ChunkUnpacked memory chunk;
_rndParams(chunk, tokenId);
// Pass rest of data
chunk.dataPointer = SSTORE2.write(bytes(dataChunk));
chunk.phaseId = phaseId;
chunk.tokenIdWithinPhase = tokenIdWithinPhase;
chunk.lastTokenIdInScan = lastTokenIdInScan;
chunk.Nicons =uint8(Nmined[msg.sender] %3);
chunk.Nbytes =uint32(bytes(dataChunk).length);
if (tokenId >0) chunk.Nbytes += unpackChunk(tokenId -1).Nbytes;
// Pack and store chunk
chunks.push(_packChunk(chunk));
// Mint card
_mint(msg.sender, tokenId);
// Increment counter of mined cards by sender
Nmined[msg.sender]++;
// Emit eventemit Mined(
msg.sender,
bytes(dataChunk).length,
tokenId,
phaseId,
tokenIdWithinPhase,
chunk.quoteId,
chunk.bgDirectionId,
chunk.bgPaletteId,
lastTokenIdInScan,
chunk.Nbytes,
chunk.Nicons,
chunk.seed
);
}
function_verifyDataChunk(stringcalldata dataChunk,
uint256 tokenId,
uint8 phaseId,
uint16 tokenIdWithinPhase,
uint16 lastTokenIdInScan,
bytes32[] calldata proof
) privateview{
bytes32 leaf =keccak256(
bytes.concat(keccak256(abi.encode(dataChunk, tokenId, phaseId, tokenIdWithinPhase, lastTokenIdInScan)))
);
require(MerkleProof.verifyCalldata(proof, _ROOT, leaf), "Invalid data");
}
functionhtmlHeader() publicpurereturns (bytesmemory) {
returnbytes(
"data:text/html;charset=utf-8,%3C!DOCTYPE%20html%3E%0D%0A%3Chtml%3E%0D%0A%20%20%20%20%3Chead%3E%0D%0A%20%20%20%20%20%20%20%20%3Cscript%3E%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20%5B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cardId%2C%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20phaseId%2C%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20tokenIdWithinPhase%2C%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20kiloBytes%2C%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20quoteId%2C%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20bgDirection%2C%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20bgPalette%2C%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Nicons%2C%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20seed%2C%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20jpegB64%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%5D%20%3D%20%5B"
);
}
functionjpegFooter() publicpurereturns (bytesmemory) {
returnbytes("/9k=");
}
}
//SPDX-License-Identifier: MIT/// @title JPEG Mining/// @author Xatarrer/// @notice Unauditedpragmasolidity ^0.8.0;import"./Array.sol";
import"./LibString.sol";
libraryButerinCardsLib{
structChunkUnpacked {
address dataPointer; // uploadedKB is obtained by getting the data and checking its length.uint8 phaseId; // 0 = HTML, 1 = B&W, 2= Grey tones, 3 = Blue chroma, 4 = Red chroma, 5 = Resolution. Value passed by miner.uint16 tokenIdWithinPhase; // Value passed by miner.uint16 lastTokenIdInScan; // Necessary for knowing when the NFT will be available. Value passed by miner.uint8 quoteId; // Range [0, 44]. Fixed randomly during mining.uint8 bgDirectionId; // Range [0, 2]. Fixed randomly during mining.uint8 bgPaletteId; // Range [1, 10]. Fixed randomly during mining.uint8 Nicons; // Range [0, 2]. Based on the #mint of a miner modulo 3uint32 Nbytes; // Counts bytes uploaded up to this chunk.uint32 seed; // Fixed randomly during mining.
}
functionparamsHTML(uint256 tokenId, ChunkUnpacked memory chunk) externalpurereturns (bytesmemory) {
returnbytes(
string.concat(
LibString.toString(tokenId +1),
"%2C",
LibString.toString(chunk.phaseId),
"%2C",
LibString.toString(chunk.tokenIdWithinPhase),
"%2C",
LibString.toString(chunk.Nbytes /1024),
"%2C",
LibString.toString(chunk.quoteId),
"%2C",
LibString.toString(chunk.bgDirectionId),
"%2C",
LibString.toString(chunk.bgPaletteId),
"%2C",
LibString.toString(chunk.Nicons),
"%2C",
LibString.toString(chunk.seed),
"%2C%22"
)
);
}
functionquoteName(uint quoteId) publicpurereturns (stringmemory) {
string[45] memory quotes = [
"%F0%9F%A6%84%20WoW",
"%F0%9F%A6%84%20The%20Hard%20Forkoooooor",
"%F0%9F%A6%84%20Bitcoiner",
"%F0%9F%A6%84%20Weeeeeeee!",
"%F0%9F%A6%84%20Humanton",
"%F0%9F%A6%84%20That%20Darn%20Rock",
"%F0%9F%A6%84%20Jason",
"%F0%9F%A6%84%20Ultra-Sound%20Money",
"Incentives",
"Sourceful",
"Paradoxical",
"Currency%20%26%20Protocol",
"Abnormal",
"Institutional",
"Revolution",
"Peer-to-peer",
"Cross-platform",
"Dub",
"Fundamentalism",
"Signal",
"Programmable",
"Scripter",
"E-God",
"Credibly%20Insane",
"Exponential",
"Asian%20Fusion",
"Blockchain%20Centrist",
"2017%20Dec%2013",
"Slippery%20Slope%20Fallacy",
"Buterin's%20Law",
"Elliptic%20Brains",
"Social%20Capital",
"Order",
"Nope",
"Legitimate",
"Theatrical",
"Blockchain",
"Metaverse",
"Paradox%20of%20Diversity",
"Freedom",
"Reminder",
"Pluralist",
"Alfalfa",
"Beware",
"Sound"
];
return quotes[quoteId];
}
functionphaseName(uint phaseId) publicpurereturns (stringmemory) {
string[6] memory phases = [
"Pencil%20Drawing",
"Black%20%26%20White",
"Grey%20Shades",
"Blue%20Chroma",
"Red%20Chroma",
"Resolution"
];
return phases[phaseId];
}
functionbgDirection(uint bgDirectionId) publicpurereturns (stringmemory) {
string[3] memory bgDirections = ["Horizontal", "Vertical", "Diagonal"];
return bgDirections[bgDirectionId];
}
functionbgPalette(uint bgPaletteId) publicpurereturns (stringmemory) {
string[10] memory bgPalettes = [
"Oceanic%20Twilight",
"Earthen%20Tones",
"Calm%20Coastline",
"Warm%20Sunset",
"Tropical%20Skies",
"Mystic%20Blossoms",
"Oceanic%20Contrast",
"Autumn%20Breeze",
"Enchanted%20Forest",
"Vibrant%20Spectrum"
];
return bgPalettes[bgPaletteId -1];
}
functioncardNotAvailable(uint256 lastTokenIdInScan) externalpurereturns (stringmemory dataURI) {
returnstring.concat(
"data%3Aimage%2Fsvg%2Bxml%3Bcharset%3DUTF-8%2C%253Csvg%250D%250A%2520%2520%2520%2520viewBox%253D%2522-20%25200%252040%252030%2522%250D%250A%2520%2520%2520%2520xmlns%253D%2522http%253A%252F%252Fwww.w3.org%252F2000%252Fsvg%2522%250D%250A%2520%2520%2520%2520xmlns%253Axlink%253D%2522http%253A%252F%252Fwww.w3.org%252F1999%252Fxlink%2522%250D%250A%2520%2520%2520%2520style%253D%2522font-size%253A%252023%2525%2522%250D%250A%253E%250D%250A%2520%2520%2520%2520%253Ctext%2520x%253D%25220%2522%2520y%253D%25225%2522%2520text-anchor%253D%2522middle%2522%253EThis%2520card%253C%252Ftext%253E%250D%250A%2520%2520%2520%2520%253Ctext%2520x%253D%25220%2522%2520y%253D%252210%2522%2520text-anchor%253D%2522middle%2522%253Ewill%2520be%2520visible%253C%252Ftext%253E%250D%250A%2520%2520%2520%2520%253Ctext%2520x%253D%25220%2522%2520y%253D%252215%2522%2520text-anchor%253D%2522middle%2522%253Ewhen%2520card%2520%2523",
LibString.toString(lastTokenIdInScan),
"%253C%252Ftext%253E%250D%250A%2520%2520%2520%2520%253Ctext%2520x%253D%25220%2522%2520y%253D%252220%2522%2520text-anchor%253D%2522middle%2522%253Eis%2520mined.%253C%252Ftext%253E%250D%250A%253C%252Fsvg%253E%250D%250A"
);
}
functioncardBackPiece4() externalpurereturns (stringmemory piece) {
return".828%25208.54-6.626%25202.396-1.748%25207.753-3.776%25202.757-.368-3.731%25201.454-7.517%25207.77-11.297%25206.995zm13.766-9.146c1.432-2.348%25205.907-3.241%25201.49-.842-.434.313-.786%25201.223-1.49.842z%2522%252F%253E%253Cpath%2520fill%253D%2522%25234ea2a6%2522%2520d%253D%2522M54.291%2520137.105c-11.816-.332-23.664-.112-35.443-1.265%25202.076-.516%25204.01-2.106%25203.14-2.782%25202.461%25201.042%25206.61-2.585%25201.805-1.548-7.001-.493%25202.024-5.8-1.018-10.03-2.747-4.168%25204.142-8.151%25204.955-3.387-.48%25205.004-1.58%252012.544%25201.252%252016.417h11.903c-5.18-3.617%25208.956-2.394%25201.658-3.734-2.88.288-4.808-1.187-2.171-3.247.853-6.79-11.322-9.534-6.531-16.58%25204.15-3.275%25205.73-7.556%25206.904-12.317%25206.453.103%252012.379-3.037%252018.503-4.809%25204.817%25204.8%252012.247.207%252017.631-.477-3.85-3.28-12.308-3.37-9.88-10.701-.891-5.11-7.461-8.144-5.953-13.852.187-2.586-.86-11.661%25201.481-5.185%25203.612%25202.898%25203.925%25207.41%25205.794%252010.49%25206.18-.322%25202.576-9.005%25203.304-13.164.224-2.375-1.394-11.042%25202.287-5.01.508%25204.707.008%25209.848.694%252014.789-.324%25206.677-11.087%25206.38-9.05-1.014-3.461-1.727-.532%25206.13%25201.715%25206.805%25204.529%25204.016-.129%252012.879%25207.235%252013.51%25206.835.423%25208.05%25206.516%25205.862%252011.874-.264%25205.065.046%252012.105-5.815%252013.911-5.136-4.211%25202.259-3.518%25203.592-5.538-1.038-1.388-8.929-.432-3.973-2.461%25201.798-3.742%25207.374-12.578-1.302-10.54-5.344%25201.86-10.722-1.39-15.785.444-3.976%25202.563-9.258%25201.816-9.218%25207.56-1.177%25205.76-12.54%25207.217-7.253%252013.76%25204.323%25204.302%25204.14%252010.754%25207.199%252015.62%252011.313.442%252022.672-.26%252033.953.933-4.043%25204.041-11.295.196-16.667%25201.602-3.603-.01-7.206-.033-10.808-.074zm11.359-16.668c-4.435-3.667%25208.421-1.861%25202.337-4.491-2.818.462-5.673-1.28-1.177-2.188%25201.878-2.608%25203.328-4.422%25204.057-.156%25201.712%25202.397-2.594%252011.122-5.217%25206.835zm-52.195-.689c2.965-1.328%25207.267-10.393%25201.964-4.532-3.968%25203.73-12.944-2.34-9.82-4.418%25202.832%25207.454%252013.29-.292%25205.9-4.728-7.347-4.139-7.597-14.924.143-18.793%25203.004-3.224%252016.256-3.829%252010.524%25202.805-1.248%25202.598.555%252010.033-3.705%25204.681-1.726-2.67%25202.636-10.802-2.71-4.992-4.002%25205.093-.68%252014.904%25204.69%252016.967%25206.516-3.126-4.114-7.218-4.381-11.557-.75-2.785%25201.157-5.387.967-.771%25201.432%25205.034%25208.216%25207.242%25208.124%252013.425-.734%25203.085%25203.498%25201.121.145%25204.278-4.922%25205.244%25201.854-4.196-2.375-5.767.13%25205.958-2.648%252012.751-9.466%252013.402zm.464-14.543c-.617-2.554-5.475-10.652-3.245-3.719.843%25201.414%25201.816%25202.838%25203.245%25203.72zm55.52-31.921c-2.38-3.685%25203.39-3.024%25200%25200zm-39.311-2.165c-1.416-6.001%252011.871-2.063%25204.173-2.13-1.633-.105-3.54.438-4.173%25202.13zm9.366-3.05c-4.091-2.369-9.25-5.39-10.822-9.803-.193-4.002%25203.613%25203.62%25206.66%25201.114%25203.73-.555%25208.945-3.666%25209.29-7.133-1.946%25203.017-5.333%25207.087-8.596%25203.082-2.775.728-6.169%25201.709-2.886-1.872%25201.69-1.305%252010.958-1.269%25207.969-2.52-3.688%25202.029-8.54-5.505-5.352-6.307%25203.795%25205.774%25209.63.167%252014.888.65%25202.724-.527-3.312-6.28.288-4.907%25202.384%25202.95%25207.708%25201.822%252010.624%25204.392-.514-2.49-.318-8.022%25201.488-2.831.503%25204.663%25208.113%25202.904%25207.375%25203.96-2%25204.874%25206.252-3.35%25202.05%25202.306-1.5%25202.753-7.71%25204.256-3.765-.36%25203.364-6.948-4.708%25204.313-4.89-.983-4.517-.761-14.364%25201.26-15.373%25201.527%25205.2.003%252010.302-2.312%252015.512-1.159-6.798%25201.35-15.67%25202.305-18.245%25209.973-1.217%25203.838.367%252012.093-6.215%252010.872zm1.17-2.82c3.407-4.633-9.658-1.052-1.732.245.616.153%25201.151-.069%25201.732-.245zm15.511-20.547c-1.207-3.563-4.684.935%25200%25200zM68.693%252059.71c-5.548-4.057%25204.373-1.526%25200%25200zm6.278-7.368c-6.526-6.566%25206.88-1.223%25200%25200z%2522%252F%253E%253Cpath%2520fill%253D%2522%2523bb438c%2522%2520d%253D%2522M54.291%2520137.105c-11.816-.332-23.664-.112-35.443-1.265%25202.076-.516%25204.01-2.106%25203.14-2.782%25202.461%25201.042%25206.61-2.585%25201.805-1.548-7.001-.493%25202.024-5.8-1.018-10.03-2.67-4.147%25203.904-8.095%25205-3.448-.768%25205.124-1.225%252011.884.864%252016.478h12.246c-5.18-3.617%25208.956-2.394%25201.658-3.734-2.88.288-4.808-1.187-2.171-3.247.853-6.79-11.322-9.534-6.531-16.579%25204.15-3.276%25205.73-7.557%25206.904-12.318%25206.453.103%252012.379-3.037%252018.503-4.809%25204.817%25204.8%252012.247.207%252017.631-.477-3.85-3.28-12.308-3.37-9.88-10.701-.891-5.11-7.461-8.144-5.953-13.852.187-2.586-.86-11.661%25201.481-5.185%25203.612%25202.898%25203.925%25207.41%25205.794%252010.49%25206.18-.322%25202.576-9.005%25203.304-13.164.372-2.166-1.578-10.744%25202.151-5.247.738%25204.773.157%252010.043.799%252015.083-.038%25206.414-11.118%25206.426-8.88-.705-3.097-3.39-1.33%25205.412%25201.324%25206.08%25204.73%25204.496.125%252013.918%25208.513%252014.2%25208.325.826%25205.123%25208.843%25204.62%252014.276.835%25203.798-2.372%252013.305-6.722%25209.95-3.751-4.128%25209.391-2.733%25202.772-5.073-1.986.561-5.932-.851-2.03-1.698%25201.798-3.742%25207.374-12.578-1.302-10.54-5.344%25201.86-10.722-1.39-15.785.444-3.976%25202.563-9.258%25201.816-9.218%25207.56-1.177%25205.76-12.54%25207.217-7.253%252013.76%25204.323%25204.302%25204.14%252010.754%25207.199%252015.62%252011.313.442%252022.672-.26%252033.953.933-4.043%25204.041-11.295.196-16.667%25201.602-3.603-.01-7.206-.033-10.808-.074zm11.359-16.668c-4.435-3.667%25208.421-1.861%25202.337-4.491-2.818.462-5.673-1.28-1.177-2.188%25201.878-2.608%25203.328-4.422%25204.057-.156%25201.712%25202.397-2.594%252011.122-5.217%25206.835zm-52.195-.689c2.965-1.328%25207.267-10.393%25201.964-4.532-3.86%25203.762-13.056-2.4-9.715-4.296%25203.046%25207.013%252012.95.01%25206.116-4.577-2.288-2.012-10.037-9.375-2.621-8.432-.42-3.242%25205.62-9.401%25201.38-3.139-2.272%25202.99%25201.69%252011.017%25202.892%25209.286-.646-2.26-5.228-7.29-.54-5.011%25201.5-2.991.345-3.77%25201.574-.077.19%25203.943%25207.555%252011.977%25207.812%25204.592-2.35-3.465-8.896-8.167-5.484-12.064-1.387%25207.178%25209.927%25209.852%25207.93%252017.108-.406%25202.358%25204.267.685.726%25203.405-1.819%25202.57-3.914%25202.05-1.39-.565%25201.678-2.6-2.433-7.987-1.492-2.311.148%25205.073-4.011%252010.177-9.152%252010.613zm7.386-22.997c-4.707-2.048%25205.25-13.376.835-5.89-1.048%25201.426%25201.261%25205.786-.835%25205.89zm48.598-23.467c-2.38-3.685%25203.39-3.024%25200%25200zm-39.311-2.165c-1.416-6.001%252011.871-2.063%25204.173-2.13-1.633-.105-3.54.438-4.173%25202.13zm9.366-3.05c-4.091-2.369-9.25-5.39-10.822-9.803-.193-4.002%25203.613%25203.62%25206.66%25201.114%25203.73-.555%25208.945-3.666%25209.29-7.133-1.946%25203.017-5.333%25207.087-8.596%25203.082-2.775.728-6.169%25201.709-2.886-1.872%25201.69-1.305%252010.958-1.269%25207.969-2.52-3.687%25202.025-8.537-5.497-5.354-6.31%25203.588%25205.81%25209.195.293%252014.181.824%25204.734%25201.576%25209.646.674%252014.618%25201.32%25202.677.038%25208.273-4.197%25205.436%25201.182%25202.315-1.258%25205.569-4.222%25202.645.22-1.455%25202.746-8.046%25204.27-3.916-.373%25203.326-6.875-4.738%25204.359-4.904-.943-4.517-.761-14.364%25201.26-15.373%25201.527%25205.2.003%252010.302-2.312%252015.512-1.159-6.798%25201.35-15.67%25202.305-18.245%25209.973-1.217%25203.838.367%252012.093-6.215%252010.872zm1.17-2.82c3.407-4.633-9.658-1.052-1.732.245.616.153%25201.151-.069%25201.732-.245zm28.029-5.54c-5.548-4.056%25204.373-1.525%25200%25200zm6.278-7.367c-6.526-6.566%25206.88-1.223%25200%25200zm-23.713-8.24c-3.366-2.186.323-6.77.17-1.577-.203.032.682%25202.179-.17%25201.577z%2522%252F%253E%253Cpath%2520fill%253D%2522%25235c5d98%2522%2520d%253D%2522M54.291%2520137.105c-11.816-.332-23.664-.112-35.443-1.265%25202.148-.485%25203.906-2.175%25203.252-2.776%25206.22%25201.38%25207.008-11.583.793-10.188-2.084-3.796.916-9.775%25204.697-5.707-.294%25205.685-1.312%252011.858.899%252017.195%25203.128.428%25206.503-.006%25209.756.146%25204.633%25201.241-.888-3.75%25204.734-2.523%25206.365.072-1.428-11.851-3.016-7.372-3.508-4.414-11.384-10.982-4.093-16.032%25205.205-3.024%25201.84-12.048%25209.046-10.405%25206.673.04%252012.319-6.91%252017.98-2.245%25204.302-.665%252011.386-.543%252013.867-3.034-4.603-2.18-12.08-3.698-9.938-10.532-1.42-4.92-7.028-8.295-5.794-13.935.139-2.552-.725-11.233%25201.496-4.824%25203.612%25202.898%25203.925%25207.41%25205.794%252010.49%25206.18-.322%25202.576-9.005%25203.304-13.164.372-2.166-1.578-10.744%25202.151-5.247.738%25204.773.157%252010.043.799%252015.083-.038%25206.414-11.118%25206.426-8.88-.705-3.097-3.39-1.33%25205.412%25201.324%25206.08%25204.73%25204.496.125%252013.918%25208.513%252014.2%25208.325.826%25205.123%25208.843%25204.62%252014.276.777%25203.8-2.25%252013.049-6.633%252010.105-2.446-4.885%25209.415-2.626%25204.951-9.21-8.511%25201.84%25204.849-8.562-3.132-8.456-5.254.677-10.589%25201.112-15.68-.17-5.257%25202.444-11.79%25202.522-12.216%25209.222-1.968%25205.127-12.361%25207.206-6.44%252013.509%25204.782%25203.768%25202.996%252012.408%25207.87%252015.061%252010.963.362%252021.966-.26%252032.894.895-4.043%25204.041-11.295.196-16.667%25201.602-3.603-.01-7.206-.033-10.808-.074zm11.359-16.668c-3.506-4.237%25206.951-.457%25204.37-6.157-.754-3.32-1.22-4.513.847-.677%25201.711%25202.397-2.595%252011.12-5.217%25206.834zm-56.332-4.509c-3.912%25201.694-5.899-9.464-2.664-3.633%25206.035%25205.979%252011.062-6.072%25203.197-7.643-1.868-1.969-6.685-7.438-1.187-6.706%25201.462-1.865%25205.019-10.046%25202.115-3.657-2.55%25203.058%25201.31%252011.426%25202.692%25209.769-.625-2.182-5.217-7.386-.588-4.926%25201.5-2.393.45-4.46%25201.45-.507%25201.938%25204.63%25207.309%252010.38%25202.924%252015.222-2.03%25202.055-5.186%25202.588-7.94%25202.081zM20.84%252096.751c-4.707-2.048%25205.25-13.376.835-5.89-1.048%25201.426%25201.261%25205.786-.835%25205.89zm48.598-23.467c-2.38-3.685%25203.39-3.024%25200%25200zm-.746-13.574c-5.548-4.057%25204.373-1.526%25200%25200zm-37.107-3.226c-.522-6.111%252010.462-2.279%25209.682-5.974-4.124%25201.722-7.952-3.136-5.974-6.966%25203.2%25208.274%252012.377-.89%252018.016%25202.831%25205.78-.373%252011.771%25201.782%252016.835-1.541%25201.512-.747-1.629%25205.093%25201.8%25202.074%25205.76-3.085-6.02%25208.277-4.052%25202.485%25202.137-2.701%25202.115-6.097-1.292-1.997-2.74%25202.919-3.359-2.535-7.064-.64-5.492%25201.098-13.577-.493-15.437%25206.32-2.99%25207.387-7.835-.2-12.514%25203.408zm19.672-12.382c-3.366-2.186.323-6.77.17-1.577-.203.032.682%25202.179-.17%25201.577z%2522%252F%253E%253Cpath%2520fill%253D%2522%252335384c%2522%2520d%253D%2522M53.13%2520137.013c-11.361-.278-22.747-.16-34.074-1.202.612-1.018%25205.354-.648%25202.204-2.927%25207.724%25201.916%25205.434-8.035%25205.697-12.567%25201.527%25201.516-1.744%252010.94%25201.902%252014.02%25203.434-.07%252010.517%25201.079%252011.4-.736-1.171-3.17%25207.848.022%25204.741-5.113-2.305-5.067-4.427-12.766-10.055-14.42-5.294-1.99%25204.885-7.295%25204.948-11.776.965-7.667%252012.052-2.317%252015.995-7.829%25204.864-1.034%25208.668%25203.7%252013.653.646%25204.338-.207%252010.717-1.854%25203.527-4.104-8.196-.356-4.635-9.348-8.906-13.935-4.538-3.784-2.913-9.648-3.09-14.875-.438-2.747%25202.425%25204.057%25204.375%25204.932%25202.366%25202.315.446%25209.645%25205.76%25206.313%25201.484-5.301.282-11.75.096-17.187.434-6.352%25204.779%25202.883%25202.558%25205.411%25201.494%25205.203%25201.417%252016.047-6.751%252013.628-2.011-1.208-1.431-9.897-3.203-4.199.833%25204.556%25206.3%25207.137%25205.963%252012.17-2.02%25207.53%25207.547%25205.856%252010.842%252010.138%25201.824%25205.71-1.099%252012.654-2.15%252018.701-.78%25204.757-6.825%25205.004-4.81-.04%25207.417.382%25205.157-8.89%25204.138-13.61-3.38-4.06-10.606%25201.478-15.042-1.444-4.995.424-12.718%25201.258-14.714%25206.688.327%25206.902-11.546%25207.345-8.345%252014.319%25204.206%25204.6%25205.633%252012.37%25208.199%252016.696%25209.659.282%252019.329.055%252028.982.555-2.002%25204.238-10.428.639-14.85%25201.815-2.997-.012-5.994-.034-8.99-.068zm13.307-15.209c-5.3-5.132%25205.594-2.024%25203.868-7.423.073-4.554%25201.9%25205.297-1.632%25206.369-.447.33-1.51%25201.838-2.236%25201.054zm-52.843-16.289c-5.844-2.461-4.009-12.912-1.208-13.868-3.783%25204.309-2.69%252011.493%25201.208%252013.868zm7.199-8.84c-3.9-2.46%25204.68-13.187.814-5.155-.492%25201.35.803%25204.898-.814%25205.156zm48.52-23.885c-1.491-3.886%25202.915-.93%25200%25200zm-1.557-13.345c-3.457-5.99%25205.857%25201.238%25200%25200zm-.528-8.177c.784-2.42%25204.42-8.375-.39-4.219-6.722%25203.902%25207.535-6.662%25202.979%25201.12%25201.954-1.91%25205.38-2.948%25202.255.352-.53%25203.145-3.753.417-4.844%25202.747z%2522%252F%253E%253C%252Fg%253E%253Crect%2520width%253D%2522100%2522%2520height%253D%2522140%2522%2520rx%253D%25225%2522%2520clip-path%253D%2522url(%2523clipFrame)%2522%252F%253E%253Cg%2520font-family%253D%2522Orbitron%2522%2520text-anchor%253D%2522middle%2522%2520filter%253D%2522url(%2523rainbowGlow)%2522%253E%253Ctext%2520x%253D%252250%2522%2520y%253D%252235%2522%2520font-size%253D%25223em%2522%253EButerin%2520Card%253C%252Ftext%253E%253C%252Fg%253E%253Ccircle%2520cx%253D%252250%2522%2520cy%253D%252285%2522%2520r%253D%252250%2522%2520fill%253D%2522url(%2523lightGlow)%2522%252F%253E%253Cuse%2520href%253D%2522%2523eth_pencil%2522";
}
functioncardBackPiece5(uint8 phaseId) externalpurereturns (stringmemory piece) {
bytes[] memory bytesSegments =newbytes[](12);
stringmemory glowStr ="%2520filter%253D%2522url(%2523rainbowGlowLarge)%2522";
if (phaseId ==0) bytesSegments[0] =bytes(glowStr);
bytesSegments[1] =bytes("%252F%253E%253Cuse%2520href%253D%2522%2523eth_bw%2522");
if (phaseId ==1) bytesSegments[2] =bytes(glowStr);
bytesSegments[3] =bytes("%252F%253E%253Cuse%2520href%253D%2522%2523eth_grey%2522");
if (phaseId ==2) bytesSegments[4] =bytes(glowStr);
bytesSegments[5] =bytes("%252F%253E%253Cuse%2520href%253D%2522%2523eth_color_a%2522");
if (phaseId ==3) bytesSegments[6] =bytes(glowStr);
bytesSegments[7] =bytes("%252F%253E%253Cuse%2520href%253D%2522%2523eth_color_b%2522");
if (phaseId ==4) bytesSegments[8] =bytes(glowStr);
bytesSegments[9] =bytes("%252F%253E%253Cuse%2520href%253D%2522%2523eth_diamond%2522");
if (phaseId ==5) bytesSegments[10] =bytes(glowStr);
bytesSegments[11] =bytes("%252F%253E%253C%252Fsvg%253E");
returnstring(Array.join(bytesSegments));
}
}
Contract Source Code
File 7 of 21: 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 8 of 21: 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 9 of 21: ERC721.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/ERC721.sol)pragmasolidity ^0.8.0;import"./IERC721.sol";
import"./IERC721Receiver.sol";
import"./IERC721Metadata.sol";
import"./Address.sol";
import"./Context.sol";
import"./Strings.sol";
import"./ERC165.sol";
/**
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
* the Metadata extension, but not including the Enumerable extension, which is available separately as
* {ERC721Enumerable}.
*/contractERC721isContext, ERC165, IERC721, IERC721Metadata{
usingAddressforaddress;
usingStringsforuint256;
// Token namestringprivate _name;
// Token symbolstringprivate _symbol;
// Mapping from token ID to owner addressmapping(uint256=>address) private _owners;
// Mapping owner address to token countmapping(address=>uint256) private _balances;
// Mapping from token ID to approved addressmapping(uint256=>address) private _tokenApprovals;
// Mapping from owner to operator approvalsmapping(address=>mapping(address=>bool)) private _operatorApprovals;
/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
*/constructor(stringmemory name_, stringmemory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(ERC165, IERC165) returns (bool) {
return
interfaceId ==type(IERC721).interfaceId||
interfaceId ==type(IERC721Metadata).interfaceId||super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/functionbalanceOf(address owner) publicviewvirtualoverridereturns (uint256) {
require(owner !=address(0), "ERC721: address zero is not a valid owner");
return _balances[owner];
}
/**
* @dev See {IERC721-ownerOf}.
*/functionownerOf(uint256 tokenId) publicviewvirtualoverridereturns (address) {
address owner = _ownerOf(tokenId);
require(owner !=address(0), "ERC721: invalid token ID");
return owner;
}
/**
* @dev See {IERC721Metadata-name}.
*/functionname() publicviewvirtualoverridereturns (stringmemory) {
return _name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/functionsymbol() publicviewvirtualoverridereturns (stringmemory) {
return _symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/functiontokenURI(uint256 tokenId) publicviewvirtualoverridereturns (stringmemory) {
_requireMinted(tokenId);
stringmemory baseURI = _baseURI();
returnbytes(baseURI).length>0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overridden in child contracts.
*/function_baseURI() internalviewvirtualreturns (stringmemory) {
return"";
}
/**
* @dev See {IERC721-approve}.
*/functionapprove(address to, uint256 tokenId) publicvirtualoverride{
address owner = ERC721.ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(
_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
"ERC721: approve caller is not token owner or approved for all"
);
_approve(to, tokenId);
}
/**
* @dev See {IERC721-getApproved}.
*/functiongetApproved(uint256 tokenId) publicviewvirtualoverridereturns (address) {
_requireMinted(tokenId);
return _tokenApprovals[tokenId];
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/functionsetApprovalForAll(address operator, bool approved) publicvirtualoverride{
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/functionisApprovedForAll(address owner, address operator) publicviewvirtualoverridereturns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) publicvirtualoverride{
//solhint-disable-next-line max-line-lengthrequire(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
_transfer(from, to, tokenId);
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) publicvirtualoverride{
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytesmemory data
) publicvirtualoverride{
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
_safeTransfer(from, to, tokenId, data);
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* `data` is additional data, it has no specified format and it is sent in call to `to`.
*
* This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
* implement alternative mechanisms to perform token transfer, such as signature-based.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/function_safeTransfer(addressfrom,
address to,
uint256 tokenId,
bytesmemory data
) internalvirtual{
_transfer(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer");
}
/**
* @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
*/function_ownerOf(uint256 tokenId) internalviewvirtualreturns (address) {
return _owners[tokenId];
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted (`_mint`),
* and stop existing when they are burned (`_burn`).
*/function_exists(uint256 tokenId) internalviewvirtualreturns (bool) {
return _ownerOf(tokenId) !=address(0);
}
/**
* @dev Returns whether `spender` is allowed to manage `tokenId`.
*
* Requirements:
*
* - `tokenId` must exist.
*/function_isApprovedOrOwner(address spender, uint256 tokenId) internalviewvirtualreturns (bool) {
address owner = ERC721.ownerOf(tokenId);
return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
}
/**
* @dev Safely mints `tokenId` and transfers it to `to`.
*
* Requirements:
*
* - `tokenId` must not exist.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/function_safeMint(address to, uint256 tokenId) internalvirtual{
_safeMint(to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/function_safeMint(address to,
uint256 tokenId,
bytesmemory data
) internalvirtual{
_mint(to, tokenId);
require(
_checkOnERC721Received(address(0), to, tokenId, data),
"ERC721: transfer to non ERC721Receiver implementer"
);
}
/**
* @dev Mints `tokenId` and transfers it to `to`.
*
* WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
*
* Requirements:
*
* - `tokenId` must not exist.
* - `to` cannot be the zero address.
*
* Emits a {Transfer} event.
*/function_mint(address to, uint256 tokenId) internalvirtual{
require(to !=address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId, 1);
// Check that tokenId was not minted by `_beforeTokenTransfer` hookrequire(!_exists(tokenId), "ERC721: token already minted");
unchecked {
// Will not overflow unless all 2**256 token ids are minted to the same owner.// Given that tokens are minted one by one, it is impossible in practice that// this ever happens. Might change if we allow batch minting.// The ERC fails to describe this case.
_balances[to] +=1;
}
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
_afterTokenTransfer(address(0), to, tokenId, 1);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
* This is an internal function that does not check if the sender is authorized to operate on the token.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/function_burn(uint256 tokenId) internalvirtual{
address owner = ERC721.ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId, 1);
// Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook
owner = ERC721.ownerOf(tokenId);
// Clear approvalsdelete _tokenApprovals[tokenId];
unchecked {
// Cannot overflow, as that would require more tokens to be burned/transferred// out than the owner initially received through minting and transferring in.
_balances[owner] -=1;
}
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
_afterTokenTransfer(owner, address(0), tokenId, 1);
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/function_transfer(addressfrom,
address to,
uint256 tokenId
) internalvirtual{
require(ERC721.ownerOf(tokenId) ==from, "ERC721: transfer from incorrect owner");
require(to !=address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId, 1);
// Check that tokenId was not transferred by `_beforeTokenTransfer` hookrequire(ERC721.ownerOf(tokenId) ==from, "ERC721: transfer from incorrect owner");
// Clear approvals from the previous ownerdelete _tokenApprovals[tokenId];
unchecked {
// `_balances[from]` cannot overflow for the same reason as described in `_burn`:// `from`'s balance is the number of token held, which is at least one before the current// transfer.// `_balances[to]` could overflow in the conditions described in `_mint`. That would require// all 2**256 token ids to be minted, which in practice is impossible.
_balances[from] -=1;
_balances[to] +=1;
}
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
_afterTokenTransfer(from, to, tokenId, 1);
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* Emits an {Approval} event.
*/function_approve(address to, uint256 tokenId) internalvirtual{
_tokenApprovals[tokenId] = to;
emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Emits an {ApprovalForAll} event.
*/function_setApprovalForAll(address owner,
address operator,
bool approved
) internalvirtual{
require(owner != operator, "ERC721: approve to caller");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Reverts if the `tokenId` has not been minted yet.
*/function_requireMinted(uint256 tokenId) internalviewvirtual{
require(_exists(tokenId), "ERC721: invalid token ID");
}
/**
* @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
* The call is not executed if the target address is not a contract.
*
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param data bytes optional data to send along with the call
* @return bool whether the call correctly returned the expected magic value
*/function_checkOnERC721Received(addressfrom,
address to,
uint256 tokenId,
bytesmemory data
) privatereturns (bool) {
if (to.isContract()) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytesmemory reason) {
if (reason.length==0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
/// @solidity memory-safe-assemblyassembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
returntrue;
}
}
/**
* @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is
* used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`.
* - When `from` is zero, the tokens will be minted for `to`.
* - When `to` is zero, ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
* - `batchSize` is non-zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/function_beforeTokenTransfer(addressfrom,
address to,
uint256, /* firstTokenId */uint256 batchSize
) internalvirtual{
if (batchSize >1) {
if (from!=address(0)) {
_balances[from] -= batchSize;
}
if (to !=address(0)) {
_balances[to] += batchSize;
}
}
}
/**
* @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is
* used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`.
* - When `from` is zero, the tokens were minted for `to`.
* - When `to` is zero, ``from``'s tokens were burned.
* - `from` and `to` are never both zero.
* - `batchSize` is non-zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/function_afterTokenTransfer(addressfrom,
address to,
uint256 firstTokenId,
uint256 batchSize
) internalvirtual{}
}
Contract Source Code
File 10 of 21: ERC721Enumerable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Enumerable.sol)pragmasolidity ^0.8.0;import"./ERC721.sol";
import"./IERC721Enumerable.sol";
/**
* @dev This implements an optional extension of {ERC721} defined in the EIP that adds
* enumerability of all the token ids in the contract as well as all token ids owned by each
* account.
*/abstractcontractERC721EnumerableisERC721, IERC721Enumerable{
// Mapping from owner to list of owned token IDsmapping(address=>mapping(uint256=>uint256)) private _ownedTokens;
// Mapping from token ID to index of the owner tokens listmapping(uint256=>uint256) private _ownedTokensIndex;
// Array with all token ids, used for enumerationuint256[] private _allTokens;
// Mapping from token id to position in the allTokens arraymapping(uint256=>uint256) private _allTokensIndex;
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(IERC165, ERC721) returns (bool) {
return interfaceId ==type(IERC721Enumerable).interfaceId||super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
*/functiontokenOfOwnerByIndex(address owner, uint256 index) publicviewvirtualoverridereturns (uint256) {
require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
return _ownedTokens[owner][index];
}
/**
* @dev See {IERC721Enumerable-totalSupply}.
*/functiontotalSupply() publicviewvirtualoverridereturns (uint256) {
return _allTokens.length;
}
/**
* @dev See {IERC721Enumerable-tokenByIndex}.
*/functiontokenByIndex(uint256 index) publicviewvirtualoverridereturns (uint256) {
require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
return _allTokens[index];
}
/**
* @dev See {ERC721-_beforeTokenTransfer}.
*/function_beforeTokenTransfer(addressfrom,
address to,
uint256 firstTokenId,
uint256 batchSize
) internalvirtualoverride{
super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
if (batchSize >1) {
// Will only trigger during construction. Batch transferring (minting) is not available afterwards.revert("ERC721Enumerable: consecutive transfers not supported");
}
uint256 tokenId = firstTokenId;
if (from==address(0)) {
_addTokenToAllTokensEnumeration(tokenId);
} elseif (from!= to) {
_removeTokenFromOwnerEnumeration(from, tokenId);
}
if (to ==address(0)) {
_removeTokenFromAllTokensEnumeration(tokenId);
} elseif (to !=from) {
_addTokenToOwnerEnumeration(to, tokenId);
}
}
/**
* @dev Private function to add a token to this extension's ownership-tracking data structures.
* @param to address representing the new owner of the given token ID
* @param tokenId uint256 ID of the token to be added to the tokens list of the given address
*/function_addTokenToOwnerEnumeration(address to, uint256 tokenId) private{
uint256 length = ERC721.balanceOf(to);
_ownedTokens[to][length] = tokenId;
_ownedTokensIndex[tokenId] = length;
}
/**
* @dev Private function to add a token to this extension's token tracking data structures.
* @param tokenId uint256 ID of the token to be added to the tokens list
*/function_addTokenToAllTokensEnumeration(uint256 tokenId) private{
_allTokensIndex[tokenId] = _allTokens.length;
_allTokens.push(tokenId);
}
/**
* @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
* while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
* gas optimizations e.g. when performing a transfer operation (avoiding double writes).
* This has O(1) time complexity, but alters the order of the _ownedTokens array.
* @param from address representing the previous owner of the given token ID
* @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/function_removeTokenFromOwnerEnumeration(addressfrom, uint256 tokenId) private{
// To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and// then delete the last slot (swap and pop).uint256 lastTokenIndex = ERC721.balanceOf(from) -1;
uint256 tokenIndex = _ownedTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessaryif (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
}
// This also deletes the contents at the last position of the arraydelete _ownedTokensIndex[tokenId];
delete _ownedTokens[from][lastTokenIndex];
}
/**
* @dev Private function to remove a token from this extension's token tracking data structures.
* This has O(1) time complexity, but alters the order of the _allTokens array.
* @param tokenId uint256 ID of the token to be removed from the tokens list
*/function_removeTokenFromAllTokensEnumeration(uint256 tokenId) private{
// To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and// then delete the last slot (swap and pop).uint256 lastTokenIndex = _allTokens.length-1;
uint256 tokenIndex = _allTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so// rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding// an 'if' statement (like in _removeTokenFromOwnerEnumeration)uint256 lastTokenId = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index// This also deletes the contents at the last position of the arraydelete _allTokensIndex[tokenId];
_allTokens.pop();
}
}
Contract Source Code
File 11 of 21: 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);
}
Contract Source Code
File 12 of 21: IERC721.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)pragmasolidity ^0.8.0;import"./IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/interfaceIERC721isIERC165{
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/eventApproval(addressindexed owner, addressindexed approved, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/eventApprovalForAll(addressindexed owner, addressindexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/functionbalanceOf(address owner) externalviewreturns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functionownerOf(uint256 tokenId) externalviewreturns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytescalldata data
) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/functionapprove(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/functionsetApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functiongetApproved(uint256 tokenId) externalviewreturns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/functionisApprovedForAll(address owner, address operator) externalviewreturns (bool);
}
Contract Source Code
File 13 of 21: IERC721Enumerable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)pragmasolidity ^0.8.0;import"./IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/interfaceIERC721EnumerableisIERC721{
/**
* @dev Returns the total amount of tokens stored by the contract.
*/functiontotalSupply() externalviewreturns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/functiontokenOfOwnerByIndex(address owner, uint256 index) externalviewreturns (uint256);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/functiontokenByIndex(uint256 index) externalviewreturns (uint256);
}
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)pragmasolidity ^0.8.0;/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/interfaceIERC721Receiver{
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/functiononERC721Received(address operator,
addressfrom,
uint256 tokenId,
bytescalldata data
) externalreturns (bytes4);
}
Contract Source Code
File 16 of 21: LibString.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.8.0;/// @notice Efficient library for creating string representations of integers./// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibString.sol)libraryLibString{
functiontoString(uint256 value) internalpurereturns (stringmemory str) {
assembly {
// The maximum value of a uint256 contains 78 digits (1 byte per digit), but we allocate 160 bytes// to keep the free memory pointer word aligned. We'll need 1 word for the length, 1 word for the// trailing zeros padding, and 3 other words for a max of 78 digits. In total: 5 * 32 = 160 bytes.let newFreeMemoryPointer :=add(mload(0x40), 160)
// Update the free memory pointer to avoid overriding our string.mstore(0x40, newFreeMemoryPointer)
// Assign str to the end of the zone of newly allocated memory.
str :=sub(newFreeMemoryPointer, 32)
// Clean the last word of memory it may not be overwritten.mstore(str, 0)
// Cache the end of the memory to calculate the length later.let end := str
// We write the string from rightmost digit to leftmost digit.// The following is essentially a do-while loop that also handles the zero case.// prettier-ignorefor { let temp := value } 1 {} {
// Move the pointer 1 byte to the left.
str :=sub(str, 1)
// Write the character to the pointer.// The ASCII index of the '0' character is 48.mstore8(str, add(48, mod(temp, 10)))
// Keep dividing temp until zero.
temp :=div(temp, 10)
// prettier-ignoreifiszero(temp) { break }
}
// Compute and cache the final total length of the string.let length :=sub(end, str)
// Move the pointer 32 bytes leftwards to make room for the length.
str :=sub(str, 32)
// Store the string's length at the start of memory allocated for our string.mstore(str, length)
}
}
}
Contract Source Code
File 17 of 21: Math.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)pragmasolidity ^0.8.0;/**
* @dev Standard math utilities missing in the Solidity language.
*/libraryMath{
enumRounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/functionmax(uint256 a, uint256 b) internalpurereturns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/functionmin(uint256 a, uint256 b) internalpurereturns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/functionaverage(uint256 a, uint256 b) internalpurereturns (uint256) {
// (a + b) / 2 can overflow.return (a & b) + (a ^ b) /2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/functionceilDiv(uint256 a, uint256 b) internalpurereturns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.return a ==0 ? 0 : (a -1) / b +1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/functionmulDiv(uint256 x,
uint256 y,
uint256 denominator
) internalpurereturns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256// variables such that product = prod1 * 2^256 + prod0.uint256 prod0; // Least significant 256 bits of the productuint256 prod1; // Most significant 256 bits of the productassembly {
let mm :=mulmod(x, y, not(0))
prod0 :=mul(x, y)
prod1 :=sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.if (prod1 ==0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.require(denominator > prod1);
///////////////////////////////////////////////// 512 by 256 division.///////////////////////////////////////////////// Make division exact by subtracting the remainder from [prod1 prod0].uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder :=mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 :=sub(prod1, gt(remainder, prod0))
prod0 :=sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.// See https://cs.stackexchange.com/q/138556/92363.// Does not overflow because the denominator cannot be zero at this stage in the function.uint256 twos = denominator & (~denominator +1);
assembly {
// Divide denominator by twos.
denominator :=div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 :=div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos :=add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for// four bits. That is, denominator * inv = 1 mod 2^4.uint256 inverse = (3* denominator) ^2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works// in modular arithmetic, doubling the correct bits in each step.
inverse *=2- denominator * inverse; // inverse mod 2^8
inverse *=2- denominator * inverse; // inverse mod 2^16
inverse *=2- denominator * inverse; // inverse mod 2^32
inverse *=2- denominator * inverse; // inverse mod 2^64
inverse *=2- denominator * inverse; // inverse mod 2^128
inverse *=2- denominator * inverse; // inverse mod 2^256// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/functionmulDiv(uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internalpurereturns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up &&mulmod(x, y, denominator) >0) {
result +=1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/functionsqrt(uint256 a) internalpurereturns (uint256) {
if (a ==0) {
return0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.//// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.//// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`//// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.uint256 result =1<< (log2(a) >>1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision// into the expected uint128 result.unchecked {
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/functionsqrt(uint256 a, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/functionlog2(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >>128>0) {
value >>=128;
result +=128;
}
if (value >>64>0) {
value >>=64;
result +=64;
}
if (value >>32>0) {
value >>=32;
result +=32;
}
if (value >>16>0) {
value >>=16;
result +=16;
}
if (value >>8>0) {
value >>=8;
result +=8;
}
if (value >>4>0) {
value >>=4;
result +=4;
}
if (value >>2>0) {
value >>=2;
result +=2;
}
if (value >>1>0) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog2(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result =log2(value);
return result + (rounding == Rounding.Up &&1<< result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/functionlog10(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >=10**64) {
value /=10**64;
result +=64;
}
if (value >=10**32) {
value /=10**32;
result +=32;
}
if (value >=10**16) {
value /=10**16;
result +=16;
}
if (value >=10**8) {
value /=10**8;
result +=8;
}
if (value >=10**4) {
value /=10**4;
result +=4;
}
if (value >=10**2) {
value /=10**2;
result +=2;
}
if (value >=10**1) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog10(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up &&10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/functionlog256(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >>128>0) {
value >>=128;
result +=16;
}
if (value >>64>0) {
value >>=64;
result +=8;
}
if (value >>32>0) {
value >>=32;
result +=4;
}
if (value >>16>0) {
value >>=16;
result +=2;
}
if (value >>8>0) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog256(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up &&1<< (result *8) < value ? 1 : 0);
}
}
}
Contract Source Code
File 18 of 21: MerkleProof.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol)pragmasolidity ^0.8.0;/**
* @dev These functions deal with verification of Merkle Tree proofs.
*
* The tree and the proofs can be generated using our
* https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
* You will find a quickstart guide in the readme.
*
* WARNING: You should avoid using leaf values that are 64 bytes long prior to
* hashing, or use a hash function other than keccak256 for hashing leaves.
* This is because the concatenation of a sorted pair of internal nodes in
* the merkle tree could be reinterpreted as a leaf value.
* OpenZeppelin's JavaScript library generates merkle trees that are safe
* against this attack out of the box.
*/libraryMerkleProof{
/**
* @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
* defined by `root`. For this, a `proof` must be provided, containing
* sibling hashes on the branch from the leaf to the root of the tree. Each
* pair of leaves and each pair of pre-images are assumed to be sorted.
*/functionverify(bytes32[] memory proof,
bytes32 root,
bytes32 leaf
) internalpurereturns (bool) {
return processProof(proof, leaf) == root;
}
/**
* @dev Calldata version of {verify}
*
* _Available since v4.7._
*/functionverifyCalldata(bytes32[] calldata proof,
bytes32 root,
bytes32 leaf
) internalpurereturns (bool) {
return processProofCalldata(proof, leaf) == root;
}
/**
* @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
* hash matches the root of the tree. When processing the proof, the pairs
* of leafs & pre-images are assumed to be sorted.
*
* _Available since v4.4._
*/functionprocessProof(bytes32[] memory proof, bytes32 leaf) internalpurereturns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i =0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Calldata version of {processProof}
*
* _Available since v4.7._
*/functionprocessProofCalldata(bytes32[] calldata proof, bytes32 leaf) internalpurereturns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i =0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by
* `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/functionmultiProofVerify(bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internalpurereturns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
/**
* @dev Calldata version of {multiProofVerify}
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/functionmultiProofVerifyCalldata(bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internalpurereturns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
/**
* @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
* proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
* leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
* respectively.
*
* CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
* is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
* tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
*
* _Available since v4.7._
*/functionprocessMultiProof(bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internalpurereturns (bytes32 merkleRoot) {
// This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of// the merkle tree.uint256 leavesLen = leaves.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.require(leavesLen + proof.length-1== totalHashes, "MerkleProof: invalid multiproof");
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".bytes32[] memory hashes =newbytes32[](totalHashes);
uint256 leafPos =0;
uint256 hashPos =0;
uint256 proofPos =0;
// At each step, we compute the next hash using two values:// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we// get the next hash.// - depending on the flag, either another value for the "main queue" (merging branches) or an element from the// `proof` array.for (uint256 i =0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes >0) {
return hashes[totalHashes -1];
} elseif (leavesLen >0) {
return leaves[0];
} else {
return proof[0];
}
}
/**
* @dev Calldata version of {processMultiProof}.
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/functionprocessMultiProofCalldata(bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internalpurereturns (bytes32 merkleRoot) {
// This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of// the merkle tree.uint256 leavesLen = leaves.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.require(leavesLen + proof.length-1== totalHashes, "MerkleProof: invalid multiproof");
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".bytes32[] memory hashes =newbytes32[](totalHashes);
uint256 leafPos =0;
uint256 hashPos =0;
uint256 proofPos =0;
// At each step, we compute the next hash using two values:// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we// get the next hash.// - depending on the flag, either another value for the "main queue" (merging branches) or an element from the// `proof` array.for (uint256 i =0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes >0) {
return hashes[totalHashes -1];
} elseif (leavesLen >0) {
return leaves[0];
} else {
return proof[0];
}
}
function_hashPair(bytes32 a, bytes32 b) privatepurereturns (bytes32) {
return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
}
function_efficientHash(bytes32 a, bytes32 b) privatepurereturns (bytes32 value) {
/// @solidity memory-safe-assemblyassembly {
mstore(0x00, a)
mstore(0x20, b)
value :=keccak256(0x00, 0x40)
}
}
}
Contract Source Code
File 19 of 21: Ownable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)pragmasolidity ^0.8.0;import"./Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/function_checkOwner() internalviewvirtual{
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(newOwner !=address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/function_transferOwnership(address newOwner) internalvirtual{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Contract Source Code
File 20 of 21: SSTORE2.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity >=0.8.0;/// @notice Read and write to persistent storage at a fraction of the cost./// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol)/// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol)librarySSTORE2{
uint256internalconstant DATA_OFFSET =1; // We skip the first byte as it's a STOP opcode to ensure the contract can't be called./*//////////////////////////////////////////////////////////////
WRITE LOGIC
//////////////////////////////////////////////////////////////*/functionwrite(bytesmemory data) internalreturns (address pointer) {
// Prefix the bytecode with a STOP opcode to ensure it cannot be called.bytesmemory runtimeCode =abi.encodePacked(hex"00", data);
bytesmemory creationCode =abi.encodePacked(
//---------------------------------------------------------------------------------------------------------------//// Opcode | Opcode + Arguments | Description | Stack View ////---------------------------------------------------------------------------------------------------------------//// 0x60 | 0x600B | PUSH1 11 | codeOffset //// 0x59 | 0x59 | MSIZE | 0 codeOffset //// 0x81 | 0x81 | DUP2 | codeOffset 0 codeOffset //// 0x38 | 0x38 | CODESIZE | codeSize codeOffset 0 codeOffset //// 0x03 | 0x03 | SUB | (codeSize - codeOffset) 0 codeOffset //// 0x80 | 0x80 | DUP | (codeSize - codeOffset) (codeSize - codeOffset) 0 codeOffset //// 0x92 | 0x92 | SWAP3 | codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) //// 0x59 | 0x59 | MSIZE | 0 codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) //// 0x39 | 0x39 | CODECOPY | 0 (codeSize - codeOffset) //// 0xf3 | 0xf3 | RETURN | ////---------------------------------------------------------------------------------------------------------------//hex"60_0B_59_81_38_03_80_92_59_39_F3", // Returns all code in the contract except for the first 11 (0B in hex) bytes.
runtimeCode // The bytecode we want the contract to have after deployment. Capped at 1 byte less than the code size limit.
);
assembly {
// Deploy a new contract with the generated creation code.// We start 32 bytes into the code to avoid copying the byte length.
pointer :=create(0, add(creationCode, 32), mload(creationCode))
}
require(pointer !=address(0), "DEPLOYMENT_FAILED");
}
/*//////////////////////////////////////////////////////////////
READ LOGIC
//////////////////////////////////////////////////////////////*/functionread(address pointer) internalviewreturns (bytesmemory) {
return readBytecode(pointer, DATA_OFFSET, pointer.code.length- DATA_OFFSET);
}
functionread(address pointer, uint256 start) internalviewreturns (bytesmemory) {
start += DATA_OFFSET;
return readBytecode(pointer, start, pointer.code.length- start);
}
functionread(address pointer,
uint256 start,
uint256 end
) internalviewreturns (bytesmemory) {
start += DATA_OFFSET;
end += DATA_OFFSET;
require(pointer.code.length>= end, "OUT_OF_BOUNDS");
return readBytecode(pointer, start, end - start);
}
/*//////////////////////////////////////////////////////////////
INTERNAL HELPER LOGIC
//////////////////////////////////////////////////////////////*/functionreadBytecode(address pointer,
uint256 start,
uint256 size
) privateviewreturns (bytesmemory data) {
assembly {
// Get a pointer to some free memory.
data :=mload(0x40)
// Update the free memory pointer to prevent overriding our data.// We use and(x, not(31)) as a cheaper equivalent to sub(x, mod(x, 32)).// Adding 31 to size and running the result through the logic above ensures// the memory pointer remains word-aligned, following the Solidity convention.mstore(0x40, add(data, and(add(add(size, 32), 31), not(31))))
// Store the size of the data in the first 32 byte chunk of free memory.mstore(data, size)
// Copy the code into memory right after the 32 bytes we used to store the size.extcodecopy(pointer, add(data, 32), start, size)
}
}
}
Contract Source Code
File 21 of 21: Strings.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)pragmasolidity ^0.8.0;import"./Math.sol";
/**
* @dev String operations.
*/libraryStrings{
bytes16privateconstant _SYMBOLS ="0123456789abcdef";
uint8privateconstant _ADDRESS_LENGTH =20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/functiontoString(uint256 value) internalpurereturns (stringmemory) {
unchecked {
uint256 length = Math.log10(value) +1;
stringmemory buffer =newstring(length);
uint256 ptr;
/// @solidity memory-safe-assemblyassembly {
ptr :=add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assemblyassembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /=10;
if (value ==0) break;
}
return buffer;
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/functiontoHexString(uint256 value) internalpurereturns (stringmemory) {
unchecked {
return toHexString(value, Math.log256(value) +1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/functiontoHexString(uint256 value, uint256 length) internalpurereturns (stringmemory) {
bytesmemory buffer =newbytes(2* length +2);
buffer[0] ="0";
buffer[1] ="x";
for (uint256 i =2* length +1; i >1; --i) {
buffer[i] = _SYMBOLS[value &0xf];
value >>=4;
}
require(value ==0, "Strings: hex length insufficient");
returnstring(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/functiontoHexString(address addr) internalpurereturns (stringmemory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}