Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
TheStalkerFRESHHELLRenderer
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
No with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; // the stalker by int.art // a permissionless collaboration program running on EVM. // Original artworks by XCOPY (FRESH HELL). // Modified artworks are CCO licensed. // If XCOPY mints a token that's not CC0, int.art has right to // block that token. import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {Base64} from "solady/src/utils/Base64.sol"; import {LibString} from "solady/src/utils/LibString.sol"; import {IScriptyBuilderV2, HTMLRequest, HTMLTagType, HTMLTag} from "scripty.sol/contracts/scripty/interfaces/IScriptyBuilderV2.sol"; import {ITheStalkerRenderer} from "./../TheStalkerCommon.sol"; interface IManifoldCreatorContract { function totalSupply(uint256 tokenId) external view returns (uint256); } interface IEfficax { function tokenData( address, uint256 ) external view returns (string calldata, string calldata); function tokenURI( address creatorContractAddress, uint256 tokenId ) external view returns (string memory); } contract TheStalkerFRESHHELLRenderer is Ownable, ITheStalkerRenderer { IScriptyBuilderV2 public immutable scriptyBuilder; address public immutable scriptyETHFSAddress; IEfficax public immutable efficax; IManifoldCreatorContract public immutable freshHell; ITheStalkerRenderer public defaultRenderer; mapping(uint256 => bool) public blockedTokenIds; error BlockedTokenId(); constructor( IScriptyBuilderV2 _scriptyBuilder, address _scriptyETHFSAddress, IEfficax _efficax, IManifoldCreatorContract _freshHell, ITheStalkerRenderer _defaultRenderer ) Ownable(msg.sender) { scriptyBuilder = _scriptyBuilder; scriptyETHFSAddress = _scriptyETHFSAddress; efficax = _efficax; freshHell = _freshHell; defaultRenderer = _defaultRenderer; } // CONTRACT OWNER function updateBlockedTokenIds( uint256 targetTokenId, bool isBlocked ) public onlyOwner { blockedTokenIds[targetTokenId] = isBlocked; emit BlockedTokenIdUpdate(targetTokenId, isBlocked); } function updateDefaultRenderer( ITheStalkerRenderer _defaultRenderer ) public onlyOwner { defaultRenderer = _defaultRenderer; emit DefaultRendererUpdate(_defaultRenderer); } // PUBLIC function canUpdateToken( address /*sender*/, uint256 /*tokenId*/, uint256 targetTokenId ) public view override returns (bool) { return !blockedTokenIds[targetTokenId]; } function isTokenRenderable( uint256 /*tokenId*/, uint256 targetTokenId ) public view override returns (bool) { return canRender(targetTokenId); } function tokenHTML( uint256 tokenId, uint256 targetTokenId ) public view override returns (string memory) { if (!canRender(targetTokenId)) { return defaultRenderer.tokenHTML(tokenId, targetTokenId); } (string memory original, ) = generateModifiedFreshHellSVG( targetTokenId ); return tokenHTMLWithFreshHellBase64SVG( string(Base64.encode(bytes(original))) ); } function tokenImage( uint256 tokenId, uint256 targetTokenId ) public view override returns (string memory) { if (!canRender(targetTokenId)) { return defaultRenderer.tokenImage(tokenId, targetTokenId); } (, string memory modified) = generateModifiedFreshHellSVG( targetTokenId ); return string( abi.encodePacked( "data:image/svg+xml;base64,", Base64.encode(bytes(modified)) ) ); } function tokenURI( uint256 tokenId, uint256 targetTokenId ) public view override returns (string memory) { if (!canRender(targetTokenId)) { return defaultRenderer.tokenURI(tokenId, targetTokenId); } ( string memory original, string memory modified ) = generateModifiedFreshHellSVG(targetTokenId); bytes memory metadata = abi.encodePacked( '{"name":"the stalker #', LibString.toString(tokenId), '", "description":"a permissionless collaboration program running on EVM - int.art x XCOPY - Original artwork by XCOPY (FRESH HELL).","animation_url":"', tokenHTMLWithFreshHellBase64SVG( string(Base64.encode(bytes(original))) ), '","image":"', abi.encodePacked( "data:image/svg+xml;base64,", Base64.encode(bytes(modified)) ), '"}' ); return string( abi.encodePacked( "data:application/json;base64,", Base64.encode(metadata) ) ); } // Modifying a little bit to make it stand out from original // FRESH HELL artworks. Hoping he keeps minting SVGs. function generateModifiedFreshHellSVG( uint256 targetTokenId ) public view returns (string memory, string memory) { if (blockedTokenIds[targetTokenId]) { revert BlockedTokenId(); } (string memory svg, ) = decodedImageFromEfficax( address(freshHell), targetTokenId ); string memory svgOriginal = string(Base64.decode(svg)); // hoping <svg ... > is the first tag uint256 svgBeginIndex = LibString.indexOf(svgOriginal, ">"); // if we can't find just return the original image if (svgBeginIndex == type(uint256).max) { return (svgOriginal, svgOriginal); } string memory svgModifiedPrefix = LibString.slice( svgOriginal, 0, svgBeginIndex + 1 ); uint256 length = bytes(svgOriginal).length; string memory svgModifiedSuffix = LibString.slice( svgOriginal, svgBeginIndex + 1, length - 6 ); string memory svgModified = LibString.concat( svgModifiedPrefix, '<g id="DUDE"><style type="text/css">@keyframes shakeAnimation {0%,75% {transform: translate(0.3%, 0.3%) scale(1.1, 1.1);}76%,100% {transform: translate(-0.3%, -0.3%) scale(1.1, 1.1);}}#DUDE {animation: shakeAnimation 0.16s infinite;transform-origin: center;}</style>' ); svgModified = LibString.concat(svgModified, svgModifiedSuffix); svgModified = LibString.concat(svgModified, "</g></svg>"); return (svgOriginal, svgModified); } // Generic Efficax decoder. This returns raw base64 image without // data uri part. This is public and generic so you can request // any raw image data from Efficax. function decodedImageFromEfficax( address collectionAddress, uint256 tokenId ) public view returns (string memory, string memory) { unchecked { string memory _tokenURI = efficax.tokenURI( collectionAddress, tokenId ); (string memory metadata, string memory mimeType) = efficax .tokenData(collectionAddress, tokenId); uint256 sliceBeginIndex = 40 + bytes(metadata).length + bytes(mimeType).length + 13; uint256 sliceEndIndex = bytes(_tokenURI).length - 2; return ( LibString.slice(_tokenURI, sliceBeginIndex, sliceEndIndex), mimeType ); } } function tokenHTMLWithFreshHellBase64SVG( string memory base64SVGWithoutDataURI ) public view virtual returns (string memory) { HTMLTag[] memory headTags = new HTMLTag[](1); headTags[0].name = "fullSizeCanvas.css"; headTags[0] .tagOpen = '<link rel="stylesheet" href="data:text/css;base64,'; headTags[0].tagClose = '">'; headTags[0].contractAddress = scriptyETHFSAddress; HTMLTag[] memory bodyTags = new HTMLTag[](2); bodyTags[0].name = "thestalkerFRESHHELL.js"; bodyTags[0].contractAddress = scriptyETHFSAddress; bodyTags[0].tagType = HTMLTagType.scriptBase64DataURI; bodyTags[1].tagContent = abi.encodePacked( "const svgData = '", base64SVGWithoutDataURI, "';", "thestalkerFRESHHELL(svgData)" ); bodyTags[1].tagType = HTMLTagType.script; HTMLRequest memory htmlRequest; htmlRequest.headTags = headTags; htmlRequest.bodyTags = bodyTags; return scriptyBuilder.getEncodedHTMLString(htmlRequest); } function canRender(uint256 targetTokenId) public view returns (bool) { uint256 totalSupply = freshHell.totalSupply(targetTokenId); return totalSupply > 0 && !blockedTokenIds[targetTokenId]; } // EVENTS event BlockedTokenIdUpdate(uint256 _tokenId, bool _isBlocked); event DefaultRendererUpdate(ITheStalkerRenderer _defaultRenderer); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/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. * * The initial owner is set to the address provided by the deployer. 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. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @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. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; // the stalker by int.art // a permissionless collaboration program running on EVM. interface ITheStalkerRenderer { function canUpdateToken( address sender, uint256 tokenId, uint256 targetTokenId ) external view returns (bool); function isTokenRenderable( uint256 tokenId, uint256 targetTokenId ) external view returns (bool); function tokenHTML( uint256 tokenId, uint256 targetTokenid ) external view returns (string memory); function tokenImage( uint256 tokenId, uint256 targetTokenid ) external view returns (string memory); function tokenURI( uint256 tokenId, uint256 targetTokenid ) external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /////////////////////////////////////////////////////////// // ░██████╗░█████╗░██████╗░██╗██████╗░████████╗██╗░░░██╗ // // ██╔════╝██╔══██╗██╔══██╗██║██╔══██╗╚══██╔══╝╚██╗░██╔╝ // // ╚█████╗░██║░░╚═╝██████╔╝██║██████╔╝░░░██║░░░░╚████╔╝░ // // ░╚═══██╗██║░░██╗██╔══██╗██║██╔═══╝░░░░██║░░░░░╚██╔╝░░ // // ██████╔╝╚█████╔╝██║░░██║██║██║░░░░░░░░██║░░░░░░██║░░░ // // ╚═════╝░░╚════╝░╚═╝░░╚═╝╚═╝╚═╝░░░░░░░░╚═╝░░░░░░╚═╝░░░ // /////////////////////////////////////////////////////////// //░░░░░░░░░░░░░░░░░░░░░░ CORE ░░░░░░░░░░░░░░░░░░░░░// /////////////////////////////////////////////////////////// import {HTMLRequest, HTMLTagType, HTMLTag} from "./ScriptyStructs.sol"; import {DynamicBuffer} from "./../utils/DynamicBuffer.sol"; import {IScriptyStorage} from "./../interfaces/IScriptyStorage.sol"; import {IContractScript} from "./../interfaces/IContractScript.sol"; contract ScriptyCore { using DynamicBuffer for bytes; // ============================================================= // TAG CONSTANTS // ============================================================= // data:text/html;base64, // raw // 22 bytes bytes public constant DATA_HTML_BASE64_URI_RAW = "data:text/html;base64,"; // url encoded // 21 bytes bytes public constant DATA_HTML_URL_SAFE = "data%3Atext%2Fhtml%2C"; // <html>, // raw // 6 bytes bytes public constant HTML_OPEN_RAW = "<html>"; // url encoded // 10 bytes bytes public constant HTML_OPEN_URL_SAFE = "%3Chtml%3E"; // <head>, // raw // 6 bytes bytes public constant HEAD_OPEN_RAW = "<head>"; // url encoded // 10 bytes bytes public constant HEAD_OPEN_URL_SAFE = "%3Chead%3E"; // </head>, // raw // 7 bytes bytes public constant HEAD_CLOSE_RAW = "</head>"; // url encoded // 13 bytes bytes public constant HEAD_CLOSE_URL_SAFE = "%3C%2Fhead%3E"; // <body> // 6 bytes bytes public constant BODY_OPEN_RAW = "<body>"; // url encoded // 10 bytes bytes public constant BODY_OPEN_URL_SAFE = "%3Cbody%3E"; // </body></html> // 14 bytes bytes public constant HTML_BODY_CLOSED_RAW = "</body></html>"; // 26 bytes bytes public constant HTML_BODY_CLOSED_URL_SAFE = "%3C%2Fbody%3E%3C%2Fhtml%3E"; // [RAW] // HTML_OPEN + HEAD_OPEN + HEAD_CLOSE + BODY_OPEN + HTML_BODY_CLOSED uint256 public constant URLS_RAW_BYTES = 39; // [URL_SAFE] // DATA_HTML_URL_SAFE + HTML_OPEN + HEAD_OPEN + HEAD_CLOSE + BODY_OPEN + HTML_BODY_CLOSED uint256 public constant URLS_SAFE_BYTES = 90; // [RAW] // HTML_OPEN + HTML_CLOSE uint256 public constant HTML_RAW_BYTES = 13; // [RAW] // HEAD_OPEN + HEAD_CLOSE uint256 public constant HEAD_RAW_BYTES = 13; // [RAW] // BODY_OPEN + BODY_CLOSE uint256 public constant BODY_RAW_BYTES = 13; // All raw // HTML_RAW_BYTES + HEAD_RAW_BYTES + BODY_RAW_BYTES uint256 public constant RAW_BYTES = 39; // [URL_SAFE] // HTML_OPEN + HTML_CLOSE uint256 public constant HTML_URL_SAFE_BYTES = 23; // [URL_SAFE] // HEAD_OPEN + HEAD_CLOSE uint256 public constant HEAD_URL_SAFE_BYTES = 23; // [URL_SAFE] // BODY_OPEN + BODY_CLOSE uint256 public constant BODY_SAFE_BYTES = 23; // All url safe // HTML_URL_SAFE_BYTES + HEAD_URL_SAFE_BYTES + BODY_URL_SAFE_BYTES // %3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3C%2Fbody%3E%3C%2Fhtml%3E uint256 public constant URL_SAFE_BYTES = 69; // data:text/html;base64, uint256 public constant HTML_BASE64_DATA_URI_BYTES = 22; // ============================================================= // TAG OPEN CLOSE TEMPLATES // ============================================================= /** * @notice Grab tag open and close depending on tag type * @dev * tagType: 0/HTMLTagType.useTagOpenAndClose or any other: * [tagOpen][CONTENT][tagClose] * * tagType: 1/HTMLTagType.script: * <script>[SCRIPT]</script> * * tagType: 2/HTMLTagType.scriptBase64DataURI: * <script src="data:text/javascript;base64,[SCRIPT]"></script> * * tagType: 3/HTMLTagType.scriptGZIPBase64DataURI: * <script type="text/javascript+gzip" src="data:text/javascript;base64,[SCRIPT]"></script> * * tagType: 4/HTMLTagType.scriptPNGBase64DataURI * <script type="text/javascript+png" name="[NAME]" src="data:text/javascript;base64,[SCRIPT]"></script> * * [IMPORTANT NOTE]: The tags `text/javascript+gzip` and `text/javascript+png` are used to identify scripts * during decompression * * @param htmlTag - HTMLTag data for code * @return (tagOpen, tagClose) - Tag open and close as a tuple */ function tagOpenCloseForHTMLTag( HTMLTag memory htmlTag ) public pure returns (bytes memory, bytes memory) { if (htmlTag.tagType == HTMLTagType.script) { return ("<script>", "</script>"); } else if (htmlTag.tagType == HTMLTagType.scriptBase64DataURI) { return ('<script src="data:text/javascript;base64,', '"></script>'); } else if (htmlTag.tagType == HTMLTagType.scriptGZIPBase64DataURI) { return ( '<script type="text/javascript+gzip" src="data:text/javascript;base64,', '"></script>' ); } else if (htmlTag.tagType == HTMLTagType.scriptPNGBase64DataURI) { return ( '<script type="text/javascript+png" src="data:text/javascript;base64,', '"></script>' ); } return (htmlTag.tagOpen, htmlTag.tagClose); } /** * @notice Grab URL safe tag open and close depending on tag type * @dev * tagType: 0/HTMLTagType.useTagOpenAndClose or any other: * [tagOpen][scriptContent or scriptFromContract][tagClose] * * tagType: 1/HTMLTagType.script: * tagType: 2/HTMLTagType.scriptBase64DataURI: * <script src="data:text/javascript;base64,[SCRIPT]"></script> * * tagType: 3/HTMLTagType.scriptGZIPBase64DataURI: * <script type="text/javascript+gzip" src="data:text/javascript;base64,[SCRIPT]"></script> * * tagType: 4/HTMLTagType.scriptPNGBase64DataURI * <script type="text/javascript+png" name="[NAME]" src="data:text/javascript;base64,[SCRIPT]"></script> * * [IMPORTANT NOTE]: The tags `text/javascript+gzip` and `text/javascript+png` are used to identify scripts * during decompression * * @param htmlTag - HTMLTag data for code * @return (tagOpen, tagClose) - Tag open and close as a tuple */ function tagOpenCloseForHTMLTagURLSafe( HTMLTag memory htmlTag ) public pure returns (bytes memory, bytes memory) { if ( htmlTag.tagType == HTMLTagType.script || htmlTag.tagType == HTMLTagType.scriptBase64DataURI ) { // <script src="data:text/javascript;base64, // "></script> return ( "%253Cscript%2520src%253D%2522data%253Atext%252Fjavascript%253Bbase64%252C", "%2522%253E%253C%252Fscript%253E" ); } else if (htmlTag.tagType == HTMLTagType.scriptGZIPBase64DataURI) { // <script type="text/javascript+gzip" src="data:text/javascript;base64, // "></script> return ( "%253Cscript%2520type%253D%2522text%252Fjavascript%252Bgzip%2522%2520src%253D%2522data%253Atext%252Fjavascript%253Bbase64%252C", "%2522%253E%253C%252Fscript%253E" ); } else if (htmlTag.tagType == HTMLTagType.scriptPNGBase64DataURI) { // <script type="text/javascript+png" src="data:text/javascript;base64, // "></script> return ( "%253Cscript%2520type%253D%2522text%252Fjavascript%252Bpng%2522%2520src%253D%2522data%253Atext%252Fjavascript%253Bbase64%252C", "%2522%253E%253C%252Fscript%253E" ); } return (htmlTag.tagOpen, htmlTag.tagClose); } // ============================================================= // TAG CONTENT FETCHER // ============================================================= /** * @notice Grabs requested tag content from storage * @dev * If given HTMLTag contains non empty tagContent * this method will return tagContent. Otherwise, * method will fetch it from the given storage * contract * * @param htmlTag - HTMLTag */ function fetchTagContent( HTMLTag memory htmlTag ) public view returns (bytes memory) { if (htmlTag.tagContent.length > 0) { return htmlTag.tagContent; } return IContractScript(htmlTag.contractAddress).getScript( htmlTag.name, htmlTag.contractData ); } // ============================================================= // SIZE OPERATIONS // ============================================================= /** * @notice Calculate the buffer size post base64 encoding * @param value - Starting buffer size * @return Final buffer size as uint256 */ function sizeForBase64Encoding( uint256 value ) public pure returns (uint256) { unchecked { return 4 * ((value + 2) / 3); } } /** * @notice Adds the required tag open/close and calculates buffer size of tags * @dev Effectively multiple functions bundled into one as this saves gas * @param htmlTags - Array of HTMLTag * @param isURLSafe - Bool to handle tag content/open/close encoding * @return Total buffersize of updated HTMLTags */ function _enrichHTMLTags( HTMLTag[] memory htmlTags, bool isURLSafe ) internal view returns (uint256) { if (htmlTags.length == 0) { return 0; } bytes memory tagOpen; bytes memory tagClose; bytes memory tagContent; uint256 totalSize; uint256 length = htmlTags.length; uint256 i; unchecked { do { tagContent = fetchTagContent(htmlTags[i]); htmlTags[i].tagContent = tagContent; if (isURLSafe && htmlTags[i].tagType == HTMLTagType.script) { totalSize += sizeForBase64Encoding(tagContent.length); } else { totalSize += tagContent.length; } if (isURLSafe) { (tagOpen, tagClose) = tagOpenCloseForHTMLTagURLSafe( htmlTags[i] ); } else { (tagOpen, tagClose) = tagOpenCloseForHTMLTag(htmlTags[i]); } htmlTags[i].tagOpen = tagOpen; htmlTags[i].tagClose = tagClose; totalSize += tagOpen.length; totalSize += tagClose.length; } while (++i < length); } return totalSize; } // ============================================================= // HTML CONCATENATION // ============================================================= /** * @notice Append tags to the html buffer for tags * @param htmlFile - bytes buffer * @param htmlTags - Tags being added to buffer * @param encodeTagContent - Bool to handle tag content encoding */ function _appendHTMLTags( bytes memory htmlFile, HTMLTag[] memory htmlTags, bool encodeTagContent ) internal pure { uint256 i; unchecked { do { _appendHTMLTag( htmlFile, htmlTags[i], encodeTagContent ); } while (++i < htmlTags.length); } } /** * @notice Append tag to the html buffer * @param htmlFile - bytes buffer * @param htmlTag - Request being added to buffer * @param encodeTagContent - Bool to handle tag content encoding */ function _appendHTMLTag( bytes memory htmlFile, HTMLTag memory htmlTag, bool encodeTagContent ) internal pure { htmlFile.appendSafe(htmlTag.tagOpen); if (encodeTagContent) { htmlFile.appendSafeBase64(htmlTag.tagContent, false, false); } else { htmlFile.appendSafe(htmlTag.tagContent); } htmlFile.appendSafe(htmlTag.tagClose); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /////////////////////////////////////////////////////////// // ░██████╗░█████╗░██████╗░██╗██████╗░████████╗██╗░░░██╗ // // ██╔════╝██╔══██╗██╔══██╗██║██╔══██╗╚══██╔══╝╚██╗░██╔╝ // // ╚█████╗░██║░░╚═╝██████╔╝██║██████╔╝░░░██║░░░░╚████╔╝░ // // ░╚═══██╗██║░░██╗██╔══██╗██║██╔═══╝░░░░██║░░░░░╚██╔╝░░ // // ██████╔╝╚█████╔╝██║░░██║██║██║░░░░░░░░██║░░░░░░██║░░░ // // ╚═════╝░░╚════╝░╚═╝░░╚═╝╚═╝╚═╝░░░░░░░░╚═╝░░░░░░╚═╝░░░ // /////////////////////////////////////////////////////////// //░░░░░░░░░░░░░░░░░░░ REQUESTS ░░░░░░░░░░░░░░░░░░░░// /////////////////////////////////////////////////////////// struct HTMLRequest { HTMLTag[] headTags; HTMLTag[] bodyTags; } enum HTMLTagType { useTagOpenAndClose, script, scriptBase64DataURI, scriptGZIPBase64DataURI, scriptPNGBase64DataURI } struct HTMLTag { string name; address contractAddress; bytes contractData; HTMLTagType tagType; bytes tagOpen; bytes tagClose; bytes tagContent; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /////////////////////////////////////////////////////////// // ░██████╗░█████╗░██████╗░██╗██████╗░████████╗██╗░░░██╗ // // ██╔════╝██╔══██╗██╔══██╗██║██╔══██╗╚══██╔══╝╚██╗░██╔╝ // // ╚█████╗░██║░░╚═╝██████╔╝██║██████╔╝░░░██║░░░░╚████╔╝░ // // ░╚═══██╗██║░░██╗██╔══██╗██║██╔═══╝░░░░██║░░░░░╚██╔╝░░ // // ██████╔╝╚█████╔╝██║░░██║██║██║░░░░░░░░██║░░░░░░██║░░░ // // ╚═════╝░░╚════╝░╚═╝░░╚═╝╚═╝╚═╝░░░░░░░░╚═╝░░░░░░╚═╝░░░ // /////////////////////////////////////////////////////////// interface IContractScript { // ============================================================= // GETTERS // ============================================================= /** * @notice Get the full script * @param name - Name given to the script. Eg: threejs.min.js_r148 * @param data - Arbitrary data to be passed to storage * @return script - Full script from merged chunks */ function getScript(string calldata name, bytes memory data) external view returns (bytes memory script); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /////////////////////////////////////////////////////////// // ░██████╗░█████╗░██████╗░██╗██████╗░████████╗██╗░░░██╗ // // ██╔════╝██╔══██╗██╔══██╗██║██╔══██╗╚══██╔══╝╚██╗░██╔╝ // // ╚█████╗░██║░░╚═╝██████╔╝██║██████╔╝░░░██║░░░░╚████╔╝░ // // ░╚═══██╗██║░░██╗██╔══██╗██║██╔═══╝░░░░██║░░░░░╚██╔╝░░ // // ██████╔╝╚█████╔╝██║░░██║██║██║░░░░░░░░██║░░░░░░██║░░░ // // ╚═════╝░░╚════╝░╚═╝░░╚═╝╚═╝╚═╝░░░░░░░░╚═╝░░░░░░╚═╝░░░ // /////////////////////////////////////////////////////////// /** @title A generic HTML builder that fetches and assembles given JS requests. @author @0xthedude @author @xtremetom Special thanks to @cxkoda and @frolic */ import "./IScriptyHTML.sol"; import "./IScriptyHTMLURLSafe.sol"; interface IScriptyBuilderV2 is IScriptyHTML, IScriptyHTMLURLSafe {}
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /////////////////////////////////////////////////////////// // ░██████╗░█████╗░██████╗░██╗██████╗░████████╗██╗░░░██╗ // // ██╔════╝██╔══██╗██╔══██╗██║██╔══██╗╚══██╔══╝╚██╗░██╔╝ // // ╚█████╗░██║░░╚═╝██████╔╝██║██████╔╝░░░██║░░░░╚████╔╝░ // // ░╚═══██╗██║░░██╗██╔══██╗██║██╔═══╝░░░░██║░░░░░╚██╔╝░░ // // ██████╔╝╚█████╔╝██║░░██║██║██║░░░░░░░░██║░░░░░░██║░░░ // // ╚═════╝░░╚════╝░╚═╝░░╚═╝╚═╝╚═╝░░░░░░░░╚═╝░░░░░░╚═╝░░░ // /////////////////////////////////////////////////////////// import {HTMLRequest, HTMLTagType, HTMLTag} from "./../core/ScriptyCore.sol"; interface IScriptyHTML { // ============================================================= // RAW HTML GETTERS // ============================================================= /** * @notice Get HTML with requested head tags and body tags * @dev Your HTML is returned in the following format: * <html> * <head> * [tagOpen[0]][contractRequest[0] | tagContent[0]][tagClose[0]] * [tagOpen[1]][contractRequest[0] | tagContent[1]][tagClose[1]] * ... * [tagOpen[n]][contractRequest[0] | tagContent[n]][tagClose[n]] * </head> * <body> * [tagOpen[0]][contractRequest[0] | tagContent[0]][tagClose[0]] * [tagOpen[1]][contractRequest[0] | tagContent[1]][tagClose[1]] * ... * [tagOpen[n]][contractRequest[0] | tagContent[n]][tagClose[n]] * </body> * </html> * @param htmlRequest - HTMLRequest * @return Full HTML with head and body tags */ function getHTML( HTMLRequest memory htmlRequest ) external view returns (bytes memory); // ============================================================= // ENCODED HTML GETTERS // ============================================================= /** * @notice Get {getHTML} and base64 encode it * @param htmlRequest - HTMLRequest * @return Full HTML with head and script tags, base64 encoded */ function getEncodedHTML( HTMLRequest memory htmlRequest ) external view returns (bytes memory); // ============================================================= // STRING UTILITIES // ============================================================= /** * @notice Convert {getHTML} output to a string * @param htmlRequest - HTMLRequest * @return {getHTMLWrapped} as a string */ function getHTMLString( HTMLRequest memory htmlRequest ) external view returns (string memory); /** * @notice Convert {getEncodedHTML} output to a string * @param htmlRequest - HTMLRequest * @return {getEncodedHTML} as a string */ function getEncodedHTMLString( HTMLRequest memory htmlRequest ) external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /////////////////////////////////////////////////////////// // ░██████╗░█████╗░██████╗░██╗██████╗░████████╗██╗░░░██╗ // // ██╔════╝██╔══██╗██╔══██╗██║██╔══██╗╚══██╔══╝╚██╗░██╔╝ // // ╚█████╗░██║░░╚═╝██████╔╝██║██████╔╝░░░██║░░░░╚████╔╝░ // // ░╚═══██╗██║░░██╗██╔══██╗██║██╔═══╝░░░░██║░░░░░╚██╔╝░░ // // ██████╔╝╚█████╔╝██║░░██║██║██║░░░░░░░░██║░░░░░░██║░░░ // // ╚═════╝░░╚════╝░╚═╝░░╚═╝╚═╝╚═╝░░░░░░░░╚═╝░░░░░░╚═╝░░░ // /////////////////////////////////////////////////////////// import {HTMLRequest, HTMLTagType, HTMLTag} from "./../core/ScriptyCore.sol"; interface IScriptyHTMLURLSafe { // ============================================================= // RAW HTML GETTERS // ============================================================= /** * @notice Get URL safe HTML with requested head tags and body tags * @dev Any tags with tagType = 1/script are converted to base64 and wrapped * with <script src="data:text/javascript;base64,[SCRIPT]"></script> * * [WARNING]: Large non-base64 libraries that need base64 encoding * carry a high risk of causing a gas out. Highly advised the use * of base64 encoded scripts where possible * * Your HTML is returned in the following format: * * <html> * <head> * [tagOpen[0]][contractRequest[0] | tagContent[0]][tagClose[0]] * [tagOpen[1]][contractRequest[0] | tagContent[1]][tagClose[1]] * ... * [tagOpen[n]][contractRequest[0] | tagContent[n]][tagClose[n]] * </head> * <body> * [tagOpen[0]][contractRequest[0] | tagContent[0]][tagClose[0]] * [tagOpen[1]][contractRequest[0] | tagContent[1]][tagClose[1]] * ... * [tagOpen[n]][contractRequest[0] | tagContent[n]][tagClose[n]] * </body> * </html> * @param htmlRequest - HTMLRequest * @return Full HTML with head and body tags */ function getHTMLURLSafe( HTMLRequest memory htmlRequest ) external view returns (bytes memory); // ============================================================= // STRING UTILITIES // ============================================================= /** * @notice Convert {getHTMLURLSafe} output to a string * @param htmlRequest - HTMLRequest * @return {getHTMLURLSafe} as a string */ function getHTMLURLSafeString( HTMLRequest memory htmlRequest ) external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /////////////////////////////////////////////////////////// // ░██████╗░█████╗░██████╗░██╗██████╗░████████╗██╗░░░██╗ // // ██╔════╝██╔══██╗██╔══██╗██║██╔══██╗╚══██╔══╝╚██╗░██╔╝ // // ╚█████╗░██║░░╚═╝██████╔╝██║██████╔╝░░░██║░░░░╚████╔╝░ // // ░╚═══██╗██║░░██╗██╔══██╗██║██╔═══╝░░░░██║░░░░░╚██╔╝░░ // // ██████╔╝╚█████╔╝██║░░██║██║██║░░░░░░░░██║░░░░░░██║░░░ // // ╚═════╝░░╚════╝░╚═╝░░╚═╝╚═╝╚═╝░░░░░░░░╚═╝░░░░░░╚═╝░░░ // /////////////////////////////////////////////////////////// interface IScriptyStorage { // ============================================================= // STRUCTS // ============================================================= struct Script { bool isVerified; bool isFrozen; address owner; uint256 size; bytes details; address[] chunks; } // ============================================================= // ERRORS // ============================================================= /** * @notice Error for, The Script you are trying to create already exists */ error ScriptExists(); /** * @notice Error for, You dont have permissions to perform this action */ error NotScriptOwner(); /** * @notice Error for, The Script you are trying to edit is frozen */ error ScriptIsFrozen(string name); // ============================================================= // EVENTS // ============================================================= /** * @notice Event for, Successful freezing of a script * @param name - Name given to the script. Eg: threejs.min.js_r148 */ event ScriptFrozen(string indexed name); /** * @notice Event for, Successful update of script verification status * @param name - Name given to the script. Eg: threejs.min.js_r148 * @param isVerified - Verification status of the script */ event ScriptVerificationUpdated(string indexed name, bool isVerified); /** * @notice Event for, Successful creation of a script * @param name - Name given to the script. Eg: threejs.min.js_r148 * @param details - Custom details of the script */ event ScriptCreated(string indexed name, bytes details); /** * @notice Event for, Successful addition of script chunk * @param name - Name given to the script. Eg: threejs.min.js_r148 * @param size - Bytes size of the chunk */ event ChunkStored(string indexed name, uint256 size); /** * @notice Event for, Successful update of custom details * @param name - Name given to the script. Eg: threejs.min.js_r148 * @param details - Custom details of the script */ event ScriptDetailsUpdated(string indexed name, bytes details); // ============================================================= // MANAGEMENT OPERATIONS // ============================================================= /** * @notice Create a new script * @param name - Name given to the script. Eg: threejs.min.js_r148 * @param details - Any details the owner wishes to store about the script * * Emits an {ScriptCreated} event. */ function createScript(string calldata name, bytes calldata details) external; /** * @notice Add a code chunk to the script * @param name - Name given to the script. Eg: threejs.min.js_r148 * @param chunk - Next sequential code chunk * * Emits an {ChunkStored} event. */ function addChunkToScript(string calldata name, bytes calldata chunk) external; /** * @notice Edit the script details * @param name - Name given to the script. Eg: threejs.min.js_r148 * @param details - Any details the owner wishes to store about the script * * Emits an {ScriptDetailsUpdated} event. */ function updateDetails(string calldata name, bytes calldata details) external; /** * @notice Update the verification status of the script * @param name - Name given to the script. Eg: threejs.min.js_r148 * @param isVerified - The verification status * * Emits an {ScriptVerificationUpdated} event. */ function updateScriptVerification(string calldata name, bool isVerified) external; }
// SPDX-License-Identifier: MIT // Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier) pragma solidity >=0.8.0; /// @title DynamicBuffer /// @author David Huber (@cxkoda) and Simon Fremaux (@dievardump). See also /// https://raw.githubusercontent.com/dievardump/solidity-dynamic-buffer /// @notice This library is used to allocate a big amount of container memory // which will be subsequently filled without needing to reallocate /// memory. /// @dev First, allocate memory. /// Then use `buffer.appendUnchecked(theBytes)` or `appendSafe()` if /// bounds checking is required. library DynamicBuffer { /// @notice Allocates container space for the DynamicBuffer /// @param capacity_ The intended max amount of bytes in the buffer /// @return buffer The memory location of the buffer /// @dev Allocates `capacity_ + 0x60` bytes of space /// The buffer array starts at the first container data position, /// (i.e. `buffer = container + 0x20`) function allocate(uint256 capacity_) internal pure returns (bytes memory buffer) { assembly { // Get next-free memory address let container := mload(0x40) // Allocate memory by setting a new next-free address { // Add 2 x 32 bytes in size for the two length fields // Add 32 bytes safety space for 32B chunked copy let size := add(capacity_, 0x60) let newNextFree := add(container, size) mstore(0x40, newNextFree) } // Set the correct container length { let length := add(capacity_, 0x40) mstore(container, length) } // The buffer starts at idx 1 in the container (0 is length) buffer := add(container, 0x20) // Init content with length 0 mstore(buffer, 0) } return buffer; } /// @notice Appends data to buffer, and update buffer length /// @param buffer the buffer to append the data to /// @param data the data to append /// @dev Does not perform out-of-bound checks (container capacity) /// for efficiency. function appendUnchecked(bytes memory buffer, bytes memory data) internal pure { assembly { let length := mload(data) for { data := add(data, 0x20) let dataEnd := add(data, length) let copyTo := add(buffer, add(mload(buffer), 0x20)) } lt(data, dataEnd) { data := add(data, 0x20) copyTo := add(copyTo, 0x20) } { // Copy 32B chunks from data to buffer. // This may read over data array boundaries and copy invalid // bytes, which doesn't matter in the end since we will // later set the correct buffer length, and have allocated an // additional word to avoid buffer overflow. mstore(copyTo, mload(data)) } // Update buffer length mstore(buffer, add(mload(buffer), length)) } } /// @notice Appends data to buffer, and update buffer length /// @param buffer the buffer to append the data to /// @param data the data to append /// @dev Performs out-of-bound checks and calls `appendUnchecked`. function appendSafe(bytes memory buffer, bytes memory data) internal pure { checkOverflow(buffer, data.length); appendUnchecked(buffer, data); } /// @notice Appends data encoded as Base64 to buffer. /// @param fileSafe Whether to replace '+' with '-' and '/' with '_'. /// @param noPadding Whether to strip away the padding. /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// See: https://datatracker.ietf.org/doc/html/rfc4648 /// Author: Modified from Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol) /// Author: Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol) /// Author: Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos. function appendSafeBase64( bytes memory buffer, bytes memory data, bool fileSafe, bool noPadding ) internal pure { uint256 dataLength = data.length; if (data.length == 0) { return; } uint256 encodedLength; uint256 r; assembly { // For each 3 bytes block, we will have 4 bytes in the base64 // encoding: `encodedLength = 4 * divCeil(dataLength, 3)`. // The `shl(2, ...)` is equivalent to multiplying by 4. encodedLength := shl(2, div(add(dataLength, 2), 3)) r := mod(dataLength, 3) if noPadding { // if r == 0 => no modification // if r == 1 => encodedLength -= 2 // if r == 2 => encodedLength -= 1 encodedLength := sub( encodedLength, add(iszero(iszero(r)), eq(r, 1)) ) } } checkOverflow(buffer, encodedLength); assembly { let nextFree := mload(0x40) // Store the table into the scratch space. // Offsetted by -1 byte so that the `mload` will load the character. // We will rewrite the free memory pointer at `0x40` later with // the allocated size. mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef") mstore( 0x3f, sub( "ghijklmnopqrstuvwxyz0123456789-_", // The magic constant 0x0230 will translate "-_" + "+/". mul(iszero(fileSafe), 0x0230) ) ) // Skip the first slot, which stores the length. let ptr := add(add(buffer, 0x20), mload(buffer)) let end := add(data, dataLength) // Run over the input, 3 bytes at a time. // prettier-ignore // solhint-disable-next-line no-empty-blocks for {} 1 {} { data := add(data, 3) // Advance 3 bytes. let input := mload(data) // Write 4 bytes. Optimized for fewer stack operations. mstore8( ptr , mload(and(shr(18, input), 0x3F))) mstore8(add(ptr, 1), mload(and(shr(12, input), 0x3F))) mstore8(add(ptr, 2), mload(and(shr( 6, input), 0x3F))) mstore8(add(ptr, 3), mload(and( input , 0x3F))) ptr := add(ptr, 4) // Advance 4 bytes. // prettier-ignore if iszero(lt(data, end)) { break } } if iszero(noPadding) { // Offset `ptr` and pad with '='. We can simply write over the end. mstore8(sub(ptr, iszero(iszero(r))), 0x3d) // Pad at `ptr - 1` if `r > 0`. mstore8(sub(ptr, shl(1, eq(r, 1))), 0x3d) // Pad at `ptr - 2` if `r == 1`. } mstore(buffer, add(mload(buffer), encodedLength)) mstore(0x40, nextFree) } } /// @notice Appends data encoded as Base64 to buffer. /// @param fileSafe Whether to replace '+' with '-' and '/' with '_'. /// @param noPadding Whether to strip away the padding. /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// See: https://datatracker.ietf.org/doc/html/rfc4648 /// Author: Modified from Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol) /// Author: Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol) /// Author: Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos. function appendUncheckedBase64( bytes memory buffer, bytes memory data, bool fileSafe, bool noPadding ) internal pure { uint256 dataLength = data.length; if (data.length == 0) { return; } uint256 encodedLength; uint256 r; assembly { // For each 3 bytes block, we will have 4 bytes in the base64 // encoding: `encodedLength = 4 * divCeil(dataLength, 3)`. // The `shl(2, ...)` is equivalent to multiplying by 4. encodedLength := shl(2, div(add(dataLength, 2), 3)) r := mod(dataLength, 3) if noPadding { // if r == 0 => no modification // if r == 1 => encodedLength -= 2 // if r == 2 => encodedLength -= 1 encodedLength := sub( encodedLength, add(iszero(iszero(r)), eq(r, 1)) ) } } assembly { let nextFree := mload(0x40) // Store the table into the scratch space. // Offsetted by -1 byte so that the `mload` will load the character. // We will rewrite the free memory pointer at `0x40` later with // the allocated size. mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef") mstore( 0x3f, sub( "ghijklmnopqrstuvwxyz0123456789-_", // The magic constant 0x0230 will translate "-_" + "+/". mul(iszero(fileSafe), 0x0230) ) ) // Skip the first slot, which stores the length. let ptr := add(add(buffer, 0x20), mload(buffer)) let end := add(data, dataLength) // Run over the input, 3 bytes at a time. // prettier-ignore // solhint-disable-next-line no-empty-blocks for {} 1 {} { data := add(data, 3) // Advance 3 bytes. let input := mload(data) // Write 4 bytes. Optimized for fewer stack operations. mstore8( ptr , mload(and(shr(18, input), 0x3F))) mstore8(add(ptr, 1), mload(and(shr(12, input), 0x3F))) mstore8(add(ptr, 2), mload(and(shr( 6, input), 0x3F))) mstore8(add(ptr, 3), mload(and( input , 0x3F))) ptr := add(ptr, 4) // Advance 4 bytes. // prettier-ignore if iszero(lt(data, end)) { break } } if iszero(noPadding) { // Offset `ptr` and pad with '='. We can simply write over the end. mstore8(sub(ptr, iszero(iszero(r))), 0x3d) // Pad at `ptr - 1` if `r > 0`. mstore8(sub(ptr, shl(1, eq(r, 1))), 0x3d) // Pad at `ptr - 2` if `r == 1`. } mstore(buffer, add(mload(buffer), encodedLength)) mstore(0x40, nextFree) } } /// @notice Returns the capacity of a given buffer. function capacity(bytes memory buffer) internal pure returns (uint256) { uint256 cap; assembly { cap := sub(mload(sub(buffer, 0x20)), 0x40) } return cap; } /// @notice Reverts if the buffer will overflow after appending a given /// number of bytes. function checkOverflow(bytes memory buffer, uint256 addedLength) internal pure { uint256 cap = capacity(buffer); uint256 newLength = buffer.length + addedLength; if (cap < newLength) { revert("DynamicBuffer: Appending out of bounds."); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library to encode strings in Base64. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol) /// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - <[email protected]>. library Base64 { /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// See: https://datatracker.ietf.org/doc/html/rfc4648 /// @param fileSafe Whether to replace '+' with '-' and '/' with '_'. /// @param noPadding Whether to strip away the padding. function encode(bytes memory data, bool fileSafe, bool noPadding) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { // Multiply by 4/3 rounded up. // The `shl(2, ...)` is equivalent to multiplying by 4. let encodedLength := shl(2, div(add(dataLength, 2), 3)) // Set `result` to point to the start of the free memory. result := mload(0x40) // Store the table into the scratch space. // Offsetted by -1 byte so that the `mload` will load the character. // We will rewrite the free memory pointer at `0x40` later with // the allocated size. // The magic constant 0x0670 will turn "-_" into "+/". mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef") mstore(0x3f, xor("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0670))) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, encodedLength) // Run over the input, 3 bytes at a time. for {} 1 {} { data := add(data, 3) // Advance 3 bytes. let input := mload(data) // Write 4 bytes. Optimized for fewer stack operations. mstore8(0, mload(and(shr(18, input), 0x3F))) mstore8(1, mload(and(shr(12, input), 0x3F))) mstore8(2, mload(and(shr(6, input), 0x3F))) mstore8(3, mload(and(input, 0x3F))) mstore(ptr, mload(0x00)) ptr := add(ptr, 4) // Advance 4 bytes. if iszero(lt(ptr, end)) { break } } mstore(0x40, add(end, 0x20)) // Allocate the memory. // Equivalent to `o = [0, 2, 1][dataLength % 3]`. let o := div(2, mod(dataLength, 3)) // Offset `ptr` and pad with '='. We can simply write over the end. mstore(sub(ptr, o), shl(240, 0x3d3d)) // Set `o` to zero if there is padding. o := mul(iszero(iszero(noPadding)), o) mstore(sub(ptr, o), 0) // Zeroize the slot after the string. mstore(result, sub(encodedLength, o)) // Store the length. } } } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, false, false)`. function encode(bytes memory data) internal pure returns (string memory result) { result = encode(data, false, false); } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, fileSafe, false)`. function encode(bytes memory data, bool fileSafe) internal pure returns (string memory result) { result = encode(data, fileSafe, false); } /// @dev Decodes base64 encoded `data`. /// /// Supports: /// - RFC 4648 (both standard and file-safe mode). /// - RFC 3501 (63: ','). /// /// Does not support: /// - Line breaks. /// /// Note: For performance reasons, /// this function will NOT revert on invalid `data` inputs. /// Outputs for invalid inputs will simply be undefined behaviour. /// It is the user's responsibility to ensure that the `data` /// is a valid base64 encoded string. function decode(string memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { let decodedLength := mul(shr(2, dataLength), 3) for {} 1 {} { // If padded. if iszero(and(dataLength, 3)) { let t := xor(mload(add(data, dataLength)), 0x3d3d) // forgefmt: disable-next-item decodedLength := sub( decodedLength, add(iszero(byte(30, t)), iszero(byte(31, t))) ) break } // If non-padded. decodedLength := add(decodedLength, sub(and(dataLength, 3), 1)) break } result := mload(0x40) // Write the length of the bytes. mstore(result, decodedLength) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, decodedLength) // Load the table into the scratch space. // Constants are optimized for smaller bytecode with zero gas overhead. // `m` also doubles as the mask of the upper 6 bits. let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc mstore(0x5b, m) mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064) mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4) for {} 1 {} { // Read 4 bytes. data := add(data, 4) let input := mload(data) // Write 3 bytes. // forgefmt: disable-next-item mstore(ptr, or( and(m, mload(byte(28, input))), shr(6, or( and(m, mload(byte(29, input))), shr(6, or( and(m, mload(byte(30, input))), shr(6, mload(byte(31, input))) )) )) )) ptr := add(ptr, 3) if iszero(lt(ptr, end)) { break } } mstore(0x40, add(end, 0x20)) // Allocate the memory. mstore(end, 0) // Zeroize the slot after the bytes. mstore(0x60, 0) // Restore the zero slot. } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for converting numbers into strings and other string operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) /// /// Note: /// For performance and bytecode compactness, most of the string operations are restricted to /// byte strings (7-bit ASCII), except where otherwise specified. /// Usage of byte string operations on charsets with runes spanning two or more bytes /// can lead to undefined behavior. library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The length of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /// @dev The length of the string is more than 32 bytes. error TooBigForSmallString(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. str := add(mload(0x40), 0x80) // Update the free memory pointer to allocate. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str let w := not(0) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `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) if iszero(temp) { break } } let length := sub(end, str) // Move the pointer 32 bytes leftwards to make room for the length. str := sub(str, 0x20) // Store the length. mstore(str, length) } } /// @dev Returns the base 10 decimal representation of `value`. function toString(int256 value) internal pure returns (string memory str) { if (value >= 0) { return toString(uint256(value)); } unchecked { str = toString(uint256(-value)); } /// @solidity memory-safe-assembly assembly { // We still have some spare memory space on the left, // as we have allocated 3 words (96 bytes) for up to 78 digits. let length := mload(str) // Load the string length. mstore(str, 0x2d) // Store the '-' character. str := sub(str, 1) // Move back the string pointer by a byte. mstore(str, add(length, 1)) // Update the string length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HEXADECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2 + 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) { str = toHexStringNoPrefix(value, length); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexStringNoPrefix(uint256 value, uint256 length) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. // We add 0x20 to the total and round down to a multiple of 0x20. // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f))) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let start := sub(str, add(length, length)) let w := not(1) // Tsk. let temp := value // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for {} 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(xor(str, start)) { break } } if temp { mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`. revert(0x1c, 0x04) } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2 + 2` bytes. function toHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x". /// The output excludes leading "0" from the `toHexString` output. /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. function toMinimalHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := add(mload(str), 2) // Compute the length. mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero. str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output excludes leading "0" from the `toHexStringNoPrefix` output. /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := mload(str) // Get the length. str := add(str, o) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. str := add(mload(0x40), 0x80) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory str) { str = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(str, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { str := mload(0x40) // Allocate the memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(str, 0x80)) // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) str := add(str, 2) mstore(str, 40) let o := add(str, 0x20) mstore(add(o, 40), 0) value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory str) { str = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { let length := mload(raw) str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(str, add(length, length)) // Store the length of the output. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let o := add(str, 0x20) let end := add(raw, length) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let mask := shl(7, div(not(0), 255)) result := 1 let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, byte string operations are restricted // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets. // Usage of byte string operations on charsets with runes spanning two or more bytes // can lead to undefined behavior. /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`. function replace(string memory subject, string memory search, string memory replacement) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) let replacementLength := mload(replacement) subject := add(subject, 0x20) search := add(search, 0x20) replacement := add(replacement, 0x20) result := add(mload(0x40), 0x20) let subjectEnd := add(subject, subjectLength) if iszero(gt(searchLength, subjectLength)) { let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. for { let o := 0 } 1 {} { mstore(add(result, o), mload(add(replacement, o))) o := add(o, 0x20) if iszero(lt(o, replacementLength)) { break } } result := add(result, replacementLength) subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } } let resultRemainder := result result := add(mload(0x40), 0x20) let k := add(sub(resultRemainder, result), sub(subjectEnd, subject)) // Copy the rest of the string one word at a time. for {} lt(subject, subjectEnd) {} { mstore(resultRemainder, mload(subject)) resultRemainder := add(resultRemainder, 0x20) subject := add(subject, 0x20) } result := sub(result, 0x20) let last := add(add(result, 0x20), k) // Zeroize the slot after the string. mstore(last, 0) mstore(0x40, add(last, 0x20)) // Allocate the memory. mstore(result, k) // Store the length. } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for { let subjectLength := mload(subject) } 1 {} { if iszero(mload(search)) { if iszero(gt(from, subjectLength)) { result := from break } result := subjectLength break } let searchLength := mload(search) let subjectStart := add(subject, 0x20) result := not(0) // Initialize to `NOT_FOUND`. subject := add(subjectStart, from) let end := add(sub(add(subjectStart, subjectLength), searchLength), 1) let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(add(search, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLength))) { break } if iszero(lt(searchLength, 0x20)) { for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if iszero(shr(m, xor(mload(subject), s))) { if eq(keccak256(subject, searchLength), h) { result := sub(subject, subjectStart) break } } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = indexOf(subject, search, 0); } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := not(0) // Initialize to `NOT_FOUND`. let searchLength := mload(search) if gt(searchLength, mload(subject)) { break } let w := result let fromMax := sub(mload(subject), searchLength) if iszero(gt(fromMax, from)) { from := fromMax } let end := add(add(subject, 0x20), w) subject := add(add(subject, 0x20), from) if iszero(gt(subject, end)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if eq(keccak256(subject, searchLength), h) { result := sub(subject, add(end, 1)) break } subject := add(subject, w) // `sub(subject, 1)`. if iszero(gt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = lastIndexOf(subject, search, uint256(int256(-1))); } /// @dev Returns true if `search` is found in `subject`, false otherwise. function contains(string memory subject, string memory search) internal pure returns (bool) { return indexOf(subject, search) != NOT_FOUND; } /// @dev Returns whether `subject` starts with `search`. function startsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( iszero(gt(searchLength, mload(subject))), eq( keccak256(add(subject, 0x20), searchLength), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns whether `subject` ends with `search`. function endsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) let subjectLength := mload(subject) // Whether `search` is not longer than `subject`. let withinRange := iszero(gt(searchLength, subjectLength)) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( withinRange, eq( keccak256( // `subject + 0x20 + max(subjectLength - searchLength, 0)`. add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))), searchLength ), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns `subject` repeated `times`. function repeat(string memory subject, uint256 times) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(or(iszero(times), iszero(subjectLength))) { subject := add(subject, 0x20) result := mload(0x40) let output := add(result, 0x20) for {} 1 {} { // Copy the `subject` one word at a time. for { let o := 0 } 1 {} { mstore(add(output, o), mload(add(subject, o))) o := add(o, 0x20) if iszero(lt(o, subjectLength)) { break } } output := add(output, subjectLength) times := sub(times, 1) if iszero(times) { break } } mstore(output, 0) // Zeroize the slot after the string. let resultLength := sub(output, add(result, 0x20)) mstore(result, resultLength) // Store the length. // Allocate the memory. mstore(0x40, add(result, add(resultLength, 0x20))) } } } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(gt(subjectLength, end)) { end := subjectLength } if iszero(gt(subjectLength, start)) { start := subjectLength } if lt(start, end) { result := mload(0x40) let resultLength := sub(end, start) mstore(result, resultLength) subject := add(subject, start) let w := not(0x1f) // Copy the `subject` one word at a time, backwards. for { let o := and(add(resultLength, 0x1f), w) } 1 {} { mstore(add(result, o), mload(add(subject, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(result, 0x20), resultLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(result, and(add(resultLength, 0x3f), w))) } } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. /// `start` is a byte offset. function slice(string memory subject, uint256 start) internal pure returns (string memory result) { result = slice(subject, start, uint256(int256(-1))); } /// @dev Returns all the indices of `search` in `subject`. /// The indices are byte offsets. function indicesOf(string memory subject, string memory search) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) if iszero(gt(searchLength, subjectLength)) { subject := add(subject, 0x20) search := add(search, 0x20) result := add(mload(0x40), 0x20) let subjectStart := subject let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Append to `result`. mstore(result, sub(subject, subjectStart)) result := add(result, 0x20) // Advance `subject` by `searchLength`. subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } let resultEnd := result // Assign `result` to the free memory pointer. result := mload(0x40) // Store the length of `result`. mstore(result, shr(5, sub(resultEnd, add(result, 0x20)))) // Allocate memory for result. // We allocate one more word, so this array can be recycled for {split}. mstore(0x40, add(resultEnd, 0x20)) } } } /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string. function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { uint256[] memory indices = indicesOf(subject, delimiter); /// @solidity memory-safe-assembly assembly { let w := not(0x1f) let indexPtr := add(indices, 0x20) let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) mstore(add(indicesEnd, w), mload(subject)) mstore(indices, add(mload(indices), 1)) let prevIndex := 0 for {} 1 {} { let index := mload(indexPtr) mstore(indexPtr, 0x60) if iszero(eq(index, prevIndex)) { let element := mload(0x40) let elementLength := sub(index, prevIndex) mstore(element, elementLength) // Copy the `subject` one word at a time, backwards. for { let o := and(add(elementLength, 0x1f), w) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(element, 0x20), elementLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(element, and(add(elementLength, 0x3f), w))) // Store the `element` into the array. mstore(indexPtr, element) } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) if iszero(lt(indexPtr, indicesEnd)) { break } } result := indices if iszero(mload(delimiter)) { result := add(indices, 0x20) mstore(result, sub(mload(indices), 2)) } } } /// @dev Returns a concatenated string of `a` and `b`. /// Cheaper than `string.concat()` and does not de-align the free memory pointer. function concat(string memory a, string memory b) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let w := not(0x1f) result := mload(0x40) let aLength := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(aLength, 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLength := mload(b) let output := add(result, aLength) // Copy `b` one word at a time, backwards. for { let o := and(add(bLength, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLength := add(aLength, bLength) let last := add(add(result, 0x20), totalLength) // Zeroize the slot after the string. mstore(last, 0) // Stores the length. mstore(result, totalLength) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 0x1f), w)) } } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let length := mload(subject) if length { result := add(mload(0x40), 0x20) subject := add(subject, 1) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) let w := not(0) for { let o := length } 1 {} { o := add(o, w) let b := and(0xff, mload(add(subject, o))) mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20))) if iszero(o) { break } } result := mload(0x40) mstore(result, length) // Store the length. let last := add(add(result, 0x20), length) mstore(last, 0) // Zeroize the slot after the string. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } } /// @dev Returns a string from a small bytes32 string. /// `s` must be null-terminated, or behavior will be undefined. function fromSmallString(bytes32 s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let n := 0 for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'. mstore(result, n) let o := add(result, 0x20) mstore(o, s) mstore(add(o, n), 0) mstore(0x40, add(result, 0x40)) } } /// @dev Returns the small string, with all bytes after the first null byte zeroized. function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'. mstore(0x00, s) mstore(result, 0x00) result := mload(0x00) } } /// @dev Returns the string as a normalized null-terminated small string. function toSmallString(string memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(s) if iszero(lt(result, 33)) { mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`. revert(0x1c, 0x04) } result := shl(shl(3, sub(32, result)), mload(add(s, result))) } } /// @dev Returns a lowercased copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function upper(string memory subject) internal pure returns (string memory result) { result = toCase(subject, true); } /// @dev Escapes the string to be used within HTML tags. function escapeHTML(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(result, c) result := add(result, 1) continue } let t := shr(248, mload(c)) mstore(result, mload(and(t, 0x1f))) result := add(result, shr(5, t)) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } // Store "\\u0000" in scratch space. // Store "0123456789abcdef" in scratch space. // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. // into the scratch space. mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) // Bitmask for detecting `["\"","\\"]`. let e := or(shl(0x22, 1), shl(0x5c, 1)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(result, c) result := add(result, 1) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), c) result := add(result, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(result, mload(0x19)) // "\\u00XX". result := add(result, 6) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), mload(add(c, 8))) result := add(result, 2) } if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { result = escapeJSON(s, false); } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`. For small strings up to 32 bytes. /// `b` must be null-terminated and normalized, or behavior will be undefined. /// See: `normalizeSmallString`. function eqs(string memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let x := and(b, add(not(b), 1)) let r := or(shl(8, iszero(b)), shl(7, iszero(iszero(shr(128, x))))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) result := gt(eq(mload(a), sub(32, shr(3, r))), shr(r, xor(b, mload(add(a, 0x20))))) } } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output behavior is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. result := mload(0x40) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(0x40, add(result, 0x40)) // Zeroize the length slot. mstore(result, 0) // Store the length and bytes. mstore(add(result, 0x1f), packed) // Right pad with zeroes. mstore(add(add(result, 0x20), mload(result)), 0) } } /// @dev Packs two strings with their lengths into a single word. /// Returns `bytes32(0)` if combined length is zero or greater than 30. function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let aLength := mload(a) // We don't need to zero right pad the strings, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes of `a` and `b`. or( shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))), mload(sub(add(b, 0x1e), aLength)) ), // `totalLength != 0 && totalLength < 31`. Abuses underflow. // Assumes that the lengths are valid and within the block gas limit. lt(sub(add(aLength, mload(b)), 1), 0x1e) ) } } /// @dev Unpacks strings packed using {packTwo}. /// Returns the empty strings if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packTwo}, the output behavior is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. resultA := mload(0x40) resultB := add(resultA, 0x40) // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. mstore(0x40, add(resultB, 0x40)) // Zeroize the length slots. mstore(resultA, 0) mstore(resultB, 0) // Store the lengths and bytes. mstore(add(resultA, 0x1f), packed) mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) // Right pad with zeroes. mstore(add(add(resultA, 0x20), mload(resultA)), 0) mstore(add(add(resultB, 0x20), mload(resultB)), 0) } } /// @dev Directly returns `a` without copying. function directReturn(string memory a) internal pure { assembly { // Assumes that the string does not start from the scratch space. let retStart := sub(a, 0x20) let retSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the string is produced // by a method that doesn't zero right pad. mstore(add(retStart, retSize), 0) // Store the return offset. mstore(retStart, 0x20) // End the transaction, returning the string. return(retStart, retSize) } } }
{ "evmVersion": "paris", "optimizer": { "enabled": false, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IScriptyBuilderV2","name":"_scriptyBuilder","type":"address"},{"internalType":"address","name":"_scriptyETHFSAddress","type":"address"},{"internalType":"contract IEfficax","name":"_efficax","type":"address"},{"internalType":"contract IManifoldCreatorContract","name":"_freshHell","type":"address"},{"internalType":"contract ITheStalkerRenderer","name":"_defaultRenderer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BlockedTokenId","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"_isBlocked","type":"bool"}],"name":"BlockedTokenIdUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ITheStalkerRenderer","name":"_defaultRenderer","type":"address"}],"name":"DefaultRendererUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"blockedTokenIds","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"targetTokenId","type":"uint256"}],"name":"canRender","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"targetTokenId","type":"uint256"}],"name":"canUpdateToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collectionAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"decodedImageFromEfficax","outputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultRenderer","outputs":[{"internalType":"contract ITheStalkerRenderer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"efficax","outputs":[{"internalType":"contract IEfficax","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"freshHell","outputs":[{"internalType":"contract IManifoldCreatorContract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"targetTokenId","type":"uint256"}],"name":"generateModifiedFreshHellSVG","outputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"targetTokenId","type":"uint256"}],"name":"isTokenRenderable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"scriptyBuilder","outputs":[{"internalType":"contract IScriptyBuilderV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"scriptyETHFSAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"targetTokenId","type":"uint256"}],"name":"tokenHTML","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"base64SVGWithoutDataURI","type":"string"}],"name":"tokenHTMLWithFreshHellBase64SVG","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"targetTokenId","type":"uint256"}],"name":"tokenImage","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"targetTokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"targetTokenId","type":"uint256"},{"internalType":"bool","name":"isBlocked","type":"bool"}],"name":"updateBlockedTokenIds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ITheStalkerRenderer","name":"_defaultRenderer","type":"address"}],"name":"updateDefaultRenderer","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101006040523480156200001257600080fd5b50604051620030f0380380620030f083398181016040528101906200003891906200041e565b33600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620000ae5760006040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401620000a59190620004b7565b60405180910390fd5b620000bf81620001dc60201b60201c565b508473ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508373ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250508273ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff16815250508173ffffffffffffffffffffffffffffffffffffffff1660e08173ffffffffffffffffffffffffffffffffffffffff168152505080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050505050620004d4565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620002d282620002a5565b9050919050565b6000620002e682620002c5565b9050919050565b620002f881620002d9565b81146200030457600080fd5b50565b6000815190506200031881620002ed565b92915050565b6200032981620002c5565b81146200033557600080fd5b50565b60008151905062000349816200031e565b92915050565b60006200035c82620002c5565b9050919050565b6200036e816200034f565b81146200037a57600080fd5b50565b6000815190506200038e8162000363565b92915050565b6000620003a182620002c5565b9050919050565b620003b38162000394565b8114620003bf57600080fd5b50565b600081519050620003d381620003a8565b92915050565b6000620003e682620002c5565b9050919050565b620003f881620003d9565b81146200040457600080fd5b50565b6000815190506200041881620003ed565b92915050565b600080600080600060a086880312156200043d576200043c620002a0565b5b60006200044d8882890162000307565b9550506020620004608882890162000338565b945050604062000473888289016200037d565b93505060606200048688828901620003c2565b9250506080620004998882890162000407565b9150509295509295909350565b620004b181620002c5565b82525050565b6000602082019050620004ce6000830184620004a6565b92915050565b60805160a05160c05160e051612bb16200053f6000396000818161066c0152818161086c01526109f00152600081816104ed01528181610593015261124101526000818161045401528181610e030152610f28015260008181610b1201526110900152612bb16000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c8063715018a6116100ad578063b53e526711610071578063b53e52671461036d578063c56c4cf11461039d578063c5c21064146103bb578063edb7e13f146103eb578063f2fde38b146104095761012c565b8063715018a6146102c75780638da5cb5b146102d157806391a0d36d146102ef57806392cb829d1461030d57806395b82c131461033d5761012c565b806341c72314116100f457806341c72314146101ea5780634801cd171461021a5780634e881a1d146102365780635cfbede3146102675780636d3781f2146102975761012c565b806301467c601461013157806305a0851c146101615780631acae6e91461017f57806339da06f11461019b578063405743c1146101cc575b600080fd5b61014b600480360381019061014691906119ce565b610425565b6040516101589190611a3c565b60405180910390f35b610169610452565b6040516101769190611a66565b60405180910390f35b61019960048036038101906101949190611aad565b610476565b005b6101b560048036038101906101b09190611aed565b6104e6565b6040516101c3929190611bbd565b60405180910390f35b6101d461066a565b6040516101e19190611c53565b60405180910390f35b61020460048036038101906101ff9190611c6e565b61068e565b6040516102119190611cae565b60405180910390f35b610234600480360381019061022f9190611d0e565b610787565b005b610250600480360381019061024b9190611d3b565b61080a565b60405161025e929190611bbd565b60405180910390f35b610281600480360381019061027c9190611d3b565b6109eb565b60405161028e9190611a3c565b60405180910390f35b6102b160048036038101906102ac9190611c6e565b610ac0565b6040516102be9190611a3c565b60405180910390f35b6102cf610ad3565b005b6102d9610ae7565b6040516102e69190611a66565b60405180910390f35b6102f7610b10565b6040516103049190611d89565b60405180910390f35b61032760048036038101906103229190611c6e565b610b34565b6040516103349190611cae565b60405180910390f35b61035760048036038101906103529190611d3b565b610c98565b6040516103649190611a3c565b60405180910390f35b61038760048036038101906103829190611ed9565b610cb8565b6040516103949190611cae565b60405180910390f35b6103a5611137565b6040516103b29190611f43565b60405180910390f35b6103d560048036038101906103d09190611c6e565b61115d565b6040516103e29190611cae565b60405180910390f35b6103f361123f565b6040516104009190611f7f565b60405180910390f35b610423600480360381019061041e9190611f9a565b611263565b005b60006002600083815260200190815260200160002060009054906101000a900460ff161590509392505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b61047e6112e9565b806002600084815260200190815260200160002060006101000a81548160ff0219169083151502179055507f0d378a01fedf2d2b1d548d97d5dd7c4a4af5205124b75891938c0b3c74b5b0e882826040516104da929190611fd6565b60405180910390a15050565b60608060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e9dc637586866040518363ffffffff1660e01b8152600401610546929190611fff565b600060405180830381865afa158015610563573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061058c9190612098565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166324ba432888886040518363ffffffff1660e01b81526004016105ec929190611fff565b600060405180830381865afa158015610609573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061063291906120e1565b915091506000600d8251845160280101019050600060028551039050610659858383611370565b839650965050505050509250929050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6060610699826109eb565b61074757600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166341c7231484846040518363ffffffff1660e01b81526004016106fa929190612159565b600060405180830381865afa158015610717573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906107409190612098565b9050610781565b60006107528361080a565b91505061075e816113e6565b60405160200161076e919061220a565b6040516020818303038152906040529150505b92915050565b61078f6112e9565b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f855112fc6fcccf938a59297fdfa1aa10e7a87f743d88b17f07af7063c1f4a13a816040516107ff9190611f43565b60405180910390a150565b6060806002600084815260200190815260200160002060009054906101000a900460ff1615610865576040517fa672b46100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006108917f0000000000000000000000000000000000000000000000000000000000000000856104e6565b509050600061089f826113fb565b905060006108e2826040518060400160405280600181526020017f3e00000000000000000000000000000000000000000000000000000000000000815250611514565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8103610919578182945094505050506109e6565b600061093383600060018561092e919061225b565b611370565b905060008351905060006109608560018661094e919061225b565b60068561095b919061228f565b611370565b905060006109898460405180610140016040528061010a8152602001612a4061010a913961152a565b9050610995818361152a565b90506109d6816040518060400160405280600a81526020017f3c2f673e3c2f7376673e0000000000000000000000000000000000000000000081525061152a565b9050858198509850505050505050505b915091565b6000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bd85b039846040518263ffffffff1660e01b8152600401610a4791906122c3565b602060405180830381865afa158015610a64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8891906122f3565b9050600081118015610ab857506002600084815260200190815260200160002060009054906101000a900460ff16155b915050919050565b6000610acb826109eb565b905092915050565b610adb6112e9565b610ae560006115a4565b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b7f000000000000000000000000000000000000000000000000000000000000000081565b6060610b3f826109eb565b610bed57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166392cb829d84846040518363ffffffff1660e01b8152600401610ba0929190612159565b600060405180830381865afa158015610bbd573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610be69190612098565b9050610c92565b600080610bf98461080a565b915091506000610c0886611668565b610c19610c14856113e6565b610cb8565b610c22846113e6565b604051602001610c32919061220a565b604051602081830303815290604052604051602001610c539392919061252f565b6040516020818303038152906040529050610c6d816113e6565b604051602001610c7d91906125d8565b60405160208183030381529060405293505050505b92915050565b60026020528060005260406000206000915054906101000a900460ff1681565b60606000600167ffffffffffffffff811115610cd757610cd6611dae565b5b604051908082528060200260200182016040528015610d1057816020015b610cfd6118a7565b815260200190600190039081610cf55790505b5090506040518060400160405280601281526020017f66756c6c53697a6543616e7661732e637373000000000000000000000000000081525081600081518110610d5d57610d5c6125fa565b5b602002602001015160000181905250604051806060016040528060328152602001612b4a6032913981600081518110610d9957610d986125fa565b5b6020026020010151608001819052506040518060400160405280600281526020017f223e00000000000000000000000000000000000000000000000000000000000081525081600081518110610df257610df16125fa565b5b602002602001015160a001819052507f000000000000000000000000000000000000000000000000000000000000000081600081518110610e3657610e356125fa565b5b60200260200101516020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506000600267ffffffffffffffff811115610e9157610e90611dae565b5b604051908082528060200260200182016040528015610eca57816020015b610eb76118a7565b815260200190600190039081610eaf5790505b5090506040518060400160405280601681526020017f7468657374616c6b6572465245534848454c4c2e6a730000000000000000000081525081600081518110610f1757610f166125fa565b5b6020026020010151600001819052507f000000000000000000000000000000000000000000000000000000000000000081600081518110610f5b57610f5a6125fa565b5b60200260200101516020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600281600081518110610faf57610fae6125fa565b5b6020026020010151606001906004811115610fcd57610fcc612629565b5b90816004811115610fe157610fe0612629565b5b8152505083604051602001610ff6919061273c565b60405160208183030381529060405281600181518110611019576110186125fa565b5b602002602001015160c0018190525060018160018151811061103e5761103d6125fa565b5b602002602001015160600190600481111561105c5761105b612629565b5b908160048111156110705761106f612629565b5b8152505061107c61190c565b8281600001819052508181602001819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a891b35e826040518263ffffffff1660e01b81526004016110e79190612a1d565b600060405180830381865afa158015611104573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061112d9190612098565b9350505050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6060611168826109eb565b61121657600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c5c2106484846040518363ffffffff1660e01b81526004016111c9929190612159565b600060405180830381865afa1580156111e6573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061120f9190612098565b9050611239565b60006112218361080a565b509050611235611230826113e6565b610cb8565b9150505b92915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b61126b6112e9565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036112dd5760006040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081526004016112d49190611a66565b60405180910390fd5b6112e6816115a4565b50565b6112f16116b9565b73ffffffffffffffffffffffffffffffffffffffff1661130f610ae7565b73ffffffffffffffffffffffffffffffffffffffff161461136e576113326116b9565b6040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016113659190611a66565b60405180910390fd5b565b6060835182811161137f578092505b83811161138a578093505b828410156113de5760405191508383038083528486019550601f1980601f8301165b6001156113c65780880151818601528181019050806113ac575b5060008260208601015280603f830116840160405250505b509392505050565b60606113f4826000806116c1565b9050919050565b60608151801561150e5760038160021c02600115611444576003821661143857613d3d828501511880601f1a1581601e1a15018203915050611444565b60016003831603810190505b6040519250808352602083018181017ffc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc80605b527804080c1014181c2024282c3034383c4044484c5054585c6064603b526ef8fcf800fcd0d4d8dce0e4e8ecf0f4601a525b6001156114f957600487019650865180601f1a5160061c81601e1a5183161760061c81601d1a5183161760061c81601c1a5183161784526003840193508284106114f357506114f9565b506114a9565b60208201604052600082526000606052505050505b50919050565b6000611522838360006117be565b905092915050565b6060601f19604051915083518160208201165b60011561155757808601518185015282810190508061153d575b5083518184018360208301165b60011561157e578087015181830152848101905080611564575b508183018060208701016000815281875285601f82011660405250505050505092915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60606080604051019050602081016040526000815280600019835b6001156116a4578184019350600a81066030018453600a8104905080611683575b50828203602084039350808452505050919050565b600033905090565b6060835180156117b6576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106708515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f52602083018181015b600115611787576003880197508751603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f81165160035360005183526004830192508183106117815750611787565b50611731565b6020810160405260038406600204613d3d60f01b81840352808715150290506000818403528084038652505050505b509392505050565b6000835160011561189f5783516117e6578083116117de5782915061189f565b80915061189f565b835160208601600019935084810196506001828483010301601f831660200360031b6020880151858810838b101661182257505050505061189f565b6020851061186f578460208a01205b60011561186457818b5118831c6118565780868c200361185557848b039750611864565b5b60018b019a50838b10611831575b50505050505061189f565b5b60011561189957808a5118821c61188b57838a039650611899565b60018a019950828a10611870575b50505050505b509392505050565b6040518060e0016040528060608152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001600060048111156118f1576118f0612629565b5b81526020016060815260200160608152602001606081525090565b604051806040016040528060608152602001606081525090565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006119658261193a565b9050919050565b6119758161195a565b811461198057600080fd5b50565b6000813590506119928161196c565b92915050565b6000819050919050565b6119ab81611998565b81146119b657600080fd5b50565b6000813590506119c8816119a2565b92915050565b6000806000606084860312156119e7576119e6611930565b5b60006119f586828701611983565b9350506020611a06868287016119b9565b9250506040611a17868287016119b9565b9150509250925092565b60008115159050919050565b611a3681611a21565b82525050565b6000602082019050611a516000830184611a2d565b92915050565b611a608161195a565b82525050565b6000602082019050611a7b6000830184611a57565b92915050565b611a8a81611a21565b8114611a9557600080fd5b50565b600081359050611aa781611a81565b92915050565b60008060408385031215611ac457611ac3611930565b5b6000611ad2858286016119b9565b9250506020611ae385828601611a98565b9150509250929050565b60008060408385031215611b0457611b03611930565b5b6000611b1285828601611983565b9250506020611b23858286016119b9565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b60005b83811015611b67578082015181840152602081019050611b4c565b60008484015250505050565b6000601f19601f8301169050919050565b6000611b8f82611b2d565b611b998185611b38565b9350611ba9818560208601611b49565b611bb281611b73565b840191505092915050565b60006040820190508181036000830152611bd78185611b84565b90508181036020830152611beb8184611b84565b90509392505050565b6000819050919050565b6000611c19611c14611c0f8461193a565b611bf4565b61193a565b9050919050565b6000611c2b82611bfe565b9050919050565b6000611c3d82611c20565b9050919050565b611c4d81611c32565b82525050565b6000602082019050611c686000830184611c44565b92915050565b60008060408385031215611c8557611c84611930565b5b6000611c93858286016119b9565b9250506020611ca4858286016119b9565b9150509250929050565b60006020820190508181036000830152611cc88184611b84565b905092915050565b6000611cdb8261195a565b9050919050565b611ceb81611cd0565b8114611cf657600080fd5b50565b600081359050611d0881611ce2565b92915050565b600060208284031215611d2457611d23611930565b5b6000611d3284828501611cf9565b91505092915050565b600060208284031215611d5157611d50611930565b5b6000611d5f848285016119b9565b91505092915050565b6000611d7382611c20565b9050919050565b611d8381611d68565b82525050565b6000602082019050611d9e6000830184611d7a565b92915050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b611de682611b73565b810181811067ffffffffffffffff82111715611e0557611e04611dae565b5b80604052505050565b6000611e18611926565b9050611e248282611ddd565b919050565b600067ffffffffffffffff821115611e4457611e43611dae565b5b611e4d82611b73565b9050602081019050919050565b82818337600083830152505050565b6000611e7c611e7784611e29565b611e0e565b905082815260208101848484011115611e9857611e97611da9565b5b611ea3848285611e5a565b509392505050565b600082601f830112611ec057611ebf611da4565b5b8135611ed0848260208601611e69565b91505092915050565b600060208284031215611eef57611eee611930565b5b600082013567ffffffffffffffff811115611f0d57611f0c611935565b5b611f1984828501611eab565b91505092915050565b6000611f2d82611c20565b9050919050565b611f3d81611f22565b82525050565b6000602082019050611f586000830184611f34565b92915050565b6000611f6982611c20565b9050919050565b611f7981611f5e565b82525050565b6000602082019050611f946000830184611f70565b92915050565b600060208284031215611fb057611faf611930565b5b6000611fbe84828501611983565b91505092915050565b611fd081611998565b82525050565b6000604082019050611feb6000830185611fc7565b611ff86020830184611a2d565b9392505050565b60006040820190506120146000830185611a57565b6120216020830184611fc7565b9392505050565b600061203b61203684611e29565b611e0e565b90508281526020810184848401111561205757612056611da9565b5b612062848285611b49565b509392505050565b600082601f83011261207f5761207e611da4565b5b815161208f848260208601612028565b91505092915050565b6000602082840312156120ae576120ad611930565b5b600082015167ffffffffffffffff8111156120cc576120cb611935565b5b6120d88482850161206a565b91505092915050565b600080604083850312156120f8576120f7611930565b5b600083015167ffffffffffffffff81111561211657612115611935565b5b6121228582860161206a565b925050602083015167ffffffffffffffff81111561214357612142611935565b5b61214f8582860161206a565b9150509250929050565b600060408201905061216e6000830185611fc7565b61217b6020830184611fc7565b9392505050565b600081905092915050565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000600082015250565b60006121c3601a83612182565b91506121ce8261218d565b601a82019050919050565b60006121e482611b2d565b6121ee8185612182565b93506121fe818560208601611b49565b80840191505092915050565b6000612215826121b6565b915061222182846121d9565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061226682611998565b915061227183611998565b92508282019050808211156122895761228861222c565b5b92915050565b600061229a82611998565b91506122a583611998565b92508282039050818111156122bd576122bc61222c565b5b92915050565b60006020820190506122d86000830184611fc7565b92915050565b6000815190506122ed816119a2565b92915050565b60006020828403121561230957612308611930565b5b6000612317848285016122de565b91505092915050565b7f7b226e616d65223a22746865207374616c6b6572202300000000000000000000600082015250565b6000612356601683612182565b915061236182612320565b601682019050919050565b7f222c20226465736372697074696f6e223a2261207065726d697373696f6e6c6560008201527f737320636f6c6c61626f726174696f6e2070726f6772616d2072756e6e696e6760208201527f206f6e2045564d202d20696e742e61727420782058434f5059202d204f72696760408201527f696e616c20617274776f726b2062792058434f5059202846524553482048454c60608201527f4c292e222c22616e696d6174696f6e5f75726c223a2200000000000000000000608082015250565b600061243a609683612182565b91506124458261236c565b609682019050919050565b7f222c22696d616765223a22000000000000000000000000000000000000000000600082015250565b6000612486600b83612182565b915061249182612450565b600b82019050919050565b600081519050919050565b600081905092915050565b60006124bd8261249c565b6124c781856124a7565b93506124d7818560208601611b49565b80840191505092915050565b7f227d000000000000000000000000000000000000000000000000000000000000600082015250565b6000612519600283612182565b9150612524826124e3565b600282019050919050565b600061253a82612349565b915061254682866121d9565b91506125518261242d565b915061255d82856121d9565b915061256882612479565b915061257482846124b2565b915061257f8261250c565b9150819050949350505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000600082015250565b60006125c2601d83612182565b91506125cd8261258c565b601d82019050919050565b60006125e3826125b5565b91506125ef82846121d9565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f636f6e73742073766744617461203d2027000000000000000000000000000000600082015250565b600061268e601183612182565b915061269982612658565b601182019050919050565b7f273b000000000000000000000000000000000000000000000000000000000000600082015250565b60006126da600283612182565b91506126e5826126a4565b600282019050919050565b7f7468657374616c6b6572465245534848454c4c28737667446174612900000000600082015250565b6000612726601c83612182565b9150612731826126f0565b601c82019050919050565b600061274782612681565b915061275382846121d9565b915061275e826126cd565b915061276982612719565b915081905092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600082825260208201905092915050565b60006127bc82611b2d565b6127c681856127a0565b93506127d6818560208601611b49565b6127df81611b73565b840191505092915050565b6127f38161195a565b82525050565b600082825260208201905092915050565b60006128158261249c565b61281f81856127f9565b935061282f818560208601611b49565b61283881611b73565b840191505092915050565b6005811061285457612853612629565b5b50565b600081905061286582612843565b919050565b600061287582612857565b9050919050565b6128858161286a565b82525050565b600060e08301600083015184820360008601526128a882826127b1565b91505060208301516128bd60208601826127ea565b50604083015184820360408601526128d5828261280a565b91505060608301516128ea606086018261287c565b5060808301518482036080860152612902828261280a565b91505060a083015184820360a086015261291c828261280a565b91505060c083015184820360c0860152612936828261280a565b9150508091505092915050565b600061294f838361288b565b905092915050565b6000602082019050919050565b600061296f82612774565b612979818561277f565b93508360208202850161298b85612790565b8060005b858110156129c757848403895281516129a88582612943565b94506129b383612957565b925060208a0199505060018101905061298f565b50829750879550505050505092915050565b600060408301600083015184820360008601526129f68282612964565b91505060208301518482036020860152612a108282612964565b9150508091505092915050565b60006020820190508181036000830152612a3781846129d9565b90509291505056fe3c672069643d2244554445223e3c7374796c6520747970653d22746578742f637373223e406b65796672616d6573207368616b65416e696d6174696f6e207b30252c373525207b7472616e73666f726d3a207472616e736c61746528302e33252c20302e332529207363616c6528312e312c20312e31293b7d3736252c31303025207b7472616e73666f726d3a207472616e736c617465282d302e33252c202d302e332529207363616c6528312e312c20312e31293b7d7d2344554445207b616e696d6174696f6e3a207368616b65416e696d6174696f6e20302e31367320696e66696e6974653b7472616e73666f726d2d6f726967696e3a2063656e7465723b7d3c2f7374796c653e3c6c696e6b2072656c3d227374796c6573686565742220687265663d22646174613a746578742f6373733b6261736536342ca2646970667358221220b2c837df060e12152f0ff75eedd951f63aa4fd20f259514ed82d9ce536782ff864736f6c634300081400330000000000000000000000005ceb91d612a735ec5f50ad68c7ad22a945c602fc000000000000000000000000fc7453da7bf4d0c739c1c53da57b3636dab0e11e000000000000000000000000323d8d9ab29731849345b97758ed4c1323a1e487000000000000000000000000bb6eefd83daab02fa1a697eb9d8495eec9f9b384000000000000000000000000c62d4ea82879aff3dabaa19a46bbac3fe4d755a6
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061012c5760003560e01c8063715018a6116100ad578063b53e526711610071578063b53e52671461036d578063c56c4cf11461039d578063c5c21064146103bb578063edb7e13f146103eb578063f2fde38b146104095761012c565b8063715018a6146102c75780638da5cb5b146102d157806391a0d36d146102ef57806392cb829d1461030d57806395b82c131461033d5761012c565b806341c72314116100f457806341c72314146101ea5780634801cd171461021a5780634e881a1d146102365780635cfbede3146102675780636d3781f2146102975761012c565b806301467c601461013157806305a0851c146101615780631acae6e91461017f57806339da06f11461019b578063405743c1146101cc575b600080fd5b61014b600480360381019061014691906119ce565b610425565b6040516101589190611a3c565b60405180910390f35b610169610452565b6040516101769190611a66565b60405180910390f35b61019960048036038101906101949190611aad565b610476565b005b6101b560048036038101906101b09190611aed565b6104e6565b6040516101c3929190611bbd565b60405180910390f35b6101d461066a565b6040516101e19190611c53565b60405180910390f35b61020460048036038101906101ff9190611c6e565b61068e565b6040516102119190611cae565b60405180910390f35b610234600480360381019061022f9190611d0e565b610787565b005b610250600480360381019061024b9190611d3b565b61080a565b60405161025e929190611bbd565b60405180910390f35b610281600480360381019061027c9190611d3b565b6109eb565b60405161028e9190611a3c565b60405180910390f35b6102b160048036038101906102ac9190611c6e565b610ac0565b6040516102be9190611a3c565b60405180910390f35b6102cf610ad3565b005b6102d9610ae7565b6040516102e69190611a66565b60405180910390f35b6102f7610b10565b6040516103049190611d89565b60405180910390f35b61032760048036038101906103229190611c6e565b610b34565b6040516103349190611cae565b60405180910390f35b61035760048036038101906103529190611d3b565b610c98565b6040516103649190611a3c565b60405180910390f35b61038760048036038101906103829190611ed9565b610cb8565b6040516103949190611cae565b60405180910390f35b6103a5611137565b6040516103b29190611f43565b60405180910390f35b6103d560048036038101906103d09190611c6e565b61115d565b6040516103e29190611cae565b60405180910390f35b6103f361123f565b6040516104009190611f7f565b60405180910390f35b610423600480360381019061041e9190611f9a565b611263565b005b60006002600083815260200190815260200160002060009054906101000a900460ff161590509392505050565b7f000000000000000000000000fc7453da7bf4d0c739c1c53da57b3636dab0e11e81565b61047e6112e9565b806002600084815260200190815260200160002060006101000a81548160ff0219169083151502179055507f0d378a01fedf2d2b1d548d97d5dd7c4a4af5205124b75891938c0b3c74b5b0e882826040516104da929190611fd6565b60405180910390a15050565b60608060007f000000000000000000000000323d8d9ab29731849345b97758ed4c1323a1e48773ffffffffffffffffffffffffffffffffffffffff1663e9dc637586866040518363ffffffff1660e01b8152600401610546929190611fff565b600060405180830381865afa158015610563573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061058c9190612098565b90506000807f000000000000000000000000323d8d9ab29731849345b97758ed4c1323a1e48773ffffffffffffffffffffffffffffffffffffffff166324ba432888886040518363ffffffff1660e01b81526004016105ec929190611fff565b600060405180830381865afa158015610609573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061063291906120e1565b915091506000600d8251845160280101019050600060028551039050610659858383611370565b839650965050505050509250929050565b7f000000000000000000000000bb6eefd83daab02fa1a697eb9d8495eec9f9b38481565b6060610699826109eb565b61074757600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166341c7231484846040518363ffffffff1660e01b81526004016106fa929190612159565b600060405180830381865afa158015610717573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906107409190612098565b9050610781565b60006107528361080a565b91505061075e816113e6565b60405160200161076e919061220a565b6040516020818303038152906040529150505b92915050565b61078f6112e9565b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f855112fc6fcccf938a59297fdfa1aa10e7a87f743d88b17f07af7063c1f4a13a816040516107ff9190611f43565b60405180910390a150565b6060806002600084815260200190815260200160002060009054906101000a900460ff1615610865576040517fa672b46100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006108917f000000000000000000000000bb6eefd83daab02fa1a697eb9d8495eec9f9b384856104e6565b509050600061089f826113fb565b905060006108e2826040518060400160405280600181526020017f3e00000000000000000000000000000000000000000000000000000000000000815250611514565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8103610919578182945094505050506109e6565b600061093383600060018561092e919061225b565b611370565b905060008351905060006109608560018661094e919061225b565b60068561095b919061228f565b611370565b905060006109898460405180610140016040528061010a8152602001612a4061010a913961152a565b9050610995818361152a565b90506109d6816040518060400160405280600a81526020017f3c2f673e3c2f7376673e0000000000000000000000000000000000000000000081525061152a565b9050858198509850505050505050505b915091565b6000807f000000000000000000000000bb6eefd83daab02fa1a697eb9d8495eec9f9b38473ffffffffffffffffffffffffffffffffffffffff1663bd85b039846040518263ffffffff1660e01b8152600401610a4791906122c3565b602060405180830381865afa158015610a64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8891906122f3565b9050600081118015610ab857506002600084815260200190815260200160002060009054906101000a900460ff16155b915050919050565b6000610acb826109eb565b905092915050565b610adb6112e9565b610ae560006115a4565b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b7f0000000000000000000000005ceb91d612a735ec5f50ad68c7ad22a945c602fc81565b6060610b3f826109eb565b610bed57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166392cb829d84846040518363ffffffff1660e01b8152600401610ba0929190612159565b600060405180830381865afa158015610bbd573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610be69190612098565b9050610c92565b600080610bf98461080a565b915091506000610c0886611668565b610c19610c14856113e6565b610cb8565b610c22846113e6565b604051602001610c32919061220a565b604051602081830303815290604052604051602001610c539392919061252f565b6040516020818303038152906040529050610c6d816113e6565b604051602001610c7d91906125d8565b60405160208183030381529060405293505050505b92915050565b60026020528060005260406000206000915054906101000a900460ff1681565b60606000600167ffffffffffffffff811115610cd757610cd6611dae565b5b604051908082528060200260200182016040528015610d1057816020015b610cfd6118a7565b815260200190600190039081610cf55790505b5090506040518060400160405280601281526020017f66756c6c53697a6543616e7661732e637373000000000000000000000000000081525081600081518110610d5d57610d5c6125fa565b5b602002602001015160000181905250604051806060016040528060328152602001612b4a6032913981600081518110610d9957610d986125fa565b5b6020026020010151608001819052506040518060400160405280600281526020017f223e00000000000000000000000000000000000000000000000000000000000081525081600081518110610df257610df16125fa565b5b602002602001015160a001819052507f000000000000000000000000fc7453da7bf4d0c739c1c53da57b3636dab0e11e81600081518110610e3657610e356125fa565b5b60200260200101516020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506000600267ffffffffffffffff811115610e9157610e90611dae565b5b604051908082528060200260200182016040528015610eca57816020015b610eb76118a7565b815260200190600190039081610eaf5790505b5090506040518060400160405280601681526020017f7468657374616c6b6572465245534848454c4c2e6a730000000000000000000081525081600081518110610f1757610f166125fa565b5b6020026020010151600001819052507f000000000000000000000000fc7453da7bf4d0c739c1c53da57b3636dab0e11e81600081518110610f5b57610f5a6125fa565b5b60200260200101516020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600281600081518110610faf57610fae6125fa565b5b6020026020010151606001906004811115610fcd57610fcc612629565b5b90816004811115610fe157610fe0612629565b5b8152505083604051602001610ff6919061273c565b60405160208183030381529060405281600181518110611019576110186125fa565b5b602002602001015160c0018190525060018160018151811061103e5761103d6125fa565b5b602002602001015160600190600481111561105c5761105b612629565b5b908160048111156110705761106f612629565b5b8152505061107c61190c565b8281600001819052508181602001819052507f0000000000000000000000005ceb91d612a735ec5f50ad68c7ad22a945c602fc73ffffffffffffffffffffffffffffffffffffffff1663a891b35e826040518263ffffffff1660e01b81526004016110e79190612a1d565b600060405180830381865afa158015611104573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061112d9190612098565b9350505050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6060611168826109eb565b61121657600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c5c2106484846040518363ffffffff1660e01b81526004016111c9929190612159565b600060405180830381865afa1580156111e6573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061120f9190612098565b9050611239565b60006112218361080a565b509050611235611230826113e6565b610cb8565b9150505b92915050565b7f000000000000000000000000323d8d9ab29731849345b97758ed4c1323a1e48781565b61126b6112e9565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036112dd5760006040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081526004016112d49190611a66565b60405180910390fd5b6112e6816115a4565b50565b6112f16116b9565b73ffffffffffffffffffffffffffffffffffffffff1661130f610ae7565b73ffffffffffffffffffffffffffffffffffffffff161461136e576113326116b9565b6040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016113659190611a66565b60405180910390fd5b565b6060835182811161137f578092505b83811161138a578093505b828410156113de5760405191508383038083528486019550601f1980601f8301165b6001156113c65780880151818601528181019050806113ac575b5060008260208601015280603f830116840160405250505b509392505050565b60606113f4826000806116c1565b9050919050565b60608151801561150e5760038160021c02600115611444576003821661143857613d3d828501511880601f1a1581601e1a15018203915050611444565b60016003831603810190505b6040519250808352602083018181017ffc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc80605b527804080c1014181c2024282c3034383c4044484c5054585c6064603b526ef8fcf800fcd0d4d8dce0e4e8ecf0f4601a525b6001156114f957600487019650865180601f1a5160061c81601e1a5183161760061c81601d1a5183161760061c81601c1a5183161784526003840193508284106114f357506114f9565b506114a9565b60208201604052600082526000606052505050505b50919050565b6000611522838360006117be565b905092915050565b6060601f19604051915083518160208201165b60011561155757808601518185015282810190508061153d575b5083518184018360208301165b60011561157e578087015181830152848101905080611564575b508183018060208701016000815281875285601f82011660405250505050505092915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60606080604051019050602081016040526000815280600019835b6001156116a4578184019350600a81066030018453600a8104905080611683575b50828203602084039350808452505050919050565b600033905090565b6060835180156117b6576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106708515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f52602083018181015b600115611787576003880197508751603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f81165160035360005183526004830192508183106117815750611787565b50611731565b6020810160405260038406600204613d3d60f01b81840352808715150290506000818403528084038652505050505b509392505050565b6000835160011561189f5783516117e6578083116117de5782915061189f565b80915061189f565b835160208601600019935084810196506001828483010301601f831660200360031b6020880151858810838b101661182257505050505061189f565b6020851061186f578460208a01205b60011561186457818b5118831c6118565780868c200361185557848b039750611864565b5b60018b019a50838b10611831575b50505050505061189f565b5b60011561189957808a5118821c61188b57838a039650611899565b60018a019950828a10611870575b50505050505b509392505050565b6040518060e0016040528060608152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001600060048111156118f1576118f0612629565b5b81526020016060815260200160608152602001606081525090565b604051806040016040528060608152602001606081525090565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006119658261193a565b9050919050565b6119758161195a565b811461198057600080fd5b50565b6000813590506119928161196c565b92915050565b6000819050919050565b6119ab81611998565b81146119b657600080fd5b50565b6000813590506119c8816119a2565b92915050565b6000806000606084860312156119e7576119e6611930565b5b60006119f586828701611983565b9350506020611a06868287016119b9565b9250506040611a17868287016119b9565b9150509250925092565b60008115159050919050565b611a3681611a21565b82525050565b6000602082019050611a516000830184611a2d565b92915050565b611a608161195a565b82525050565b6000602082019050611a7b6000830184611a57565b92915050565b611a8a81611a21565b8114611a9557600080fd5b50565b600081359050611aa781611a81565b92915050565b60008060408385031215611ac457611ac3611930565b5b6000611ad2858286016119b9565b9250506020611ae385828601611a98565b9150509250929050565b60008060408385031215611b0457611b03611930565b5b6000611b1285828601611983565b9250506020611b23858286016119b9565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b60005b83811015611b67578082015181840152602081019050611b4c565b60008484015250505050565b6000601f19601f8301169050919050565b6000611b8f82611b2d565b611b998185611b38565b9350611ba9818560208601611b49565b611bb281611b73565b840191505092915050565b60006040820190508181036000830152611bd78185611b84565b90508181036020830152611beb8184611b84565b90509392505050565b6000819050919050565b6000611c19611c14611c0f8461193a565b611bf4565b61193a565b9050919050565b6000611c2b82611bfe565b9050919050565b6000611c3d82611c20565b9050919050565b611c4d81611c32565b82525050565b6000602082019050611c686000830184611c44565b92915050565b60008060408385031215611c8557611c84611930565b5b6000611c93858286016119b9565b9250506020611ca4858286016119b9565b9150509250929050565b60006020820190508181036000830152611cc88184611b84565b905092915050565b6000611cdb8261195a565b9050919050565b611ceb81611cd0565b8114611cf657600080fd5b50565b600081359050611d0881611ce2565b92915050565b600060208284031215611d2457611d23611930565b5b6000611d3284828501611cf9565b91505092915050565b600060208284031215611d5157611d50611930565b5b6000611d5f848285016119b9565b91505092915050565b6000611d7382611c20565b9050919050565b611d8381611d68565b82525050565b6000602082019050611d9e6000830184611d7a565b92915050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b611de682611b73565b810181811067ffffffffffffffff82111715611e0557611e04611dae565b5b80604052505050565b6000611e18611926565b9050611e248282611ddd565b919050565b600067ffffffffffffffff821115611e4457611e43611dae565b5b611e4d82611b73565b9050602081019050919050565b82818337600083830152505050565b6000611e7c611e7784611e29565b611e0e565b905082815260208101848484011115611e9857611e97611da9565b5b611ea3848285611e5a565b509392505050565b600082601f830112611ec057611ebf611da4565b5b8135611ed0848260208601611e69565b91505092915050565b600060208284031215611eef57611eee611930565b5b600082013567ffffffffffffffff811115611f0d57611f0c611935565b5b611f1984828501611eab565b91505092915050565b6000611f2d82611c20565b9050919050565b611f3d81611f22565b82525050565b6000602082019050611f586000830184611f34565b92915050565b6000611f6982611c20565b9050919050565b611f7981611f5e565b82525050565b6000602082019050611f946000830184611f70565b92915050565b600060208284031215611fb057611faf611930565b5b6000611fbe84828501611983565b91505092915050565b611fd081611998565b82525050565b6000604082019050611feb6000830185611fc7565b611ff86020830184611a2d565b9392505050565b60006040820190506120146000830185611a57565b6120216020830184611fc7565b9392505050565b600061203b61203684611e29565b611e0e565b90508281526020810184848401111561205757612056611da9565b5b612062848285611b49565b509392505050565b600082601f83011261207f5761207e611da4565b5b815161208f848260208601612028565b91505092915050565b6000602082840312156120ae576120ad611930565b5b600082015167ffffffffffffffff8111156120cc576120cb611935565b5b6120d88482850161206a565b91505092915050565b600080604083850312156120f8576120f7611930565b5b600083015167ffffffffffffffff81111561211657612115611935565b5b6121228582860161206a565b925050602083015167ffffffffffffffff81111561214357612142611935565b5b61214f8582860161206a565b9150509250929050565b600060408201905061216e6000830185611fc7565b61217b6020830184611fc7565b9392505050565b600081905092915050565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000600082015250565b60006121c3601a83612182565b91506121ce8261218d565b601a82019050919050565b60006121e482611b2d565b6121ee8185612182565b93506121fe818560208601611b49565b80840191505092915050565b6000612215826121b6565b915061222182846121d9565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061226682611998565b915061227183611998565b92508282019050808211156122895761228861222c565b5b92915050565b600061229a82611998565b91506122a583611998565b92508282039050818111156122bd576122bc61222c565b5b92915050565b60006020820190506122d86000830184611fc7565b92915050565b6000815190506122ed816119a2565b92915050565b60006020828403121561230957612308611930565b5b6000612317848285016122de565b91505092915050565b7f7b226e616d65223a22746865207374616c6b6572202300000000000000000000600082015250565b6000612356601683612182565b915061236182612320565b601682019050919050565b7f222c20226465736372697074696f6e223a2261207065726d697373696f6e6c6560008201527f737320636f6c6c61626f726174696f6e2070726f6772616d2072756e6e696e6760208201527f206f6e2045564d202d20696e742e61727420782058434f5059202d204f72696760408201527f696e616c20617274776f726b2062792058434f5059202846524553482048454c60608201527f4c292e222c22616e696d6174696f6e5f75726c223a2200000000000000000000608082015250565b600061243a609683612182565b91506124458261236c565b609682019050919050565b7f222c22696d616765223a22000000000000000000000000000000000000000000600082015250565b6000612486600b83612182565b915061249182612450565b600b82019050919050565b600081519050919050565b600081905092915050565b60006124bd8261249c565b6124c781856124a7565b93506124d7818560208601611b49565b80840191505092915050565b7f227d000000000000000000000000000000000000000000000000000000000000600082015250565b6000612519600283612182565b9150612524826124e3565b600282019050919050565b600061253a82612349565b915061254682866121d9565b91506125518261242d565b915061255d82856121d9565b915061256882612479565b915061257482846124b2565b915061257f8261250c565b9150819050949350505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000600082015250565b60006125c2601d83612182565b91506125cd8261258c565b601d82019050919050565b60006125e3826125b5565b91506125ef82846121d9565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f636f6e73742073766744617461203d2027000000000000000000000000000000600082015250565b600061268e601183612182565b915061269982612658565b601182019050919050565b7f273b000000000000000000000000000000000000000000000000000000000000600082015250565b60006126da600283612182565b91506126e5826126a4565b600282019050919050565b7f7468657374616c6b6572465245534848454c4c28737667446174612900000000600082015250565b6000612726601c83612182565b9150612731826126f0565b601c82019050919050565b600061274782612681565b915061275382846121d9565b915061275e826126cd565b915061276982612719565b915081905092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600082825260208201905092915050565b60006127bc82611b2d565b6127c681856127a0565b93506127d6818560208601611b49565b6127df81611b73565b840191505092915050565b6127f38161195a565b82525050565b600082825260208201905092915050565b60006128158261249c565b61281f81856127f9565b935061282f818560208601611b49565b61283881611b73565b840191505092915050565b6005811061285457612853612629565b5b50565b600081905061286582612843565b919050565b600061287582612857565b9050919050565b6128858161286a565b82525050565b600060e08301600083015184820360008601526128a882826127b1565b91505060208301516128bd60208601826127ea565b50604083015184820360408601526128d5828261280a565b91505060608301516128ea606086018261287c565b5060808301518482036080860152612902828261280a565b91505060a083015184820360a086015261291c828261280a565b91505060c083015184820360c0860152612936828261280a565b9150508091505092915050565b600061294f838361288b565b905092915050565b6000602082019050919050565b600061296f82612774565b612979818561277f565b93508360208202850161298b85612790565b8060005b858110156129c757848403895281516129a88582612943565b94506129b383612957565b925060208a0199505060018101905061298f565b50829750879550505050505092915050565b600060408301600083015184820360008601526129f68282612964565b91505060208301518482036020860152612a108282612964565b9150508091505092915050565b60006020820190508181036000830152612a3781846129d9565b90509291505056fe3c672069643d2244554445223e3c7374796c6520747970653d22746578742f637373223e406b65796672616d6573207368616b65416e696d6174696f6e207b30252c373525207b7472616e73666f726d3a207472616e736c61746528302e33252c20302e332529207363616c6528312e312c20312e31293b7d3736252c31303025207b7472616e73666f726d3a207472616e736c617465282d302e33252c202d302e332529207363616c6528312e312c20312e31293b7d7d2344554445207b616e696d6174696f6e3a207368616b65416e696d6174696f6e20302e31367320696e66696e6974653b7472616e73666f726d2d6f726967696e3a2063656e7465723b7d3c2f7374796c653e3c6c696e6b2072656c3d227374796c6573686565742220687265663d22646174613a746578742f6373733b6261736536342ca2646970667358221220b2c837df060e12152f0ff75eedd951f63aa4fd20f259514ed82d9ce536782ff864736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005ceb91d612a735ec5f50ad68c7ad22a945c602fc000000000000000000000000fc7453da7bf4d0c739c1c53da57b3636dab0e11e000000000000000000000000323d8d9ab29731849345b97758ed4c1323a1e487000000000000000000000000bb6eefd83daab02fa1a697eb9d8495eec9f9b384000000000000000000000000c62d4ea82879aff3dabaa19a46bbac3fe4d755a6
-----Decoded View---------------
Arg [0] : _scriptyBuilder (address): 0x5CEB91D612a735EC5f50Ad68c7AD22a945c602FC
Arg [1] : _scriptyETHFSAddress (address): 0xFc7453dA7bF4d0c739C1c53da57b3636dAb0e11e
Arg [2] : _efficax (address): 0x323d8d9aB29731849345b97758eD4C1323A1e487
Arg [3] : _freshHell (address): 0xbB6EefD83DaaB02Fa1a697EB9D8495eEc9f9B384
Arg [4] : _defaultRenderer (address): 0xC62D4Ea82879afF3DaBAa19A46Bbac3FE4D755a6
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000005ceb91d612a735ec5f50ad68c7ad22a945c602fc
Arg [1] : 000000000000000000000000fc7453da7bf4d0c739c1c53da57b3636dab0e11e
Arg [2] : 000000000000000000000000323d8d9ab29731849345b97758ed4c1323a1e487
Arg [3] : 000000000000000000000000bb6eefd83daab02fa1a697eb9d8495eec9f9b384
Arg [4] : 000000000000000000000000c62d4ea82879aff3dabaa19a46bbac3fe4d755a6
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.