Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 456 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Set Artworks | 21239554 | 39 hrs ago | IN | 0 ETH | 0.0005452 | ||||
Set Artwork | 21239262 | 40 hrs ago | IN | 0 ETH | 0.00049595 | ||||
Set Artworks | 21233501 | 2 days ago | IN | 0 ETH | 0.0003996 | ||||
Set Artwork | 21228827 | 3 days ago | IN | 0 ETH | 0.0004016 | ||||
Set Artwork | 21224600 | 3 days ago | IN | 0 ETH | 0.0005901 | ||||
Set Artwork | 21221601 | 4 days ago | IN | 0 ETH | 0.00039147 | ||||
Set Artwork | 21202746 | 6 days ago | IN | 0 ETH | 0.00041138 | ||||
Set Artwork | 21177294 | 10 days ago | IN | 0 ETH | 0.00064176 | ||||
Set Artwork | 21177095 | 10 days ago | IN | 0 ETH | 0.00066697 | ||||
Set Artwork | 21177033 | 10 days ago | IN | 0 ETH | 0.00087481 | ||||
Set Artworks | 21170979 | 11 days ago | IN | 0 ETH | 0.00550074 | ||||
Set Artworks | 21160225 | 12 days ago | IN | 0 ETH | 0.00078081 | ||||
Set Artwork | 21148824 | 14 days ago | IN | 0 ETH | 0.00042834 | ||||
Set Artwork | 21108715 | 19 days ago | IN | 0 ETH | 0.00017952 | ||||
Set Artworks | 21089043 | 22 days ago | IN | 0 ETH | 0.00047159 | ||||
Set Artworks | 21075967 | 24 days ago | IN | 0 ETH | 0.00055744 | ||||
Set Artwork | 21041270 | 29 days ago | IN | 0 ETH | 0.00023939 | ||||
Set Artworks | 21041260 | 29 days ago | IN | 0 ETH | 0.00033217 | ||||
Set Artworks | 21021499 | 32 days ago | IN | 0 ETH | 0.00231332 | ||||
Set Artwork | 21010963 | 33 days ago | IN | 0 ETH | 0.00033253 | ||||
Set Artwork | 20989191 | 36 days ago | IN | 0 ETH | 0.00050235 | ||||
Set Artwork | 20976601 | 38 days ago | IN | 0 ETH | 0.00038506 | ||||
Set Artwork | 20969600 | 39 days ago | IN | 0 ETH | 0.0004733 | ||||
Set Artwork | 20965831 | 39 days ago | IN | 0 ETH | 0.00096353 | ||||
Set Artworks | 20930090 | 44 days ago | IN | 0 ETH | 0.01338613 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
MoonbirdsRenderer
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {Ownable} from "solady/auth/Ownable.sol"; import {LibString} from "solady/utils/LibString.sol"; import {LibBitmap} from "solady/utils/LibBitmap.sol"; import {ILegacyMoonbirdsRenderer, Attribute} from "../interfaces/ILegacyMoonbirdsRenderer.sol"; import {IERC721Ownership} from "../interfaces/IERC721Ownership.sol"; contract MoonbirdsRenderer is Ownable { using LibString for uint256; using LibBitmap for LibBitmap.Bitmap; error NotOwnerOfToken(uint256 tokenId); error ArrayLengthMismatch(); ILegacyMoonbirdsRenderer public immutable legacyRenderer; IERC721Ownership public immutable moonbirds; string public baseUri; string public animationBaseUri; LibBitmap.Bitmap private _useNewArtwork; uint32 private _scaleFactor = 15; constructor( address moonbirds_, address legacyRenderer_, string memory baseUri_, string memory animationBaseUri_ ) { _initializeOwner(msg.sender); moonbirds = IERC721Ownership(moonbirds_); legacyRenderer = ILegacyMoonbirdsRenderer(legacyRenderer_); baseUri = baseUri_; animationBaseUri = animationBaseUri_; } function tokenURI(uint256 tokenId) external view returns (string memory) { string memory tokenIdString = tokenId.toString(); return string.concat( 'data:application/json;utf-8,{"name":"Moonbirds #', tokenIdString, '","external_url":"https://proof.xyz/moonbirds/', tokenIdString, '","animation_url":"', animationUri(tokenId), '","image":"', artworkUri(tokenId), '","alternate_image":"', alternateArtworkUri(tokenId), '","attributes":', attributesJson(tokenId), "}" ); } function attributesJson( uint256 tokenId ) public view returns (string memory) { Attribute[] memory attrs = legacyRenderer.attributes(tokenId); string memory result = "["; for (uint256 i = 0; i < attrs.length; i++) { string memory comma = i == 0 ? "" : ","; string memory end = i == attrs.length - 1 ? "]" : ""; result = string.concat( result, comma, '{"trait_type":"', attrs[i].name, '","value":"', attrs[i].value, '"}', end ); } return result; } function artworkUri(uint256 tokenId) public view returns (string memory) { if (_useNewArtwork.get(tokenId)) { return string(abi.encodePacked(baseUri, tokenId.toString(), ".png")); } return legacyRenderer.artworkURI(tokenId, _scaleFactor); } function alternateArtworkUri( uint256 tokenId ) public view returns (string memory) { if (_useNewArtwork.get(tokenId)) { return legacyRenderer.artworkURI(tokenId, _scaleFactor); } return string(abi.encodePacked(baseUri, tokenId.toString(), ".png")); } function animationUri(uint256 tokenId) public view returns (string memory) { string memory useNew = _useNewArtwork.get(tokenId) ? "true" : "false"; return string( abi.encodePacked( animationBaseUri, "?tokenId=", tokenId.toString(), "&useNewArtwork=", useNew ) ); } function setArtwork(uint256 tokenId, bool useNew) public { if (moonbirds.ownerOf(tokenId) != msg.sender) { revert NotOwnerOfToken(tokenId); } _useNewArtwork.setTo(tokenId, useNew); } function setArtworks( uint256[] calldata tokenIds, bool[] calldata values ) external { uint256 length = tokenIds.length; if (length != values.length) { revert ArrayLengthMismatch(); } for (uint256 i = 0; i < length; ++i) { setArtwork(tokenIds[i], values[i]); } } function setBaseUri(string memory baseUri_) external onlyOwner { baseUri = baseUri_; } function useNewArtwork(uint256 tokenId) external view returns (bool) { return _useNewArtwork.get(tokenId); } function setAnimationBaseUri( string memory animationBaseUri_ ) external onlyOwner { animationBaseUri = animationBaseUri_; } function setScaleFactor(uint32 scaleFactor) external onlyOwner { _scaleFactor = scaleFactor; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /// @dev Cannot double-initialize. error AlreadyInitialized(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. bytes32 internal constant _OWNER_SLOT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override to return true to make `_initializeOwner` prevent double-initialization. function _guardInitializeOwner() internal pure virtual returns (bool guard) {} /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT if sload(ownerSlot) { mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`. revert(0x1c, 0x04) } // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } else { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(_OWNER_SLOT, newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) } } else { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(_OWNER_SLOT))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. /// Override to return a different value if needed. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ownershipHandoverValidFor() internal view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + _ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(_OWNER_SLOT) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for converting numbers into strings and other string operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) /// /// @dev Note: /// For performance and bytecode compactness, most of the string operations are restricted to /// byte strings (7-bit ASCII), except where otherwise specified. /// Usage of byte string operations on charsets with runes spanning two or more bytes /// can lead to undefined behavior. library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The length of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /// @dev The length of the string is more than 32 bytes. error TooBigForSmallString(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. str := add(mload(0x40), 0x80) // Update the free memory pointer to allocate. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str let w := not(0) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 1)`. // Write the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) // Keep dividing `temp` until zero. temp := div(temp, 10) if iszero(temp) { break } } let length := sub(end, str) // Move the pointer 32 bytes leftwards to make room for the length. str := sub(str, 0x20) // Store the length. mstore(str, length) } } /// @dev Returns the base 10 decimal representation of `value`. function toString(int256 value) internal pure returns (string memory str) { if (value >= 0) { return toString(uint256(value)); } unchecked { str = toString(~uint256(value) + 1); } /// @solidity memory-safe-assembly assembly { // We still have some spare memory space on the left, // as we have allocated 3 words (96 bytes) for up to 78 digits. let length := mload(str) // Load the string length. mstore(str, 0x2d) // Store the '-' character. str := sub(str, 1) // Move back the string pointer by a byte. mstore(str, add(length, 1)) // Update the string length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HEXADECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2 + 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) { str = toHexStringNoPrefix(value, length); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexStringNoPrefix(uint256 value, uint256 length) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. // We add 0x20 to the total and round down to a multiple of 0x20. // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f))) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let start := sub(str, add(length, length)) let w := not(1) // Tsk. let temp := value // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for {} 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(xor(str, start)) { break } } if temp { mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`. revert(0x1c, 0x04) } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2 + 2` bytes. function toHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x". /// The output excludes leading "0" from the `toHexString` output. /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. function toMinimalHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := add(mload(str), 2) // Compute the length. mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero. str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output excludes leading "0" from the `toHexStringNoPrefix` output. /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := mload(str) // Get the length. str := add(str, o) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. str := add(mload(0x40), 0x80) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory str) { str = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(str, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { str := mload(0x40) // Allocate the memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(str, 0x80)) // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) str := add(str, 2) mstore(str, 40) let o := add(str, 0x20) mstore(add(o, 40), 0) value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory str) { str = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { let length := mload(raw) str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(str, add(length, length)) // Store the length of the output. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let o := add(str, 0x20) let end := add(raw, length) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let mask := shl(7, div(not(0), 255)) result := 1 let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, byte string operations are restricted // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets. // Usage of byte string operations on charsets with runes spanning two or more bytes // can lead to undefined behavior. /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`. function replace(string memory subject, string memory search, string memory replacement) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) let replacementLength := mload(replacement) subject := add(subject, 0x20) search := add(search, 0x20) replacement := add(replacement, 0x20) result := add(mload(0x40), 0x20) let subjectEnd := add(subject, subjectLength) if iszero(gt(searchLength, subjectLength)) { let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. for { let o := 0 } 1 {} { mstore(add(result, o), mload(add(replacement, o))) o := add(o, 0x20) if iszero(lt(o, replacementLength)) { break } } result := add(result, replacementLength) subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } } let resultRemainder := result result := add(mload(0x40), 0x20) let k := add(sub(resultRemainder, result), sub(subjectEnd, subject)) // Copy the rest of the string one word at a time. for {} lt(subject, subjectEnd) {} { mstore(resultRemainder, mload(subject)) resultRemainder := add(resultRemainder, 0x20) subject := add(subject, 0x20) } result := sub(result, 0x20) let last := add(add(result, 0x20), k) // Zeroize the slot after the string. mstore(last, 0) mstore(0x40, add(last, 0x20)) // Allocate the memory. mstore(result, k) // Store the length. } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for { let subjectLength := mload(subject) } 1 {} { if iszero(mload(search)) { if iszero(gt(from, subjectLength)) { result := from break } result := subjectLength break } let searchLength := mload(search) let subjectStart := add(subject, 0x20) result := not(0) // Initialize to `NOT_FOUND`. subject := add(subjectStart, from) let end := add(sub(add(subjectStart, subjectLength), searchLength), 1) let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(add(search, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLength))) { break } if iszero(lt(searchLength, 0x20)) { for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if iszero(shr(m, xor(mload(subject), s))) { if eq(keccak256(subject, searchLength), h) { result := sub(subject, subjectStart) break } } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = indexOf(subject, search, 0); } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := not(0) // Initialize to `NOT_FOUND`. let searchLength := mload(search) if gt(searchLength, mload(subject)) { break } let w := result let fromMax := sub(mload(subject), searchLength) if iszero(gt(fromMax, from)) { from := fromMax } let end := add(add(subject, 0x20), w) subject := add(add(subject, 0x20), from) if iszero(gt(subject, end)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if eq(keccak256(subject, searchLength), h) { result := sub(subject, add(end, 1)) break } subject := add(subject, w) // `sub(subject, 1)`. if iszero(gt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = lastIndexOf(subject, search, uint256(int256(-1))); } /// @dev Returns true if `search` is found in `subject`, false otherwise. function contains(string memory subject, string memory search) internal pure returns (bool) { return indexOf(subject, search) != NOT_FOUND; } /// @dev Returns whether `subject` starts with `search`. function startsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( iszero(gt(searchLength, mload(subject))), eq( keccak256(add(subject, 0x20), searchLength), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns whether `subject` ends with `search`. function endsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) let subjectLength := mload(subject) // Whether `search` is not longer than `subject`. let withinRange := iszero(gt(searchLength, subjectLength)) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( withinRange, eq( keccak256( // `subject + 0x20 + max(subjectLength - searchLength, 0)`. add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))), searchLength ), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns `subject` repeated `times`. function repeat(string memory subject, uint256 times) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(or(iszero(times), iszero(subjectLength))) { subject := add(subject, 0x20) result := mload(0x40) let output := add(result, 0x20) for {} 1 {} { // Copy the `subject` one word at a time. for { let o := 0 } 1 {} { mstore(add(output, o), mload(add(subject, o))) o := add(o, 0x20) if iszero(lt(o, subjectLength)) { break } } output := add(output, subjectLength) times := sub(times, 1) if iszero(times) { break } } mstore(output, 0) // Zeroize the slot after the string. let resultLength := sub(output, add(result, 0x20)) mstore(result, resultLength) // Store the length. // Allocate the memory. mstore(0x40, add(result, add(resultLength, 0x20))) } } } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(gt(subjectLength, end)) { end := subjectLength } if iszero(gt(subjectLength, start)) { start := subjectLength } if lt(start, end) { result := mload(0x40) let resultLength := sub(end, start) mstore(result, resultLength) subject := add(subject, start) let w := not(0x1f) // Copy the `subject` one word at a time, backwards. for { let o := and(add(resultLength, 0x1f), w) } 1 {} { mstore(add(result, o), mload(add(subject, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(result, 0x20), resultLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(result, and(add(resultLength, 0x3f), w))) } } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. /// `start` is a byte offset. function slice(string memory subject, uint256 start) internal pure returns (string memory result) { result = slice(subject, start, uint256(int256(-1))); } /// @dev Returns all the indices of `search` in `subject`. /// The indices are byte offsets. function indicesOf(string memory subject, string memory search) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) if iszero(gt(searchLength, subjectLength)) { subject := add(subject, 0x20) search := add(search, 0x20) result := add(mload(0x40), 0x20) let subjectStart := subject let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Append to `result`. mstore(result, sub(subject, subjectStart)) result := add(result, 0x20) // Advance `subject` by `searchLength`. subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } let resultEnd := result // Assign `result` to the free memory pointer. result := mload(0x40) // Store the length of `result`. mstore(result, shr(5, sub(resultEnd, add(result, 0x20)))) // Allocate memory for result. // We allocate one more word, so this array can be recycled for {split}. mstore(0x40, add(resultEnd, 0x20)) } } } /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string. function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { uint256[] memory indices = indicesOf(subject, delimiter); /// @solidity memory-safe-assembly assembly { let w := not(0x1f) let indexPtr := add(indices, 0x20) let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) mstore(add(indicesEnd, w), mload(subject)) mstore(indices, add(mload(indices), 1)) let prevIndex := 0 for {} 1 {} { let index := mload(indexPtr) mstore(indexPtr, 0x60) if iszero(eq(index, prevIndex)) { let element := mload(0x40) let elementLength := sub(index, prevIndex) mstore(element, elementLength) // Copy the `subject` one word at a time, backwards. for { let o := and(add(elementLength, 0x1f), w) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(element, 0x20), elementLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(element, and(add(elementLength, 0x3f), w))) // Store the `element` into the array. mstore(indexPtr, element) } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) if iszero(lt(indexPtr, indicesEnd)) { break } } result := indices if iszero(mload(delimiter)) { result := add(indices, 0x20) mstore(result, sub(mload(indices), 2)) } } } /// @dev Returns a concatenated string of `a` and `b`. /// Cheaper than `string.concat()` and does not de-align the free memory pointer. function concat(string memory a, string memory b) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let w := not(0x1f) result := mload(0x40) let aLength := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(aLength, 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLength := mload(b) let output := add(result, aLength) // Copy `b` one word at a time, backwards. for { let o := and(add(bLength, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLength := add(aLength, bLength) let last := add(add(result, 0x20), totalLength) // Zeroize the slot after the string. mstore(last, 0) // Stores the length. mstore(result, totalLength) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 0x1f), w)) } } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let length := mload(subject) if length { result := add(mload(0x40), 0x20) subject := add(subject, 1) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) let w := not(0) for { let o := length } 1 {} { o := add(o, w) let b := and(0xff, mload(add(subject, o))) mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20))) if iszero(o) { break } } result := mload(0x40) mstore(result, length) // Store the length. let last := add(add(result, 0x20), length) mstore(last, 0) // Zeroize the slot after the string. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } } /// @dev Returns a string from a small bytes32 string. /// `s` must be null-terminated, or behavior will be undefined. function fromSmallString(bytes32 s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let n := 0 for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'. mstore(result, n) let o := add(result, 0x20) mstore(o, s) mstore(add(o, n), 0) mstore(0x40, add(result, 0x40)) } } /// @dev Returns the small string, with all bytes after the first null byte zeroized. function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'. mstore(0x00, s) mstore(result, 0x00) result := mload(0x00) } } /// @dev Returns the string as a normalized null-terminated small string. function toSmallString(string memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(s) if iszero(lt(result, 33)) { mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`. revert(0x1c, 0x04) } result := shl(shl(3, sub(32, result)), mload(add(s, result))) } } /// @dev Returns a lowercased copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function upper(string memory subject) internal pure returns (string memory result) { result = toCase(subject, true); } /// @dev Escapes the string to be used within HTML tags. function escapeHTML(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(result, c) result := add(result, 1) continue } let t := shr(248, mload(c)) mstore(result, mload(and(t, 0x1f))) result := add(result, shr(5, t)) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } // Store "\\u0000" in scratch space. // Store "0123456789abcdef" in scratch space. // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. // into the scratch space. mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) // Bitmask for detecting `["\"","\\"]`. let e := or(shl(0x22, 1), shl(0x5c, 1)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(result, c) result := add(result, 1) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), c) result := add(result, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(result, mload(0x19)) // "\\u00XX". result := add(result, 6) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), mload(add(c, 8))) result := add(result, 2) } if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { result = escapeJSON(s, false); } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string. function eqs(string memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. let x := not(or(m, or(b, add(m, and(b, m))))) let r := shl(7, iszero(iszero(shr(128, x)))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) } } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output behavior is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. result := mload(0x40) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(0x40, add(result, 0x40)) // Zeroize the length slot. mstore(result, 0) // Store the length and bytes. mstore(add(result, 0x1f), packed) // Right pad with zeroes. mstore(add(add(result, 0x20), mload(result)), 0) } } /// @dev Packs two strings with their lengths into a single word. /// Returns `bytes32(0)` if combined length is zero or greater than 30. function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let aLength := mload(a) // We don't need to zero right pad the strings, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes of `a` and `b`. or( shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))), mload(sub(add(b, 0x1e), aLength)) ), // `totalLength != 0 && totalLength < 31`. Abuses underflow. // Assumes that the lengths are valid and within the block gas limit. lt(sub(add(aLength, mload(b)), 1), 0x1e) ) } } /// @dev Unpacks strings packed using {packTwo}. /// Returns the empty strings if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packTwo}, the output behavior is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. resultA := mload(0x40) resultB := add(resultA, 0x40) // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. mstore(0x40, add(resultB, 0x40)) // Zeroize the length slots. mstore(resultA, 0) mstore(resultB, 0) // Store the lengths and bytes. mstore(add(resultA, 0x1f), packed) mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) // Right pad with zeroes. mstore(add(add(resultA, 0x20), mload(resultA)), 0) mstore(add(add(resultB, 0x20), mload(resultB)), 0) } } /// @dev Directly returns `a` without copying. function directReturn(string memory a) internal pure { assembly { // Assumes that the string does not start from the scratch space. let retStart := sub(a, 0x20) let retSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the string is produced // by a method that doesn't zero right pad. mstore(add(retStart, retSize), 0) // Store the return offset. mstore(retStart, 0x20) // End the transaction, returning the string. return(retStart, retSize) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import {LibBit} from "./LibBit.sol"; /// @notice Library for storage of packed unsigned booleans. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBitmap.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibBitmap.sol) /// @author Modified from Solidity-Bits (https://github.com/estarriolvetch/solidity-bits/blob/main/contracts/BitMaps.sol) library LibBitmap { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when a bitmap scan does not find a result. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev A bitmap in storage. struct Bitmap { mapping(uint256 => uint256) map; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the boolean value of the bit at `index` in `bitmap`. function get(Bitmap storage bitmap, uint256 index) internal view returns (bool isSet) { // It is better to set `isSet` to either 0 or 1, than zero vs non-zero. // Both cost the same amount of gas, but the former allows the returned value // to be reused without cleaning the upper bits. uint256 b = (bitmap.map[index >> 8] >> (index & 0xff)) & 1; /// @solidity memory-safe-assembly assembly { isSet := b } } /// @dev Updates the bit at `index` in `bitmap` to true. function set(Bitmap storage bitmap, uint256 index) internal { bitmap.map[index >> 8] |= (1 << (index & 0xff)); } /// @dev Updates the bit at `index` in `bitmap` to false. function unset(Bitmap storage bitmap, uint256 index) internal { bitmap.map[index >> 8] &= ~(1 << (index & 0xff)); } /// @dev Flips the bit at `index` in `bitmap`. /// Returns the boolean result of the flipped bit. function toggle(Bitmap storage bitmap, uint256 index) internal returns (bool newIsSet) { /// @solidity memory-safe-assembly assembly { mstore(0x20, bitmap.slot) mstore(0x00, shr(8, index)) let storageSlot := keccak256(0x00, 0x40) let shift := and(index, 0xff) let storageValue := xor(sload(storageSlot), shl(shift, 1)) // It makes sense to return the `newIsSet`, // as it allow us to skip an additional warm `sload`, // and it costs minimal gas (about 15), // which may be optimized away if the returned value is unused. newIsSet := and(1, shr(shift, storageValue)) sstore(storageSlot, storageValue) } } /// @dev Updates the bit at `index` in `bitmap` to `shouldSet`. function setTo(Bitmap storage bitmap, uint256 index, bool shouldSet) internal { /// @solidity memory-safe-assembly assembly { mstore(0x20, bitmap.slot) mstore(0x00, shr(8, index)) let storageSlot := keccak256(0x00, 0x40) let storageValue := sload(storageSlot) let shift := and(index, 0xff) sstore( storageSlot, // Unsets the bit at `shift` via `and`, then sets its new value via `or`. or(and(storageValue, not(shl(shift, 1))), shl(shift, iszero(iszero(shouldSet)))) ) } } /// @dev Consecutively sets `amount` of bits starting from the bit at `start`. function setBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { let max := not(0) let shift := and(start, 0xff) mstore(0x20, bitmap.slot) mstore(0x00, shr(8, start)) if iszero(lt(add(shift, amount), 257)) { let storageSlot := keccak256(0x00, 0x40) sstore(storageSlot, or(sload(storageSlot), shl(shift, max))) let bucket := add(mload(0x00), 1) let bucketEnd := add(mload(0x00), shr(8, add(amount, shift))) amount := and(add(amount, shift), 0xff) shift := 0 for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } { mstore(0x00, bucket) sstore(keccak256(0x00, 0x40), max) } mstore(0x00, bucket) } let storageSlot := keccak256(0x00, 0x40) sstore(storageSlot, or(sload(storageSlot), shl(shift, shr(sub(256, amount), max)))) } } /// @dev Consecutively unsets `amount` of bits starting from the bit at `start`. function unsetBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { let shift := and(start, 0xff) mstore(0x20, bitmap.slot) mstore(0x00, shr(8, start)) if iszero(lt(add(shift, amount), 257)) { let storageSlot := keccak256(0x00, 0x40) sstore(storageSlot, and(sload(storageSlot), not(shl(shift, not(0))))) let bucket := add(mload(0x00), 1) let bucketEnd := add(mload(0x00), shr(8, add(amount, shift))) amount := and(add(amount, shift), 0xff) shift := 0 for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } { mstore(0x00, bucket) sstore(keccak256(0x00, 0x40), 0) } mstore(0x00, bucket) } let storageSlot := keccak256(0x00, 0x40) sstore( storageSlot, and(sload(storageSlot), not(shl(shift, shr(sub(256, amount), not(0))))) ) } } /// @dev Returns number of set bits within a range by /// scanning `amount` of bits starting from the bit at `start`. function popCount(Bitmap storage bitmap, uint256 start, uint256 amount) internal view returns (uint256 count) { unchecked { uint256 bucket = start >> 8; uint256 shift = start & 0xff; if (!(amount + shift < 257)) { count = LibBit.popCount(bitmap.map[bucket] >> shift); uint256 bucketEnd = bucket + ((amount + shift) >> 8); amount = (amount + shift) & 0xff; shift = 0; for (++bucket; bucket != bucketEnd; ++bucket) { count += LibBit.popCount(bitmap.map[bucket]); } } count += LibBit.popCount((bitmap.map[bucket] >> shift) << (256 - amount)); } } /// @dev Returns the index of the most significant set bit in `[0..upTo]`. /// If no set bit is found, returns `NOT_FOUND`. function findLastSet(Bitmap storage bitmap, uint256 upTo) internal view returns (uint256 setBitIndex) { uint256 bucket; uint256 bucketBits; /// @solidity memory-safe-assembly assembly { setBitIndex := not(0) bucket := shr(8, upTo) mstore(0x00, bucket) mstore(0x20, bitmap.slot) let offset := and(0xff, not(upTo)) // `256 - (255 & upTo) - 1`. bucketBits := shr(offset, shl(offset, sload(keccak256(0x00, 0x40)))) if iszero(or(bucketBits, iszero(bucket))) { for {} 1 {} { bucket := add(bucket, setBitIndex) // `sub(bucket, 1)`. mstore(0x00, bucket) bucketBits := sload(keccak256(0x00, 0x40)) if or(bucketBits, iszero(bucket)) { break } } } } if (bucketBits != 0) { setBitIndex = (bucket << 8) | LibBit.fls(bucketBits); /// @solidity memory-safe-assembly assembly { setBitIndex := or(setBitIndex, sub(0, gt(setBitIndex, upTo))) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; struct Attribute { string name; string value; } interface ILegacyMoonbirdsRenderer { function artworkURI(uint256 tokenId, uint32 scaleFactor) external view returns (string memory); function attributes(uint256 tokenId) external view returns (Attribute[] memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IERC721Ownership { function ownerOf(uint256 tokenId) external view returns (address); function balanceOf(address owner) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for bit twiddling and boolean operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBit.sol) /// @author Inspired by (https://graphics.stanford.edu/~seander/bithacks.html) library LibBit { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BIT TWIDDLING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Find last set. /// Returns the index of the most significant bit of `x`, /// counting from the least significant bit position. /// If `x` is zero, returns 256. function fls(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, x))) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)) } } /// @dev Count leading zeros. /// Returns the number of zeros preceding the most significant one bit. /// If `x` is zero, returns 256. function clz(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item r := add(xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)), iszero(x)) } } /// @dev Find first set. /// Returns the index of the least significant bit of `x`, /// counting from the least significant bit position. /// If `x` is zero, returns 256. /// Equivalent to `ctz` (count trailing zeros), which gives /// the number of zeros following the least significant one bit. function ffs(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { // Isolate the least significant bit. let b := and(x, add(not(x), 1)) r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, b))) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, b)))) r := or(r, shl(5, lt(0xffffffff, shr(r, b)))) // For the remaining 32 bits, use a De Bruijn lookup. // forgefmt: disable-next-item r := or(r, byte(and(div(0xd76453e0, shr(r, b)), 0x1f), 0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405)) } } /// @dev Returns the number of set bits in `x`. function popCount(uint256 x) internal pure returns (uint256 c) { /// @solidity memory-safe-assembly assembly { let max := not(0) let isMax := eq(x, max) x := sub(x, and(shr(1, x), div(max, 3))) x := add(and(x, div(max, 5)), and(shr(2, x), div(max, 5))) x := and(add(x, shr(4, x)), div(max, 17)) c := or(shl(8, isMax), shr(248, mul(x, div(max, 255)))) } } /// @dev Returns whether `x` is a power of 2. function isPo2(uint256 x) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // Equivalent to `x && !(x & (x - 1))`. result := iszero(add(and(x, sub(x, 1)), iszero(x))) } } /// @dev Returns `x` reversed at the bit level. function reverseBits(uint256 x) internal pure returns (uint256 r) { uint256 m0 = 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f; uint256 m1 = m0 ^ (m0 << 2); uint256 m2 = m1 ^ (m1 << 1); r = reverseBytes(x); r = (m2 & (r >> 1)) | ((m2 & r) << 1); r = (m1 & (r >> 2)) | ((m1 & r) << 2); r = (m0 & (r >> 4)) | ((m0 & r) << 4); } /// @dev Returns `x` reversed at the byte level. function reverseBytes(uint256 x) internal pure returns (uint256 r) { unchecked { // Computing masks on-the-fly reduces bytecode size by about 200 bytes. uint256 m0 = 0x100000000000000000000000000000001 * (~toUint(x == 0) >> 192); uint256 m1 = m0 ^ (m0 << 32); uint256 m2 = m1 ^ (m1 << 16); uint256 m3 = m2 ^ (m2 << 8); r = (m3 & (x >> 8)) | ((m3 & x) << 8); r = (m2 & (r >> 16)) | ((m2 & r) << 16); r = (m1 & (r >> 32)) | ((m1 & r) << 32); r = (m0 & (r >> 64)) | ((m0 & r) << 64); r = (r >> 128) | (r << 128); } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BOOLEAN OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // A Solidity bool on the stack or memory is represented as a 256-bit word. // Non-zero values are true, zero is false. // A clean bool is either 0 (false) or 1 (true) under the hood. // Usually, if not always, the bool result of a regular Solidity expression, // or the argument of a public/external function will be a clean bool. // You can usually use the raw variants for more performance. // If uncertain, test (best with exact compiler settings). // Or use the non-raw variants (compiler can sometimes optimize out the double `iszero`s). /// @dev Returns `x & y`. Inputs must be clean. function rawAnd(bool x, bool y) internal pure returns (bool z) { /// @solidity memory-safe-assembly assembly { z := and(x, y) } } /// @dev Returns `x & y`. function and(bool x, bool y) internal pure returns (bool z) { /// @solidity memory-safe-assembly assembly { z := and(iszero(iszero(x)), iszero(iszero(y))) } } /// @dev Returns `x | y`. Inputs must be clean. function rawOr(bool x, bool y) internal pure returns (bool z) { /// @solidity memory-safe-assembly assembly { z := or(x, y) } } /// @dev Returns `x | y`. function or(bool x, bool y) internal pure returns (bool z) { /// @solidity memory-safe-assembly assembly { z := or(iszero(iszero(x)), iszero(iszero(y))) } } /// @dev Returns 1 if `b` is true, else 0. Input must be clean. function rawToUint(bool b) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := b } } /// @dev Returns 1 if `b` is true, else 0. function toUint(bool b) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := iszero(iszero(b)) } } }
{ "remappings": [ "ds-test/=lib/erc721s/lib/forge-std/lib/ds-test/src/", "erc721a/=lib/erc721s/lib/erc721a/contracts/", "erc721s/=lib/erc721s/src/", "forge-std/=lib/forge-std/src/", "openzeppelin/=lib/erc721s/lib/openzeppelin/", "solady/=lib/solady/src/", "soladymocks/=lib/solady/test/utils/mocks/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"moonbirds_","type":"address"},{"internalType":"address","name":"legacyRenderer_","type":"address"},{"internalType":"string","name":"baseUri_","type":"string"},{"internalType":"string","name":"animationBaseUri_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"NotOwnerOfToken","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"alternateArtworkUri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"animationBaseUri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"animationUri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"artworkUri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"attributesJson","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseUri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"legacyRenderer","outputs":[{"internalType":"contract ILegacyMoonbirdsRenderer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"moonbirds","outputs":[{"internalType":"contract IERC721Ownership","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"animationBaseUri_","type":"string"}],"name":"setAnimationBaseUri","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bool","name":"useNew","type":"bool"}],"name":"setArtwork","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"bool[]","name":"values","type":"bool[]"}],"name":"setArtworks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"baseUri_","type":"string"}],"name":"setBaseUri","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"scaleFactor","type":"uint32"}],"name":"setScaleFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"useNewArtwork","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60c06040526003805463ffffffff1916600f1790553480156200002157600080fd5b50604051620019b7380380620019b78339810160408190526200004491620001ab565b6200004f336200008a565b6001600160a01b0380851660a05283166080526000620000708382620002cc565b5060016200007f8282620002cc565b505050505062000398565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b80516001600160a01b0381168114620000de57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200010b57600080fd5b81516001600160401b0380821115620001285762000128620000e3565b604051601f8301601f19908116603f01168101908282118183101715620001535762000153620000e3565b81604052838152602092508660208588010111156200017157600080fd5b600091505b8382101562000195578582018301518183018401529082019062000176565b6000602085830101528094505050505092915050565b60008060008060808587031215620001c257600080fd5b620001cd85620000c6565b9350620001dd60208601620000c6565b60408601519093506001600160401b0380821115620001fb57600080fd5b6200020988838901620000f9565b935060608701519150808211156200022057600080fd5b506200022f87828801620000f9565b91505092959194509250565b600181811c908216806200025057607f821691505b6020821081036200027157634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620002c7576000816000526020600020601f850160051c81016020861015620002a25750805b601f850160051c820191505b81811015620002c357828155600101620002ae565b5050505b505050565b81516001600160401b03811115620002e857620002e8620000e3565b6200030081620002f984546200023b565b8462000277565b602080601f8311600181146200033857600084156200031f5750858301515b600019600386901b1c1916600185901b178555620002c3565b600085815260208120601f198616915b82811015620003695788860151825594840194600190910190840162000348565b5085821015620003885787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a0516115dd620003da600039600081816102640152610a6e01526000818161037b015281816104800152818161056c015261062201526115dd6000f3fe6080604052600436106101355760003560e01c80638a0349fb116100ab578063c87b56dd1161006f578063c87b56dd14610329578063cb36c11714610349578063de26bc3514610369578063f04e283e1461039d578063f2fde38b146103b0578063fee81cf4146103c357600080fd5b80638a0349fb146102a65780638da5cb5b146102bb5780639abc8320146102d4578063a0bcfc7f146102e9578063c443d4fa1461030957600080fd5b80633d44c286116100fd5780633d44c286146101da57806354d1f13d146101fa5780636b1e676b146102025780636c24a457146102325780636f7013a814610252578063715018a61461029e57600080fd5b80630dbc4e741461013a5780631680ed7b146101705780631db6151a1461019257806325692962146101b257806327b3a84b146101ba575b600080fd5b34801561014657600080fd5b5061015a610155366004610c3a565b610404565b6040516101679190610c77565b60405180910390f35b34801561017c57600080fd5b5061019061018b366004610caa565b6104fe565b005b34801561019e57600080fd5b5061015a6101ad366004610c3a565b610522565b6101906105ae565b3480156101c657600080fd5b5061015a6101d5366004610c3a565b6105fe565b3480156101e657600080fd5b506101906101f5366004610d23565b6107b1565b610190610830565b34801561020e57600080fd5b5061022261021d366004610c3a565b61086c565b6040519015158152602001610167565b34801561023e57600080fd5b5061015a61024d366004610c3a565b61088d565b34801561025e57600080fd5b506102867f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610167565b610190610929565b3480156102b257600080fd5b5061015a61093d565b3480156102c757600080fd5b50638b78c6d81954610286565b3480156102e057600080fd5b5061015a6109cb565b3480156102f557600080fd5b50610190610304366004610e27565b6109d8565b34801561031557600080fd5b50610190610324366004610e27565b6109f0565b34801561033557600080fd5b5061015a610344366004610c3a565b610a04565b34801561035557600080fd5b50610190610364366004610ebc565b610a4e565b34801561037557600080fd5b506102867f000000000000000000000000000000000000000000000000000000000000000081565b6101906103ab366004610efd565b610b36565b6101906103be366004610efd565b610b76565b3480156103cf57600080fd5b506103f66103de366004610efd565b63389a75e1600c908152600091909152602090205490565b604051908152602001610167565b600881901c60009081526002602052604090205460609060ff83161c6001161561045a57600061043383610b9d565b604051602001610444929190610fe3565b6040516020818303038152906040529050919050565b6003546040516359bd015360e01b81526004810184905263ffffffff90911660248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906359bd0153906044015b600060405180830381865afa1580156104d0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104f89190810190611064565b92915050565b610506610be1565b6003805463ffffffff191663ffffffff92909216919091179055565b600881901c60009081526002602052604090205460609060ff83161c600116156105a3576003546040516359bd015360e01b81526004810184905263ffffffff90911660248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906359bd0153906044016104b3565b600061043383610b9d565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b60405163682ee63560e11b8152600481018290526060906000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d05dcc6a90602401600060405180830381865afa158015610669573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106919190810190611099565b6040805180820190915260018152605b60f81b602082015290915060005b82518110156107a957600081156106df57604051806040016040528060018152602001600b60fa1b8152506106f0565b604051806020016040528060008152505b905060006001855161070291906111b7565b831461071d5760405180602001604052806000815250610738565b604051806040016040528060018152602001605d60f81b8152505b9050838286858151811061074e5761074e6111d8565b60200260200101516000015187868151811061076c5761076c6111d8565b6020026020010151602001518460405160200161078d9594939291906111ee565b60408051808303601f19018152919052935050506001016106af565b509392505050565b828181146107d25760405163512509d360e11b815260040160405180910390fd5b60005b81811015610828576108208686838181106107f2576107f26111d8565b9050602002013585858481811061080b5761080b6111d8565b9050602002016020810190610364919061129d565b6001016107d5565b505050505050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b600881901c60009081526002602052604081205460ff83161c6001166104f8565b600881901c6000908152600260205260408120546060919060ff84161c6001166108d4576040518060400160405280600581526020016466616c736560d81b8152506108f2565b604051806040016040528060048152602001637472756560e01b8152505b905060016108ff84610b9d565b82604051602001610912939291906112b8565b604051602081830303815290604052915050919050565b610931610be1565b61093b6000610bfc565b565b6001805461094a90610f1a565b80601f016020809104026020016040519081016040528092919081815260200182805461097690610f1a565b80156109c35780601f10610998576101008083540402835291602001916109c3565b820191906000526020600020905b8154815290600101906020018083116109a657829003601f168201915b505050505081565b6000805461094a90610f1a565b6109e0610be1565b60006109ec8282611370565b5050565b6109f8610be1565b60016109ec8282611370565b60606000610a1183610b9d565b90508081610a1e8561088d565b610a2786610404565b610a3087610522565b610a39886105fe565b60405160200161091296959493929190611430565b6040516331a9108f60e11b81526004810183905233906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015610ab5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ad9919061158a565b6001600160a01b031614610b0757604051633b94a19960e01b81526004810183905260240160405180910390fd5b6002602052600882901c6000908152604090208054600160ff851690811b1990911683151590911b1790555050565b610b3e610be1565b63389a75e1600c52806000526020600c208054421115610b6657636f5e88186000526004601cfd5b60009055610b7381610bfc565b50565b610b7e610be1565b8060601b610b9457637448fbae6000526004601cfd5b610b7381610bfc565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a900480610bb8575050819003601f19909101908152919050565b638b78c6d81954331461093b576382b429006000526004601cfd5b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b600060208284031215610c4c57600080fd5b5035919050565b60005b83811015610c6e578181015183820152602001610c56565b50506000910152565b6020815260008251806020840152610c96816040850160208701610c53565b601f01601f19169190910160400192915050565b600060208284031215610cbc57600080fd5b813563ffffffff81168114610cd057600080fd5b9392505050565b60008083601f840112610ce957600080fd5b50813567ffffffffffffffff811115610d0157600080fd5b6020830191508360208260051b8501011115610d1c57600080fd5b9250929050565b60008060008060408587031215610d3957600080fd5b843567ffffffffffffffff80821115610d5157600080fd5b610d5d88838901610cd7565b90965094506020870135915080821115610d7657600080fd5b50610d8387828801610cd7565b95989497509550505050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610dc857610dc8610d8f565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715610df757610df7610d8f565b604052919050565b600067ffffffffffffffff821115610e1957610e19610d8f565b50601f01601f191660200190565b600060208284031215610e3957600080fd5b813567ffffffffffffffff811115610e5057600080fd5b8201601f81018413610e6157600080fd5b8035610e74610e6f82610dff565b610dce565b818152856020838501011115610e8957600080fd5b81602084016020830137600091810160200191909152949350505050565b80358015158114610eb757600080fd5b919050565b60008060408385031215610ecf57600080fd5b82359150610edf60208401610ea7565b90509250929050565b6001600160a01b0381168114610b7357600080fd5b600060208284031215610f0f57600080fd5b8135610cd081610ee8565b600181811c90821680610f2e57607f821691505b602082108103610f4e57634e487b7160e01b600052602260045260246000fd5b50919050565b60008154610f6181610f1a565b60018281168015610f795760018114610f8e57610fbd565b60ff1984168752821515830287019450610fbd565b8560005260208060002060005b85811015610fb45781548a820152908401908201610f9b565b50505082870194505b5050505092915050565b60008151610fd9818560208601610c53565b9290920192915050565b6000610fef8285610f54565b8351610fff818360208801610c53565b632e706e6760e01b9101908152600401949350505050565b600082601f83011261102857600080fd5b8151611036610e6f82610dff565b81815284602083860101111561104b57600080fd5b61105c826020830160208701610c53565b949350505050565b60006020828403121561107657600080fd5b815167ffffffffffffffff81111561108d57600080fd5b61105c84828501611017565b600060208083850312156110ac57600080fd5b825167ffffffffffffffff808211156110c457600080fd5b818501915085601f8301126110d857600080fd5b8151818111156110ea576110ea610d8f565b8060051b6110f9858201610dce565b918252838101850191858101908984111561111357600080fd5b86860192505b838310156111aa578251858111156111315760008081fd5b86016040818c03601f19018113156111495760008081fd5b611151610da5565b89830151888111156111635760008081fd5b6111718e8c83870101611017565b8252509082015190878211156111875760008081fd5b6111958d8b84860101611017565b818b0152845250509186019190860190611119565b9998505050505050505050565b818103818111156104f857634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60008651611200818460208b01610c53565b865190830190611214818360208b01610c53565b6e3d913a3930b4ba2fba3cb832911d1160891b9101908152855161123f81600f840160208a01610c53565b6a1116113b30b63ab2911d1160a91b600f9290910191820152845161126b81601a840160208901610c53565b61227d60f01b601a9290910191820152835161128e81601c840160208801610c53565b01601c01979650505050505050565b6000602082840312156112af57600080fd5b610cd082610ea7565b60006112c48286610f54565b683f746f6b656e49643d60b81b815284516112e6816009840160208901610c53565b6e267573654e6577417274776f726b3d60881b600992909101918201528351611316816018840160208801610c53565b0160180195945050505050565b601f82111561136b576000816000526020600020601f850160051c8101602086101561134c5750805b601f850160051c820191505b8181101561082857828155600101611358565b505050565b815167ffffffffffffffff81111561138a5761138a610d8f565b61139e816113988454610f1a565b84611323565b602080601f8311600181146113d357600084156113bb5750858301515b600019600386901b1c1916600185901b178555610828565b600085815260208120601f198616915b82811015611402578886015182559484019460019091019084016113e3565b50858210156114205787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b7f646174613a6170706c69636174696f6e2f6a736f6e3b7574662d382c7b226e6181526f6d65223a224d6f6f6e6269726473202360801b602082015260008751611481816030850160208c01610c53565b7f222c2265787465726e616c5f75726c223a2268747470733a2f2f70726f6f662e6030918401918201526d78797a2f6d6f6f6e62697264732f60901b605082015287516114d581605e840160208c01610c53565b016114f8605e82017211161130b734b6b0ba34b7b72fbab936111d1160691b9052565b6115056071820188610fc7565b6a11161134b6b0b3b2911d1160a91b81529050611525600b820187610fc7565b7411161130b63a32b93730ba32afb4b6b0b3b2911d1160591b8152905061154f6015820186610fc7565b6e11161130ba3a3934b13aba32b9911d60891b81529050611573600f820185610fc7565b607d60f81b81526001019998505050505050505050565b60006020828403121561159c57600080fd5b8151610cd081610ee856fea2646970667358221220234147f4d670181f998dfd884314b4bf3c11051a8f8dfb24319113047664948d64736f6c6343000817003300000000000000000000000023581767a106ae21c074b2276d25e5c3e136a68b000000000000000000000000b1befc9e7b76c1e846ebbf3e6e1ab029c86e7435000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000003568747470733a2f2f636f6c6c656374696f6e2d6173736574732e70726f6f662e78797a2f6d6f6f6e62697264732f696d616765732f0000000000000000000000000000000000000000000000000000000000000000000000000000000000003868747470733a2f2f636f6c6c656374696f6e2d6173736574732e70726f6f662e78797a2f6d6f6f6e62697264732f656d6265642e68746d6c0000000000000000
Deployed Bytecode
0x6080604052600436106101355760003560e01c80638a0349fb116100ab578063c87b56dd1161006f578063c87b56dd14610329578063cb36c11714610349578063de26bc3514610369578063f04e283e1461039d578063f2fde38b146103b0578063fee81cf4146103c357600080fd5b80638a0349fb146102a65780638da5cb5b146102bb5780639abc8320146102d4578063a0bcfc7f146102e9578063c443d4fa1461030957600080fd5b80633d44c286116100fd5780633d44c286146101da57806354d1f13d146101fa5780636b1e676b146102025780636c24a457146102325780636f7013a814610252578063715018a61461029e57600080fd5b80630dbc4e741461013a5780631680ed7b146101705780631db6151a1461019257806325692962146101b257806327b3a84b146101ba575b600080fd5b34801561014657600080fd5b5061015a610155366004610c3a565b610404565b6040516101679190610c77565b60405180910390f35b34801561017c57600080fd5b5061019061018b366004610caa565b6104fe565b005b34801561019e57600080fd5b5061015a6101ad366004610c3a565b610522565b6101906105ae565b3480156101c657600080fd5b5061015a6101d5366004610c3a565b6105fe565b3480156101e657600080fd5b506101906101f5366004610d23565b6107b1565b610190610830565b34801561020e57600080fd5b5061022261021d366004610c3a565b61086c565b6040519015158152602001610167565b34801561023e57600080fd5b5061015a61024d366004610c3a565b61088d565b34801561025e57600080fd5b506102867f00000000000000000000000023581767a106ae21c074b2276d25e5c3e136a68b81565b6040516001600160a01b039091168152602001610167565b610190610929565b3480156102b257600080fd5b5061015a61093d565b3480156102c757600080fd5b50638b78c6d81954610286565b3480156102e057600080fd5b5061015a6109cb565b3480156102f557600080fd5b50610190610304366004610e27565b6109d8565b34801561031557600080fd5b50610190610324366004610e27565b6109f0565b34801561033557600080fd5b5061015a610344366004610c3a565b610a04565b34801561035557600080fd5b50610190610364366004610ebc565b610a4e565b34801561037557600080fd5b506102867f000000000000000000000000b1befc9e7b76c1e846ebbf3e6e1ab029c86e743581565b6101906103ab366004610efd565b610b36565b6101906103be366004610efd565b610b76565b3480156103cf57600080fd5b506103f66103de366004610efd565b63389a75e1600c908152600091909152602090205490565b604051908152602001610167565b600881901c60009081526002602052604090205460609060ff83161c6001161561045a57600061043383610b9d565b604051602001610444929190610fe3565b6040516020818303038152906040529050919050565b6003546040516359bd015360e01b81526004810184905263ffffffff90911660248201527f000000000000000000000000b1befc9e7b76c1e846ebbf3e6e1ab029c86e74356001600160a01b0316906359bd0153906044015b600060405180830381865afa1580156104d0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104f89190810190611064565b92915050565b610506610be1565b6003805463ffffffff191663ffffffff92909216919091179055565b600881901c60009081526002602052604090205460609060ff83161c600116156105a3576003546040516359bd015360e01b81526004810184905263ffffffff90911660248201527f000000000000000000000000b1befc9e7b76c1e846ebbf3e6e1ab029c86e74356001600160a01b0316906359bd0153906044016104b3565b600061043383610b9d565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b60405163682ee63560e11b8152600481018290526060906000906001600160a01b037f000000000000000000000000b1befc9e7b76c1e846ebbf3e6e1ab029c86e7435169063d05dcc6a90602401600060405180830381865afa158015610669573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106919190810190611099565b6040805180820190915260018152605b60f81b602082015290915060005b82518110156107a957600081156106df57604051806040016040528060018152602001600b60fa1b8152506106f0565b604051806020016040528060008152505b905060006001855161070291906111b7565b831461071d5760405180602001604052806000815250610738565b604051806040016040528060018152602001605d60f81b8152505b9050838286858151811061074e5761074e6111d8565b60200260200101516000015187868151811061076c5761076c6111d8565b6020026020010151602001518460405160200161078d9594939291906111ee565b60408051808303601f19018152919052935050506001016106af565b509392505050565b828181146107d25760405163512509d360e11b815260040160405180910390fd5b60005b81811015610828576108208686838181106107f2576107f26111d8565b9050602002013585858481811061080b5761080b6111d8565b9050602002016020810190610364919061129d565b6001016107d5565b505050505050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b600881901c60009081526002602052604081205460ff83161c6001166104f8565b600881901c6000908152600260205260408120546060919060ff84161c6001166108d4576040518060400160405280600581526020016466616c736560d81b8152506108f2565b604051806040016040528060048152602001637472756560e01b8152505b905060016108ff84610b9d565b82604051602001610912939291906112b8565b604051602081830303815290604052915050919050565b610931610be1565b61093b6000610bfc565b565b6001805461094a90610f1a565b80601f016020809104026020016040519081016040528092919081815260200182805461097690610f1a565b80156109c35780601f10610998576101008083540402835291602001916109c3565b820191906000526020600020905b8154815290600101906020018083116109a657829003601f168201915b505050505081565b6000805461094a90610f1a565b6109e0610be1565b60006109ec8282611370565b5050565b6109f8610be1565b60016109ec8282611370565b60606000610a1183610b9d565b90508081610a1e8561088d565b610a2786610404565b610a3087610522565b610a39886105fe565b60405160200161091296959493929190611430565b6040516331a9108f60e11b81526004810183905233906001600160a01b037f00000000000000000000000023581767a106ae21c074b2276d25e5c3e136a68b1690636352211e90602401602060405180830381865afa158015610ab5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ad9919061158a565b6001600160a01b031614610b0757604051633b94a19960e01b81526004810183905260240160405180910390fd5b6002602052600882901c6000908152604090208054600160ff851690811b1990911683151590911b1790555050565b610b3e610be1565b63389a75e1600c52806000526020600c208054421115610b6657636f5e88186000526004601cfd5b60009055610b7381610bfc565b50565b610b7e610be1565b8060601b610b9457637448fbae6000526004601cfd5b610b7381610bfc565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a900480610bb8575050819003601f19909101908152919050565b638b78c6d81954331461093b576382b429006000526004601cfd5b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b600060208284031215610c4c57600080fd5b5035919050565b60005b83811015610c6e578181015183820152602001610c56565b50506000910152565b6020815260008251806020840152610c96816040850160208701610c53565b601f01601f19169190910160400192915050565b600060208284031215610cbc57600080fd5b813563ffffffff81168114610cd057600080fd5b9392505050565b60008083601f840112610ce957600080fd5b50813567ffffffffffffffff811115610d0157600080fd5b6020830191508360208260051b8501011115610d1c57600080fd5b9250929050565b60008060008060408587031215610d3957600080fd5b843567ffffffffffffffff80821115610d5157600080fd5b610d5d88838901610cd7565b90965094506020870135915080821115610d7657600080fd5b50610d8387828801610cd7565b95989497509550505050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610dc857610dc8610d8f565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715610df757610df7610d8f565b604052919050565b600067ffffffffffffffff821115610e1957610e19610d8f565b50601f01601f191660200190565b600060208284031215610e3957600080fd5b813567ffffffffffffffff811115610e5057600080fd5b8201601f81018413610e6157600080fd5b8035610e74610e6f82610dff565b610dce565b818152856020838501011115610e8957600080fd5b81602084016020830137600091810160200191909152949350505050565b80358015158114610eb757600080fd5b919050565b60008060408385031215610ecf57600080fd5b82359150610edf60208401610ea7565b90509250929050565b6001600160a01b0381168114610b7357600080fd5b600060208284031215610f0f57600080fd5b8135610cd081610ee8565b600181811c90821680610f2e57607f821691505b602082108103610f4e57634e487b7160e01b600052602260045260246000fd5b50919050565b60008154610f6181610f1a565b60018281168015610f795760018114610f8e57610fbd565b60ff1984168752821515830287019450610fbd565b8560005260208060002060005b85811015610fb45781548a820152908401908201610f9b565b50505082870194505b5050505092915050565b60008151610fd9818560208601610c53565b9290920192915050565b6000610fef8285610f54565b8351610fff818360208801610c53565b632e706e6760e01b9101908152600401949350505050565b600082601f83011261102857600080fd5b8151611036610e6f82610dff565b81815284602083860101111561104b57600080fd5b61105c826020830160208701610c53565b949350505050565b60006020828403121561107657600080fd5b815167ffffffffffffffff81111561108d57600080fd5b61105c84828501611017565b600060208083850312156110ac57600080fd5b825167ffffffffffffffff808211156110c457600080fd5b818501915085601f8301126110d857600080fd5b8151818111156110ea576110ea610d8f565b8060051b6110f9858201610dce565b918252838101850191858101908984111561111357600080fd5b86860192505b838310156111aa578251858111156111315760008081fd5b86016040818c03601f19018113156111495760008081fd5b611151610da5565b89830151888111156111635760008081fd5b6111718e8c83870101611017565b8252509082015190878211156111875760008081fd5b6111958d8b84860101611017565b818b0152845250509186019190860190611119565b9998505050505050505050565b818103818111156104f857634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60008651611200818460208b01610c53565b865190830190611214818360208b01610c53565b6e3d913a3930b4ba2fba3cb832911d1160891b9101908152855161123f81600f840160208a01610c53565b6a1116113b30b63ab2911d1160a91b600f9290910191820152845161126b81601a840160208901610c53565b61227d60f01b601a9290910191820152835161128e81601c840160208801610c53565b01601c01979650505050505050565b6000602082840312156112af57600080fd5b610cd082610ea7565b60006112c48286610f54565b683f746f6b656e49643d60b81b815284516112e6816009840160208901610c53565b6e267573654e6577417274776f726b3d60881b600992909101918201528351611316816018840160208801610c53565b0160180195945050505050565b601f82111561136b576000816000526020600020601f850160051c8101602086101561134c5750805b601f850160051c820191505b8181101561082857828155600101611358565b505050565b815167ffffffffffffffff81111561138a5761138a610d8f565b61139e816113988454610f1a565b84611323565b602080601f8311600181146113d357600084156113bb5750858301515b600019600386901b1c1916600185901b178555610828565b600085815260208120601f198616915b82811015611402578886015182559484019460019091019084016113e3565b50858210156114205787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b7f646174613a6170706c69636174696f6e2f6a736f6e3b7574662d382c7b226e6181526f6d65223a224d6f6f6e6269726473202360801b602082015260008751611481816030850160208c01610c53565b7f222c2265787465726e616c5f75726c223a2268747470733a2f2f70726f6f662e6030918401918201526d78797a2f6d6f6f6e62697264732f60901b605082015287516114d581605e840160208c01610c53565b016114f8605e82017211161130b734b6b0ba34b7b72fbab936111d1160691b9052565b6115056071820188610fc7565b6a11161134b6b0b3b2911d1160a91b81529050611525600b820187610fc7565b7411161130b63a32b93730ba32afb4b6b0b3b2911d1160591b8152905061154f6015820186610fc7565b6e11161130ba3a3934b13aba32b9911d60891b81529050611573600f820185610fc7565b607d60f81b81526001019998505050505050505050565b60006020828403121561159c57600080fd5b8151610cd081610ee856fea2646970667358221220234147f4d670181f998dfd884314b4bf3c11051a8f8dfb24319113047664948d64736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000023581767a106ae21c074b2276d25e5c3e136a68b000000000000000000000000b1befc9e7b76c1e846ebbf3e6e1ab029c86e7435000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000003568747470733a2f2f636f6c6c656374696f6e2d6173736574732e70726f6f662e78797a2f6d6f6f6e62697264732f696d616765732f0000000000000000000000000000000000000000000000000000000000000000000000000000000000003868747470733a2f2f636f6c6c656374696f6e2d6173736574732e70726f6f662e78797a2f6d6f6f6e62697264732f656d6265642e68746d6c0000000000000000
-----Decoded View---------------
Arg [0] : moonbirds_ (address): 0x23581767a106ae21c074b2276D25e5C3e136a68b
Arg [1] : legacyRenderer_ (address): 0xb1bEfc9E7B76C1e846EBBf3e6E1Ab029C86e7435
Arg [2] : baseUri_ (string): https://collection-assets.proof.xyz/moonbirds/images/
Arg [3] : animationBaseUri_ (string): https://collection-assets.proof.xyz/moonbirds/embed.html
-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 00000000000000000000000023581767a106ae21c074b2276d25e5c3e136a68b
Arg [1] : 000000000000000000000000b1befc9e7b76c1e846ebbf3e6e1ab029c86e7435
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [3] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000035
Arg [5] : 68747470733a2f2f636f6c6c656374696f6e2d6173736574732e70726f6f662e
Arg [6] : 78797a2f6d6f6f6e62697264732f696d616765732f0000000000000000000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000038
Arg [8] : 68747470733a2f2f636f6c6c656374696f6e2d6173736574732e70726f6f662e
Arg [9] : 78797a2f6d6f6f6e62697264732f656d6265642e68746d6c0000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.