¡El código fuente de este contrato está verificado!
Metadatos del Contrato
Compilador
0.8.21+commit.d9974bed
Idioma
Solidity
Código Fuente del Contrato
Archivo 1 de 6: GnarsHD.sol
// SPDX-License-Identifier: CC0-1.0pragmasolidity 0.8.21;/// @title Gnars HD/// @notice High definition Gnars counterparts/// @author Volky/// @dev This contract describes Gnars HD as 1:1 counterparts for each GnarV2. They are not mintable, since the ownership of the respective GnarV2 is mirrored on the GnarHD.///////////////////////////////////////////////////////////////////////////////////////////////// //// //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▀▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▄▄░░░░▄ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀▀ ▀▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▄▒░░░░░░░░░▌ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▄▐▒░░░░ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▀░▐░░░░░░░░▌▐ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▄▒░░░░░░░▐ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▌░ ░░░░░░░░░░▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▄░░░░░░░░░▌▌ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▌ ▄▒ ▒░░░░░░░░░░▌ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▐░ ░░░░░░▐▐▌▌ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓ ░ ▐░░░░░░░░░░▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▌ ▐░░░░░░░░░▓ ▓▓▓▓▓▓▓▓▓▓▓▓ ▓▒ ░░░░░░░░░░▐ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▌ ▒ ░░░░░░░░░░▐ ▓▓▓▓▓▓▓▓▓▓▓▓ ▌░▒░░░░░░░░░░▌ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▌ ▒ ░░░░░░░░░░▐ ▓▓▀▀▀ ▐░ ░░░░░░░░░░▐ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▌ ▒ ▐░░░░░░░░░░ ▄▄▄▄▄▄▄▄▄▐░░░░░░░░░░░░▌ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▌ ▌░▐░░░░░░░░░░▌ ▐░ ░░░░░░░░░░▌░░░░░░░░░░░▐ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▐░ ▒░░░░░░░░░░▄▄░░░░░░░░░░░░░░▌░░░░░░░░░░▌▌ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌ ▌▒░░░░░░░░░░░▓░░░░░░░░░░░░░░░▌░░░░░░░░░░▒▌ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▒░░░░░░░░░░░▌░░░░░▄▄▀▀▀▀▀▀▀▀▀▒░░░░░░░░░▀▄ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌ ▐░░░░░░░░░░░▌░░░░▀░░░░░░░░░░░░░░░░░░░░░░░░▌ ▀▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌ ▐░░░░░░░░░░▒░░░▌▒▒░░░░░░░░░░░░░░░░░░░░░░░░▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▐░░░░░░░░░▒░░░▌▄▐░░░░░░░░░░░░░░░░░░░░░░░░▒▌ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▒░░░░░░░░▓░░░░▓░▄░▀▒░░░░░░░░░░░░░░░░░░░▒▐▐ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ░░░░░░░░░░▌░░░░░▀▀▒▄▄▄▄▄▄▄▓▀▀▒░░░░░░░░░░░▐ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▐░░░░░░░░░░░▒▀▄▄░▄▄░▀░░░░░░░░░░░░░░░░░░░░░▌ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▐░░░░░░░░░░░░░░░░▓░░░░░░░░░░░░░░░░░░░░░░░▌ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▒░░░░░░░░░░░░░░░▒░░░░░░░░░░░░░░░░░░░░░░▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▐░░░░░░░░░░░░░░░▒░░░░░░░░░░░░░░░░░░░░▄▀ ▄▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌ ▒░░░░░░░░░░░░░▀▒░░░░░░░░░░░░░░░░░▒▀ ▄▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ █▀▀▄▄▄░░░░░░░░░▀▄░░░░░░░░░░░▄▄█ ▄▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▌ ▐░░░░░░░░░░░░░░░░░▒▀▀▀▀▀▀▒░░░░▐ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▀░░░░░░░░░░░░░░░░░░░░░░░░░▄▀ ▄▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄ ▀▀▒▄░░░░░░░░░░░░░░░▒▀▀ ▄▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄ ▄▄▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄▄▄▄▄▄▄▄▄▄▄▄▄▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ //// //// ░██████╗░███╗░░██╗░█████╗░██████╗░░██████╗ ██╗░░██╗██████╗░ //// ██╔════╝░████╗░██║██╔══██╗██╔══██╗██╔════╝ ██║░░██║██╔══██╗ //// ██║░░██╗░██╔██╗██║███████║██████╔╝╚█████╗░ ███████║██║░░██║ //// ██║░░╚██╗██║╚████║██╔══██║██╔══██╗░╚═══██╗ ██╔══██║██║░░██║ //// ╚██████╔╝██║░╚███║██║░░██║██║░░██║██████╔╝ ██║░░██║██████╔╝ //// ░╚═════╝░╚═╝░░╚══╝╚═╝░░╚═╝╚═╝░░╚═╝╚═════╝░ ╚═╝░░╚═╝╚═════╝░ //// //// //////////////////////////////////////////////////////////////////////////////////////////////import {Strings} from"openzeppelin-contracts/contracts/utils/Strings.sol";
import {Owned} from"solmate/auth/Owned.sol";
import {Base64} from"base64/base64.sol";
contractGnarsHDisOwned{
/* ⌐◨—————————————————————————————————————————————————————————————◨
STRUCTS / EVENTS / ERRORS
⌐◨—————————————————————————————————————————————————————————————◨ */structArtwork {
string ipfsFolder;
uint48 amountBackgrounds;
uint48 amountBodies;
uint48 amountAccessories;
uint48 amountHeads;
uint48 amountNoggles;
}
eventTransfer(addressindexed _from, addressindexed _to, uint256indexed _tokenId);
errorUntransferable();
errorTokenDoesNotExist(uint256 tokenId);
/* ⌐◨—————————————————————————————————————————————————————————————◨
STORAGE
⌐◨—————————————————————————————————————————————————————————————◨ */stringpublic name ="Gnars HD";
stringpublic symbol ="GNARSHD";
stringpublic rendererBaseUri;
stringpublic contractURI;
Artwork public artwork;
ISkateContractV2 public gnarsV2;
/* ⌐◨—————————————————————————————————————————————————————————————◨
CONSTRUCTOR
⌐◨—————————————————————————————————————————————————————————————◨ */constructor(address _gnarsV2Address,
stringmemory _rendererBaseUri,
Artwork memory _artwork,
stringmemory _contractURI,
address _owner
) Owned(_owner) {
gnarsV2 = ISkateContractV2(_gnarsV2Address);
rendererBaseUri = _rendererBaseUri;
artwork = _artwork;
contractURI = _contractURI;
}
/* ⌐◨—————————————————————————————————————————————————————————————◨
MAIN LOGIC
⌐◨—————————————————————————————————————————————————————————————◨ */functionsetArtwork(Artwork memory _artwork) publiconlyOwner{
artwork = _artwork;
}
functionsetContractUri(stringmemory _contractURI) publiconlyOwner{
contractURI = _contractURI;
}
functionsetRendererBaseUri(stringmemory _rendererBaseUri) publiconlyOwner{
rendererBaseUri = _rendererBaseUri;
}
/// @notice The properties and query string for a generated token/// @param _tokenId The ERC-721 token idfunctiongetAttributes(uint256 _tokenId)
publicviewreturns (stringmemory resultAttributes, stringmemory queryString)
{
(uint48 background, uint48 body, uint48 accessory, uint48 head, uint48 glasses) = gnarsV2.seeds(_tokenId);
IGnarDescriptorV2 descriptor = IGnarDescriptorV2(gnarsV2.descriptor());
IGnarDecorator decorator = IGnarDecorator(descriptor.decorator());
queryString =string.concat(
"?contractAddress=",
Strings.toHexString(address(this)),
"&tokenId=",
Strings.toString(_tokenId),
getBackgroundQueryParam(background),
getPartQueryParam("BODY", body, artwork.amountBodies),
getPartQueryParam("ACCESSORY", accessory, artwork.amountAccessories),
getPartQueryParam("HEADS", head, artwork.amountHeads),
getPartQueryParam("NOGGLES", glasses, artwork.amountNoggles)
);
resultAttributes =string.concat(
getPartTrait("Background", background, decorator.backgrounds),
",",
getPartTrait("Body", body, decorator.bodies),
",",
getPartTrait("Accessory", accessory, decorator.accessories),
",",
getPartTrait("Head", head, decorator.heads),
",",
getPartTrait("Glasses", glasses, decorator.glasses)
);
}
functiongetPartQueryParam(stringmemory folder, uint48 partIndex, uint48 amountOfPart)
publicviewreturns (stringmemory)
{
if (partIndex >= amountOfPart) {
returnstring.concat("&images=", artwork.ipfsFolder, "/", folder, "/FALLBACK.PNG");
}
returnstring.concat("&images=", artwork.ipfsFolder, "/", folder, "/", Strings.toString(partIndex), ".PNG");
}
functiongetBackgroundQueryParam(uint48 backgroundIndex) publicviewreturns (stringmemory) {
if (backgroundIndex >= artwork.amountBackgrounds) {
returnstring.concat("&images=", artwork.ipfsFolder, "/BACKGROUND/FALLBACK.PNG");
}
returnstring.concat("&images=", artwork.ipfsFolder, "/BACKGROUND/", Strings.toString(backgroundIndex), ".PNG");
}
functiongetPartTrait(stringmemory traitType,
uint48 partIndex,
function (uint256) externalviewreturns (stringmemory) getPartDescription
) publicviewreturns (stringmemory) {
try getPartDescription(partIndex) returns (stringmemory partDescription) {
returnstring.concat('{"trait_type":"', traitType, '","value":"', partDescription, '"}');
} catch {
returnstring.concat('{"trait_type":"', traitType, '","value":"Unknown"}');
}
}
functiontokenURI(uint256 _tokenId) publicviewreturns (stringmemory) {
if (gnarsV2.ownerOf(_tokenId) ==address(0)) {
revert TokenDoesNotExist(_tokenId);
}
(stringmemory attributes, stringmemory queryString) = getAttributes(_tokenId);
returnstring(
abi.encodePacked(
"data:application/json;base64,",
Base64.encode(
bytes(
abi.encodePacked(
'{"name":"Gnar HD #',
Strings.toString(_tokenId),
'", "description":"High definition Gnar #',
Strings.toString(_tokenId),
" counterpart",
'", "attributes": [',
attributes,
'], "image": "',
string.concat(rendererBaseUri, queryString),
'"}'
)
)
)
)
);
}
/* ⌐◨—————————————————————————————————————————————————————————————◨
PASSTHROUGH METHODS
⌐◨—————————————————————————————————————————————————————————————◨ *//// @notice Returns the total amount of Gnars HD in existence/// @dev Delegates to the Gnars V2 contractfunctiontotalSupply() externalviewreturns (uint256) {
return gnarsV2.totalSupply();
}
/// @notice Returns the tokenId of the Gnar HD by index/// @dev Delegates to the Gnars V2 contractfunctiontokenByIndex(uint256 _index) externalviewreturns (uint256) {
return gnarsV2.tokenByIndex(_index);
}
/// @notice Returns the Gnar HD owner's address by token index/// @dev Delegates to the Gnars V2 contractfunctiontokenOfOwnerByIndex(address _owner, uint256 _index) externalviewreturns (uint256) {
return gnarsV2.tokenOfOwnerByIndex(_owner, _index);
}
/// @notice Returns the Gnar HD owner's address by token id/// @dev Delegates to the Gnars V2 contractfunctionownerOf(uint256 id) publicviewreturns (address owner) {
return gnarsV2.ownerOf(id);
}
/// @notice Returns the amount of Gnars HD owned by the specified address/// @dev Delegates to the Gnars V2 contractfunctionbalanceOf(address owner) publicviewreturns (uint256) {
return gnarsV2.balanceOf(owner);
}
/// @notice Refresh ownership of specified tokens on marketplaces/datasets that are showing out of date information/// @dev Since this token is not mintable, there's no Transfer event. This method emits the Transfer event so that consumers that can detect the creation/new ownership of the token./// @param tokenIds The ids of tokens to refreshfunctionassertOwnership(uint256[] memory tokenIds) public{
for (uint256 i =0; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
emit Transfer(address(0), gnarsV2.ownerOf(tokenId), tokenId);
}
}
/* ⌐◨—————————————————————————————————————————————————————————————◨
ERC721 LOGIC
⌐◨—————————————————————————————————————————————————————————————◨ *//// @notice Gnars HD are not transferable/// @dev Will always revertfunctionapprove(address, uint256) publicpure{
revert Untransferable();
}
/// @notice Gnars HD are not transferable/// @dev Will always revertfunctionsetApprovalForAll(address, bool) publicpure{
revert Untransferable();
}
/// @notice Gnars HD are not transferable/// @dev Will always revertfunctiontransferFrom(address, address, uint256) publicpure{
revert Untransferable();
}
/// @notice Gnars HD are not transferable/// @dev Will always revertfunctionsafeTransferFrom(address, address, uint256) publicpure{
revert Untransferable();
}
/// @notice Gnars HD are not transferable/// @dev Will always revertfunctionsafeTransferFrom(address, address, uint256, bytescalldata) publicpure{
revert Untransferable();
}
/* ⌐◨—————————————————————————————————————————————————————————————◨
ERC6454 LOGIC
⌐◨—————————————————————————————————————————————————————————————◨ *//// @notice Gnars HD are not transferable/// @dev Will always return falsefunctionisTransferable(uint256, address, address) externalpurereturns (bool) {
returnfalse;
}
/* ⌐◨—————————————————————————————————————————————————————————————◨
ERC165 LOGIC
⌐◨—————————————————————————————————————————————————————————————◨ */functionsupportsInterface(bytes4 interfaceId) publicviewvirtualreturns (bool) {
return interfaceId ==0x01ffc9a7// ERC165 Interface ID for ERC165|| interfaceId ==0x80ac58cd// ERC165 Interface ID for ERC721|| interfaceId ==0x5b5e139f// ERC165 Interface ID for ERC721Metadata|| interfaceId ==0x780e9d63// ERC165 Interface ID for ERC721Enumerable|| interfaceId ==0x7f5828d0// ERC165 Interface ID for ERC173|| interfaceId ==0x91a6262f; // ERC165 Interface ID for ERC6454
}
}
interfaceIGnarDecorator{
functionaccessories(uint256) externalviewreturns (stringmemory);
functionbackgrounds(uint256) externalviewreturns (stringmemory);
functionbodies(uint256) externalviewreturns (stringmemory);
functionglasses(uint256) externalviewreturns (stringmemory);
functionheads(uint256) externalviewreturns (stringmemory);
}
interfaceIGnarDescriptorV2{
functiondecorator() externalviewreturns (address);
}
interfaceISkateContractV2{
functionbalanceOf(address owner) externalviewreturns (uint256);
functiondescriptor() externalviewreturns (address);
functionownerOf(uint256 tokenId) externalviewreturns (address);
functionseeds(uint256)
externalviewreturns (uint48 background, uint48 body, uint48 accessory, uint48 head, uint48 glasses);
functiontokenByIndex(uint256 index) externalviewreturns (uint256);
functiontokenOfOwnerByIndex(address owner, uint256 index) externalviewreturns (uint256);
functiontotalSupply() externalviewreturns (uint256);
}
Código Fuente del Contrato
Archivo 2 de 6: Math.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.9.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) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.// The surrounding unchecked block does not change this fact.// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////// 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 256, 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 <<3) < value ? 1 : 0);
}
}
}
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)pragmasolidity ^0.8.0;/**
* @dev Standard signed math utilities missing in the Solidity language.
*/librarySignedMath{
/**
* @dev Returns the largest of two signed numbers.
*/functionmax(int256 a, int256 b) internalpurereturns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/functionmin(int256 a, int256 b) internalpurereturns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/functionaverage(int256 a, int256 b) internalpurereturns (int256) {
// Formula from the book "Hacker's Delight"int256 x = (a & b) + ((a ^ b) >>1);
return x + (int256(uint256(x) >>255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/functionabs(int256 n) internalpurereturns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`returnuint256(n >=0 ? n : -n);
}
}
}
Código Fuente del Contrato
Archivo 5 de 6: Strings.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)pragmasolidity ^0.8.0;import"./math/Math.sol";
import"./math/SignedMath.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 `int256` to its ASCII `string` decimal representation.
*/functiontoString(int256 value) internalpurereturns (stringmemory) {
returnstring(abi.encodePacked(value <0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @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);
}
/**
* @dev Returns true if the two strings are equal.
*/functionequal(stringmemory a, stringmemory b) internalpurereturns (bool) {
returnkeccak256(bytes(a)) ==keccak256(bytes(b));
}
}
Código Fuente del Contrato
Archivo 6 de 6: base64.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.6.0;/// @title Base64/// @author Brecht Devos - <brecht@loopring.org>/// @notice Provides functions for encoding/decoding base64libraryBase64{
stringinternalconstant TABLE_ENCODE ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
bytesinternalconstant TABLE_DECODE =hex"0000000000000000000000000000000000000000000000000000000000000000"hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000"hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000"hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000";
functionencode(bytesmemory data) internalpurereturns (stringmemory) {
if (data.length==0) return'';
// load the table into memorystringmemory table = TABLE_ENCODE;
// multiply by 4/3 rounded upuint256 encodedLen =4* ((data.length+2) /3);
// add some extra buffer at the end required for the writingstringmemory result =newstring(encodedLen +32);
assembly {
// set the actual output lengthmstore(result, encodedLen)
// prepare the lookup tablelet tablePtr :=add(table, 1)
// input ptrlet dataPtr := data
let endPtr :=add(dataPtr, mload(data))
// result ptr, jump over lengthlet resultPtr :=add(result, 32)
// run over the input, 3 bytes at a timefor {} lt(dataPtr, endPtr) {}
{
// read 3 bytes
dataPtr :=add(dataPtr, 3)
let input :=mload(dataPtr)
// write 4 charactersmstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr :=add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr :=add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and(shr( 6, input), 0x3F))))
resultPtr :=add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and( input, 0x3F))))
resultPtr :=add(resultPtr, 1)
}
// padding with '='switchmod(mload(data), 3)
case1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) }
case2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) }
}
return result;
}
functiondecode(stringmemory _data) internalpurereturns (bytesmemory) {
bytesmemory data =bytes(_data);
if (data.length==0) returnnewbytes(0);
require(data.length%4==0, "invalid base64 decoder input");
// load the table into memorybytesmemory table = TABLE_DECODE;
// every 4 characters represent 3 bytesuint256 decodedLen = (data.length/4) *3;
// add some extra buffer at the end required for the writingbytesmemory result =newbytes(decodedLen +32);
assembly {
// padding with '='let lastBytes :=mload(add(data, mload(data)))
ifeq(and(lastBytes, 0xFF), 0x3d) {
decodedLen :=sub(decodedLen, 1)
ifeq(and(lastBytes, 0xFFFF), 0x3d3d) {
decodedLen :=sub(decodedLen, 1)
}
}
// set the actual output lengthmstore(result, decodedLen)
// prepare the lookup tablelet tablePtr :=add(table, 1)
// input ptrlet dataPtr := data
let endPtr :=add(dataPtr, mload(data))
// result ptr, jump over lengthlet resultPtr :=add(result, 32)
// run over the input, 4 characters at a timefor {} lt(dataPtr, endPtr) {}
{
// read 4 characters
dataPtr :=add(dataPtr, 4)
let input :=mload(dataPtr)
// write 3 byteslet output :=add(
add(
shl(18, and(mload(add(tablePtr, and(shr(24, input), 0xFF))), 0xFF)),
shl(12, and(mload(add(tablePtr, and(shr(16, input), 0xFF))), 0xFF))),
add(
shl( 6, and(mload(add(tablePtr, and(shr( 8, input), 0xFF))), 0xFF)),
and(mload(add(tablePtr, and( input , 0xFF))), 0xFF)
)
)
mstore(resultPtr, shl(232, output))
resultPtr :=add(resultPtr, 3)
}
}
return result;
}
}