Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
RabbitHoleTickets
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 5000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.18; import {Ownable} from 'solady/src/auth/Ownable.sol'; import {ERC1155} from 'solady/src/tokens/ERC1155.sol'; import {Base64} from 'solady/src/utils/Base64.sol'; import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; import {IERC165Upgradeable, IERC2981Upgradeable} from '@openzeppelin/contracts-upgradeable/interfaces/IERC2981Upgradeable.sol'; contract RabbitHoleTickets is Initializable, Ownable, ERC1155, IERC2981Upgradeable { error OnlyMinter(); event RoyaltyFeeSet(uint256 indexed royaltyFee); event MinterAddressSet(address indexed minterAddress); // storage address public royaltyRecipient; address public minterAddress; uint public royaltyFee; string public imageIPFSCID; string public animationUrlIPFSCID; /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize( address royaltyRecipient_, address minterAddress_, uint royaltyFee_, address owner_, string memory imageIPFSCID_, string memory animationUrlIPFSCID_ ) external initializer { _initializeOwner(owner_); royaltyRecipient = royaltyRecipient_; minterAddress = minterAddress_; royaltyFee = royaltyFee_; imageIPFSCID = imageIPFSCID_; animationUrlIPFSCID = animationUrlIPFSCID_; } modifier onlyMinter() { if (msg.sender != minterAddress) revert OnlyMinter(); _; } /// @dev set the image IPFS CID /// @param imageIPFSCID_ the image IPFS CID function setImageIPFSCID(string memory imageIPFSCID_) external onlyOwner { imageIPFSCID = imageIPFSCID_; } /// @dev set the animation url IPFS CID /// @param animationUrlIPFSCID_ the animation url IPFS CID function setAnimationUrlIPFSCID(string memory animationUrlIPFSCID_) external onlyOwner { animationUrlIPFSCID = animationUrlIPFSCID_; } /// @dev set the royalty recipient /// @param royaltyRecipient_ the address of the royalty recipient function setRoyaltyRecipient(address royaltyRecipient_) external onlyOwner { royaltyRecipient = royaltyRecipient_; } /// @dev set the royalty fee /// @param royaltyFee_ the royalty fee function setRoyaltyFee(uint256 royaltyFee_) external onlyOwner { royaltyFee = royaltyFee_; emit RoyaltyFeeSet(royaltyFee_); } /// @dev set the minter address /// @param minterAddress_ the address of the minter function setMinterAddress(address minterAddress_) external onlyOwner { minterAddress = minterAddress_; emit MinterAddressSet(minterAddress_); } /// @dev mint a single ticket, only callable by the allowed minter /// @param to_ the address to mint the ticket to /// @param id_ the id of the ticket to mint /// @param amount_ the amount of the ticket to mint /// @param data_ the data to pass to the mint function function mint(address to_, uint256 id_, uint256 amount_, bytes memory data_) external onlyMinter { _mint(to_, id_, amount_, data_); } /// @dev mint a batch of tickets, only callable by the allowed minter /// @param to_ the address to mint the tickets to /// @param ids_ the ids of the tickets to mint /// @param amounts_ the amounts of the tickets to mint /// @param data_ the data to pass to the mint function function mintBatch( address to_, uint256[] memory ids_, uint256[] memory amounts_, bytes memory data_ ) external onlyMinter { _batchMint(to_, ids_, amounts_, data_); } /// @dev returns the token uri function uri(uint256) public view override(ERC1155) returns (string memory) { bytes memory dataURI = generateDataURI(); return string(abi.encodePacked('data:application/json;base64,', Base64.encode(dataURI))); } /// @dev returns the data uri in json format function generateDataURI() internal view virtual returns (bytes memory) { bytes memory dataURI = abi.encodePacked( '{', '"name": "', "RabbitHole Ticket", '",', '"description": "', "RabbitHole Tickets", '",', '"image": "', tokenImage(imageIPFSCID), '",', '"animation_url": "', animationUrl(animationUrlIPFSCID), '"', '}' ); return dataURI; } function tokenImage(string memory imageIPFSCID_) internal view virtual returns (string memory) { return string(abi.encodePacked('ipfs://', imageIPFSCID_)); } function animationUrl(string memory animationUrlIPFSCID_) internal view virtual returns (string memory) { if (bytes(animationUrlIPFSCID_).length == 0) { return ''; } return string(abi.encodePacked('ipfs://', animationUrlIPFSCID_)); } /// @dev See {IERC165-royaltyInfo} /// @param salePrice_ the sale price function royaltyInfo( uint256, uint256 salePrice_ ) external view override returns (address receiver, uint256 royaltyAmount) { uint256 royaltyPayment = (salePrice_ * royaltyFee) / 10_000; return (royaltyRecipient, royaltyPayment); } /// @dev returns true if the supplied interface id is supported /// @param interfaceId_ the interface id function supportsInterface( bytes4 interfaceId_ ) public view virtual override(ERC1155, IERC165Upgradeable) returns (bool) { return interfaceId_ == type(IERC2981Upgradeable).interfaceId || super.supportsInterface(interfaceId_); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165Upgradeable.sol"; /** * @dev Interface for the NFT Royalty Standard. * * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal * support for royalty payments across all NFT marketplaces and ecosystem participants. * * _Available since v4.5._ */ interface IERC2981Upgradeable is IERC165Upgradeable { /** * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. */ function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Internal function that returns the initialized version. Returns `_initialized` */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Internal function that returns the initialized version. Returns `_initializing` */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165Upgradeable { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// 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 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(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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: `not(_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. uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; /// 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 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 { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(not(_OWNER_SLOT_NOT), 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 { /// @solidity memory-safe-assembly assembly { let ownerSlot := not(_OWNER_SLOT_NOT) // 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(not(_OWNER_SLOT_NOT)))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 be 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(not(_OWNER_SLOT_NOT)) } } /// @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)) } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. function ownershipHandoverValidFor() public view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 Simple ERC1155 implementation. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC1155.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC1155/ERC1155.sol) /// /// @dev Note: /// The ERC1155 standard allows for self-approvals. /// For performance, this implementation WILL NOT revert for such actions. /// Please add any checks with overrides if desired. abstract contract ERC1155 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The lengths of the input arrays are not the same. error ArrayLengthsMismatch(); /// @dev Cannot mint or transfer to the zero address. error TransferToZeroAddress(); /// @dev The recipient's balance has overflowed. error AccountBalanceOverflow(); /// @dev Insufficient balance. error InsufficientBalance(); /// @dev Only the token owner or an approved account can manage the tokens. error NotOwnerNorApproved(); /// @dev Cannot safely transfer to a contract that does not implement /// the ERC1155Receiver interface. error TransferToNonERC1155ReceiverImplementer(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when `amount` of token `id` is transferred /// from `from` to `to` by `operator`. event TransferSingle( address indexed operator, address indexed from, address indexed to, uint256 id, uint256 amount ); /// @dev Emitted when `amounts` of token `ids` are transferred /// from `from` to `to` by `operator`. event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] amounts ); /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens. event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved); /// @dev Emitted when the Uniform Resource Identifier (URI) for token `id` /// is updated to `value`. This event is not used in the base contract. /// You may need to emit this event depending on your URI logic. /// /// See: https://eips.ethereum.org/EIPS/eip-1155#metadata event URI(string value, uint256 indexed id); /// @dev `keccak256(bytes("TransferSingle(address,address,address,uint256,uint256)"))`. uint256 private constant _TRANSFER_SINGLE_EVENT_SIGNATURE = 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62; /// @dev `keccak256(bytes("TransferBatch(address,address,address,uint256[],uint256[])"))`. uint256 private constant _TRANSFER_BATCH_EVENT_SIGNATURE = 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb; /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`. uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `ownerSlotSeed` of a given owner is given by. /// ``` /// let ownerSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner)) /// ``` /// /// The balance slot of `owner` is given by. /// ``` /// mstore(0x20, ownerSlotSeed) /// mstore(0x00, id) /// let balanceSlot := keccak256(0x00, 0x40) /// ``` /// /// The operator approval slot of `owner` is given by. /// ``` /// mstore(0x20, ownerSlotSeed) /// mstore(0x00, operator) /// let operatorApprovalSlot := keccak256(0x0c, 0x34) /// ``` uint256 private constant _ERC1155_MASTER_SLOT_SEED = 0x9a31110384e0b0c9; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1155 METADATA */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the URI for token `id`. /// /// You can either return the same templated URI for all token IDs, /// (e.g. "https://example.com/api/{id}.json"), /// or return a unique URI for each `id`. /// /// See: https://eips.ethereum.org/EIPS/eip-1155#metadata function uri(uint256 id) public view virtual returns (string memory); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1155 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the amount of `id` owned by `owner`. function balanceOf(address owner, uint256 id) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, owner) mstore(0x00, id) result := sload(keccak256(0x00, 0x40)) } } /// @dev Returns whether `operator` is approved to manage the tokens of `owner`. function isApprovedForAll(address owner, address operator) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, owner) mstore(0x00, operator) result := sload(keccak256(0x0c, 0x34)) } } /// @dev Sets whether `operator` is approved to manage the tokens of the caller. /// /// Emits a {ApprovalForAll} event. function setApprovalForAll(address operator, bool isApproved) public virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`msg.sender`, `operator`). mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, caller()) mstore(0x00, operator) sstore(keccak256(0x0c, 0x34), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) // forgefmt: disable-next-line log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator))) } } /// @dev Transfers `amount` of `id` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `from` must have at least `amount` of `id`. /// - If the caller is not `from`, /// it must be approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155Reveived}, which is called upon a batch transfer. /// /// Emits a {Transfer} event. function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) public virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from)) let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to)) mstore(0x20, fromSlotSeed) // Clear the upper 96 bits. from := shr(96, fromSlotSeed) to := shr(96, toSlotSeed) // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // If the caller is not `from`, do the authorization check. if iszero(eq(caller(), from)) { mstore(0x00, caller()) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Subtract and store the updated balance of `from`. { mstore(0x00, id) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, toSlotSeed) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } // Emit a {TransferSingle} event. mstore(0x20, amount) log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), from, to) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { // Do the {onERC1155Received} check if `to` is a smart contract. if extcodesize(to) { // Prepare the calldata. let m := mload(0x40) // `onERC1155Received(address,address,uint256,uint256,bytes)`. mstore(m, 0xf23a6e61) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), from) mstore(add(m, 0x60), id) mstore(add(m, 0x80), amount) mstore(add(m, 0xa0), 0xa0) calldatacopy(add(m, 0xc0), sub(data.offset, 0x20), add(0x20, data.length)) // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, data.length), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } mstore(m, 0) } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xf23a6e61))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } } /// @dev Transfers `amounts` of `ids` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `from` must have at least `amount` of `id`. /// - `ids` and `amounts` must have the same length. /// - If the caller is not `from`, /// it must be approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer. /// /// Emits a {TransferBatch} event. function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) public virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { if iszero(eq(ids.length, amounts.length)) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from)) let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to)) mstore(0x20, fromSlotSeed) // Clear the upper 96 bits. from := shr(96, fromSlotSeed) to := shr(96, toSlotSeed) // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // If the caller is not `from`, do the authorization check. if iszero(eq(caller(), from)) { mstore(0x00, caller()) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Loop through all the `ids` and update the balances. { let end := shl(5, ids.length) for { let i := 0 } iszero(eq(i, end)) { i := add(i, 0x20) } { let amount := calldataload(add(amounts.offset, i)) // Subtract and store the updated balance of `from`. { mstore(0x20, fromSlotSeed) mstore(0x00, calldataload(add(ids.offset, i))) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, toSlotSeed) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, ids.length)) let o := add(m, 0x40) calldatacopy(o, sub(ids.offset, 0x20), n) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, n)) o := add(o, n) n := add(0x20, shl(5, amounts.length)) calldatacopy(o, sub(amounts.offset, 0x20), n) n := sub(add(o, n), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), from, to) } } if (_useAfterTokenTransfer()) { _afterTokenTransferCalldata(from, to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { // Do the {onERC1155BatchReceived} check if `to` is a smart contract. if extcodesize(to) { let m := mload(0x40) // Prepare the calldata. // `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`. mstore(m, 0xbc197c81) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), from) // Copy the `ids`. mstore(add(m, 0x60), 0xa0) let n := add(0x20, shl(5, ids.length)) let o := add(m, 0xc0) calldatacopy(o, sub(ids.offset, 0x20), n) // Copy the `amounts`. let s := add(0xa0, n) mstore(add(m, 0x80), s) o := add(o, n) n := add(0x20, shl(5, amounts.length)) calldatacopy(o, sub(amounts.offset, 0x20), n) // Copy the `data`. mstore(add(m, 0xa0), add(s, n)) o := add(o, n) n := add(0x20, data.length) calldatacopy(o, sub(data.offset, 0x20), n) n := sub(add(o, n), add(m, 0x1c)) // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), n, m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } mstore(m, 0) } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xbc197c81))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } } /// @dev Returns the amounts of `ids` for `owners. /// /// Requirements: /// - `owners` and `ids` must have the same length. function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) public view virtual returns (uint256[] memory balances) { /// @solidity memory-safe-assembly assembly { if iszero(eq(ids.length, owners.length)) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } balances := mload(0x40) mstore(balances, ids.length) let o := add(balances, 0x20) let end := shl(5, ids.length) mstore(0x40, add(end, o)) // Loop through all the `ids` and load the balances. for { let i := 0 } iszero(eq(i, end)) { i := add(i, 0x20) } { let owner := calldataload(add(owners.offset, i)) mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner))) mstore(0x00, calldataload(add(ids.offset, i))) mstore(add(o, i), sload(keccak256(0x00, 0x40))) } } } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC1155: 0xd9b67a26, ERC1155MetadataURI: 0x0e89341c. result := or(or(eq(s, 0x01ffc9a7), eq(s, 0xd9b67a26)), eq(s, 0x0e89341c)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL MINT FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Mints `amount` of `id` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155Reveived}, which is called upon a batch transfer. /// /// Emits a {Transfer} event. function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(address(0), to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Increase and store the updated balance of `to`. { mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, to) mstore(0x00, id) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } // Emit a {TransferSingle} event. mstore(0x00, id) mstore(0x20, amount) log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), 0, shr(96, to_)) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(address(0), to, _single(id), _single(amount), data); } if (_hasCode(to)) _checkOnERC1155Received(address(0), to, id, amount, data); } /// @dev Mints `amounts` of `ids` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `ids` and `amounts` must have the same length. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer. /// /// Emits a {TransferBatch} event. function _batchMint( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(address(0), to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { if iszero(eq(mload(ids), mload(amounts))) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Loop through all the `ids` and update the balances. { mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_)) let end := shl(5, mload(ids)) for { let i := 0 } iszero(eq(i, end)) {} { i := add(i, 0x20) let amount := mload(add(amounts, i)) // Increase and store the updated balance of `to`. { mstore(0x00, mload(add(ids, i))) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0x40) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, returndatasize())) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) n := sub(add(o, returndatasize()), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), 0, shr(96, to_)) } } if (_useAfterTokenTransfer()) { _afterTokenTransfer(address(0), to, ids, amounts, data); } if (_hasCode(to)) _checkOnERC1155BatchReceived(address(0), to, ids, amounts, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL BURN FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_burn(address(0), from, id, amount)`. function _burn(address from, uint256 id, uint256 amount) internal virtual { _burn(address(0), from, id, amount); } /// @dev Destroys `amount` of `id` from `from`. /// /// Requirements: /// - `from` must have at least `amount` of `id`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// /// Emits a {Transfer} event. function _burn(address by, address from, uint256 id, uint256 amount) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, address(0), _single(id), _single(amount), ""); } /// @solidity memory-safe-assembly assembly { let from_ := shl(96, from) mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_)) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. if iszero(or(iszero(shl(96, by)), eq(shl(96, by), from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Decrease and store the updated balance of `from`. { mstore(0x00, id) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Emit a {TransferSingle} event. mstore(0x00, id) mstore(0x20, amount) log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), 0) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, address(0), _single(id), _single(amount), ""); } } /// @dev Equivalent to `_batchBurn(address(0), from, ids, amounts)`. function _batchBurn(address from, uint256[] memory ids, uint256[] memory amounts) internal virtual { _batchBurn(address(0), from, ids, amounts); } /// @dev Destroys `amounts` of `ids` from `from`. /// /// Requirements: /// - `ids` and `amounts` must have the same length. /// - `from` must have at least `amounts` of `ids`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// /// Emits a {TransferBatch} event. function _batchBurn(address by, address from, uint256[] memory ids, uint256[] memory amounts) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, address(0), ids, amounts, ""); } /// @solidity memory-safe-assembly assembly { if iszero(eq(mload(ids), mload(amounts))) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let from_ := shl(96, from) mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_)) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. let by_ := shl(96, by) if iszero(or(iszero(by_), eq(by_, from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Loop through all the `ids` and update the balances. { let end := shl(5, mload(ids)) for { let i := 0 } iszero(eq(i, end)) {} { i := add(i, 0x20) let amount := mload(add(amounts, i)) // Decrease and store the updated balance of `to`. { mstore(0x00, mload(add(ids, i))) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0x40) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, returndatasize())) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) n := sub(add(o, returndatasize()), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), 0) } } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, address(0), ids, amounts, ""); } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL APPROVAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Approve or remove the `operator` as an operator for `by`, /// without authorization checks. /// /// Emits a {ApprovalForAll} event. function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`by`, `operator`). mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, by) mstore(0x00, operator) sstore(keccak256(0x0c, 0x34), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) let m := shr(96, not(0)) log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, and(m, by), and(m, operator)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL TRANSFER FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_safeTransfer(address(0), from, to, id, amount, data)`. function _safeTransfer(address from, address to, uint256 id, uint256 amount, bytes memory data) internal virtual { _safeTransfer(address(0), from, to, id, amount, data); } /// @dev Transfers `amount` of `id` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `from` must have at least `amount` of `id`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155Reveived}, which is called upon a batch transfer. /// /// Emits a {Transfer} event. function _safeTransfer( address by, address from, address to, uint256 id, uint256 amount, bytes memory data ) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { let from_ := shl(96, from) let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_)) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. let by_ := shl(96, by) if iszero(or(iszero(by_), eq(by_, from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Subtract and store the updated balance of `from`. { mstore(0x00, id) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_)) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } // Emit a {TransferSingle} event. mstore(0x20, amount) // forgefmt: disable-next-line log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_)) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, _single(id), _single(amount), data); } if (_hasCode(to)) _checkOnERC1155Received(from, to, id, amount, data); } /// @dev Equivalent to `_safeBatchTransfer(address(0), from, to, ids, amounts, data)`. function _safeBatchTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { _safeBatchTransfer(address(0), from, to, ids, amounts, data); } /// @dev Transfers `amounts` of `ids` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `ids` and `amounts` must have the same length. /// - `from` must have at least `amounts` of `ids`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer. /// /// Emits a {TransferBatch} event. function _safeBatchTransfer( address by, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { if iszero(eq(mload(ids), mload(amounts))) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let from_ := shl(96, from) let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, from_) let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, to_) mstore(0x20, fromSlotSeed) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. let by_ := shl(96, by) if iszero(or(iszero(by_), eq(by_, from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Loop through all the `ids` and update the balances. { let end := shl(5, mload(ids)) for { let i := 0 } iszero(eq(i, end)) {} { i := add(i, 0x20) let amount := mload(add(amounts, i)) // Subtract and store the updated balance of `from`. { mstore(0x20, fromSlotSeed) mstore(0x00, mload(add(ids, i))) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, toSlotSeed) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0x40) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, returndatasize())) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) n := sub(add(o, returndatasize()), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_)) } } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, ids, amounts, data); } if (_hasCode(to)) _checkOnERC1155BatchReceived(from, to, ids, amounts, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HOOKS FOR OVERRIDING */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override this function to return true if `_beforeTokenTransfer` is used. /// The is to help the compiler avoid producing dead bytecode. function _useBeforeTokenTransfer() internal view virtual returns (bool) { return false; } /// @dev Hook that is called before any token transfer. /// This includes minting and burning, as well as batched variants. /// /// The same hook is called on both single and batched variants. /// For single transfers, the length of the `id` and `amount` arrays are 1. function _beforeTokenTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} /// @dev Override this function to return true if `_afterTokenTransfer` is used. /// The is to help the compiler avoid producing dead bytecode. function _useAfterTokenTransfer() internal view virtual returns (bool) { return false; } /// @dev Hook that is called after any token transfer. /// This includes minting and burning, as well as batched variants. /// /// The same hook is called on both single and batched variants. /// For single transfers, the length of the `id` and `amount` arrays are 1. function _afterTokenTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Helper for calling the `_afterTokenTransfer` hook. /// The is to help the compiler avoid producing dead bytecode. function _afterTokenTransferCalldata( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) private { if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, ids, amounts, data); } } /// @dev Returns if `a` has bytecode of non-zero length. function _hasCode(address a) private view returns (bool result) { /// @solidity memory-safe-assembly assembly { result := extcodesize(a) // Can handle dirty upper bits. } } /// @dev Perform a call to invoke {IERC1155Receiver-onERC1155Received} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC1155Received( address from, address to, uint256 id, uint256 amount, bytes memory data ) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) // `onERC1155Received(address,address,uint256,uint256,bytes)`. mstore(m, 0xf23a6e61) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), shr(96, shl(96, from))) mstore(add(m, 0x60), id) mstore(add(m, 0x80), amount) mstore(add(m, 0xa0), 0xa0) let n := mload(data) mstore(add(m, 0xc0), n) if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xe0), n)) } // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, n), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } mstore(m, 0) } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xf23a6e61))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } /// @dev Perform a call to invoke {IERC1155Receiver-onERC1155BatchReceived} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC1155BatchReceived( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) // `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`. mstore(m, 0xbc197c81) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), shr(96, shl(96, from))) // Copy the `ids`. mstore(add(m, 0x60), 0xa0) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0xc0) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. let s := add(0xa0, returndatasize()) mstore(add(m, 0x80), s) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) // Copy the `data`. mstore(add(m, 0xa0), add(s, returndatasize())) o := add(o, returndatasize()) n := add(0x20, mload(data)) pop(staticcall(gas(), 4, data, n, o, n)) n := sub(add(o, returndatasize()), add(m, 0x1c)) // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), n, m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } mstore(m, 0) } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xbc197c81))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } /// @dev Returns `x` in an array with a single element. function _single(uint256 x) private pure returns (uint256[] memory result) { assembly { result := mload(0x40) mstore(0x40, add(result, 0x40)) mstore(result, 1) mstore(add(result, 0x20), x) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library to encode strings in Base64. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol) /// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - <[email protected]>. library Base64 { /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// See: https://datatracker.ietf.org/doc/html/rfc4648 /// @param fileSafe Whether to replace '+' with '-' and '/' with '_'. /// @param noPadding Whether to strip away the padding. function encode(bytes memory data, bool fileSafe, bool noPadding) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { // Multiply by 4/3 rounded up. // The `shl(2, ...)` is equivalent to multiplying by 4. let encodedLength := shl(2, div(add(dataLength, 2), 3)) // Set `result` to point to the start of the free memory. result := mload(0x40) // Store the table into the scratch space. // Offsetted by -1 byte so that the `mload` will load the character. // We will rewrite the free memory pointer at `0x40` later with // the allocated size. // The magic constant 0x0230 will translate "-_" + "+/". mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef") mstore(0x3f, sub("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0230))) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, encodedLength) // Run over the input, 3 bytes at a time. for {} 1 {} { data := add(data, 3) // Advance 3 bytes. let input := mload(data) // Write 4 bytes. Optimized for fewer stack operations. mstore8(0, mload(and(shr(18, input), 0x3F))) mstore8(1, mload(and(shr(12, input), 0x3F))) mstore8(2, mload(and(shr(6, input), 0x3F))) mstore8(3, mload(and(input, 0x3F))) mstore(ptr, mload(0x00)) ptr := add(ptr, 4) // Advance 4 bytes. if iszero(lt(ptr, end)) { break } } mstore(0x40, add(end, 0x20)) // Allocate the memory. // Equivalent to `o = [0, 2, 1][dataLength % 3]`. let o := div(2, mod(dataLength, 3)) // Offset `ptr` and pad with '='. We can simply write over the end. mstore(sub(ptr, o), shl(240, 0x3d3d)) // Set `o` to zero if there is padding. o := mul(iszero(iszero(noPadding)), o) mstore(sub(ptr, o), 0) // Zeroize the slot after the string. mstore(result, sub(encodedLength, o)) // Store the length. } } } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, false, false)`. function encode(bytes memory data) internal pure returns (string memory result) { result = encode(data, false, false); } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, fileSafe, false)`. function encode(bytes memory data, bool fileSafe) internal pure returns (string memory result) { result = encode(data, fileSafe, false); } /// @dev Decodes base64 encoded `data`. /// /// Supports: /// - RFC 4648 (both standard and file-safe mode). /// - RFC 3501 (63: ','). /// /// Does not support: /// - Line breaks. /// /// Note: For performance reasons, /// this function will NOT revert on invalid `data` inputs. /// Outputs for invalid inputs will simply be undefined behaviour. /// It is the user's responsibility to ensure that the `data` /// is a valid base64 encoded string. function decode(string memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { let decodedLength := mul(shr(2, dataLength), 3) for {} 1 {} { // If padded. if iszero(and(dataLength, 3)) { let t := xor(mload(add(data, dataLength)), 0x3d3d) // forgefmt: disable-next-item decodedLength := sub( decodedLength, add(iszero(byte(30, t)), iszero(byte(31, t))) ) break } // If non-padded. decodedLength := add(decodedLength, sub(and(dataLength, 3), 1)) break } result := mload(0x40) // Write the length of the bytes. mstore(result, decodedLength) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, decodedLength) // Load the table into the scratch space. // Constants are optimized for smaller bytecode with zero gas overhead. // `m` also doubles as the mask of the upper 6 bits. let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc mstore(0x5b, m) mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064) mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4) for {} 1 {} { // Read 4 bytes. data := add(data, 4) let input := mload(data) // Write 3 bytes. // forgefmt: disable-next-item mstore(ptr, or( and(m, mload(byte(28, input))), shr(6, or( and(m, mload(byte(29, input))), shr(6, or( and(m, mload(byte(30, input))), shr(6, mload(byte(31, input))) )) )) )) ptr := add(ptr, 3) if iszero(lt(ptr, end)) { break } } mstore(0x40, add(end, 0x20)) // Allocate the memory. mstore(end, 0) // Zeroize the slot after the bytes. mstore(0x60, 0) // Restore the zero slot. } } } }
{ "optimizer": { "enabled": true, "runs": 5000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"ArrayLengthsMismatch","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"OnlyMinter","type":"error"},{"inputs":[],"name":"TransferToNonERC1155ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minterAddress","type":"address"}],"name":"MinterAddressSet","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"royaltyFee","type":"uint256"}],"name":"RoyaltyFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[],"name":"animationUrlIPFSCID","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"owners","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"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":"imageIPFSCID","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"royaltyRecipient_","type":"address"},{"internalType":"address","name":"minterAddress_","type":"address"},{"internalType":"uint256","name":"royaltyFee_","type":"uint256"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"string","name":"imageIPFSCID_","type":"string"},{"internalType":"string","name":"animationUrlIPFSCID_","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256[]","name":"ids_","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts_","type":"uint256[]"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"mintBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minterAddress","outputs":[{"internalType":"address","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":"ownershipHandoverValidFor","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"royaltyFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"salePrice_","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"royaltyRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"animationUrlIPFSCID_","type":"string"}],"name":"setAnimationUrlIPFSCID","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"isApproved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"imageIPFSCID_","type":"string"}],"name":"setImageIPFSCID","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minterAddress_","type":"address"}],"name":"setMinterAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"royaltyFee_","type":"uint256"}],"name":"setRoyaltyFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"royaltyRecipient_","type":"address"}],"name":"setRoyaltyRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId_","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5061001961001e565b6100de565b600054610100900460ff161561008a5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811610156100dc576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61241780620000ee6000396000f3fe6080604052600436106101cc5760003560e01c806365401a9c116100f7578063b8997a9711610095578063f04e283e11610064578063f04e283e14610583578063f242432a14610596578063f2fde38b146105b6578063fee81cf4146105c957600080fd5b8063b8997a97146104f6578063d7533f021461050c578063e4e1ff011461052a578063e985e9c51461054a57600080fd5b80638da5cb5b116100d15780638da5cb5b1461047d578063a22cb46514610496578063a3106b95146104b6578063a4a53539146104d657600080fd5b806365401a9c14610435578063715018a614610455578063731133e91461045d57600080fd5b80632eb2c2d61161016f578063498719bc1161013e578063498719bc146103b85780634c00de82146103cd5780634e1273f41461040057806354d1f13d1461042d57600080fd5b80632eb2c2d61461030657806334d722c9146103265780633e4086e51461037857806341e42f301461039857600080fd5b80630e89341c116101ab5780630e89341c146102705780631f7fdffa1461029057806325692962146102b25780632a55205a146102ba57600080fd5b8062fdd58e146101d157806301ffc9a71461021e5780630b497f381461024e575b600080fd5b3480156101dd57600080fd5b5061020b6101ec366004611853565b679a31110384e0b0c96020526014919091526000908152604090205490565b6040519081526020015b60405180910390f35b34801561022a57600080fd5b5061023e61023936600461187d565b6105fc565b6040519015158152602001610215565b34801561025a57600080fd5b50610263610675565b60405161021591906118ea565b34801561027c57600080fd5b5061026361028b36600461191d565b610703565b34801561029c57600080fd5b506102b06102ab366004611a86565b610741565b005b6102b06107a4565b3480156102c657600080fd5b506102da6102d5366004611b1f565b6107f4565b6040805173ffffffffffffffffffffffffffffffffffffffff9093168352602083019190915201610215565b34801561031257600080fd5b506102b0610321366004611bc8565b610840565b34801561033257600080fd5b506001546103539073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610215565b34801561038457600080fd5b506102b061039336600461191d565b610aa5565b3480156103a457600080fd5b506102b06103b3366004611c83565b610ae0565b3480156103c457600080fd5b50610263610b35565b3480156103d957600080fd5b506000546103539062010000900473ffffffffffffffffffffffffffffffffffffffff1681565b34801561040c57600080fd5b5061042061041b366004611c9e565b610b42565b6040516102159190611d0a565b6102b0610bb2565b34801561044157600080fd5b506102b0610450366004611d4e565b610bee565b6102b0610c06565b34801561046957600080fd5b506102b0610478366004611d8b565b610c1a565b34801561048957600080fd5b50638b78c6d81954610353565b3480156104a257600080fd5b506102b06104b1366004611de0565b610c77565b3480156104c257600080fd5b506102b06104d1366004611c83565b610ccd565b3480156104e257600080fd5b506102b06104f1366004611d4e565b610d44565b34801561050257600080fd5b5061020b60025481565b34801561051857600080fd5b506040516202a3008152602001610215565b34801561053657600080fd5b506102b0610545366004611e1c565b610d58565b34801561055657600080fd5b5061023e610565366004611eba565b679a31110384e0b0c96020526014919091526000526034600c205490565b6102b0610591366004611c83565b610f90565b3480156105a257600080fd5b506102b06105b1366004611eed565b610fd0565b6102b06105c4366004611c83565b611157565b3480156105d557600080fd5b5061020b6105e4366004611c83565b63389a75e1600c908152600091909152602090205490565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f2a55205a00000000000000000000000000000000000000000000000000000000148061066f575061066f826301ffc9a760e09190911c90811463d9b67a26821417630e89341c9091141790565b92915050565b6004805461068290611f65565b80601f01602080910402602001604051908101604052809291908181526020018280546106ae90611f65565b80156106fb5780601f106106d0576101008083540402835291602001916106fb565b820191906000526020600020905b8154815290600101906020018083116106de57829003601f168201915b505050505081565b6060600061070f61117e565b905061071a816112cf565b60405160200161072a9190611fd4565b604051602081830303815290604052915050919050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610792576040517f9cdc2ed500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61079e848484846112dd565b50505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b60008060006127106002548561080a9190612019565b6108149190612057565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1693509150505b9250929050565b82851461085557633b800a466000526004601cfd5b8760601b679a31110384e0b0c9178760601b679a31110384e0b0c917816020528160601c99508060601c9850886108945763ea553b346000526004601cfd5b8933146108b757336000526034600c20546108b757634b6e7f186000526004601cfd5b8660051b60005b818114610928578088013584602052818b013560005260406000208054808311156108f15763f4d678b86000526004601cfd5b82900390556020849052604060002080548083018181101561091b576301336cea6000526004601cfd5b90915550506020016108be565b50505050604051604081528560051b602001604082018160208a03823760408201602084810191909152600587901b01910181601f198801823701819003888a337f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8486a45050610997600090565b156109ac576109ac88888888888888886113f7565b863b15610a9b5760405163bc197c81815233602082015288604082015260a060608201528560051b60200160c082018160208a0382378160a00180608085015282820191508660051b602001925082602089038337820160a084015260208401910181601f1986018237018190037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe40160208282601c820160008d5af1610a62573d15610a5d573d6000803e3d6000fd5b600082525b5080517fbc197c810000000000000000000000000000000000000000000000000000000014610a9957639c05499b6000526004601cfd5b505b5050505050505050565b610aad6113fc565b600281905560405181907fc36422dcc77a5c93a5c48743078f8130c9fcc2a0ff893904ee62a3565688117c90600090a250565b610ae86113fc565b6000805473ffffffffffffffffffffffffffffffffffffffff90921662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909216919091179055565b6003805461068290611f65565b6060838214610b5957633b800a466000526004601cfd5b6040519050818152602081018260051b81810160405260005b818114610ba757679a31110384e0b0c98882013560601b17602090815286820135600090815260409020548483015201610b72565b505050949350505050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b610bf66113fc565b6004610c0282826120dd565b5050565b610c0e6113fc565b610c186000611417565b565b60015473ffffffffffffffffffffffffffffffffffffffff163314610c6b576040517f9cdc2ed500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61079e84848484611462565b8015159050679a31110384e0b0c96020523360145281600052806034600c2055806000528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206000a35050565b610cd56113fc565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f09e32743122b4d02dc06c38a35ee1587a02854644d47574bb35a6ef75a22fa9890600090a250565b610d4c6113fc565b6003610c0282826120dd565b600054610100900460ff1615808015610d785750600054600160ff909116105b80610d925750303b158015610d92575060005460ff166001145b610e22576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610e8057600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610e89846114fe565b600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff8a81169190910291909117909155600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001691881691909117905560028590556003610f1684826120dd565b506004610f2383826120dd565b508015610f8757600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b610f986113fc565b63389a75e1600c52806000526020600c208054421115610fc057636f5e88186000526004601cfd5b60009055610fcd81611417565b50565b8560601b679a31110384e0b0c9178560601b679a31110384e0b0c917816020528160601c97508060601c96508661100f5763ea553b346000526004601cfd5b87331461103257336000526034600c205461103257634b6e7f186000526004601cfd5b85600052604060002091508154808611156110555763f4d678b86000526004601cfd5b8581038355508060205260406000209150815485810181811015611081576301336cea6000526004601cfd5b909255505060208390528486337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406000a4843b1561114f5760405163f23a6e61815233602082015286604082015284606082015283608082015260a080820152816020016020840360c08301376020818360c401601c840160008a5af1611119573d15611114573d6000803e3d6000fd5b600081525b80517ff23a6e610000000000000000000000000000000000000000000000000000000014610f8757639c05499b6000526004601cfd5b505050505050565b61115f6113fc565b8060601b61117557637448fbae6000526004601cfd5b610fcd81611417565b606060006112156003805461119290611f65565b80601f01602080910402602001604051908101604052809291908181526020018280546111be90611f65565b801561120b5780601f106111e05761010080835404028352916020019161120b565b820191906000526020600020905b8154815290600101906020018083116111ee57829003601f168201915b5050505050611547565b6112a86004805461122590611f65565b80601f016020809104026020016040519081016040528092919081815260200182805461125190611f65565b801561129e5780601f106112735761010080835404028352916020019161129e565b820191906000526020600020905b81548152906001019060200180831161128157829003601f168201915b5050505050611570565b6040516020016112b99291906121d9565b60408051601f1981840301815291905292915050565b606061066f826000806115a0565b81518351146112f457633b800a466000526004601cfd5b8360601b8061130b5763ea553b346000526004601cfd5b80679a31110384e0b0c917602052835160051b60005b8181146113645760208101905080850151818701516000526040600020805482810181811015611359576301336cea6000526004601cfd5b909155506113219050565b505060405160408152845160051b602001604082018181838960045afa503d60400160208401523d81019050855160051b60200191508181838860045afa50823d8201039150508260601c6000337f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8486a45050506113e1600090565b50833b1561079e5761079e6000858585856116a3565b610a9b565b638b78c6d819543314610c18576382b429006000526004601cfd5b638b78c6d819805473ffffffffffffffffffffffffffffffffffffffff9092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b8360601b806114795763ea553b346000526004601cfd5b679a31110384e0b0c9602052846014528360005260406000208054848101818110156114ad576301336cea6000526004601cfd5b80835550505083600052826020528060601c6000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406000a450833b1561079e5761079e60008585858561177e565b73ffffffffffffffffffffffffffffffffffffffff16638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b60608160405160200161155a919061239c565b6040516020818303038152906040529050919050565b6060815160000361158f57505060408051602081019091526000815290565b8160405160200161155a919061239c565b60608351801561169b576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526102308515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f03603f52602083018181015b6003880197508751603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f811651600353506000518252600482019150808210611610576020016040527f3d3d000000000000000000000000000000000000000000000000000000000000600384066002048083039190915260008615159091029182900352900382525b509392505050565b60405163bc197c8181523360208201528560601b60601c604082015260a06060820152835160051b60200160c082018181838860045afa503d60a0018060808501523d82019150855160051b60200192508282848860045afa503d0160a0840152835160200191503d018181818660045afa50601c83013d82010391505060208282601c850160008a5af1611747573d15611742573d6000803e3d6000fd5b600082525b5080517fbc197c81000000000000000000000000000000000000000000000000000000001461114f57639c05499b6000526004601cfd5b60405163f23a6e6181523360208201528560601b60601c604082015283606082015282608082015260a08082015281518060c083015280156117ca578060e08301826020860160045afa505b6020828260c401601c850160008a5af16117f3573d156117ee573d6000803e3d6000fd5b600082525b5080517ff23a6e61000000000000000000000000000000000000000000000000000000001461114f57639c05499b6000526004601cfd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461184e57600080fd5b919050565b6000806040838503121561186657600080fd5b61186f8361182a565b946020939093013593505050565b60006020828403121561188f57600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146118bf57600080fd5b9392505050565b60005b838110156118e15781810151838201526020016118c9565b50506000910152565b60208152600082518060208401526119098160408501602087016118c6565b601f01601f19169190910160400192915050565b60006020828403121561192f57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561198e5761198e611936565b604052919050565b600082601f8301126119a757600080fd5b8135602067ffffffffffffffff8211156119c3576119c3611936565b8160051b6119d2828201611965565b92835284810182019282810190878511156119ec57600080fd5b83870192505b84831015611a0b578235825291830191908301906119f2565b979650505050505050565b600082601f830112611a2757600080fd5b813567ffffffffffffffff811115611a4157611a41611936565b611a546020601f19601f84011601611965565b818152846020838601011115611a6957600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215611a9c57600080fd5b611aa58561182a565b9350602085013567ffffffffffffffff80821115611ac257600080fd5b611ace88838901611996565b94506040870135915080821115611ae457600080fd5b611af088838901611996565b93506060870135915080821115611b0657600080fd5b50611b1387828801611a16565b91505092959194509250565b60008060408385031215611b3257600080fd5b50508035926020909101359150565b60008083601f840112611b5357600080fd5b50813567ffffffffffffffff811115611b6b57600080fd5b6020830191508360208260051b850101111561083957600080fd5b60008083601f840112611b9857600080fd5b50813567ffffffffffffffff811115611bb057600080fd5b60208301915083602082850101111561083957600080fd5b60008060008060008060008060a0898b031215611be457600080fd5b611bed8961182a565b9750611bfb60208a0161182a565b9650604089013567ffffffffffffffff80821115611c1857600080fd5b611c248c838d01611b41565b909850965060608b0135915080821115611c3d57600080fd5b611c498c838d01611b41565b909650945060808b0135915080821115611c6257600080fd5b50611c6f8b828c01611b86565b999c989b5096995094979396929594505050565b600060208284031215611c9557600080fd5b6118bf8261182a565b60008060008060408587031215611cb457600080fd5b843567ffffffffffffffff80821115611ccc57600080fd5b611cd888838901611b41565b90965094506020870135915080821115611cf157600080fd5b50611cfe87828801611b41565b95989497509550505050565b6020808252825182820181905260009190848201906040850190845b81811015611d4257835183529284019291840191600101611d26565b50909695505050505050565b600060208284031215611d6057600080fd5b813567ffffffffffffffff811115611d7757600080fd5b611d8384828501611a16565b949350505050565b60008060008060808587031215611da157600080fd5b611daa8561182a565b93506020850135925060408501359150606085013567ffffffffffffffff811115611dd457600080fd5b611b1387828801611a16565b60008060408385031215611df357600080fd5b611dfc8361182a565b915060208301358015158114611e1157600080fd5b809150509250929050565b60008060008060008060c08789031215611e3557600080fd5b611e3e8761182a565b9550611e4c6020880161182a565b945060408701359350611e616060880161182a565b9250608087013567ffffffffffffffff80821115611e7e57600080fd5b611e8a8a838b01611a16565b935060a0890135915080821115611ea057600080fd5b50611ead89828a01611a16565b9150509295509295509295565b60008060408385031215611ecd57600080fd5b611ed68361182a565b9150611ee46020840161182a565b90509250929050565b60008060008060008060a08789031215611f0657600080fd5b611f0f8761182a565b9550611f1d6020880161182a565b94506040870135935060608701359250608087013567ffffffffffffffff811115611f4757600080fd5b611f5389828a01611b86565b979a9699509497509295939492505050565b600181811c90821680611f7957607f821691505b602082108103611fb2577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60008151611fca8185602086016118c6565b9290920192915050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081526000825161200c81601d8501602087016118c6565b91909101601d0192915050565b808202811582820484141761066f577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008261208d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b601f8211156120d857600081815260208120601f850160051c810160208610156120b95750805b601f850160051c820191505b8181101561114f578281556001016120c5565b505050565b815167ffffffffffffffff8111156120f7576120f7611936565b61210b816121058454611f65565b84612092565b602080601f83116001811461215e57600084156121285750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855561114f565b600085815260208120601f198616915b8281101561218d5788860151825594840194600190910190840161216e565b50858210156121c957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b7f7b0000000000000000000000000000000000000000000000000000000000000081527f226e616d65223a2022000000000000000000000000000000000000000000000060018201527f526162626974486f6c65205469636b6574000000000000000000000000000000600a82015260007f222c00000000000000000000000000000000000000000000000000000000000080601b8401527f226465736372697074696f6e223a202200000000000000000000000000000000601d8401527f526162626974486f6c65205469636b6574730000000000000000000000000000602d84015280603f8401527f22696d616765223a202200000000000000000000000000000000000000000000604184015284516122fc81604b8601602089016118c6565b808401905081604b8201527f22616e696d6174696f6e5f75726c223a20220000000000000000000000000000604d820152612392612369612340605f840188611fb8565b7f2200000000000000000000000000000000000000000000000000000000000000815260010190565b7f7d00000000000000000000000000000000000000000000000000000000000000815260010190565b9695505050505050565b7f697066733a2f2f000000000000000000000000000000000000000000000000008152600082516123d48160078501602087016118c6565b919091016007019291505056fea264697066735822122054a5056bab36f4f1cacb36222c6e63ce321d5900f606cb129bdefd1dcf6b050264736f6c63430008120033
Deployed Bytecode
0x6080604052600436106101cc5760003560e01c806365401a9c116100f7578063b8997a9711610095578063f04e283e11610064578063f04e283e14610583578063f242432a14610596578063f2fde38b146105b6578063fee81cf4146105c957600080fd5b8063b8997a97146104f6578063d7533f021461050c578063e4e1ff011461052a578063e985e9c51461054a57600080fd5b80638da5cb5b116100d15780638da5cb5b1461047d578063a22cb46514610496578063a3106b95146104b6578063a4a53539146104d657600080fd5b806365401a9c14610435578063715018a614610455578063731133e91461045d57600080fd5b80632eb2c2d61161016f578063498719bc1161013e578063498719bc146103b85780634c00de82146103cd5780634e1273f41461040057806354d1f13d1461042d57600080fd5b80632eb2c2d61461030657806334d722c9146103265780633e4086e51461037857806341e42f301461039857600080fd5b80630e89341c116101ab5780630e89341c146102705780631f7fdffa1461029057806325692962146102b25780632a55205a146102ba57600080fd5b8062fdd58e146101d157806301ffc9a71461021e5780630b497f381461024e575b600080fd5b3480156101dd57600080fd5b5061020b6101ec366004611853565b679a31110384e0b0c96020526014919091526000908152604090205490565b6040519081526020015b60405180910390f35b34801561022a57600080fd5b5061023e61023936600461187d565b6105fc565b6040519015158152602001610215565b34801561025a57600080fd5b50610263610675565b60405161021591906118ea565b34801561027c57600080fd5b5061026361028b36600461191d565b610703565b34801561029c57600080fd5b506102b06102ab366004611a86565b610741565b005b6102b06107a4565b3480156102c657600080fd5b506102da6102d5366004611b1f565b6107f4565b6040805173ffffffffffffffffffffffffffffffffffffffff9093168352602083019190915201610215565b34801561031257600080fd5b506102b0610321366004611bc8565b610840565b34801561033257600080fd5b506001546103539073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610215565b34801561038457600080fd5b506102b061039336600461191d565b610aa5565b3480156103a457600080fd5b506102b06103b3366004611c83565b610ae0565b3480156103c457600080fd5b50610263610b35565b3480156103d957600080fd5b506000546103539062010000900473ffffffffffffffffffffffffffffffffffffffff1681565b34801561040c57600080fd5b5061042061041b366004611c9e565b610b42565b6040516102159190611d0a565b6102b0610bb2565b34801561044157600080fd5b506102b0610450366004611d4e565b610bee565b6102b0610c06565b34801561046957600080fd5b506102b0610478366004611d8b565b610c1a565b34801561048957600080fd5b50638b78c6d81954610353565b3480156104a257600080fd5b506102b06104b1366004611de0565b610c77565b3480156104c257600080fd5b506102b06104d1366004611c83565b610ccd565b3480156104e257600080fd5b506102b06104f1366004611d4e565b610d44565b34801561050257600080fd5b5061020b60025481565b34801561051857600080fd5b506040516202a3008152602001610215565b34801561053657600080fd5b506102b0610545366004611e1c565b610d58565b34801561055657600080fd5b5061023e610565366004611eba565b679a31110384e0b0c96020526014919091526000526034600c205490565b6102b0610591366004611c83565b610f90565b3480156105a257600080fd5b506102b06105b1366004611eed565b610fd0565b6102b06105c4366004611c83565b611157565b3480156105d557600080fd5b5061020b6105e4366004611c83565b63389a75e1600c908152600091909152602090205490565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f2a55205a00000000000000000000000000000000000000000000000000000000148061066f575061066f826301ffc9a760e09190911c90811463d9b67a26821417630e89341c9091141790565b92915050565b6004805461068290611f65565b80601f01602080910402602001604051908101604052809291908181526020018280546106ae90611f65565b80156106fb5780601f106106d0576101008083540402835291602001916106fb565b820191906000526020600020905b8154815290600101906020018083116106de57829003601f168201915b505050505081565b6060600061070f61117e565b905061071a816112cf565b60405160200161072a9190611fd4565b604051602081830303815290604052915050919050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610792576040517f9cdc2ed500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61079e848484846112dd565b50505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b60008060006127106002548561080a9190612019565b6108149190612057565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1693509150505b9250929050565b82851461085557633b800a466000526004601cfd5b8760601b679a31110384e0b0c9178760601b679a31110384e0b0c917816020528160601c99508060601c9850886108945763ea553b346000526004601cfd5b8933146108b757336000526034600c20546108b757634b6e7f186000526004601cfd5b8660051b60005b818114610928578088013584602052818b013560005260406000208054808311156108f15763f4d678b86000526004601cfd5b82900390556020849052604060002080548083018181101561091b576301336cea6000526004601cfd5b90915550506020016108be565b50505050604051604081528560051b602001604082018160208a03823760408201602084810191909152600587901b01910181601f198801823701819003888a337f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8486a45050610997600090565b156109ac576109ac88888888888888886113f7565b863b15610a9b5760405163bc197c81815233602082015288604082015260a060608201528560051b60200160c082018160208a0382378160a00180608085015282820191508660051b602001925082602089038337820160a084015260208401910181601f1986018237018190037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe40160208282601c820160008d5af1610a62573d15610a5d573d6000803e3d6000fd5b600082525b5080517fbc197c810000000000000000000000000000000000000000000000000000000014610a9957639c05499b6000526004601cfd5b505b5050505050505050565b610aad6113fc565b600281905560405181907fc36422dcc77a5c93a5c48743078f8130c9fcc2a0ff893904ee62a3565688117c90600090a250565b610ae86113fc565b6000805473ffffffffffffffffffffffffffffffffffffffff90921662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909216919091179055565b6003805461068290611f65565b6060838214610b5957633b800a466000526004601cfd5b6040519050818152602081018260051b81810160405260005b818114610ba757679a31110384e0b0c98882013560601b17602090815286820135600090815260409020548483015201610b72565b505050949350505050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b610bf66113fc565b6004610c0282826120dd565b5050565b610c0e6113fc565b610c186000611417565b565b60015473ffffffffffffffffffffffffffffffffffffffff163314610c6b576040517f9cdc2ed500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61079e84848484611462565b8015159050679a31110384e0b0c96020523360145281600052806034600c2055806000528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206000a35050565b610cd56113fc565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f09e32743122b4d02dc06c38a35ee1587a02854644d47574bb35a6ef75a22fa9890600090a250565b610d4c6113fc565b6003610c0282826120dd565b600054610100900460ff1615808015610d785750600054600160ff909116105b80610d925750303b158015610d92575060005460ff166001145b610e22576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610e8057600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610e89846114fe565b600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff8a81169190910291909117909155600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001691881691909117905560028590556003610f1684826120dd565b506004610f2383826120dd565b508015610f8757600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b610f986113fc565b63389a75e1600c52806000526020600c208054421115610fc057636f5e88186000526004601cfd5b60009055610fcd81611417565b50565b8560601b679a31110384e0b0c9178560601b679a31110384e0b0c917816020528160601c97508060601c96508661100f5763ea553b346000526004601cfd5b87331461103257336000526034600c205461103257634b6e7f186000526004601cfd5b85600052604060002091508154808611156110555763f4d678b86000526004601cfd5b8581038355508060205260406000209150815485810181811015611081576301336cea6000526004601cfd5b909255505060208390528486337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406000a4843b1561114f5760405163f23a6e61815233602082015286604082015284606082015283608082015260a080820152816020016020840360c08301376020818360c401601c840160008a5af1611119573d15611114573d6000803e3d6000fd5b600081525b80517ff23a6e610000000000000000000000000000000000000000000000000000000014610f8757639c05499b6000526004601cfd5b505050505050565b61115f6113fc565b8060601b61117557637448fbae6000526004601cfd5b610fcd81611417565b606060006112156003805461119290611f65565b80601f01602080910402602001604051908101604052809291908181526020018280546111be90611f65565b801561120b5780601f106111e05761010080835404028352916020019161120b565b820191906000526020600020905b8154815290600101906020018083116111ee57829003601f168201915b5050505050611547565b6112a86004805461122590611f65565b80601f016020809104026020016040519081016040528092919081815260200182805461125190611f65565b801561129e5780601f106112735761010080835404028352916020019161129e565b820191906000526020600020905b81548152906001019060200180831161128157829003601f168201915b5050505050611570565b6040516020016112b99291906121d9565b60408051601f1981840301815291905292915050565b606061066f826000806115a0565b81518351146112f457633b800a466000526004601cfd5b8360601b8061130b5763ea553b346000526004601cfd5b80679a31110384e0b0c917602052835160051b60005b8181146113645760208101905080850151818701516000526040600020805482810181811015611359576301336cea6000526004601cfd5b909155506113219050565b505060405160408152845160051b602001604082018181838960045afa503d60400160208401523d81019050855160051b60200191508181838860045afa50823d8201039150508260601c6000337f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8486a45050506113e1600090565b50833b1561079e5761079e6000858585856116a3565b610a9b565b638b78c6d819543314610c18576382b429006000526004601cfd5b638b78c6d819805473ffffffffffffffffffffffffffffffffffffffff9092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b8360601b806114795763ea553b346000526004601cfd5b679a31110384e0b0c9602052846014528360005260406000208054848101818110156114ad576301336cea6000526004601cfd5b80835550505083600052826020528060601c6000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406000a450833b1561079e5761079e60008585858561177e565b73ffffffffffffffffffffffffffffffffffffffff16638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b60608160405160200161155a919061239c565b6040516020818303038152906040529050919050565b6060815160000361158f57505060408051602081019091526000815290565b8160405160200161155a919061239c565b60608351801561169b576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526102308515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f03603f52602083018181015b6003880197508751603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f811651600353506000518252600482019150808210611610576020016040527f3d3d000000000000000000000000000000000000000000000000000000000000600384066002048083039190915260008615159091029182900352900382525b509392505050565b60405163bc197c8181523360208201528560601b60601c604082015260a06060820152835160051b60200160c082018181838860045afa503d60a0018060808501523d82019150855160051b60200192508282848860045afa503d0160a0840152835160200191503d018181818660045afa50601c83013d82010391505060208282601c850160008a5af1611747573d15611742573d6000803e3d6000fd5b600082525b5080517fbc197c81000000000000000000000000000000000000000000000000000000001461114f57639c05499b6000526004601cfd5b60405163f23a6e6181523360208201528560601b60601c604082015283606082015282608082015260a08082015281518060c083015280156117ca578060e08301826020860160045afa505b6020828260c401601c850160008a5af16117f3573d156117ee573d6000803e3d6000fd5b600082525b5080517ff23a6e61000000000000000000000000000000000000000000000000000000001461114f57639c05499b6000526004601cfd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461184e57600080fd5b919050565b6000806040838503121561186657600080fd5b61186f8361182a565b946020939093013593505050565b60006020828403121561188f57600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146118bf57600080fd5b9392505050565b60005b838110156118e15781810151838201526020016118c9565b50506000910152565b60208152600082518060208401526119098160408501602087016118c6565b601f01601f19169190910160400192915050565b60006020828403121561192f57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561198e5761198e611936565b604052919050565b600082601f8301126119a757600080fd5b8135602067ffffffffffffffff8211156119c3576119c3611936565b8160051b6119d2828201611965565b92835284810182019282810190878511156119ec57600080fd5b83870192505b84831015611a0b578235825291830191908301906119f2565b979650505050505050565b600082601f830112611a2757600080fd5b813567ffffffffffffffff811115611a4157611a41611936565b611a546020601f19601f84011601611965565b818152846020838601011115611a6957600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215611a9c57600080fd5b611aa58561182a565b9350602085013567ffffffffffffffff80821115611ac257600080fd5b611ace88838901611996565b94506040870135915080821115611ae457600080fd5b611af088838901611996565b93506060870135915080821115611b0657600080fd5b50611b1387828801611a16565b91505092959194509250565b60008060408385031215611b3257600080fd5b50508035926020909101359150565b60008083601f840112611b5357600080fd5b50813567ffffffffffffffff811115611b6b57600080fd5b6020830191508360208260051b850101111561083957600080fd5b60008083601f840112611b9857600080fd5b50813567ffffffffffffffff811115611bb057600080fd5b60208301915083602082850101111561083957600080fd5b60008060008060008060008060a0898b031215611be457600080fd5b611bed8961182a565b9750611bfb60208a0161182a565b9650604089013567ffffffffffffffff80821115611c1857600080fd5b611c248c838d01611b41565b909850965060608b0135915080821115611c3d57600080fd5b611c498c838d01611b41565b909650945060808b0135915080821115611c6257600080fd5b50611c6f8b828c01611b86565b999c989b5096995094979396929594505050565b600060208284031215611c9557600080fd5b6118bf8261182a565b60008060008060408587031215611cb457600080fd5b843567ffffffffffffffff80821115611ccc57600080fd5b611cd888838901611b41565b90965094506020870135915080821115611cf157600080fd5b50611cfe87828801611b41565b95989497509550505050565b6020808252825182820181905260009190848201906040850190845b81811015611d4257835183529284019291840191600101611d26565b50909695505050505050565b600060208284031215611d6057600080fd5b813567ffffffffffffffff811115611d7757600080fd5b611d8384828501611a16565b949350505050565b60008060008060808587031215611da157600080fd5b611daa8561182a565b93506020850135925060408501359150606085013567ffffffffffffffff811115611dd457600080fd5b611b1387828801611a16565b60008060408385031215611df357600080fd5b611dfc8361182a565b915060208301358015158114611e1157600080fd5b809150509250929050565b60008060008060008060c08789031215611e3557600080fd5b611e3e8761182a565b9550611e4c6020880161182a565b945060408701359350611e616060880161182a565b9250608087013567ffffffffffffffff80821115611e7e57600080fd5b611e8a8a838b01611a16565b935060a0890135915080821115611ea057600080fd5b50611ead89828a01611a16565b9150509295509295509295565b60008060408385031215611ecd57600080fd5b611ed68361182a565b9150611ee46020840161182a565b90509250929050565b60008060008060008060a08789031215611f0657600080fd5b611f0f8761182a565b9550611f1d6020880161182a565b94506040870135935060608701359250608087013567ffffffffffffffff811115611f4757600080fd5b611f5389828a01611b86565b979a9699509497509295939492505050565b600181811c90821680611f7957607f821691505b602082108103611fb2577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60008151611fca8185602086016118c6565b9290920192915050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081526000825161200c81601d8501602087016118c6565b91909101601d0192915050565b808202811582820484141761066f577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008261208d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b601f8211156120d857600081815260208120601f850160051c810160208610156120b95750805b601f850160051c820191505b8181101561114f578281556001016120c5565b505050565b815167ffffffffffffffff8111156120f7576120f7611936565b61210b816121058454611f65565b84612092565b602080601f83116001811461215e57600084156121285750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855561114f565b600085815260208120601f198616915b8281101561218d5788860151825594840194600190910190840161216e565b50858210156121c957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b7f7b0000000000000000000000000000000000000000000000000000000000000081527f226e616d65223a2022000000000000000000000000000000000000000000000060018201527f526162626974486f6c65205469636b6574000000000000000000000000000000600a82015260007f222c00000000000000000000000000000000000000000000000000000000000080601b8401527f226465736372697074696f6e223a202200000000000000000000000000000000601d8401527f526162626974486f6c65205469636b6574730000000000000000000000000000602d84015280603f8401527f22696d616765223a202200000000000000000000000000000000000000000000604184015284516122fc81604b8601602089016118c6565b808401905081604b8201527f22616e696d6174696f6e5f75726c223a20220000000000000000000000000000604d820152612392612369612340605f840188611fb8565b7f2200000000000000000000000000000000000000000000000000000000000000815260010190565b7f7d00000000000000000000000000000000000000000000000000000000000000815260010190565b9695505050505050565b7f697066733a2f2f000000000000000000000000000000000000000000000000008152600082516123d48160078501602087016118c6565b919091016007019291505056fea264697066735822122054a5056bab36f4f1cacb36222c6e63ce321d5900f606cb129bdefd1dcf6b050264736f6c63430008120033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.