Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
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
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.