Polygon Sponsored slots available. Book your slot here!
Contract Overview
Balance:
0 MATIC
MATIC Value:
$0.00
My Name Tag:
Not Available, login to update
Latest 1 internal transaction
Parent Txn Hash | Block | From | To | Value | |||
---|---|---|---|---|---|---|---|
0x30a4a985c8a4103f3cf0fc2b95f3bb8b80ec93a3d22fb0fc2a6b649507aebba6 | 37116758 | 165 days 10 hrs ago | 0x4e59b44847b379578588920ca78fbf26c0b4956c | Contract Creation | 0 MATIC |
[ Download CSV Export ]
Contract Source Code Verified (Exact Match)
Contract Name:
Edition
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0 /** * █▄░█ █▀▀ ▀█▀ █▀▀ █▀▄ █ ▀█▀ █ █▀█ █▄░█ █▀ * █░▀█ █▀░ ░█░ ██▄ █▄▀ █ ░█░ █ █▄█ █░▀█ ▄█ * * ▀█ █▀█ █▀█ ▄▀█ * █▄ █▄█ █▀▄ █▀█ */ pragma solidity ^0.8.6; import { IERC2981Upgradeable, IERC165Upgradeable } from "@openzeppelin-contracts-upgradeable/interfaces/IERC2981Upgradeable.sol"; import {AddressUpgradeable} from "@openzeppelin-contracts-upgradeable/utils/AddressUpgradeable.sol"; import {ERC721, ERC721I} from "./solmate-initializable/tokens/ERC721I.sol"; import {OwnedInitializable} from "./solmate-initializable/auth/OwnedInitializable.sol"; import {EditionMetadataRenderer} from "./EditionMetadataRenderer.sol"; import {IEdition} from "./interfaces/IEdition.sol"; import {OptionalOperatorFilterer} from "./utils/OptionalOperatorFilterer.sol"; import "./interfaces/Errors.sol"; /// @notice This is a smart contract for handling dynamic contract minting. /// @dev This allows creators to mint a unique serial edition of the same media within a custom contract /// @dev This is a fork of ZORA Editions for Showtime Drops /// @author karmacoma [Showtime Drops](https://github.com/showtime-xyz/nft-editions) /// @author iain nash [ZORA Editions](https://github.com/ourzora/nft-editions) contract Edition is EditionMetadataRenderer, ERC721I, IEdition, IERC2981Upgradeable, OwnedInitializable, OptionalOperatorFilterer { struct EditionState { // how many tokens have been minted (can not be more than editionSize) uint64 numberMinted; // reserved space to keep the state a uint256 uint16 __reserved; // Price to mint in twei (1 twei = 1000 gwei), so the supported price range is 0.000001 to 4294.967295 ETH // To accept ERC20 or a different price range, use a specialized sales contract as the approved minter uint32 salePriceTwei; // Royalty amount in bps (uint16 is large enough to store 10000 bps) uint16 royaltyBPS; // the edition can be minted up to this timestamp in seconds -- 0 means no end date uint64 endOfMintPeriod; // Total size of edition that can be minted uint64 editionSize; } EditionState private state; // Addresses allowed to mint edition mapping(address => bool) allowedMinters; /// @notice Function to create a new edition. Can only be called by the allowed creator /// Sets the only allowed minter to the address that creates/owns the edition. /// This can be re-assigned or updated later /// @param _owner User that owns and can mint the edition, gets royalty and sales payouts and can update the base url if needed. /// @param _name Name of edition, used in the title as "$NAME NUMBER/TOTAL" /// @param _symbol Symbol of the new token contract /// @param _description Description of edition, used in the description field of the NFT /// @param _imageUrl Image URL of the edition. Strongly encouraged to be used, but if necessary, only animation URL can be used. One of animation and image url need to exist in a edition to render the NFT. /// @param _animationUrl Animation URL of the edition. Not required, but if omitted image URL needs to be included. This follows the opensea spec for NFTs /// @param _editionSize Number of editions that can be minted in total. If 0, unlimited editions can be minted. /// @param _royaltyBPS BPS of the royalty set on the contract. Can be 0 for no royalty. /// @param _mintPeriodSeconds The amount of time in seconds after which editions can no longer be minted or purchased. Use 0 to have no expiration function initialize( address _owner, string calldata _name, string calldata _symbol, string calldata _description, string calldata _animationUrl, string calldata _imageUrl, uint256 _editionSize, uint256 _royaltyBPS, uint256 _mintPeriodSeconds ) public override initializer { __ERC721_init(_name, _symbol); // Set ownership to original sender of contract call __Owned_init(_owner); description = _description; animationUrl = _animationUrl; imageUrl = _imageUrl; uint64 _endOfMintPeriod; if (_mintPeriodSeconds > 0) { // overflows are not expected to happen for timestamps, and have no security implications unchecked { uint256 endOfMintPeriodUint256 = block.timestamp + _mintPeriodSeconds; _endOfMintPeriod = requireUint64(endOfMintPeriodUint256); } } state = EditionState({ editionSize: requireUint64(_editionSize), endOfMintPeriod: _endOfMintPeriod, royaltyBPS: requireUint16(_royaltyBPS), salePriceTwei: 0, numberMinted: 0, __reserved: 0 }); } /*////////////////////////////////////////////////////////////// OPERATOR FILTERER OVERRIDES //////////////////////////////////////////////////////////////*/ function transferFrom(address from, address to, uint256 tokenId) public override onlyAllowedOperator(from) { super.transferFrom(from, to, tokenId); } function safeTransferFrom(address from, address to, uint256 tokenId) public override onlyAllowedOperator(from) { super.safeTransferFrom(from, to, tokenId); } function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) public override onlyAllowedOperator(from) { super.safeTransferFrom(from, to, tokenId, data); } /*////////////////////////////////////////////////////////////// CREATOR / COLLECTION OWNER FUNCTIONS //////////////////////////////////////////////////////////////*/ /// @notice This sets a simple ETH sales price /// Setting a sales price allows users to mint the edition until it sells out. /// The supported price range is 0.000001 to 4294.967295 ETH (or relevant chain gas token) /// For more granular sales, use an external sales contract. /// @param _salePriceWei sale price in wei, 0 to disable sales function setSalePrice(uint256 _salePriceWei) external override onlyOwner { // convert to milli-eth internally uint32 salePriceTwei = requireUint32(_salePriceWei / 1e12); if (salePriceTwei == 0 && _salePriceWei > 0) { revert PriceTooLow(); } state.salePriceTwei = salePriceTwei; emit PriceChanged(_salePriceWei); } /// @dev This withdraws ETH from the contract to the contract owner. function withdraw() external override onlyOwner { // No need for gas limit to trusted address. AddressUpgradeable.sendValue(payable(owner), address(this).balance); } /// @notice Sets the approved minting status of the given address. /// @param minter address to set approved minting status for /// @param allowed boolean if that address is allowed to mint /// @dev This requires that msg.sender is the owner of the given edition id. /// @dev If the ZeroAddress (address(0x0)) is set as a minter, anyone will be allowed to mint. /// @dev This setup is similar to setApprovalForAll in the ERC721 spec. function setApprovedMinter(address minter, bool allowed) public override onlyOwner { allowedMinters[minter] = allowed; } /// @notice Updates the external_url field in the metadata function setExternalUrl(string calldata _externalUrl) public override onlyOwner { emit ExternalUrlUpdated(externalUrl, _externalUrl); externalUrl = _externalUrl; } function setStringProperties(string[] calldata names, string[] calldata values) public override onlyOwner { uint256 length = names.length; if (values.length != length) { revert LengthMismatch(); } namesOfStringProperties = names; for (uint256 i = 0; i < length;) { string calldata name = names[i]; string calldata value = values[i]; if (bytes(name).length == 0 || bytes(value).length == 0) { revert BadAttribute(name, value); } emit PropertyUpdated(name, stringProperties[name], value); stringProperties[name] = value; unchecked { ++i; } } } function setOperatorFilter(address operatorFilter) public override onlyOwner { _setOperatorFilter(operatorFilter); } function enableDefaultOperatorFilter() public override onlyOwner { _setOperatorFilter(CANONICAL_OPENSEA_SUBSCRIPTION); } /*////////////////////////////////////////////////////////////// COLLECTOR / TOKEN OWNER FUNCTIONS //////////////////////////////////////////////////////////////*/ /// @param to address to send the newly minted edition to /// @dev This mints one edition to the given address by an allowed minter function mint(address to) external payable override returns (uint256 tokenId) { tokenId = _mintPreFlightChecks(1); _mint(to, tokenId); } function safeMint(address to) external payable override returns (uint256 tokenId) { tokenId = _mintPreFlightChecks(1); _safeMint(to, tokenId); } /// @param recipients list of addresses to send the newly minted editions to /// @dev This mints multiple editions to the given list of addresses. function mintBatch(address[] calldata recipients) external payable override returns (uint256 lastTokenId) { uint64 n = uint64(recipients.length); if (n == 0) { revert InvalidArgument(); } lastTokenId = _mintPreFlightChecks(n); unchecked { uint256 firstTokenId = lastTokenId + 1 - n; for (uint256 i = 0; i < n;) { _safeMint(recipients[i], firstTokenId + i); ++i; } } } /*////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ function requireUint16(uint256 value) internal pure returns (uint16) { if (value > uint256(type(uint16).max)) { revert IntegerOverflow(value); } return uint16(value); } function requireUint32(uint256 value) internal pure returns (uint32) { if (value > uint256(type(uint32).max)) { revert IntegerOverflow(value); } return uint32(value); } function requireUint64(uint256 value) internal pure returns (uint64) { if (value > uint256(type(uint64).max)) { revert IntegerOverflow(value); } return uint64(value); } /// @dev stateless version of isMintingEnded function enforceTimeLimit(uint64 _endOfMintPeriod) internal view { if (_endOfMintPeriod > 0 && uint64(block.timestamp) > _endOfMintPeriod) { revert TimeLimitReached(); } } function enforceSupplyLimit(uint64 _editionSize, uint64 _numberMinted) internal pure { if (_editionSize > 0 && _numberMinted > _editionSize) { revert SoldOut(); } } function enforceSalePrice(uint256 _salePriceTwei, uint256 quantity) internal view { unchecked { if (msg.value != quantity * _salePriceTwei * 1e12) { revert WrongPrice(); } } } /// @dev This helper function checks if the msg.sender is allowed to mint function _isAllowedToMint() internal view returns (bool) { // optimize by likelihood: // 1. check allowlist/minter contracts // 2. open mints // 3. owner mints return allowedMinters[msg.sender] || allowedMinters[address(0x0)] || owner == msg.sender; } /// @dev Validates the supply and time limits for minting with a single SLOAD and SSTORE function _mintPreFlightChecks(uint256 quantity) internal returns (uint64 _tokenId) { if (!_isAllowedToMint()) { revert Unauthorized(); } uint256 _state; uint256 _postState; uint64 _editionSize; uint64 _endOfMintPeriod; uint32 _salePriceTwei; assembly ("memory-safe") { _state := sload(state.slot) _editionSize := shr(192, _state) _endOfMintPeriod := shr(128, _state) _salePriceTwei := shr(80, _state) // can not realistically overflow // the fields in EditionState are ordered so that incrementing state increments numberMinted _postState := add(_state, quantity) // perform the addition only once and extract numberMinted + 1 from _postState _tokenId := and(_postState, 0xffffffffffffffff) } enforceSupplyLimit(_editionSize, _tokenId); enforceTimeLimit(_endOfMintPeriod); enforceSalePrice(_salePriceTwei, quantity); // update storage assembly ("memory-safe") { sstore(state.slot, _postState) } return _tokenId; } /*////////////////////////////////////////////////////////////// METADATA FUNCTIONS //////////////////////////////////////////////////////////////*/ function editionSize() external view override returns (uint256) { return state.editionSize; } /// @dev Returns the sale price in wei function salePrice() public view override returns (uint256) { unchecked { // can not overflow return uint256(state.salePriceTwei) * 1e12; } } /// Returns the timestamp when the minting period ends, or 0 if there is no time limit function endOfMintPeriod() public view override returns (uint256) { return state.endOfMintPeriod; } /// Returns whether the edition can still be minted/purchased function isMintingEnded() public view override returns (bool) { uint256 _endOfMintPeriod = state.endOfMintPeriod; return _endOfMintPeriod > 0 && uint64(block.timestamp) > _endOfMintPeriod; } function totalSupply() public view override returns (uint256) { return state.numberMinted; } /// @notice Get the base64-encoded json metadata for a token /// @param tokenId the token id to get the metadata for /// @return base64-encoded json metadata object function tokenURI(uint256 tokenId) public view override returns (string memory) { require(_ownerOf[tokenId] != address(0), "No token"); return createTokenMetadata(name, tokenId, state.editionSize); } /// @notice Get the base64-encoded json metadata object for the edition function contractURI() public view override returns (string memory) { return createContractMetadata(name, state.royaltyBPS, owner); } /// @notice Get royalty information for token /// @param _salePrice Sale price for the token function royaltyInfo(uint256, uint256 _salePrice) external view override returns (address receiver, uint256 royaltyAmount) { if (owner == address(0x0)) { return (address(0x0), 0); } return (owner, (_salePrice * state.royaltyBPS) / 10_000); } function supportsInterface(bytes4 interfaceId) public view override (ERC721, IERC165Upgradeable) returns (bool) { return type(IERC2981Upgradeable).interfaceId == interfaceId || ERC721.supportsInterface(interfaceId); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.6; import {Base64} from "./utils/Base64.sol"; import {LibString} from "./utils/LibString.sol"; import {EditionMetadataState} from "./EditionMetadataState.sol"; /// logic for rendering metadata associated with editions contract EditionMetadataRenderer is EditionMetadataState { /// Generate edition metadata from storage information as base64-json blob /// Combines the media data and metadata /// @param name Name of NFT in metadata /// @param tokenId Token ID for specific token /// @param editionSize Size of entire edition to show function createTokenMetadata( string memory name, uint256 tokenId, uint256 editionSize ) internal view returns (string memory) { return toBase64DataUrl( createTokenMetadataJson(name, tokenId, editionSize) ); } /// Function to create the metadata json string for the nft edition /// @param name Name of NFT in metadata /// @param tokenId Token ID for specific token /// @param editionSize Size of entire edition to show function createTokenMetadataJson( string memory name, uint256 tokenId, uint256 editionSize ) internal view returns (string memory) { string memory editionSizeText; if (editionSize > 0) { editionSizeText = string.concat( "/", LibString.toString(editionSize) ); } string memory externalURLText = ""; if (bytes(externalUrl).length > 0) { externalURLText = string.concat('","external_url":"', externalUrl); } string memory mediaData = tokenMediaData(imageUrl, animationUrl); return string.concat( '{"name":"', LibString.escapeJSON(name), " #", LibString.toString(tokenId), editionSizeText, '","', 'description":"', LibString.escapeJSON(description), externalURLText, '"', mediaData, getPropertiesJson(), "}" ); } /// Encodes contract level metadata into base64-data url format /// @dev see https://docs.opensea.io/docs/contract-level-metadata /// @dev borrowed from https://github.com/ourzora/zora-drops-contracts/blob/main/src/utils/NFTMetadataRenderer.sol function createContractMetadata( string memory name, uint256 royaltyBPS, address royaltyRecipient ) internal view returns (string memory) { string memory imageSpace = ""; if (bytes(imageUrl).length > 0) { imageSpace = string.concat('","image":"', imageUrl); } string memory externalURLSpace = ""; if (bytes(externalUrl).length > 0) { externalURLSpace = string.concat( '","external_link":"', externalUrl ); } return toBase64DataUrl( string.concat( '{"name":"', LibString.escapeJSON(name), '","description":"', LibString.escapeJSON(description), // this is for opensea since they don't respect ERC2981 right now '","seller_fee_basis_points":', LibString.toString(royaltyBPS), ',"fee_recipient":"', LibString.toHexString(royaltyRecipient), imageSpace, externalURLSpace, '"}' ) ); } /// Encodes the argument json bytes into base64-data uri format /// @param json Raw json to base64 and turn into a data-uri function toBase64DataUrl(string memory json) internal pure returns (string memory) { return string.concat( "data:application/json;base64,", Base64.encode(bytes(json)) ); } function tokenMediaData(string memory imageUrl, string memory animationUrl) internal pure returns (string memory) { bool hasImage = bytes(imageUrl).length > 0; bool hasAnimation = bytes(animationUrl).length > 0; string memory buffer = ""; if (hasImage) { buffer = string.concat(',"image":"', imageUrl, '"'); } if (hasAnimation) { buffer = string.concat( buffer, ',"animation_url":"', animationUrl, '"' ); } return buffer; } /// Produces Enjin Metadata style simple properties /// @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md#erc-1155-metadata-uri-json-schema function getPropertiesJson() internal view returns (string memory) { uint256 length = namesOfStringProperties.length; if (length == 0) { return ',"properties":{}'; } string memory buffer = ',"properties":{'; unchecked { // `length - 1` can not underflow because of the `length == 0` check above uint256 lengthMinusOne = length - 1; for (uint256 i = 0; i < lengthMinusOne; ) { string storage _name = namesOfStringProperties[i]; string storage _value = stringProperties[_name]; buffer = string.concat( buffer, stringifyStringAttribute(_name, _value), "," ); // counter increment can not overflow ++i; } // add the last attribute without a trailing comma string storage lastName = namesOfStringProperties[lengthMinusOne]; buffer = string.concat( buffer, stringifyStringAttribute(lastName, stringProperties[lastName]) ); } buffer = string.concat(buffer, "}"); return buffer; } function stringifyStringAttribute(string storage name, string storage value) internal pure returns (string memory) { // let's only escape the value, property names should not be using any special characters return string.concat('"', name, '":"', LibString.escapeJSON(value), '"'); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.6; contract EditionMetadataState { string public description; // Media Urls // animation_url field in the metadata string public animationUrl; // Image in the metadata string public imageUrl; // URL that will appear below the asset's image on OpenSea string public externalUrl; string[] internal namesOfStringProperties; mapping(string => string) internal stringProperties; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.6; error BadAttribute(string name, string value); error IntegerOverflow(uint256 value); error InvalidArgument(); error LengthMismatch(); error NotForSale(); error OperatorNotAllowed(address operator); error PriceTooLow(); error SoldOut(); error TimeLimitReached(); error Unauthorized(); error WrongPrice();
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.6; interface IEdition { event PriceChanged(uint256 amount); event ExternalUrlUpdated(string oldExternalUrl, string newExternalUrl); event PropertyUpdated(string name, string oldValue, string newValue); function contractURI() external view returns (string memory); function editionSize() external view returns (uint256); function initialize( address _owner, string memory _name, string memory _symbol, string memory _description, string memory _animationUrl, string memory _imageUrl, uint256 _editionSize, uint256 _royaltyBPS, uint256 _mintPeriodSeconds ) external; function enableDefaultOperatorFilter() external; function endOfMintPeriod() external view returns (uint256); function isMintingEnded() external view returns (bool); function mint(address to) external payable returns (uint256); function safeMint(address to) external payable returns (uint256); function mintBatch(address[] memory recipients) external payable returns (uint256); function salePrice() external view returns (uint256); function setApprovedMinter(address minter, bool allowed) external; function setExternalUrl(string calldata _externalUrl) external; function setOperatorFilter(address operatorFilter) external; function setStringProperties(string[] calldata names, string[] calldata values) external; function setSalePrice(uint256 _salePrice) external; function totalSupply() external view returns (uint256); function withdraw() external; }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {Initializable} from "../utils/Initializable.sol"; /// @notice Simple single owner authorization mixin. /// @author karmacoma (replaced constructor with initializer) /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol) abstract contract OwnedInitializable is Initializable { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event OwnershipTransferred(address indexed user, address indexed newOwner); /*////////////////////////////////////////////////////////////// OWNERSHIP STORAGE //////////////////////////////////////////////////////////////*/ address public owner; modifier onlyOwner() virtual { require(msg.sender == owner, "UNAUTHORIZED"); _; } /*////////////////////////////////////////////////////////////// INITIALIZER //////////////////////////////////////////////////////////////*/ function __Owned_init(address _owner) internal onlyInitializing { owner = _owner; emit OwnershipTransferred(address(0), _owner); } /*////////////////////////////////////////////////////////////// OWNERSHIP LOGIC //////////////////////////////////////////////////////////////*/ function transferOwnership(address newOwner) public virtual onlyOwner { owner = newOwner; emit OwnershipTransferred(msg.sender, newOwner); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {Initializable} from "../utils/Initializable.sol"; import {ERC721} from "solmate/tokens/ERC721.sol"; import {ERC721TokenReceiver} from "./ERC721TokenReceiver.sol"; /// @notice Initializable version of Solmate's ERC721 abstract contract ERC721I is ERC721, Initializable { /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor() ERC721("", "") { _lockInitializers(); } /*////////////////////////////////////////////////////////////// INITIALIZER //////////////////////////////////////////////////////////////*/ function __ERC721_init(string memory _name, string memory _symbol) internal onlyInitializing { name = _name; symbol = _symbol; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice A generic interface for a contract which properly accepts ERC721 tokens. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) abstract contract ERC721TokenReceiver { function onERC721Received( address, address, uint256, bytes calldata ) external virtual returns (bytes4) { return ERC721TokenReceiver.onERC721Received.selector; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern, minimalist, and gas efficient Initializable implementation with no reinitializers /// @dev warning: this contract is not compatible with OpenZeppelin's Initializable /// @dev warning: this should be considered very experimental /// @author karmacoma abstract contract Initializable { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Initialized(); /*////////////////////////////////////////////////////////////// STORAGE //////////////////////////////////////////////////////////////*/ enum InitState { NOT_INITIALIZED, INITIALIZING, INITIALIZED } InitState private _initState; /*////////////////////////////////////////////////////////////// INITIALIZABLE LOGIC //////////////////////////////////////////////////////////////*/ modifier initializer() { bool isTopLevelCall = _initState == InitState.NOT_INITIALIZED; require( (isTopLevelCall) || (_initState == InitState.INITIALIZING), "ALREADY_INITIALIZED" ); if (isTopLevelCall) { _initState = InitState.INITIALIZING; } _; if (isTopLevelCall) { _initState = InitState.INITIALIZED; emit Initialized(); } } modifier onlyInitializing() { require(_initState == InitState.INITIALIZING, "NOT_INITIALIZING"); _; } /// locks the contract, preventing any further initialization function _lockInitializers() internal virtual { require( _initState == InitState.NOT_INITIALIZED, "MUST_BE_NOT_INITIALIZED" ); _initState = InitState.INITIALIZED; emit Initialized(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library to encode strings in Base64. /// @author Modified from Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol) @ 41d29ed /// @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) { assembly ("memory-safe") { 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 0x0230 will translate "-_" + "+/". mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef") mstore( 0x3f, sub( "ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0230) ) ) // 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. // prettier-ignore 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(ptr, end)) { break } } let r := mod(dataLength, 3) switch noPadding case 0 { // 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`. // Write the length of the string. mstore(result, encodedLength) } default { // Write the length of the string. mstore( result, sub(encodedLength, add(iszero(iszero(r)), eq(r, 1))) ) } // Allocate the memory for the string. // Add 31 and mask with `not(31)` to round the // free memory pointer up the next multiple of 32. mstore(0x40, and(add(end, 31), not(31))) } } } /// @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 Encodes 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) { assembly { let dataLength := mload(data) if dataLength { let end := add(data, dataLength) let decodedLength := mul(shr(2, dataLength), 3) switch and(dataLength, 3) case 0 { // If padded. decodedLength := sub( decodedLength, add( eq(and(mload(end), 0xFF), 0x3d), eq(and(mload(end), 0xFFFF), 0x3d3d) ) ) } default { // If non-padded. decodedLength := add( decodedLength, sub(and(dataLength, 3), 1) ) } result := mload(0x40) // Write the length of the string. mstore(result, decodedLength) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) // 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) // prettier-ignore for {} 1 {} { // Read 4 bytes. data := add(data, 4) let input := mload(data) // Write 3 bytes. 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) // prettier-ignore if iszero(lt(data, end)) { break } } // Allocate the memory for the string. // Add 32 + 31 and mask with `not(31)` to round the // free memory pointer up the next multiple of 32. mstore(0x40, and(add(add(result, decodedLength), 63), not(31))) // Restore the zero slot. mstore(0x60, 0) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for converting numbers into strings and other string operations. /// @author Modified from Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) @ 016c4ac /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `length` of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = uint256(int256(-1)); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory str) { assembly ("memory-safe") { // 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. Total: 5 * 0x20 = 0xa0. let m := add(mload(0x40), 0xa0) // Update the free memory pointer to allocate. mstore(0x40, m) // Assign the `str` to the end. str := sub(m, 0x20) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. // prettier-ignore for { let temp := value } 1 {} { str := sub(str, 1) // Write the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) // Keep dividing `temp` until zero. temp := div(temp, 10) // prettier-ignore 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) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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) { assembly { let start := mload(0x40) // 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. let m := add(start, and(add(shl(1, length), 0x62), not(0x1f))) // Allocate the memory. mstore(0x40, m) // Assign the `str` to the end. str := sub(m, 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 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. // prettier-ignore for {} 1 {} { str := sub(str, 2) mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) length := sub(length, 1) // prettier-ignore if iszero(length) { break } } if temp { // Store the function selector of `HexLengthInsufficient()`. mstore(0x00, 0x2194895a) // Revert with (offset, size). revert(0x1c, 0x04) } // Compute the string's length. let strLength := add(sub(end, str), 2) // Move the pointer and write the "0x" prefix. str := sub(str, 0x20) mstore(str, 0x3078) // Move the pointer and write the length. str := sub(str, 2) 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) { assembly { let start := mload(0x40) // 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. let m := add(start, 0xa0) // Allocate the memory. mstore(0x40, m) // Assign the `str` to the end. str := sub(m, 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) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. // prettier-ignore for { let temp := value } 1 {} { str := sub(str, 2) mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) // prettier-ignore if iszero(temp) { break } } // Compute the string's length. let strLength := add(sub(end, str), 2) // Move the pointer and write the "0x" prefix. str := sub(str, 0x20) mstore(str, 0x3078) // Move the pointer and write the length. str := sub(str, 2) mstore(str, strLength) } } /// @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) { assembly ("memory-safe") { let start := mload(0x40) // We need 0x20 bytes for the length, 0x02 bytes for the prefix, // and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x02 + 0x28) is 0x60. str := add(start, 0x60) // Allocate the memory. mstore(0x40, str) // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let length := 20 // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. // prettier-ignore for { let temp := value } 1 {} { str := sub(str, 2) mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) length := sub(length, 1) // prettier-ignore if iszero(length) { break } } // Move the pointer and write the "0x" prefix. str := sub(str, 32) mstore(str, 0x3078) // Move the pointer and write the length. str := sub(str, 2) mstore(str, 42) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OTHER STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, all indices of the following operations // are byte (ASCII) offsets, not UTF character offsets. /// @dev Returns `subject` all occurances of `search` replaced with `replacement`. function replace( string memory subject, string memory search, string memory replacement ) internal pure returns (string memory result) { 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, 32)) { h := keccak256(search, searchLength) } let m := shl(3, sub(32, and(searchLength, 31))) let s := mload(search) // prettier-ignore 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) // prettier-ignore if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. // prettier-ignore for { let o := 0 } 1 {} { mstore(add(result, o), mload(add(replacement, o))) o := add(o, 0x20) // prettier-ignore if iszero(lt(o, replacementLength)) { break } } result := add(result, replacementLength) subject := add(subject, searchLength) if searchLength { // prettier-ignore if iszero(lt(subject, subjectSearchEnd)) { break } continue } } mstore(result, t) result := add(result, 1) subject := add(subject, 1) // prettier-ignore 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. // prettier-ignore for {} lt(subject, subjectEnd) {} { mstore(resultRemainder, mload(subject)) resultRemainder := add(resultRemainder, 0x20) subject := add(subject, 0x20) } result := sub(result, 0x20) // Zeroize the slot after the string. let last := add(add(result, 0x20), k) mstore(last, 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 31), not(31))) // Store the length of the result. mstore(result, k) } } /// @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) { assembly { // prettier-ignore for { let subjectLength := mload(subject) } 1 {} { if iszero(mload(search)) { // `result = min(from, subjectLength)`. result := xor(from, mul(xor(from, subjectLength), lt(subjectLength, from))) break } let searchLength := mload(search) let subjectStart := add(subject, 0x20) result := not(0) // Initialize to `NOT_FOUND`. subject := add(subjectStart, from) let subjectSearchEnd := add(sub(add(subjectStart, subjectLength), searchLength), 1) let m := shl(3, sub(32, and(searchLength, 31))) let s := mload(add(search, 0x20)) // prettier-ignore if iszero(lt(subject, subjectSearchEnd)) { break } if iszero(lt(searchLength, 32)) { // prettier-ignore 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) // prettier-ignore if iszero(lt(subject, subjectSearchEnd)) { break } } break } // prettier-ignore for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) // prettier-ignore if iszero(lt(subject, subjectSearchEnd)) { 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) { assembly { // prettier-ignore for {} 1 {} { let searchLength := mload(search) let fromMax := sub(mload(subject), searchLength) if iszero(gt(fromMax, from)) { from := fromMax } if iszero(mload(search)) { result := from break } result := not(0) // Initialize to `NOT_FOUND`. let subjectSearchEnd := sub(add(subject, 0x20), 1) subject := add(add(subject, 0x20), from) // prettier-ignore if iszero(gt(subject, subjectSearchEnd)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. // prettier-ignore for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if eq(keccak256(subject, searchLength), h) { result := sub(subject, add(subjectSearchEnd, 1)) break } subject := sub(subject, 1) // prettier-ignore if iszero(gt(subject, subjectSearchEnd)) { break } } break } } } /// @dev Returns the 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 whether `subject` starts with `search`. function startsWith(string memory subject, string memory search) internal pure returns (bool result) { assembly { let searchLength := mload(search) // Just using keccak256 directly is actually cheaper. 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) { 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. 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) { assembly { let subjectLength := mload(subject) if iszero(or(iszero(times), iszero(subjectLength))) { subject := add(subject, 0x20) result := mload(0x40) let output := add(result, 0x20) // prettier-ignore for {} 1 {} { // Copy the `subject` one word at a time. // prettier-ignore for { let o := 0 } 1 {} { mstore(add(output, o), mload(add(subject, o))) o := add(o, 0x20) // prettier-ignore if iszero(lt(o, subjectLength)) { break } } output := add(output, subjectLength) times := sub(times, 1) // prettier-ignore if iszero(times) { break } } // Zeroize the slot after the string. mstore(output, 0) // Store the length. let resultLength := sub(output, add(result, 0x20)) mstore(result, resultLength) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(result, and(add(resultLength, 63), not(31)))) } } } /// @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) { 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) // Copy the `subject` one word at a time, backwards. // prettier-ignore for { let o := and(add(resultLength, 31), not(31)) } 1 {} { mstore(add(result, o), mload(add(subject, o))) o := sub(o, 0x20) // prettier-ignore 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, 63), not(31)))) } } } /// @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) { 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, 32)) { h := keccak256(search, searchLength) } let m := shl(3, sub(32, and(searchLength, 31))) let s := mload(search) // prettier-ignore 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) // prettier-ignore 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 { // prettier-ignore if iszero(lt(subject, subjectSearchEnd)) { break } continue } } subject := add(subject, 1) // prettier-ignore 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); assembly { if mload(indices) { let indexPtr := add(indices, 0x20) let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) mstore(sub(indicesEnd, 0x20), mload(subject)) mstore(indices, add(mload(indices), 1)) let prevIndex := 0 // prettier-ignore 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. // prettier-ignore for { let o := and(add(elementLength, 31), not(31)) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := sub(o, 0x20) // prettier-ignore 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, 63), not(31)))) // Store the `element` into the array. mstore(indexPtr, element) } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) // prettier-ignore 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) { assembly ("memory-safe") { result := mload(0x40) let aLength := mload(a) // Copy `a` one word at a time, backwards. // prettier-ignore for { let o := and(add(mload(a), 32), not(31)) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := sub(o, 0x20) // prettier-ignore if iszero(o) { break } } let bLength := mload(b) let output := add(result, mload(a)) // Copy `b` one word at a time, backwards. // prettier-ignore for { let o := and(add(bLength, 32), not(31)) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := sub(o, 0x20) // prettier-ignore 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, 31), not(31))) } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { assembly ("memory-safe") { // prettier-ignore for { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // 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)) } 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) } let last := result // Zeroize the slot after the string. mstore(last, 0) // Restore the result to the start of the free memory. result := mload(0x40) // Store the length of the result. mstore(result, sub(last, add(result, 0x20))) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 31), not(31))) } } /// @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) { 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 behaviour is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { 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) { 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 behaviour is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { 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 { // Right pad with zeroes. Just in case the string is produced // by a method that doesn't zero right pad. mstore(add(add(a, 0x20), mload(a)), 0) // Store the return offset. // Assumes that the string does not start from the scratch space. mstore(sub(a, 0x20), 0x20) // End the transaction, returning the string. return(sub(a, 0x20), add(mload(a), 0x40)) } } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.6; import { IOperatorFilterRegistry } from "operator-filter-registry/IOperatorFilterRegistry.sol"; import { OperatorNotAllowed } from "../interfaces/Errors.sol"; /// Less aggro than DefaultOperatorFilterer, it does not automatically register and subscribe to the default filter /// Instead, this is off by default, opt-in, and relies only on view functions (no register call) abstract contract OptionalOperatorFilterer { address public constant CANONICAL_OPENSEA_SUBSCRIPTION = address(0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6); address public constant CANONICAL_OPENSEA_REGISTRY = address(0x000000000000AAeB6D7670E522A718067333cd4E); address public activeOperatorFilter = address(0); event OperatorFilterChanged(address indexed operatorFilter); /// Set to CANONICAL_OPENSEA_SUBSCRIPTION to use the default OpenSea operator filter /// Set to address(0) to disable operator filtering function _setOperatorFilter(address operatorFilter) internal { activeOperatorFilter = operatorFilter; emit OperatorFilterChanged(operatorFilter); } /// @dev modified from operator-filter-registry/OperatorFilterer.sol modifier onlyAllowedOperator(address from) virtual { // Allow spending tokens from addresses with balance // Note that this still allows listings and marketplaces with escrow to transfer tokens if transferred // from an EOA. if (from != msg.sender) { _checkFilterOperator(msg.sender); } _; } /// @dev modified from operator-filter-registry/OperatorFilterer.sol function _checkFilterOperator(address operator) internal view { if (activeOperatorFilter == address(0)) { return; } // Check registry code length to facilitate testing in environments without a deployed registry. if (CANONICAL_OPENSEA_REGISTRY.code.length == 0) { return; } if (!IOperatorFilterRegistry(CANONICAL_OPENSEA_REGISTRY).isOperatorAllowed(activeOperatorFilter, operator)) { revert OperatorNotAllowed(operator); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; interface IOperatorFilterRegistry { function isOperatorAllowed(address registrant, address operator) external view returns (bool); function register(address registrant) external; function registerAndSubscribe(address registrant, address subscription) external; function registerAndCopyEntries(address registrant, address registrantToCopy) external; function unregister(address addr) external; function updateOperator(address registrant, address operator, bool filtered) external; function updateOperators(address registrant, address[] calldata operators, bool filtered) external; function updateCodeHash(address registrant, bytes32 codehash, bool filtered) external; function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered) external; function subscribe(address registrant, address registrantToSubscribe) external; function unsubscribe(address registrant, bool copyExistingEntries) external; function subscriptionOf(address addr) external returns (address registrant); function subscribers(address registrant) external returns (address[] memory); function subscriberAt(address registrant, uint256 index) external returns (address); function copyEntriesOf(address registrant, address registrantToCopy) external; function isOperatorFiltered(address registrant, address operator) external returns (bool); function isCodeHashOfFiltered(address registrant, address operatorWithCode) external returns (bool); function isCodeHashFiltered(address registrant, bytes32 codeHash) external returns (bool); function filteredOperators(address addr) external returns (address[] memory); function filteredCodeHashes(address addr) external returns (bytes32[] memory); function filteredOperatorAt(address registrant, uint256 index) external returns (address); function filteredCodeHashAt(address registrant, uint256 index) external returns (bytes32); function isRegistered(address addr) external returns (bool); function codeHashOf(address addr) external returns (bytes32); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern, minimalist, and gas efficient ERC-721 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) abstract contract ERC721 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 indexed id); event Approval(address indexed owner, address indexed spender, uint256 indexed id); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /*////////////////////////////////////////////////////////////// METADATA STORAGE/LOGIC //////////////////////////////////////////////////////////////*/ string public name; string public symbol; function tokenURI(uint256 id) public view virtual returns (string memory); /*////////////////////////////////////////////////////////////// ERC721 BALANCE/OWNER STORAGE //////////////////////////////////////////////////////////////*/ mapping(uint256 => address) internal _ownerOf; mapping(address => uint256) internal _balanceOf; function ownerOf(uint256 id) public view virtual returns (address owner) { require((owner = _ownerOf[id]) != address(0), "NOT_MINTED"); } function balanceOf(address owner) public view virtual returns (uint256) { require(owner != address(0), "ZERO_ADDRESS"); return _balanceOf[owner]; } /*////////////////////////////////////////////////////////////// ERC721 APPROVAL STORAGE //////////////////////////////////////////////////////////////*/ mapping(uint256 => address) public getApproved; mapping(address => mapping(address => bool)) public isApprovedForAll; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor(string memory _name, string memory _symbol) { name = _name; symbol = _symbol; } /*////////////////////////////////////////////////////////////// ERC721 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 id) public virtual { address owner = _ownerOf[id]; require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED"); getApproved[id] = spender; emit Approval(owner, spender, id); } function setApprovalForAll(address operator, bool approved) public virtual { isApprovedForAll[msg.sender][operator] = approved; emit ApprovalForAll(msg.sender, operator, approved); } function transferFrom( address from, address to, uint256 id ) public virtual { require(from == _ownerOf[id], "WRONG_FROM"); require(to != address(0), "INVALID_RECIPIENT"); require( msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id], "NOT_AUTHORIZED" ); // Underflow of the sender's balance is impossible because we check for // ownership above and the recipient's balance can't realistically overflow. unchecked { _balanceOf[from]--; _balanceOf[to]++; } _ownerOf[id] = to; delete getApproved[id]; emit Transfer(from, to, id); } function safeTransferFrom( address from, address to, uint256 id ) public virtual { transferFrom(from, to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } function safeTransferFrom( address from, address to, uint256 id, bytes calldata data ) public virtual { transferFrom(from, to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } /*////////////////////////////////////////////////////////////// ERC165 LOGIC //////////////////////////////////////////////////////////////*/ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721 interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 id) internal virtual { require(to != address(0), "INVALID_RECIPIENT"); require(_ownerOf[id] == address(0), "ALREADY_MINTED"); // Counter overflow is incredibly unrealistic. unchecked { _balanceOf[to]++; } _ownerOf[id] = to; emit Transfer(address(0), to, id); } function _burn(uint256 id) internal virtual { address owner = _ownerOf[id]; require(owner != address(0), "NOT_MINTED"); // Ownership check above ensures no underflow. unchecked { _balanceOf[owner]--; } delete _ownerOf[id]; delete getApproved[id]; emit Transfer(owner, address(0), id); } /*////////////////////////////////////////////////////////////// INTERNAL SAFE MINT LOGIC //////////////////////////////////////////////////////////////*/ function _safeMint(address to, uint256 id) internal virtual { _mint(to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } function _safeMint( address to, uint256 id, bytes memory data ) internal virtual { _mint(to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } } /// @notice A generic interface for a contract which properly accepts ERC721 tokens. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) abstract contract ERC721TokenReceiver { function onERC721Received( address, address, uint256, bytes calldata ) external virtual returns (bytes4) { return ERC721TokenReceiver.onERC721Received.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165Upgradeable.sol"; /** * @dev Interface for the NFT Royalty Standard. * * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal * support for royalty payments across all NFT marketplaces and ecosystem participants. * * _Available since v4.5._ */ interface IERC2981Upgradeable is IERC165Upgradeable { /** * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. */ function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165Upgradeable { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "remappings": [ "@ensdomains/=lib/nft-editions/node_modules/@ensdomains/", "@openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/=lib/openzeppelin-contracts/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "base64/=lib/base64/", "ds-test/=lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "eth-gas-reporter/=lib/nft-editions/node_modules/eth-gas-reporter/", "forge-std/=lib/forge-std/src/", "gsn/=lib/gsn/", "hardhat-deploy/=lib/nft-editions/node_modules/hardhat-deploy/", "hardhat/=lib/nft-editions/node_modules/hardhat/", "lib/=lib/", "nft-editions/=lib/nft-editions/contracts/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/", "operator-filter-registry/=lib/nft-editions/lib/operator-filter-registry/src/", "solmate/=lib/nft-editions/lib/solmate/src/", "src/=src/", "test/=test/" ], "optimizer": { "enabled": true, "runs": 1000000 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"value","type":"string"}],"name":"BadAttribute","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"IntegerOverflow","type":"error"},{"inputs":[],"name":"InvalidArgument","type":"error"},{"inputs":[],"name":"LengthMismatch","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"OperatorNotAllowed","type":"error"},{"inputs":[],"name":"PriceTooLow","type":"error"},{"inputs":[],"name":"SoldOut","type":"error"},{"inputs":[],"name":"TimeLimitReached","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"WrongPrice","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"oldExternalUrl","type":"string"},{"indexed":false,"internalType":"string","name":"newExternalUrl","type":"string"}],"name":"ExternalUrlUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operatorFilter","type":"address"}],"name":"OperatorFilterChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PriceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"oldValue","type":"string"},{"indexed":false,"internalType":"string","name":"newValue","type":"string"}],"name":"PropertyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"CANONICAL_OPENSEA_REGISTRY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CANONICAL_OPENSEA_SUBSCRIPTION","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activeOperatorFilter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"animationUrl","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"description","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"editionSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enableDefaultOperatorFilter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endOfMintPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"externalUrl","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"imageUrl","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"string","name":"_description","type":"string"},{"internalType":"string","name":"_animationUrl","type":"string"},{"internalType":"string","name":"_imageUrl","type":"string"},{"internalType":"uint256","name":"_editionSize","type":"uint256"},{"internalType":"uint256","name":"_royaltyBPS","type":"uint256"},{"internalType":"uint256","name":"_mintPeriodSeconds","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isMintingEnded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"recipients","type":"address[]"}],"name":"mintBatch","outputs":[{"internalType":"uint256","name":"lastTokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"_salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"safeMint","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"salePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"setApprovedMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_externalUrl","type":"string"}],"name":"setExternalUrl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operatorFilter","type":"address"}],"name":"setOperatorFilter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_salePriceWei","type":"uint256"}],"name":"setSalePrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string[]","name":"names","type":"string[]"},{"internalType":"string[]","name":"values","type":"string[]"}],"name":"setStringProperties","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6080604052346200037c576200001462000381565b6200001e62000381565b8151906001600160401b03908183116200028e57600654906001938483811c931695861562000371575b602096878510146200026d578190601f948581116200031a575b508790858311600114620002b057600092620002a4575b5050600019600383901b1c191690851b176006555b80519283116200028e576007548481811c9116801562000283575b868210146200026d5782811162000221575b5084918311600114620001b757928293918392600094620001ab575b50501b916000199060031b1c1916176007555b600c549060ff821660038110156200019557620001515760ff198216600217600c556040517f5daa87a0e9463431830481fd4b6e3403442dfb9a12b9c07597e9f61d50b633c8600080a1600d80546001600160a01b03191690556155299081620003a68239f35b6064906040519062461bcd60e51b82526004820152601760248201527f4d5553545f42455f4e4f545f494e495449414c495a45440000000000000000006044820152fd5b634e487b7160e01b600052602160045260246000fd5b015192503880620000d7565b90601f19831691600760005283866000209360005b8888838310620002095750505010620001ef575b505050811b01600755620000ea565b015160001960f88460031b161c19169055388080620001e0565b868601518855909601959485019487935001620001cc565b6007600052856000208380860160051c82019288871062000263575b0160051c019085905b82811062000256575050620000bb565b6000815501859062000246565b925081926200023d565b634e487b7160e01b600052602260045260246000fd5b90607f1690620000a9565b634e487b7160e01b600052604160045260246000fd5b01519050388062000079565b90879350601f198316916006600052896000209260005b8b828210620003035750508411620002e9575b505050811b016006556200008e565b015160001960f88460031b161c19169055388080620002da565b8385015186558b97909501949384019301620002c7565b9091506006600052876000208580850160051c8201928a861062000367575b918991869594930160051c01915b8281106200035757505062000062565b6000815585945089910162000347565b9250819262000339565b92607f169262000048565b600080fd5b60405190602082016001600160401b038111838210176200028e576040526000825256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a714613f865750806306fdde0314613ec2578063081812fc14613e62578063095ea7b314613d6457806317788d8714613d1b57806318160ddd14613cd55780631919fed714613b8c5780631a4a9f9714613b3a57806323b872dd146139cc57806326d58ad3146136b957806329ec16dd146136415780632a55205a146135e3578063397b5b24146135225780633ccfd60b146133a357806340d097c31461335357806342842e0e146130ac57806350cf310814612b2357806357db967a14612ad65780635ba05fe414612a8f5780636352211e146129ca5780636a6278421461297257806370a08231146128a95780637284e4161461286f578063735dd1f71461280b5780638da5cb5b146127b65780638fc73484146126f2578063927f59ba1461247b57806395d89b41146123b7578063a22cb46514612313578063aba8315014612209578063b88d4fde14611ee1578063c87b56dd146117cd578063d40cd8be14610b9e578063d5cb6c1a14610ae3578063d783925b14610a32578063e8a3d485146103b5578063e985e9c514610333578063f2fde38b14610267578063f4ed0f46146102285763f51f96dd146101d757600080fd5b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261022357602064e8d4a5100063ffffffff600e5460501c1602604051908152f35b600080fd5b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610223576020600e5460c01c604051908152f35b346102235760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102235761029e6142b8565b600c549073ffffffffffffffffffffffffffffffffffffffff916102c8838260081c1633146144d9565b7fffffffffffffffffffffff0000000000000000000000000000000000000000ff74ffffffffffffffffffffffffffffffffffffffff008360081b16911617600c5516337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b346102235760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102235761036a6142b8565b6103726142db565b9073ffffffffffffffffffffffffffffffffffffffff809116600052600b60205260406000209116600052602052602060ff604060002054166040519015158152f35b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102235761ffff600e5460701c16600c54604051916000916006549284610406856140a6565b9182825260019586811690816000146109f55750600114610994575b61042e92500385614131565b60405161043a816140f9565b6000815260025461044a816140a6565b610870575b5060405161045c816140f9565b600081529461046c6003546140a6565b6107fe575b61047a90614f91565b916040516000805461048b816140a6565b808452908881169081156107be5750600114610762575b50816104b66104c1936104bb930382614131565b614f91565b94614eee565b94606060405101918260405281600f916f30313233343536373839616263646566835260149073ffffffffffffffffffffffffffffffffffffffff600891821c16945b6106ed575b506106e96106dd8a6106d8606a8c8f8d6106a38e8e6130787fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffde8101602a815261067d6040519a8b9860296105b18b60209a7f7b226e616d65223a2200000000000000000000000000000000000000000000008c8301528b815194859301910161424b565b8a017f222c226465736372697074696f6e223a2200000000000000000000000000000060298201526105ec825180938b603a8501910161424b565b017f222c2273656c6c65725f6665655f62617369735f706f696e7473223a00000000603a820152610626825180938a60568501910161424b565b01917f2c226665655f726563697069656e74223a22000000000000000000000000000060568401525180937ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe60688501910161424b565b01610691825180938660688501910161424b565b0191835193849160688501910161424b565b017f227d000000000000000000000000000000000000000000000000000000000000606882015203604a810184520182614131565b614a22565b6040519182918261426e565b0390f35b90919293947ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe810195858116517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80930153858160041c16518753821c920192831561075d579193929082610504565b610509565b60008080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563939250905b888183106107a6575091925082016020019050816104a2565b8460209294955483858801015201910190929161078d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b840190910191508290506104a2565b945061047a6040517f222c2265787465726e616c5f6c696e6b223a220000000000000000000000000060208201526108688161083c603382016148d5565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282614131565b959050610471565b9050604051908160207f222c22696d616765223a22000000000000000000000000000000000000000000818301526000906108aa846140a6565b9388811690811561095557506001146108f6575b506108f09250037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282614131565b8561044f565b905060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace876000915b85831061093d5750505050602b6108f092820101886108be565b8054878401602b015286945091830191899101610923565b602b93506108f09592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009150168284015280151502820101886108be565b509060066000527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f90856000925b8284106109db5750505090602061042e92820101610422565b6020929450805483858b01015201910190918587936109c2565b6020925061042e9491507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682840152151560051b820101610422565b346102235760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261022357610a696142b8565b73ffffffffffffffffffffffffffffffffffffffff90610a9182600c5460081c1633146144d9565b16807fffffffffffffffffffffffff0000000000000000000000000000000000000000600d541617600d557f1981d792ba7e5e4e717880fe63bc42752988e02b286966dbc96973456774166b600080a2005b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261022357610b3873ffffffffffffffffffffffffffffffffffffffff600c5460081c1633146144d9565b733cc6cdda760b79bafa08df41ecfa224f810dceb6807fffffffffffffffffffffffff0000000000000000000000000000000000000000600d541617600d557f1981d792ba7e5e4e717880fe63bc42752988e02b286966dbc96973456774166b600080a2005b34610223576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261022357610bd66142b8565b60243567ffffffffffffffff811161022357610bf690369060040161435e565b9060443567ffffffffffffffff811161022357610c1790369060040161435e565b60649491943567ffffffffffffffff811161022357610c3a90369060040161435e565b9060843567ffffffffffffffff811161022357610c5b90369060040161435e565b94909360a43567ffffffffffffffff811161022357610c7e90369060040161435e565b989099600c54600360ff821610156114aa5760ff811615998a80156117c0575b1561176257610cc193610cb9928c611734575b503691614451565b923691614451565b9060ff600c541660038110156114aa576001610cdd9114614e89565b80519067ffffffffffffffff82116110a3578190610cfc6006546140a6565b601f81116116e5575b50602090601f831160011461162257600092611617575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c1916176006555b80519067ffffffffffffffff82116110a3578190610d6e6007546140a6565b601f81116115c8575b50602090601f83116001146114e4576000926114d9575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c1916176007555b600c5490600360ff831610156114aa5781610df6600160ff73ffffffffffffffffffffffffffffffffffffffff951614614e89565b7fffffffffffffffffffffff0000000000000000000000000000000000000000ff74ffffffffffffffffffffffffffffffffffffffff008360081b16911617600c551660007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a367ffffffffffffffff82116110a3578190610e7b6000546140a6565b601f811161145c575b50600090601f831160011461137d57600092611372575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c1916176000555b67ffffffffffffffff82116110a3578190610eea6001546140a6565b601f8111611323575b50600090601f831160011461124257600092611237575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c1916176001555b67ffffffffffffffff82116110a357600291610f5983546140a6565b601f81116111de575b506000601f82116001146111205781929394600092611115575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161782555b60006101043580611103575b50610fc660c43561469e565b9060e4359161ffff83116110d25760405167ffffffffffffffff60c082019182109111176110a3576fffff00000000000000000000000000007fffffffffffffffff00000000000000000000000000000000000000000000000077ffffffffffffffff000000000000000000000000000000009260c01b169360701b169160801b161717600e5561105357005b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00600c541617600c557f5daa87a0e9463431830481fd4b6e3403442dfb9a12b9c07597e9f61d50b633c8600080a1005b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b602483604051907ffd0e06810000000000000000000000000000000000000000000000000000000082526004820152fd5b61110f9150420161469e565b83610fba565b013590508480610f7c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0821694846000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace9160005b8781106111c657508360019596971061118e575b505050811b018255610fae565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88560031b161c19910135169055848080611181565b9092602060018192868601358155019401910161116d565b61122790846000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f840160051c8101916020851061122d575b601f0160051c0190614488565b84610f62565b909150819061121a565b013590508580610f0a565b6001600090815293507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08416851061130b5760019450837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08116106112d3575b505050811b01600155610f3d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88560031b161c199101351690558580806112c5565b8181013583556020948501946001909301920161126e565b61136c9060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f850160051c8101916020861061122d57601f0160051c0190614488565b86610ef3565b013590508780610e9b565b600080805293507f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563915b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0841685106114445760019450837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081161061140c575b505050811b01600055610ece565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88560031b161c199101351690558780806113fe565b818101358355602094850194600190930192016113a7565b6114a490600080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563601f850160051c8101916020861061122d57601f0160051c0190614488565b88610e84565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b015190508a80610d8e565b925060076000527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688906000935b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0841685106115ad5760019450837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0811610611576575b505050811b01600755610dc1565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558a8080611568565b81810151835560209485019460019093019290910190611511565b6116119060076000527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688601f850160051c8101916020861061122d57601f0160051c0190614488565b8b610d77565b015190508b80610d1c565b915060066000527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f9160007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516905b8181106116cd5750908460019594939210611696575b505050811b01600655610d4f565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558b8080611688565b92936020600181928786015181550195019301611672565b61172e9060066000527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f601f850160051c8101916020861061122d57601f0160051c0190614488565b8c610d05565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117600c558e610cb1565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f414c52454144595f494e495449414c495a4544000000000000000000000000006044820152fd5b50600160ff831614610c9e565b34610223576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102235760043590816000526008815273ffffffffffffffffffffffffffffffffffffffff6040600020541615611e8357600e5460c01c906040516000906006549181611845846140a6565b91828252600194868682169182600014611e48575050600114611dea575b61186f92500382614131565b60609380611d88575b50604051611885816140f9565b60008152906118956003546140a6565b611d48575b60405192600060025490856118ae836140a6565b9182825288820193898682169182600014611d0f575050600114611cb1575b6118d992500386614131565b6040519060008354936118eb856140a6565b90818552898501958181169081600014611c775750600114611c24575b505095603e956106e99a956106dd9a958a86611ace966119316119bf9e996106d89e0383614131565b86511515968251151591604051611947816140f9565b6000815298611ba1575b5050611b03575b50505061196761196d91614f91565b96614eee565b946119796104b6614172565b90611982614bd3565b9660296040519c8d809b7f7b226e616d65223a2200000000000000000000000000000000000000000000008b8301528a815194859301910161424b565b89017f202300000000000000000000000000000000000000000000000000000000000060298201526119fa825180938a602b8501910161424b565b01611a0e8251809389602b8501910161424b565b017f222c220000000000000000000000000000000000000000000000000000000000602b8201527f6465736372697074696f6e223a22000000000000000000000000000000000000602e820152611a6e8251809388603c8501910161424b565b01611a828251809387603c8501910161424b565b017f2200000000000000000000000000000000000000000000000000000000000000603c820152611abc8251809386603d8501910161424b565b01918351938491603d8501910161424b565b017f7d00000000000000000000000000000000000000000000000000000000000000603d82015203601e810184520182614131565b603361196d9496611967947f2c22616e696d6174696f6e5f75726c223a22000000000000000000000000000094611b62611b97956040519785611b4f8a9751809287808b01910161424b565b860193840152518093603284019061424b565b017f22000000000000000000000000000000000000000000000000000000000000006032820152036013810184520182614131565b939150858e611958565b611be6929850611c1c91602b916040519485927f2c22696d616765223a220000000000000000000000000000000000000000000089850152518092602a85019061424b565b81017f2200000000000000000000000000000000000000000000000000000000000000602a82015203600b810184520182614131565b953880611951565b600081815292507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b828410611c645750505082018701856106e9611908565b80548685018c0152928a01928101611c4d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001687525050151560051b830188019050856106e9611908565b5050600260005285877f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace856000915b858310611cf65750506118d993508201016118cd565b80919294505483858c0101520191018890858993611ce0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686526118d994151560051b84010191506118cd9050565b90506040517f222c2265787465726e616c5f75726c223a22000000000000000000000000000084820152611d828161083c603282016148d5565b9061189a565b611d93919450614eee565b611de3602160405180937f2f0000000000000000000000000000000000000000000000000000000000000087830152611dd48151809289868601910161424b565b81010384810184520182614131565b9285611878565b5050600660005281847ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f856000915b858310611e2f57505061186f9350820101611863565b8091929450548385880101520191018590858593611e19565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168482015261186f94151560051b84010191506118639050565b606490604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152600860248201527f4e6f20746f6b656e0000000000000000000000000000000000000000000000006044820152fd5b346102235760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261022357611f186142b8565b611f206142db565b906044359060643567ffffffffffffffff811161022357611f4590369060040161435e565b909173ffffffffffffffffffffffffffffffffffffffff8091169233841415806121fb575b6121ed575b84600052602092600884528260406000205416850361218f57611fb283881693611f9a851515615203565b86331490811561216b575b8115612152575b5061519e565b846000526009845260406000207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff815401905582600052604060002060018154019055856000526008845260406000207fffffffffffffffffffffffff0000000000000000000000000000000000000000908482825416179055600a85526040600020908154169055604051968684877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a43b1595861561207c575b61207a876152a0565b005b84959650876120d281959482946000947f150b7a02000000000000000000000000000000000000000000000000000000009b8c8652336004870152602486015260448501526080606485015260848401916145f3565b03925af180156121465761207a937fffffffff0000000000000000000000000000000000000000000000000000000092600092612119575b50501614828080808080612071565b6121389250803d1061213f575b6121308183614131565b810190615268565b848061210a565b503d612126565b6040513d6000823e3d90fd5b905087600052600a865260406000205416331489611fac565b905086600052600b8652604060002033600052865260ff6040600020541690611fa5565b606484604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152600a60248201527f57524f4e475f46524f4d000000000000000000000000000000000000000000006044820152fd5b6121f633615099565b611f6f565b61220433615099565b611f6a565b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610223576040516000600254612249816140a6565b808452906001908181169081156122ce5750600114612273575b6106e9846106dd81860382614131565b6002600090815292507f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8284106122b65750505081016020016106dd82612263565b8054602085870181019190915290930192810161229e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208087019190915292151560051b850190920192506106dd9150839050612263565b34610223576123213661438c565b33600052600b60205273ffffffffffffffffffffffffffffffffffffffff6040600020921691826000526020526123878160406000209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b60405190151581527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102235760405160006007546123f7816140a6565b808452906001908181169081156122ce5750600114612420576106e9846106dd81860382614131565b6007600090815292507fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6885b8284106124635750505081016020016106dd82612263565b8054602085870181019190915290930192810161244b565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102235767ffffffffffffffff600435818111610223576124c69036906004016143e6565b808316929183156126c85733600052600f60205260ff6040600020541680156126b5575b8015612691575b1561266757600e54928360c01c938581019180831695801515908161265d575b5061263357808260801c168015159182612627575b50506125fd5760501c63ffffffff16850264e8d4a510000234036125d357600e558383039160005b85811061256057602085604051908152f35b818110156125a4578060051b8301359073ffffffffffffffffffffffffffffffffffffffff821682036102235761259e600192838388010190615409565b0161254e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60046040517ff7760f25000000000000000000000000000000000000000000000000000000008152fd5b60046040517f5cde67a1000000000000000000000000000000000000000000000000000000008152fd5b42161190508780612526565b60046040517f52df9fe5000000000000000000000000000000000000000000000000000000008152fd5b9050861188612511565b60046040517f82b42900000000000000000000000000000000000000000000000000000000008152fd5b503373ffffffffffffffffffffffffffffffffffffffff600c5460081c16146124f1565b506000805260ff604060002054166124ea565b60046040517fa9cb9e0d000000000000000000000000000000000000000000000000000000008152fd5b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610223576040516000600354612732816140a6565b808452906001908181169081156122ce575060011461275b576106e9846106dd81860382614131565b6003600090815292507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b82841061279e5750505081016020016106dd82612263565b80546020858701810191909152909301928101612786565b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261022357602073ffffffffffffffffffffffffffffffffffffffff600c5460081c16604051908152f35b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261022357602067ffffffffffffffff80600e5460801c168015159182612863575b50506040519015158152f35b42161190508280612857565b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610223576106e96106dd614172565b346102235760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102235773ffffffffffffffffffffffffffffffffffffffff6128f56142b8565b1680156129145760005260096020526020604060002054604051908152f35b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5a45524f5f4144445245535300000000000000000000000000000000000000006044820152fd5b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102235760206129a66142b8565b6129c267ffffffffffffffff6129ba6146e4565b168092615305565b604051908152f35b346102235760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261022357600435600052600860205273ffffffffffffffffffffffffffffffffffffffff604060002054168015612a3157602090604051908152f35b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f4e4f545f4d494e544544000000000000000000000000000000000000000000006044820152fd5b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102235760206040516daaeb6d7670e522a718067333cd4e8152f35b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610223576020604051733cc6cdda760b79bafa08df41ecfa224f810dceb68152f35b34610223577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6040813601126102235767ffffffffffffffff9060043582811161022357612b759036906004016143e6565b929091602490813583811161022357612b929036906004016143e6565b929095612bbb73ffffffffffffffffffffffffffffffffffffffff600c5460081c1633146144d9565b808403613082576801000000000000000081116130545760045481600455808210612fbf575b508560046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b906000905b838210612e865750505060005b818110612c2457005b612c2f818389614683565b90612c3b83888c614683565b91909280158015612e7e575b612e285760405191818184378183019060058083527f35a0e6c026ba9e1609921ce31cd0af9c40f2abf102210d06376ad2413d0470d3612cb28660208098819703019020612cc1604051928392612ca5606080865285018b8a6145f3565b908482038a86015261453e565b82810360408401528a8c6145f3565b0390a183604051948593843782019081520301902092898311612dfa57612cf283612cec86546140a6565b8661449f565b600091601f8411600114612d52575060019493929160009183612d47575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82861b9260031b1c19161790555b01612c1b565b013590508c80612d10565b917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe084168560005283600020936000905b828210612de25750509084600197969594939210612daa575b505050831b83019055612d41565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88560031b161c199101351690558b8080612d9c565b80600185978294968801358155019601930190612d83565b867f4e487b710000000000000000000000000000000000000000000000000000000060005260416004526000fd5b612e7a8884868a612e6c6040519788977fd0956713000000000000000000000000000000000000000000000000000000008952604060048a015260448901916145f3565b9386850301908601526145f3565b0390fd5b508215612c47565b612e90818a614632565b90898211612dfa57612eac82612ea687546140a6565b8761449f565b600090601f8311600114612f15579282600194936020938695600092612f0a575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82861b9260031b1c19161786555b01930191019091612c0e565b013590508f80612ecd565b6000868152602080822093917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828210612fa757505092600195928592879660209610612f6f575b505050831b83018655612efe565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88560031b161c199101351690558e8080612f61565b80600185978294968801358155019601930190612f46565b6004600052817f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b91820191015b818110612ff95750612be1565b80613006600192546140a6565b80613013575b5001612fec565b601f808211841461302b575050600081555b8a61300c565b61304960009284845285602093848620920160051c82019101614488565b812081835555613025565b507f4e487b710000000000000000000000000000000000000000000000000000000060005260416004526000fd5b60046040517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b34610223576130ba366142fe565b909173ffffffffffffffffffffffffffffffffffffffff809116903382141580613345575b613337575b8260005260209060088252806040600020541683036132d9576131268186169161310f831515615203565b8433149081156132b5575b811561329c575061519e565b826000526009825260406000207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff815401905580600052604060002060018154019055836000526008825260406000207fffffffffffffffffffffffff0000000000000000000000000000000000000000908282825416179055600a83526040600020908154169055604051948482857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a43b159384156131ee575b61207a856152a0565b82939450856000819360a4937f150b7a02000000000000000000000000000000000000000000000000000000009889855233600486015260248501526044840152608060648401528160848401525af180156121465761207a937fffffffff000000000000000000000000000000000000000000000000000000009260009261327f575b50501614828080806131e5565b6132959250803d1061213f576121308183614131565b8480613272565b905085600052600a845260406000205416331487611fac565b905084600052600b8452604060002033600052845260ff604060002054169061311a565b606482604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152600a60248201527f57524f4e475f46524f4d000000000000000000000000000000000000000000006044820152fd5b61334033615099565b6130e4565b61334e33615099565b6130df565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102235760206133876142b8565b6129c267ffffffffffffffff61339b6146e4565b168092615409565b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102235773ffffffffffffffffffffffffffffffffffffffff600c5460081c166133f98133146144d9565b47908147106134c457600080809381935af13d156134bf573d61341b81614417565b906134296040519283614131565b8152600060203d92013e5b1561343b57005b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152fd5b613434565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152fd5b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102235760405160006001805490613564826140a6565b808552918181169081156122ce575060011461358a576106e9846106dd81860382614131565b600081815292507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8284106135cb5750505081016020016106dd82612263565b805460208587018101919091529093019281016135b3565b346102235760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261022357604061361f602435614856565b73ffffffffffffffffffffffffffffffffffffffff8351921682526020820152f35b346102235761207a6136523661438c565b9073ffffffffffffffffffffffffffffffffffffffff9061367b82600c5460081c1633146144d9565b16600052600f60205260406000209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b34610223576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102235767ffffffffffffffff906004358281116102235761370b90369060040161435e565b9161373273ffffffffffffffffffffffffffffffffffffffff600c5460081c1633146144d9565b604051916040835260009260039586549161374c836140a6565b958660408301526001968785168060001461398e57600114613935575b50908061379f83827fb732d810343ee7bd21f58e936fa948ad353be2c8a9e75c29c925d37572e52add9503898401528a886145f3565b0390a185116110a3576137b1906140a6565b601f81116138ec575b50600091601f85116001146138345750600091849182613809575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91921b92841b1c1916179055600080f35b013591507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff866137d5565b91847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0819596167fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b946000905b888383106138d2575050501061389c575b505050811b019055005b01357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83861b60f8161c19169055838080613892565b868601358855909601959384019387935090810190613881565b61392f907fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f870160051c81019185881061122d57601f0160051c0190614488565b856137ba565b60008a8152915086887fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b8385106139765750505050810160600181613769565b805486860160600152919093019288918a9101613960565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00851660608085019190915290151560051b830101905081613769565b34610223576139da366142fe565b919073ffffffffffffffffffffffffffffffffffffffff80921690338203613b2c575b8360005260209060088252836040600020541683036132d95783613a3f911693613a28851515615203565b833314908115613b08575b8115613aef575061519e565b816000526009815260406000207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8154019055826000526040600020600181540190558360005260088152600a6040600020917fffffffffffffffffffffffff00000000000000000000000000000000000000009285848254161790555260406000209081541690557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4005b905085600052600a835260406000205416331486611fac565b905083600052600b8352604060002033600052835260ff6040600020541690613a33565b613b3533615099565b6139fd565b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261022357602073ffffffffffffffffffffffffffffffffffffffff600d5416604051908152f35b346102235760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261022357600435613be473ffffffffffffffffffffffffffffffffffffffff600c5460081c1633146144d9565b64e8d4a51000810463ffffffff808211613ca45781161580613c9b575b613c71577fa6dc15bdb68da224c66db4b3838d9a2b205138e8cff6774e57d0af91e196d622916020917fffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffff6dffffffff00000000000000000000600e549260501b16911617600e55604051908152a1005b60046040517fdbbbe822000000000000000000000000000000000000000000000000000000008152fd5b50811515613c01565b602482604051907ffd0e06810000000000000000000000000000000000000000000000000000000082526004820152fd5b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261022357602067ffffffffffffffff600e5416604051908152f35b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261022357602067ffffffffffffffff600e5460801c16604051908152f35b346102235760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261022357613d9b6142b8565b6024359081600052600860205273ffffffffffffffffffffffffffffffffffffffff8060406000205416908133148015613e39575b613dd99061519e565b83600052600a6020526040600020921691827fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a4005b5081600052600b602052604060002033600052602052613dd960ff604060002054169050613dd0565b346102235760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261022357600435600052600a602052602073ffffffffffffffffffffffffffffffffffffffff60406000205416604051908152f35b346102235760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610223576040516000600654613f02816140a6565b808452906001908181169081156122ce5750600114613f2b576106e9846106dd81860382614131565b6006600090815292507ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f5b828410613f6e5750505081016020016106dd82612263565b80546020858701810191909152909301928101613f56565b346102235760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261022357600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361022357816020927f2a55205a0000000000000000000000000000000000000000000000000000000014908115614018575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000081149150811561407c575b8115614052575b5083614011565b7f5b5e139f000000000000000000000000000000000000000000000000000000009150148361404b565b7f80ac58cd0000000000000000000000000000000000000000000000000000000081149150614044565b90600182811c921680156140ef575b60208310146140c057565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f16916140b5565b6020810190811067ffffffffffffffff8211176110a357604052565b6040810190811067ffffffffffffffff8211176110a357604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176110a357604052565b60405190600082815491614185836140a6565b8083529260019081811690811561420b57506001146141ae575b506141ac92500383614131565b565b600080805291507f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b8483106141f057506141ac93505081016020013861419f565b81935090816020925483858a010152019101909185926141d7565b602093506141ac9592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b8201013861419f565b60005b83811061425e5750506000910152565b818101518382015260200161424e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f604093602084526142b1815180928160208801526020888801910161424b565b0116010190565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361022357565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361022357565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60609101126102235773ffffffffffffffffffffffffffffffffffffffff90600435828116810361022357916024359081168103610223579060443590565b9181601f840112156102235782359167ffffffffffffffff8311610223576020838186019501011161022357565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60409101126102235760043573ffffffffffffffffffffffffffffffffffffffff81168103610223579060243580151581036102235790565b9181601f840112156102235782359167ffffffffffffffff8311610223576020808501948460051b01011161022357565b67ffffffffffffffff81116110a357601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b92919261445d82614417565b9161446b6040519384614131565b829481845281830111610223578281602093846000960137010152565b818110614493575050565b60008155600101614488565b9190601f81116144ae57505050565b6141ac926000526020600020906020601f840160051c8301931061122d57601f0160051c0190614488565b156144e057565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152fd5b906000929180549161454f836140a6565b9182825260019384811690816000146145b15750600114614571575b50505050565b90919394506000526020928360002092846000945b83861061459d57505050500101903880808061456b565b805485870183015294019385908201614586565b91505060209495507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009193501683830152151560051b0101903880808061456b565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610223570180359067ffffffffffffffff82116102235760200191813603831361022357565b908210156125a45761469a9160051b810190614632565b9091565b67ffffffffffffffff908181116146b3571690565b602490604051907ffd0e06810000000000000000000000000000000000000000000000000000000082526004820152fd5b33600052600f602052604060ff8160002054168015614844575b8015614820575b156147f757600e548060c01c91600182019167ffffffffffffffff8084169480151590816147ed575b506147c457808260801c1680151591826147b8575b505061478f5760501c63ffffffff1664e8d4a510000234036147665750600e5590565b600490517ff7760f25000000000000000000000000000000000000000000000000000000008152fd5b600482517f5cde67a1000000000000000000000000000000000000000000000000000000008152fd5b42161190503880614743565b600483517f52df9fe5000000000000000000000000000000000000000000000000000000008152fd5b905085113861472e565b600490517f82b42900000000000000000000000000000000000000000000000000000000008152fd5b503373ffffffffffffffffffffffffffffffffffffffff600c5460081c1614614705565b506000805260ff8160002054166146fe565b9073ffffffffffffffffffffffffffffffffffffffff600c5460081c1680156148cc5761ffff600e5460701c169283810293818504149015171561489d5761271090920490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b50600091508190565b600354600092916148e5826140a6565b91600190818116908115614951575060011461490057505050565b909192935060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b906000915b84831061493e575050500190565b8181602092548587015201920191614930565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001683525050811515909102019150565b600092918154614991816140a6565b926001918083169081156149e957506001146149ad5750505050565b90919293945060005260209081600020906000915b8583106149d8575050505001903880808061456b565b8054858401529183019181016149c2565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001684525050508115159091020191503880808061456b565b806060915180614a85575b5050614a82603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000006020830152614a72815180926020868601910161424b565b810103601d810184520182614131565b90565b90915060039160028381840104811b604051947f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f52603f937ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd07f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f018552602087018388019460048460208801945b0192888451818160121c165183538181600c1c16516001840153818160061c165185840153165186820153019183831015614b54576004908590614b15565b505090506001603d927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09706838115158403531460011b900353845201166040523880614a2d565b6004548110156125a45760046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b0190600090565b6004548015614d8657604090815190614beb82614115565b600f82527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6020927f2c2270726f70657274696573223a7b000000000000000000000000000000000084820152910160005b818110614cfb575092614a82927f7d00000000000000000000000000000000000000000000000000000000000000602193614c9a614c7d614ce798614b9c565b5085518581614c8c8185614982565b600581520301902090614dc0565b93614cd7848251809782614cb7818401978881519384920161424b565b8201614ccb8251809386808501910161424b565b01038088520186614131565b519687945180928587019061424b565b830191820152036001810184520182614131565b91614d17614d0884614b9c565b5086518681614c8c8185614982565b9085519181614d2f849351809289808701910161424b565b8201614d438251809389808501910161424b565b017f2c00000000000000000000000000000000000000000000000000000000000000868201520390614d7f602160019384810184520182614131565b9201614c3d565b50604051614d9381614115565b601081527f2c2270726f70657274696573223a7b7d00000000000000000000000000000000602082015290565b906004614de3614ddc6104b6614a82946040519283809261453e565b0382614131565b604051938491614e1e7f2200000000000000000000000000000000000000000000000000000000000000928360208601526021850190614982565b7f223a2200000000000000000000000000000000000000000000000000000000008152614e5582518093602060038501910161424b565b01906003820152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4810184520182614131565b15614e9057565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e4f545f494e495449414c495a494e47000000000000000000000000000000006044820152fd5b9060405160a081016040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608082019360008552935b0192600a90818106603001855304928315614f61577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90614f25565b92506080837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09203019201918252565b908151820160208060405101937b5c75303030303031323334353637383961626364656662746e0066726015525b828103615003575050506000825260405191601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe091828582030185520116604052565b6001949192948091019182519160ff831692858410156150675761370082851b161561504357506008600293605c845301519082015301935b9190614fbf565b905060069250600f90818160041c1651601d531651601e536019518152019361503c565b50916b10000000000000040000000083821b161561509057600292605c8353820153019361503c565b8153019361503c565b73ffffffffffffffffffffffffffffffffffffffff80600d54168015615199576daaeb6d7670e522a718067333cd4e92833b1561456b57604460209260405194859384927fc6171134000000000000000000000000000000000000000000000000000000008452600484015216958660248301525afa90811561214657600091615158575b50156151275750565b602490604051907fede71dcc0000000000000000000000000000000000000000000000000000000082526004820152fd5b6020813d8211615191575b8161517060209383614131565b8101031261518d575190811515820361518a57503861511e565b80fd5b5080fd5b3d9150615163565b505050565b156151a557565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e4f545f415554484f52495a45440000000000000000000000000000000000006044820152fd5b1561520a57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f494e56414c49445f524543495049454e540000000000000000000000000000006044820152fd5b9081602091031261022357517fffffffff00000000000000000000000000000000000000000000000000000000811681036102235790565b156152a757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f554e534146455f524543495049454e54000000000000000000000000000000006044820152fd5b73ffffffffffffffffffffffffffffffffffffffff80911690615329821515615203565b60009083825260086020526040822054166153ab5781815260096020526040812060018154019055828152600860205260408120827fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f414c52454144595f4d494e5445440000000000000000000000000000000000006044820152fd5b906154148183615305565b813b1591821561542a575b50506141ac906152a0565b6000925073ffffffffffffffffffffffffffffffffffffffff60a460209260405195869384927f150b7a020000000000000000000000000000000000000000000000000000000097888552336004860152836024860152604485015260806064850152826084850152165af1918215612146576141ac927fffffffff00000000000000000000000000000000000000000000000000000000916000916154d5575b501614903861541f565b6154ed915060203d811161213f576121308183614131565b386154cb56fea26469706673582212205fd1a08b90f9b7ae441d457d90ed4a980b31416b68e89e1b2f30af728263848864736f6c63430008110033
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.