Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
Cross-Chain Transactions
Loading...
Loading
Contract Name:
RabbitHoleTickets
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 1000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;
import {Ownable} from "solady/auth/Ownable.sol";
import {ERC1155} from "solady/tokens/ERC1155.sol";
import {Base64} from "solady/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 {
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error OnlyMinter();
event RoyaltyFeeSet(uint256 indexed royaltyFee);
event MinterAddressSet(address indexed minterAddress);
/*//////////////////////////////////////////////////////////////
STORAGE
//////////////////////////////////////////////////////////////*/
address public royaltyRecipient;
address public minterAddress;
uint256 public royaltyFee;
string public imageIPFSCID;
string public animationUrlIPFSCID;
// insert new vars here at the end to keep the storage layout the same
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
/// @custom:oz-upgrades-unsafe-allow constructor
// solhint-disable-next-line func-visibility
constructor() {
_disableInitializers();
}
function initialize(
address royaltyRecipient_,
address minterAddress_,
uint256 royaltyFee_,
address owner_,
string memory imageIPFSCID_,
string memory animationUrlIPFSCID_
) external initializer {
_initializeOwner(owner_);
royaltyRecipient = royaltyRecipient_;
minterAddress = minterAddress_;
royaltyFee = royaltyFee_;
imageIPFSCID = imageIPFSCID_;
animationUrlIPFSCID = animationUrlIPFSCID_;
}
/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
modifier onlyMinter() {
if (msg.sender != minterAddress) revert OnlyMinter();
_;
}
/*//////////////////////////////////////////////////////////////
EXTERNAL UPDATE
//////////////////////////////////////////////////////////////*/
/*//////////////////////////////////////////////////////////////
MINT
//////////////////////////////////////////////////////////////*/
/// @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_);
}
/*//////////////////////////////////////////////////////////////
SET
//////////////////////////////////////////////////////////////*/
/// @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 image IPFS CID
/// @param imageIPFSCID_ the image IPFS CID
function setImageIPFSCID(string memory imageIPFSCID_) external onlyOwner {
imageIPFSCID = imageIPFSCID_;
}
/// @dev set the minter address
/// @param minterAddress_ the address of the minter
function setMinterAddress(address minterAddress_) external onlyOwner {
minterAddress = minterAddress_;
emit MinterAddressSet(minterAddress_);
}
/// @dev set the royalty fee
/// @param royaltyFee_ the royalty fee
function setRoyaltyFee(uint256 royaltyFee_) external onlyOwner {
royaltyFee = royaltyFee_;
emit RoyaltyFeeSet(royaltyFee_);
}
/// @dev set the royalty recipient
/// @param royaltyRecipient_ the address of the royalty recipient
function setRoyaltyRecipient(address royaltyRecipient_) external onlyOwner {
royaltyRecipient = royaltyRecipient_;
}
/*//////////////////////////////////////////////////////////////
EXTERNAL VIEW
//////////////////////////////////////////////////////////////*/
/// @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_);
}
/// @dev returns the token uri
function uri(uint256 tokenId_) public view override (ERC1155) returns (string memory) {
bytes memory dataURI = generateDataURI(tokenId_);
return string(abi.encodePacked("data:application/json;base64,", Base64.encode(dataURI)));
}
/*//////////////////////////////////////////////////////////////
INTERNAL VIEW
//////////////////////////////////////////////////////////////*/
/// @dev returns the data uri in json format
function generateDataURI(uint256 tokenId_) internal view virtual returns (bytes memory) {
// solhint-disable quotes
bytes memory dataURI = abi.encodePacked(
"{",
'"name": "',
getNameForToken(tokenId_),
'",',
'"description": "',
getDescriptionForToken(tokenId_),
'",',
'"image": "',
makeIPFSUrl(getImageCidForToken(tokenId_)),
'",',
'"animation_url": "',
makeIPFSUrl(getAnimationCidForToken(tokenId_)),
'"',
"}"
);
// solhint-enable quotes
return dataURI;
}
function getNameForToken(uint256 tokenId_) internal view virtual returns (string memory) {
if(tokenId_ == 2) {
return "2023 RabbitHole Holiday Reward";
} else {
return "RabbitHole Ticket";
}
}
function getDescriptionForToken(uint256 tokenId_) internal view virtual returns (string memory) {
if(tokenId_ == 2) {
return "You unwrapped a Christmas gift from RabbitHole for being a loyal member and completing our 2023 Holiday campaign";
} else {
return "RabbitHole Tickets";
}
}
function getAnimationCidForToken(uint256 tokenId_) internal view virtual returns (string memory) {
if(tokenId_ == 2) {
return "bafybeig7sfklww3qsd2yah4tottv6ewvroad5cqidvxswtdrblzvd7gf64";
} else {
return animationUrlIPFSCID;
}
}
function getImageCidForToken(uint256 tokenId_) internal view virtual returns (string memory) {
if(tokenId_ == 2) {
return "bafybeigoo4rnwlmeyyq2rgcteqb3srxaida24jpiedxsoqa7cvpbjhnzni";
} else {
return imageIPFSCID;
}
}
function makeIPFSUrl(string memory ipfsCid_) internal view virtual returns (string memory) {
if (bytes(ipfsCid_).length == 0) {
return "";
}
return string(abi.encodePacked("ipfs://", ipfsCid_));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The caller is not authorized to call the function.
error Unauthorized();
/// @dev The `newOwner` cannot be the zero address.
error NewOwnerIsZeroAddress();
/// @dev The `pendingOwner` does not have a valid handover request.
error NoHandoverRequest();
/// @dev Cannot double-initialize.
error AlreadyInitialized();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ownership is transferred from `oldOwner` to `newOwner`.
/// This event is intentionally kept the same as OpenZeppelin's Ownable to be
/// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
/// despite it not being as lightweight as a single argument event.
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
/// @dev An ownership handover to `pendingOwner` has been requested.
event OwnershipHandoverRequested(address indexed pendingOwner);
/// @dev The ownership handover to `pendingOwner` has been canceled.
event OwnershipHandoverCanceled(address indexed pendingOwner);
/// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;
/// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;
/// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The owner slot is given by:
/// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`.
/// It is intentionally chosen to be a high value
/// to avoid collision with lower slots.
/// The choice of manual storage layout is to enable compatibility
/// with both regular and upgradeable contracts.
bytes32 internal constant _OWNER_SLOT =
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;
/// The ownership handover slot of `newOwner` is given by:
/// ```
/// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
/// let handoverSlot := keccak256(0x00, 0x20)
/// ```
/// It stores the expiry timestamp of the two-step ownership handover.
uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Override to return true to make `_initializeOwner` prevent double-initialization.
function _guardInitializeOwner() internal pure virtual returns (bool guard) {}
/// @dev Initializes the owner directly without authorization guard.
/// This function must be called upon initialization,
/// regardless of whether the contract is upgradeable or not.
/// This is to enable generalization to both regular and upgradeable contracts,
/// and to save gas in case the initial owner is not the caller.
/// For performance reasons, this function will not check if there
/// is an existing owner.
function _initializeOwner(address newOwner) internal virtual {
if (_guardInitializeOwner()) {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
if sload(ownerSlot) {
mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.
revert(0x1c, 0x04)
}
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Store the new value.
sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
} else {
/// @solidity memory-safe-assembly
assembly {
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Store the new value.
sstore(_OWNER_SLOT, newOwner)
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
}
}
/// @dev Sets the owner directly without authorization guard.
function _setOwner(address newOwner) internal virtual {
if (_guardInitializeOwner()) {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
// Store the new value.
sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
}
} else {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
// Store the new value.
sstore(ownerSlot, newOwner)
}
}
}
/// @dev Throws if the sender is not the owner.
function _checkOwner() internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// If the caller is not the stored owner, revert.
if iszero(eq(caller(), sload(_OWNER_SLOT))) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Returns how long a two-step ownership handover is valid for in seconds.
/// Override to return a different value if needed.
/// Made internal to conserve bytecode. Wrap it in a public function if needed.
function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
return 48 * 3600;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC UPDATE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Allows the owner to transfer the ownership to `newOwner`.
function transferOwnership(address newOwner) public payable virtual onlyOwner {
/// @solidity memory-safe-assembly
assembly {
if iszero(shl(96, newOwner)) {
mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
revert(0x1c, 0x04)
}
}
_setOwner(newOwner);
}
/// @dev Allows the owner to renounce their ownership.
function renounceOwnership() public payable virtual onlyOwner {
_setOwner(address(0));
}
/// @dev Request a two-step ownership handover to the caller.
/// The request will automatically expire in 48 hours (172800 seconds) by default.
function requestOwnershipHandover() public payable virtual {
unchecked {
uint256 expires = block.timestamp + _ownershipHandoverValidFor();
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to `expires`.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), expires)
// Emit the {OwnershipHandoverRequested} event.
log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
}
}
}
/// @dev Cancels the two-step ownership handover to the caller, if any.
function cancelOwnershipHandover() public payable virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), 0)
// Emit the {OwnershipHandoverCanceled} event.
log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
}
}
/// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
/// Reverts if there is no existing ownership handover requested by `pendingOwner`.
function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
let handoverSlot := keccak256(0x0c, 0x20)
// If the handover does not exist, or has expired.
if gt(timestamp(), sload(handoverSlot)) {
mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
revert(0x1c, 0x04)
}
// Set the handover slot to 0.
sstore(handoverSlot, 0)
}
_setOwner(pendingOwner);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC READ FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the owner of the contract.
function owner() public view virtual returns (address result) {
/// @solidity memory-safe-assembly
assembly {
result := sload(_OWNER_SLOT)
}
}
/// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
function ownershipHandoverExpiresAt(address pendingOwner)
public
view
virtual
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
// Compute the handover slot.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
// Load the handover slot.
result := sload(keccak256(0x0c, 0x20))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MODIFIERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Marks a function as only callable by the owner.
modifier onlyOwner() virtual {
_checkOwner();
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice 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.
/// - The transfer functions use the identity precompile (0x4)
/// to copy memory internally.
///
/// If you are overriding:
/// - Make sure all variables written to storage are properly cleaned
// (e.g. the bool value for `isApprovedForAll` MUST be either 1 or 0 under the hood).
/// - Check that the overridden function is actually used in the function you want to
/// change the behavior of. Much of the code has been manually inlined for performance.
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(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
// 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.
{
for { let i := shl(5, ids.length) } i {} {
i := sub(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))
calldatacopy(add(o, n), sub(amounts.offset, 0x20), n)
// Do the emit.
log4(m, add(add(n, n), 0x40), _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) {
mstore(0x00, to) // Cache `to` to prevent stack too deep.
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)
calldatacopy(add(o, n), sub(amounts.offset, 0x20), n)
// Copy the `data`.
mstore(add(m, 0xa0), add(s, n))
calldatacopy(add(o, add(n, n)), sub(data.offset, 0x20), add(0x20, data.length))
let nAll := add(0xc4, add(data.length, add(n, n)))
// Revert if the call reverts.
if iszero(call(gas(), mload(0x00), 0, add(m, 0x1c), nAll, m, 0x20)) {
if returndatasize() {
// Bubble up the revert if the call reverts.
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
// 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 i := shl(5, ids.length)
mstore(0x40, add(i, o))
// Loop through all the `ids` and load the balances.
for {} i {} {
i := sub(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(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_))
for { let i := shl(5, mload(ids)) } i { i := sub(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(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.
{
for { let i := shl(5, mload(ids)) } i { i := sub(i, 0x20) } {
let amount := mload(add(amounts, i))
// Decrease and store the updated balance of `from`.
{
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.
{
for { let i := shl(5, mload(ids)) } i { i := sub(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.
/// This 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.
/// This 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.
/// This 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(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
// 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(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
// 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) {
/// @solidity memory-safe-assembly
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 0x0670 will turn "-_" into "+/". mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef") mstore(0x3f, xor("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0670))) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, encodedLength) // Run over the input, 3 bytes at a time. for {} 1 {} { data := add(data, 3) // Advance 3 bytes. let input := mload(data) // Write 4 bytes. Optimized for fewer stack operations. mstore8(0, mload(and(shr(18, input), 0x3F))) mstore8(1, mload(and(shr(12, input), 0x3F))) mstore8(2, mload(and(shr(6, input), 0x3F))) mstore8(3, mload(and(input, 0x3F))) mstore(ptr, mload(0x00)) ptr := add(ptr, 4) // Advance 4 bytes. if iszero(lt(ptr, end)) { break } } mstore(0x40, add(end, 0x20)) // Allocate the memory. // Equivalent to `o = [0, 2, 1][dataLength % 3]`. let o := div(2, mod(dataLength, 3)) // Offset `ptr` and pad with '='. We can simply write over the end. mstore(sub(ptr, o), shl(240, 0x3d3d)) // Set `o` to zero if there is padding. o := mul(iszero(iszero(noPadding)), o) mstore(sub(ptr, o), 0) // Zeroize the slot after the string. mstore(result, sub(encodedLength, o)) // Store the length. } } } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, false, false)`. function encode(bytes memory data) internal pure returns (string memory result) { result = encode(data, false, false); } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, fileSafe, false)`. function encode(bytes memory data, bool fileSafe) internal pure returns (string memory result) { result = encode(data, fileSafe, false); } /// @dev Decodes base64 encoded `data`. /// /// Supports: /// - RFC 4648 (both standard and file-safe mode). /// - RFC 3501 (63: ','). /// /// Does not support: /// - Line breaks. /// /// Note: For performance reasons, /// this function will NOT revert on invalid `data` inputs. /// Outputs for invalid inputs will simply be undefined behaviour. /// It is the user's responsibility to ensure that the `data` /// is a valid base64 encoded string. function decode(string memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { let decodedLength := mul(shr(2, dataLength), 3) for {} 1 {} { // If padded. if iszero(and(dataLength, 3)) { let t := xor(mload(add(data, dataLength)), 0x3d3d) // forgefmt: disable-next-item decodedLength := sub( decodedLength, add(iszero(byte(30, t)), iszero(byte(31, t))) ) break } // If non-padded. decodedLength := add(decodedLength, sub(and(dataLength, 3), 1)) break } result := mload(0x40) // Write the length of the bytes. mstore(result, decodedLength) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, decodedLength) // Load the table into the scratch space. // Constants are optimized for smaller bytecode with zero gas overhead. // `m` also doubles as the mask of the upper 6 bits. let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc mstore(0x5b, m) mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064) mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4) for {} 1 {} { // Read 4 bytes. data := add(data, 4) let input := mload(data) // Write 3 bytes. // forgefmt: disable-next-item mstore(ptr, or( and(m, mload(byte(28, input))), shr(6, or( and(m, mload(byte(29, input))), shr(6, or( and(m, mload(byte(30, input))), shr(6, mload(byte(31, input))) )) )) )) ptr := add(ptr, 3) if iszero(lt(ptr, end)) { break } } mstore(0x40, add(end, 0x20)) // Allocate the memory. mstore(end, 0) // Zeroize the slot after the bytes. mstore(0x60, 0) // Restore the zero slot. } } } }
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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]
* ```solidity
* 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 Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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.9.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
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [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://consensys.net/diligence/blog/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.8.0/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 Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"remappings": [
"forge-std/=lib/forge-std/src/",
"solady/=lib/solady/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"sablier/=lib/v2-core/src/",
"@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/",
"@prb/math/=lib/v2-core/lib/prb-math/",
"@prb/test/=lib/v2-core/lib/prb-test/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/",
"prb-math/=lib/v2-core/lib/prb-math/src/",
"prb-test/=lib/v2-core/lib/prb-test/src/",
"solarray/=lib/v2-core/lib/solarray/src/",
"v2-core/=lib/v2-core/"
],
"optimizer": {
"enabled": true,
"runs": 1000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"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":"AlreadyInitialized","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":"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":"tokenId_","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b5061001961001e565b6100dd565b600054610100900460ff161561008a5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116146100db576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6122cd80620000ed6000396000f3fe6080604052600436106101c15760003560e01c806354d1f13d116100f7578063a4a5353911610095578063f04e283e11610064578063f04e283e14610526578063f242432a14610539578063f2fde38b14610559578063fee81cf41461056c57600080fd5b8063a4a5353914610497578063b8997a97146104b7578063e4e1ff01146104cd578063e985e9c5146104ed57600080fd5b8063731133e9116100d1578063731133e91461041e5780638da5cb5b1461043e578063a22cb46514610457578063a3106b951461047757600080fd5b806354d1f13d146103ee57806365401a9c146103f6578063715018a61461041657600080fd5b80632eb2c2d61161016457806341e42f301161013e57806341e42f3014610366578063498719bc146103865780634c00de821461039b5780634e1273f4146103c157600080fd5b80632eb2c2d6146102ee57806334d722c91461030e5780633e4086e51461034657600080fd5b80630e89341c116101a05780630e89341c146102655780631f7fdffa1461028557806325692962146102a75780632a55205a146102af57600080fd5b8062fdd58e146101c657806301ffc9a7146102135780630b497f3814610243575b600080fd5b3480156101d257600080fd5b506102006101e13660046116e7565b679a31110384e0b0c96020526014919091526000908152604090205490565b6040519081526020015b60405180910390f35b34801561021f57600080fd5b5061023361022e366004611711565b61059f565b604051901515815260200161020a565b34801561024f57600080fd5b50610258610618565b60405161020a919061177e565b34801561027157600080fd5b506102586102803660046117b1565b6106a6565b34801561029157600080fd5b506102a56102a0366004611901565b6106e5565b005b6102a5610722565b3480156102bb57600080fd5b506102cf6102ca36600461199a565b610772565b604080516001600160a01b03909316835260208301919091520161020a565b3480156102fa57600080fd5b506102a5610309366004611a43565b6107b1565b34801561031a57600080fd5b5060015461032e906001600160a01b031681565b6040516001600160a01b03909116815260200161020a565b34801561035257600080fd5b506102a56103613660046117b1565b6109cd565b34801561037257600080fd5b506102a5610381366004611afe565b610a08565b34801561039257600080fd5b50610258610a47565b3480156103a757600080fd5b5060005461032e906201000090046001600160a01b031681565b3480156103cd57600080fd5b506103e16103dc366004611b19565b610a54565b60405161020a9190611b85565b6102a5610ac4565b34801561040257600080fd5b506102a5610411366004611bc9565b610b00565b6102a5610b18565b34801561042a57600080fd5b506102a5610439366004611c06565b610b2c565b34801561044a57600080fd5b50638b78c6d8195461032e565b34801561046357600080fd5b506102a5610472366004611c5b565b610b63565b34801561048357600080fd5b506102a5610492366004611afe565b610bb9565b3480156104a357600080fd5b506102a56104b2366004611bc9565b610c18565b3480156104c357600080fd5b5061020060025481565b3480156104d957600080fd5b506102a56104e8366004611c97565b610c2c565b3480156104f957600080fd5b50610233610508366004611d35565b679a31110384e0b0c96020526014919091526000526034600c205490565b6102a5610534366004611afe565b610deb565b34801561054557600080fd5b506102a5610554366004611d68565b610e2b565b6102a5610567366004611afe565b610f93565b34801561057857600080fd5b50610200610587366004611afe565b63389a75e1600c908152600091909152602090205490565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f2a55205a0000000000000000000000000000000000000000000000000000000014806106125750610612826301ffc9a760e09190911c90811463d9b67a26821417630e89341c9091141790565b92915050565b6004805461062590611de0565b80601f016020809104026020016040519081016040528092919081815260200182805461065190611de0565b801561069e5780601f106106735761010080835404028352916020019161069e565b820191906000526020600020905b81548152906001019060200180831161068157829003601f168201915b505050505081565b606060006106b383610fba565b90506106be81611017565b6040516020016106ce9190611e36565b604051602081830303815290604052915050919050565b6001546001600160a01b0316331461071057604051639cdc2ed560e01b815260040160405180910390fd5b61071c84848484611025565b50505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b6000806000612710600254856107889190611e7b565b6107929190611ea0565b6000546201000090046001600160a01b031693509150505b9250929050565b8285146107c657633b800a466000526004601cfd5b8760601b679a31110384e0b0c9178760601b679a31110384e0b0c917816020528160601c99508060601c9850886108055763ea553b346000526004601cfd5b89331461082857336000526034600c205461082857634b6e7f186000526004601cfd5b8660051b5b801561089a576020810390508087013583602052818a013560005260406000208054808311156108655763f4d678b86000526004601cfd5b82900390556020839052604060002080548083018181101561088f576301336cea6000526004601cfd5b9091555061082d9050565b505050604051604081528560051b602001604082018160208a03823781604001602084015281602088038383013750888a337f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb60408586010186a450506108ff600090565b15610914576109148888888888888888611138565b863b156109c3578660005260405163bc197c81815233602082015288604082015260a060608201528560051b60200160c082018160208a0382378160a001806080850152826020890384840137820160a084015260208401601f19860183800183013750808101830160c401905060208282601c8501600080515af16109a3573d156109a3573d6000833e3d82fd5b50805163bc197c8160e01b146109c157639c05499b6000526004601cfd5b505b5050505050505050565b6109d561113d565b600281905560405181907fc36422dcc77a5c93a5c48743078f8130c9fcc2a0ff893904ee62a3565688117c90600090a250565b610a1061113d565b600080546001600160a01b03909216620100000275ffffffffffffffffffffffffffffffffffffffff000019909216919091179055565b6003805461062590611de0565b6060838214610a6b57633b800a466000526004601cfd5b6040519050818152602081018260051b8181016040525b8015610aba57602081039050808701358060601b679a31110384e0b0c917602052508085013560005260406000205481830152610a82565b5050949350505050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b610b0861113d565b6004610b148282611f0d565b5050565b610b2061113d565b610b2a6000611158565b565b6001546001600160a01b03163314610b5757604051639cdc2ed560e01b815260040160405180910390fd5b61071c84848484611196565b8015159050679a31110384e0b0c96020523360145281600052806034600c2055806000528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206000a35050565b610bc161113d565b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f09e32743122b4d02dc06c38a35ee1587a02854644d47574bb35a6ef75a22fa9890600090a250565b610c2061113d565b6003610b148282611f0d565b600054610100900460ff1615808015610c4c5750600054600160ff909116105b80610c665750303b158015610c66575060005460ff166001145b610cf6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b6000805460ff191660011790558015610d19576000805461ff0019166101001790555b610d228461122e565b6000805475ffffffffffffffffffffffffffffffffffffffff00001916620100006001600160a01b038a811691909102919091179091556001805473ffffffffffffffffffffffffffffffffffffffff191691881691909117905560028590556003610d8e8482611f0d565b506004610d9b8382611f0d565b508015610de2576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b610df361113d565b63389a75e1600c52806000526020600c208054421115610e1b57636f5e88186000526004601cfd5b60009055610e2881611158565b50565b8560601b679a31110384e0b0c9178560601b679a31110384e0b0c917816020528160601c97508060601c965086610e6a5763ea553b346000526004601cfd5b873314610e8d57336000526034600c2054610e8d57634b6e7f186000526004601cfd5b8560005260406000209150815480861115610eb05763f4d678b86000526004601cfd5b8581038355508060205260406000209150815485810181811015610edc576301336cea6000526004601cfd5b909255505060208390528486337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406000a4843b15610f8b5760405163f23a6e61815233602082015286604082015284606082015283608082015260a080820152816020016020840360c08301376020818360c401601c840160008a5af1610f6e573d15610f6e573d6000823e3d81fd5b805163f23a6e6160e01b14610de257639c05499b6000526004601cfd5b505050505050565b610f9b61113d565b8060601b610fb157637448fbae6000526004601cfd5b610e2881611158565b60606000610fc78361126a565b610fd0846112eb565b610fe1610fdc8661134d565b611408565b610fed610fdc8761144e565b6040516020016110009493929190611fcd565b60408051601f198184030181529190529392505050565b606061061282600080611484565b815183511461103c57633b800a466000526004601cfd5b8360601b806110535763ea553b346000526004601cfd5b80679a31110384e0b0c917602052835160051b5b80156110a65780840151818601516000526040600020805482810181811015611098576301336cea6000526004601cfd5b9091555050601f1901611067565b5060405160408152845160051b602001604082018181838960045afa503d60400160208401523d81019050855160051b60200191508181838860045afa50823d8201039150508260601c6000337f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8486a4505050611122600090565b50833b1561071c5761071c600085858585611587565b6109c3565b638b78c6d819543314610b2a576382b429006000526004601cfd5b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b8360601b806111ad5763ea553b346000526004601cfd5b679a31110384e0b0c9602052846014528360005260406000208054848101818110156111e1576301336cea6000526004601cfd5b808355505050826020528060601c6000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406000a450833b1561071c5761071c600085858585611643565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6060816002036112ad57505060408051808201909152601e81527f3230323320526162626974486f6c6520486f6c69646179205265776172640000602082015290565b505060408051808201909152601181527f526162626974486f6c65205469636b6574000000000000000000000000000000602082015290565b919050565b606081600203611314576040518060a00160405280607081526020016121b26070913992915050565b505060408051808201909152601281527f526162626974486f6c65205469636b6574730000000000000000000000000000602082015290565b606081600203611376576040518060600160405280603b815260200161225d603b913992915050565b6003805461138390611de0565b80601f01602080910402602001604051908101604052809291908181526020018280546113af90611de0565b80156113fc5780601f106113d1576101008083540402835291602001916113fc565b820191906000526020600020905b8154815290600101906020018083116113df57829003601f168201915b50505050509050919050565b6060815160000361142757505060408051602081019091526000815290565b81604051602001611438919061216c565b6040516020818303038152906040529050919050565b606081600203611477576040518060600160405280603b8152602001612222603b913992915050565b6004805461138390611de0565b60608351801561157f576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106708515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f52602083018181015b6003880197508751603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f8116516003535060005182526004820191508082106114f4576020016040527f3d3d000000000000000000000000000000000000000000000000000000000000600384066002048083039190915260008615159091029182900352900382525b509392505050565b60405163bc197c8181523360208201528560601b60601c604082015260a06060820152835160051b60200160c082018181838860045afa503d60a0018060808501523d82019150855160051b60200192508282848860045afa503d0160a0840152835160200191503d018181818660045afa50601c83013d82010391505060208282601c850160008a5af1611625573d15611625573d6000833e3d82fd5b50805163bc197c8160e01b14610f8b57639c05499b6000526004601cfd5b60405163f23a6e6181523360208201528560601b60601c604082015283606082015282608082015260a08082015281518060c0830152801561168f578060e08301826020860160045afa505b6020828260c401601c850160008a5af16116b2573d156116b2573d6000833e3d82fd5b50805163f23a6e6160e01b14610f8b57639c05499b6000526004601cfd5b80356001600160a01b03811681146112e657600080fd5b600080604083850312156116fa57600080fd5b611703836116d0565b946020939093013593505050565b60006020828403121561172357600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461175357600080fd5b9392505050565b60005b8381101561177557818101518382015260200161175d565b50506000910152565b602081526000825180602084015261179d81604085016020870161175a565b601f01601f19169190910160400192915050565b6000602082840312156117c357600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715611809576118096117ca565b604052919050565b600082601f83011261182257600080fd5b8135602067ffffffffffffffff82111561183e5761183e6117ca565b8160051b61184d8282016117e0565b928352848101820192828101908785111561186757600080fd5b83870192505b848310156118865782358252918301919083019061186d565b979650505050505050565b600082601f8301126118a257600080fd5b813567ffffffffffffffff8111156118bc576118bc6117ca565b6118cf601f8201601f19166020016117e0565b8181528460208386010111156118e457600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000806080858703121561191757600080fd5b611920856116d0565b9350602085013567ffffffffffffffff8082111561193d57600080fd5b61194988838901611811565b9450604087013591508082111561195f57600080fd5b61196b88838901611811565b9350606087013591508082111561198157600080fd5b5061198e87828801611891565b91505092959194509250565b600080604083850312156119ad57600080fd5b50508035926020909101359150565b60008083601f8401126119ce57600080fd5b50813567ffffffffffffffff8111156119e657600080fd5b6020830191508360208260051b85010111156107aa57600080fd5b60008083601f840112611a1357600080fd5b50813567ffffffffffffffff811115611a2b57600080fd5b6020830191508360208285010111156107aa57600080fd5b60008060008060008060008060a0898b031215611a5f57600080fd5b611a68896116d0565b9750611a7660208a016116d0565b9650604089013567ffffffffffffffff80821115611a9357600080fd5b611a9f8c838d016119bc565b909850965060608b0135915080821115611ab857600080fd5b611ac48c838d016119bc565b909650945060808b0135915080821115611add57600080fd5b50611aea8b828c01611a01565b999c989b5096995094979396929594505050565b600060208284031215611b1057600080fd5b611753826116d0565b60008060008060408587031215611b2f57600080fd5b843567ffffffffffffffff80821115611b4757600080fd5b611b53888389016119bc565b90965094506020870135915080821115611b6c57600080fd5b50611b79878288016119bc565b95989497509550505050565b6020808252825182820181905260009190848201906040850190845b81811015611bbd57835183529284019291840191600101611ba1565b50909695505050505050565b600060208284031215611bdb57600080fd5b813567ffffffffffffffff811115611bf257600080fd5b611bfe84828501611891565b949350505050565b60008060008060808587031215611c1c57600080fd5b611c25856116d0565b93506020850135925060408501359150606085013567ffffffffffffffff811115611c4f57600080fd5b61198e87828801611891565b60008060408385031215611c6e57600080fd5b611c77836116d0565b915060208301358015158114611c8c57600080fd5b809150509250929050565b60008060008060008060c08789031215611cb057600080fd5b611cb9876116d0565b9550611cc7602088016116d0565b945060408701359350611cdc606088016116d0565b9250608087013567ffffffffffffffff80821115611cf957600080fd5b611d058a838b01611891565b935060a0890135915080821115611d1b57600080fd5b50611d2889828a01611891565b9150509295509295509295565b60008060408385031215611d4857600080fd5b611d51836116d0565b9150611d5f602084016116d0565b90509250929050565b60008060008060008060a08789031215611d8157600080fd5b611d8a876116d0565b9550611d98602088016116d0565b94506040870135935060608701359250608087013567ffffffffffffffff811115611dc257600080fd5b611dce89828a01611a01565b979a9699509497509295939492505050565b600181811c90821680611df457607f821691505b602082108103611e1457634e487b7160e01b600052602260045260246000fd5b50919050565b60008151611e2c81856020860161175a565b9290920192915050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251611e6e81601d85016020870161175a565b91909101601d0192915050565b808202811582820484141761061257634e487b7160e01b600052601160045260246000fd5b600082611ebd57634e487b7160e01b600052601260045260246000fd5b500490565b601f821115611f0857600081815260208120601f850160051c81016020861015611ee95750805b601f850160051c820191505b81811015610f8b57828155600101611ef5565b505050565b815167ffffffffffffffff811115611f2757611f276117ca565b611f3b81611f358454611de0565b84611ec2565b602080601f831160018114611f705760008415611f585750858301515b600019600386901b1c1916600185901b178555610f8b565b600085815260208120601f198616915b82811015611f9f57888601518255948401946001909101908401611f80565b5085821015611fbd5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b7f7b0000000000000000000000000000000000000000000000000000000000000081527f226e616d65223a2022000000000000000000000000000000000000000000000060018201526000855161202b81600a850160208a0161175a565b80830190507f222c00000000000000000000000000000000000000000000000000000000000080600a8301527f226465736372697074696f6e223a202200000000000000000000000000000000600c830152865161209081601c850160208b0161175a565b601c92019182018190527f22696d616765223a202200000000000000000000000000000000000000000000601e83015285516120d3816028850160208a0161175a565b602892019182015261188661214361211a612114602a85017f22616e696d6174696f6e5f75726c223a20220000000000000000000000000000815260120190565b87611e1a565b7f2200000000000000000000000000000000000000000000000000000000000000815260010190565b7f7d00000000000000000000000000000000000000000000000000000000000000815260010190565b7f697066733a2f2f000000000000000000000000000000000000000000000000008152600082516121a481600785016020870161175a565b919091016007019291505056fe596f7520756e777261707065642061204368726973746d617320676966742066726f6d20526162626974486f6c6520666f72206265696e672061206c6f79616c206d656d62657220616e6420636f6d706c6574696e67206f7572203230323320486f6c696461792063616d706169676e62616679626569673773666b6c7777337173643279616834746f74747636657776726f6164356371696476787377746472626c7a7664376766363462616679626569676f6f34726e776c6d657979713272676374657162337372786169646132346a7069656478736f716137637670626a686e7a6e69a26469706673582212203bbde892360bc27f2616239c8a3e2dc314542295cf30b12c715c81c2acf882d364736f6c63430008130033
Deployed Bytecode
0x6080604052600436106101c15760003560e01c806354d1f13d116100f7578063a4a5353911610095578063f04e283e11610064578063f04e283e14610526578063f242432a14610539578063f2fde38b14610559578063fee81cf41461056c57600080fd5b8063a4a5353914610497578063b8997a97146104b7578063e4e1ff01146104cd578063e985e9c5146104ed57600080fd5b8063731133e9116100d1578063731133e91461041e5780638da5cb5b1461043e578063a22cb46514610457578063a3106b951461047757600080fd5b806354d1f13d146103ee57806365401a9c146103f6578063715018a61461041657600080fd5b80632eb2c2d61161016457806341e42f301161013e57806341e42f3014610366578063498719bc146103865780634c00de821461039b5780634e1273f4146103c157600080fd5b80632eb2c2d6146102ee57806334d722c91461030e5780633e4086e51461034657600080fd5b80630e89341c116101a05780630e89341c146102655780631f7fdffa1461028557806325692962146102a75780632a55205a146102af57600080fd5b8062fdd58e146101c657806301ffc9a7146102135780630b497f3814610243575b600080fd5b3480156101d257600080fd5b506102006101e13660046116e7565b679a31110384e0b0c96020526014919091526000908152604090205490565b6040519081526020015b60405180910390f35b34801561021f57600080fd5b5061023361022e366004611711565b61059f565b604051901515815260200161020a565b34801561024f57600080fd5b50610258610618565b60405161020a919061177e565b34801561027157600080fd5b506102586102803660046117b1565b6106a6565b34801561029157600080fd5b506102a56102a0366004611901565b6106e5565b005b6102a5610722565b3480156102bb57600080fd5b506102cf6102ca36600461199a565b610772565b604080516001600160a01b03909316835260208301919091520161020a565b3480156102fa57600080fd5b506102a5610309366004611a43565b6107b1565b34801561031a57600080fd5b5060015461032e906001600160a01b031681565b6040516001600160a01b03909116815260200161020a565b34801561035257600080fd5b506102a56103613660046117b1565b6109cd565b34801561037257600080fd5b506102a5610381366004611afe565b610a08565b34801561039257600080fd5b50610258610a47565b3480156103a757600080fd5b5060005461032e906201000090046001600160a01b031681565b3480156103cd57600080fd5b506103e16103dc366004611b19565b610a54565b60405161020a9190611b85565b6102a5610ac4565b34801561040257600080fd5b506102a5610411366004611bc9565b610b00565b6102a5610b18565b34801561042a57600080fd5b506102a5610439366004611c06565b610b2c565b34801561044a57600080fd5b50638b78c6d8195461032e565b34801561046357600080fd5b506102a5610472366004611c5b565b610b63565b34801561048357600080fd5b506102a5610492366004611afe565b610bb9565b3480156104a357600080fd5b506102a56104b2366004611bc9565b610c18565b3480156104c357600080fd5b5061020060025481565b3480156104d957600080fd5b506102a56104e8366004611c97565b610c2c565b3480156104f957600080fd5b50610233610508366004611d35565b679a31110384e0b0c96020526014919091526000526034600c205490565b6102a5610534366004611afe565b610deb565b34801561054557600080fd5b506102a5610554366004611d68565b610e2b565b6102a5610567366004611afe565b610f93565b34801561057857600080fd5b50610200610587366004611afe565b63389a75e1600c908152600091909152602090205490565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f2a55205a0000000000000000000000000000000000000000000000000000000014806106125750610612826301ffc9a760e09190911c90811463d9b67a26821417630e89341c9091141790565b92915050565b6004805461062590611de0565b80601f016020809104026020016040519081016040528092919081815260200182805461065190611de0565b801561069e5780601f106106735761010080835404028352916020019161069e565b820191906000526020600020905b81548152906001019060200180831161068157829003601f168201915b505050505081565b606060006106b383610fba565b90506106be81611017565b6040516020016106ce9190611e36565b604051602081830303815290604052915050919050565b6001546001600160a01b0316331461071057604051639cdc2ed560e01b815260040160405180910390fd5b61071c84848484611025565b50505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b6000806000612710600254856107889190611e7b565b6107929190611ea0565b6000546201000090046001600160a01b031693509150505b9250929050565b8285146107c657633b800a466000526004601cfd5b8760601b679a31110384e0b0c9178760601b679a31110384e0b0c917816020528160601c99508060601c9850886108055763ea553b346000526004601cfd5b89331461082857336000526034600c205461082857634b6e7f186000526004601cfd5b8660051b5b801561089a576020810390508087013583602052818a013560005260406000208054808311156108655763f4d678b86000526004601cfd5b82900390556020839052604060002080548083018181101561088f576301336cea6000526004601cfd5b9091555061082d9050565b505050604051604081528560051b602001604082018160208a03823781604001602084015281602088038383013750888a337f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb60408586010186a450506108ff600090565b15610914576109148888888888888888611138565b863b156109c3578660005260405163bc197c81815233602082015288604082015260a060608201528560051b60200160c082018160208a0382378160a001806080850152826020890384840137820160a084015260208401601f19860183800183013750808101830160c401905060208282601c8501600080515af16109a3573d156109a3573d6000833e3d82fd5b50805163bc197c8160e01b146109c157639c05499b6000526004601cfd5b505b5050505050505050565b6109d561113d565b600281905560405181907fc36422dcc77a5c93a5c48743078f8130c9fcc2a0ff893904ee62a3565688117c90600090a250565b610a1061113d565b600080546001600160a01b03909216620100000275ffffffffffffffffffffffffffffffffffffffff000019909216919091179055565b6003805461062590611de0565b6060838214610a6b57633b800a466000526004601cfd5b6040519050818152602081018260051b8181016040525b8015610aba57602081039050808701358060601b679a31110384e0b0c917602052508085013560005260406000205481830152610a82565b5050949350505050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b610b0861113d565b6004610b148282611f0d565b5050565b610b2061113d565b610b2a6000611158565b565b6001546001600160a01b03163314610b5757604051639cdc2ed560e01b815260040160405180910390fd5b61071c84848484611196565b8015159050679a31110384e0b0c96020523360145281600052806034600c2055806000528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206000a35050565b610bc161113d565b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f09e32743122b4d02dc06c38a35ee1587a02854644d47574bb35a6ef75a22fa9890600090a250565b610c2061113d565b6003610b148282611f0d565b600054610100900460ff1615808015610c4c5750600054600160ff909116105b80610c665750303b158015610c66575060005460ff166001145b610cf6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b6000805460ff191660011790558015610d19576000805461ff0019166101001790555b610d228461122e565b6000805475ffffffffffffffffffffffffffffffffffffffff00001916620100006001600160a01b038a811691909102919091179091556001805473ffffffffffffffffffffffffffffffffffffffff191691881691909117905560028590556003610d8e8482611f0d565b506004610d9b8382611f0d565b508015610de2576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b610df361113d565b63389a75e1600c52806000526020600c208054421115610e1b57636f5e88186000526004601cfd5b60009055610e2881611158565b50565b8560601b679a31110384e0b0c9178560601b679a31110384e0b0c917816020528160601c97508060601c965086610e6a5763ea553b346000526004601cfd5b873314610e8d57336000526034600c2054610e8d57634b6e7f186000526004601cfd5b8560005260406000209150815480861115610eb05763f4d678b86000526004601cfd5b8581038355508060205260406000209150815485810181811015610edc576301336cea6000526004601cfd5b909255505060208390528486337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406000a4843b15610f8b5760405163f23a6e61815233602082015286604082015284606082015283608082015260a080820152816020016020840360c08301376020818360c401601c840160008a5af1610f6e573d15610f6e573d6000823e3d81fd5b805163f23a6e6160e01b14610de257639c05499b6000526004601cfd5b505050505050565b610f9b61113d565b8060601b610fb157637448fbae6000526004601cfd5b610e2881611158565b60606000610fc78361126a565b610fd0846112eb565b610fe1610fdc8661134d565b611408565b610fed610fdc8761144e565b6040516020016110009493929190611fcd565b60408051601f198184030181529190529392505050565b606061061282600080611484565b815183511461103c57633b800a466000526004601cfd5b8360601b806110535763ea553b346000526004601cfd5b80679a31110384e0b0c917602052835160051b5b80156110a65780840151818601516000526040600020805482810181811015611098576301336cea6000526004601cfd5b9091555050601f1901611067565b5060405160408152845160051b602001604082018181838960045afa503d60400160208401523d81019050855160051b60200191508181838860045afa50823d8201039150508260601c6000337f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8486a4505050611122600090565b50833b1561071c5761071c600085858585611587565b6109c3565b638b78c6d819543314610b2a576382b429006000526004601cfd5b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b8360601b806111ad5763ea553b346000526004601cfd5b679a31110384e0b0c9602052846014528360005260406000208054848101818110156111e1576301336cea6000526004601cfd5b808355505050826020528060601c6000337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260406000a450833b1561071c5761071c600085858585611643565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6060816002036112ad57505060408051808201909152601e81527f3230323320526162626974486f6c6520486f6c69646179205265776172640000602082015290565b505060408051808201909152601181527f526162626974486f6c65205469636b6574000000000000000000000000000000602082015290565b919050565b606081600203611314576040518060a00160405280607081526020016121b26070913992915050565b505060408051808201909152601281527f526162626974486f6c65205469636b6574730000000000000000000000000000602082015290565b606081600203611376576040518060600160405280603b815260200161225d603b913992915050565b6003805461138390611de0565b80601f01602080910402602001604051908101604052809291908181526020018280546113af90611de0565b80156113fc5780601f106113d1576101008083540402835291602001916113fc565b820191906000526020600020905b8154815290600101906020018083116113df57829003601f168201915b50505050509050919050565b6060815160000361142757505060408051602081019091526000815290565b81604051602001611438919061216c565b6040516020818303038152906040529050919050565b606081600203611477576040518060600160405280603b8152602001612222603b913992915050565b6004805461138390611de0565b60608351801561157f576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106708515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f52602083018181015b6003880197508751603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f8116516003535060005182526004820191508082106114f4576020016040527f3d3d000000000000000000000000000000000000000000000000000000000000600384066002048083039190915260008615159091029182900352900382525b509392505050565b60405163bc197c8181523360208201528560601b60601c604082015260a06060820152835160051b60200160c082018181838860045afa503d60a0018060808501523d82019150855160051b60200192508282848860045afa503d0160a0840152835160200191503d018181818660045afa50601c83013d82010391505060208282601c850160008a5af1611625573d15611625573d6000833e3d82fd5b50805163bc197c8160e01b14610f8b57639c05499b6000526004601cfd5b60405163f23a6e6181523360208201528560601b60601c604082015283606082015282608082015260a08082015281518060c0830152801561168f578060e08301826020860160045afa505b6020828260c401601c850160008a5af16116b2573d156116b2573d6000833e3d82fd5b50805163f23a6e6160e01b14610f8b57639c05499b6000526004601cfd5b80356001600160a01b03811681146112e657600080fd5b600080604083850312156116fa57600080fd5b611703836116d0565b946020939093013593505050565b60006020828403121561172357600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461175357600080fd5b9392505050565b60005b8381101561177557818101518382015260200161175d565b50506000910152565b602081526000825180602084015261179d81604085016020870161175a565b601f01601f19169190910160400192915050565b6000602082840312156117c357600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715611809576118096117ca565b604052919050565b600082601f83011261182257600080fd5b8135602067ffffffffffffffff82111561183e5761183e6117ca565b8160051b61184d8282016117e0565b928352848101820192828101908785111561186757600080fd5b83870192505b848310156118865782358252918301919083019061186d565b979650505050505050565b600082601f8301126118a257600080fd5b813567ffffffffffffffff8111156118bc576118bc6117ca565b6118cf601f8201601f19166020016117e0565b8181528460208386010111156118e457600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000806080858703121561191757600080fd5b611920856116d0565b9350602085013567ffffffffffffffff8082111561193d57600080fd5b61194988838901611811565b9450604087013591508082111561195f57600080fd5b61196b88838901611811565b9350606087013591508082111561198157600080fd5b5061198e87828801611891565b91505092959194509250565b600080604083850312156119ad57600080fd5b50508035926020909101359150565b60008083601f8401126119ce57600080fd5b50813567ffffffffffffffff8111156119e657600080fd5b6020830191508360208260051b85010111156107aa57600080fd5b60008083601f840112611a1357600080fd5b50813567ffffffffffffffff811115611a2b57600080fd5b6020830191508360208285010111156107aa57600080fd5b60008060008060008060008060a0898b031215611a5f57600080fd5b611a68896116d0565b9750611a7660208a016116d0565b9650604089013567ffffffffffffffff80821115611a9357600080fd5b611a9f8c838d016119bc565b909850965060608b0135915080821115611ab857600080fd5b611ac48c838d016119bc565b909650945060808b0135915080821115611add57600080fd5b50611aea8b828c01611a01565b999c989b5096995094979396929594505050565b600060208284031215611b1057600080fd5b611753826116d0565b60008060008060408587031215611b2f57600080fd5b843567ffffffffffffffff80821115611b4757600080fd5b611b53888389016119bc565b90965094506020870135915080821115611b6c57600080fd5b50611b79878288016119bc565b95989497509550505050565b6020808252825182820181905260009190848201906040850190845b81811015611bbd57835183529284019291840191600101611ba1565b50909695505050505050565b600060208284031215611bdb57600080fd5b813567ffffffffffffffff811115611bf257600080fd5b611bfe84828501611891565b949350505050565b60008060008060808587031215611c1c57600080fd5b611c25856116d0565b93506020850135925060408501359150606085013567ffffffffffffffff811115611c4f57600080fd5b61198e87828801611891565b60008060408385031215611c6e57600080fd5b611c77836116d0565b915060208301358015158114611c8c57600080fd5b809150509250929050565b60008060008060008060c08789031215611cb057600080fd5b611cb9876116d0565b9550611cc7602088016116d0565b945060408701359350611cdc606088016116d0565b9250608087013567ffffffffffffffff80821115611cf957600080fd5b611d058a838b01611891565b935060a0890135915080821115611d1b57600080fd5b50611d2889828a01611891565b9150509295509295509295565b60008060408385031215611d4857600080fd5b611d51836116d0565b9150611d5f602084016116d0565b90509250929050565b60008060008060008060a08789031215611d8157600080fd5b611d8a876116d0565b9550611d98602088016116d0565b94506040870135935060608701359250608087013567ffffffffffffffff811115611dc257600080fd5b611dce89828a01611a01565b979a9699509497509295939492505050565b600181811c90821680611df457607f821691505b602082108103611e1457634e487b7160e01b600052602260045260246000fd5b50919050565b60008151611e2c81856020860161175a565b9290920192915050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251611e6e81601d85016020870161175a565b91909101601d0192915050565b808202811582820484141761061257634e487b7160e01b600052601160045260246000fd5b600082611ebd57634e487b7160e01b600052601260045260246000fd5b500490565b601f821115611f0857600081815260208120601f850160051c81016020861015611ee95750805b601f850160051c820191505b81811015610f8b57828155600101611ef5565b505050565b815167ffffffffffffffff811115611f2757611f276117ca565b611f3b81611f358454611de0565b84611ec2565b602080601f831160018114611f705760008415611f585750858301515b600019600386901b1c1916600185901b178555610f8b565b600085815260208120601f198616915b82811015611f9f57888601518255948401946001909101908401611f80565b5085821015611fbd5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b7f7b0000000000000000000000000000000000000000000000000000000000000081527f226e616d65223a2022000000000000000000000000000000000000000000000060018201526000855161202b81600a850160208a0161175a565b80830190507f222c00000000000000000000000000000000000000000000000000000000000080600a8301527f226465736372697074696f6e223a202200000000000000000000000000000000600c830152865161209081601c850160208b0161175a565b601c92019182018190527f22696d616765223a202200000000000000000000000000000000000000000000601e83015285516120d3816028850160208a0161175a565b602892019182015261188661214361211a612114602a85017f22616e696d6174696f6e5f75726c223a20220000000000000000000000000000815260120190565b87611e1a565b7f2200000000000000000000000000000000000000000000000000000000000000815260010190565b7f7d00000000000000000000000000000000000000000000000000000000000000815260010190565b7f697066733a2f2f000000000000000000000000000000000000000000000000008152600082516121a481600785016020870161175a565b919091016007019291505056fe596f7520756e777261707065642061204368726973746d617320676966742066726f6d20526162626974486f6c6520666f72206265696e672061206c6f79616c206d656d62657220616e6420636f6d706c6574696e67206f7572203230323320486f6c696461792063616d706169676e62616679626569673773666b6c7777337173643279616834746f74747636657776726f6164356371696476787377746472626c7a7664376766363462616679626569676f6f34726e776c6d657979713272676374657162337372786169646132346a7069656478736f716137637670626a686e7a6e69a26469706673582212203bbde892360bc27f2616239c8a3e2dc314542295cf30b12c715c81c2acf882d364736f6c63430008130033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 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.