-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathRabbitHoleTickets.json
1 lines (1 loc) · 96.6 KB
/
RabbitHoleTickets.json
1
{"language":"Solidity","sources":{"contracts/RabbitHoleTickets.sol":{"content":"// SPDX-License-Identifier: UNLICENSED\r\npragma solidity 0.8.19;\r\n\r\nimport {Ownable} from \"solady/auth/Ownable.sol\";\r\nimport {ERC1155} from \"solady/tokens/ERC1155.sol\";\r\nimport {Base64} from \"solady/utils/Base64.sol\";\r\nimport {Initializable} from \"openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol\";\r\nimport {\r\n IERC165Upgradeable,\r\n IERC2981Upgradeable\r\n} from \"openzeppelin-contracts-upgradeable/interfaces/IERC2981Upgradeable.sol\";\r\n\r\ncontract RabbitHoleTickets is Initializable, Ownable, ERC1155, IERC2981Upgradeable {\r\n /*//////////////////////////////////////////////////////////////\r\n ERRORS\r\n //////////////////////////////////////////////////////////////*/\r\n error OnlyMinter();\r\n\r\n event RoyaltyFeeSet(uint256 indexed royaltyFee);\r\n event MinterAddressSet(address indexed minterAddress);\r\n\r\n /*//////////////////////////////////////////////////////////////\r\n STORAGE\r\n //////////////////////////////////////////////////////////////*/\r\n address public royaltyRecipient;\r\n address public minterAddress;\r\n uint256 public royaltyFee;\r\n string public imageIPFSCID;\r\n string public animationUrlIPFSCID;\r\n // insert new vars here at the end to keep the storage layout the same\r\n\r\n /*//////////////////////////////////////////////////////////////\r\n CONSTRUCTOR\r\n //////////////////////////////////////////////////////////////*/\r\n /// @custom:oz-upgrades-unsafe-allow constructor\r\n // solhint-disable-next-line func-visibility\r\n constructor() {\r\n _disableInitializers();\r\n }\r\n\r\n function initialize(\r\n address royaltyRecipient_,\r\n address minterAddress_,\r\n uint256 royaltyFee_,\r\n address owner_,\r\n string memory imageIPFSCID_,\r\n string memory animationUrlIPFSCID_\r\n ) external initializer {\r\n _initializeOwner(owner_);\r\n royaltyRecipient = royaltyRecipient_;\r\n minterAddress = minterAddress_;\r\n royaltyFee = royaltyFee_;\r\n imageIPFSCID = imageIPFSCID_;\r\n animationUrlIPFSCID = animationUrlIPFSCID_;\r\n }\r\n\r\n /*//////////////////////////////////////////////////////////////\r\n MODIFIERS\r\n //////////////////////////////////////////////////////////////*/\r\n modifier onlyMinter() {\r\n if (msg.sender != minterAddress) revert OnlyMinter();\r\n _;\r\n }\r\n\r\n /*//////////////////////////////////////////////////////////////\r\n EXTERNAL UPDATE\r\n //////////////////////////////////////////////////////////////*/\r\n\r\n /*//////////////////////////////////////////////////////////////\r\n MINT\r\n //////////////////////////////////////////////////////////////*/\r\n /// @dev mint a single ticket, only callable by the allowed minter\r\n /// @param to_ the address to mint the ticket to\r\n /// @param id_ the id of the ticket to mint\r\n /// @param amount_ the amount of the ticket to mint\r\n /// @param data_ the data to pass to the mint function\r\n function mint(address to_, uint256 id_, uint256 amount_, bytes memory data_) external onlyMinter {\r\n _mint(to_, id_, amount_, data_);\r\n }\r\n\r\n /// @dev mint a batch of tickets, only callable by the allowed minter\r\n /// @param to_ the address to mint the tickets to\r\n /// @param ids_ the ids of the tickets to mint\r\n /// @param amounts_ the amounts of the tickets to mint\r\n /// @param data_ the data to pass to the mint function\r\n function mintBatch(\r\n address to_,\r\n uint256[] memory ids_,\r\n uint256[] memory amounts_,\r\n bytes memory data_\r\n ) external onlyMinter {\r\n _batchMint(to_, ids_, amounts_, data_);\r\n }\r\n\r\n /*//////////////////////////////////////////////////////////////\r\n SET\r\n //////////////////////////////////////////////////////////////*/\r\n /// @dev set the animation url IPFS CID\r\n /// @param animationUrlIPFSCID_ the animation url IPFS CID\r\n function setAnimationUrlIPFSCID(string memory animationUrlIPFSCID_) external onlyOwner {\r\n animationUrlIPFSCID = animationUrlIPFSCID_;\r\n }\r\n\r\n /// @dev set the image IPFS CID\r\n /// @param imageIPFSCID_ the image IPFS CID\r\n function setImageIPFSCID(string memory imageIPFSCID_) external onlyOwner {\r\n imageIPFSCID = imageIPFSCID_;\r\n }\r\n\r\n /// @dev set the minter address\r\n /// @param minterAddress_ the address of the minter\r\n function setMinterAddress(address minterAddress_) external onlyOwner {\r\n minterAddress = minterAddress_;\r\n emit MinterAddressSet(minterAddress_);\r\n }\r\n\r\n /// @dev set the royalty fee\r\n /// @param royaltyFee_ the royalty fee\r\n function setRoyaltyFee(uint256 royaltyFee_) external onlyOwner {\r\n royaltyFee = royaltyFee_;\r\n emit RoyaltyFeeSet(royaltyFee_);\r\n }\r\n\r\n /// @dev set the royalty recipient\r\n /// @param royaltyRecipient_ the address of the royalty recipient\r\n function setRoyaltyRecipient(address royaltyRecipient_) external onlyOwner {\r\n royaltyRecipient = royaltyRecipient_;\r\n }\r\n\r\n /*//////////////////////////////////////////////////////////////\r\n EXTERNAL VIEW\r\n //////////////////////////////////////////////////////////////*/\r\n\r\n /// @dev See {IERC165-royaltyInfo}\r\n /// @param salePrice_ the sale price\r\n function royaltyInfo(\r\n uint256,\r\n uint256 salePrice_\r\n ) external view override returns (address receiver, uint256 royaltyAmount) {\r\n uint256 royaltyPayment = (salePrice_ * royaltyFee) / 10_000;\r\n return (royaltyRecipient, royaltyPayment);\r\n }\r\n\r\n /// @dev returns true if the supplied interface id is supported\r\n /// @param interfaceId_ the interface id\r\n function supportsInterface(bytes4 interfaceId_)\r\n public\r\n view\r\n virtual\r\n override (ERC1155, IERC165Upgradeable)\r\n returns (bool)\r\n {\r\n return interfaceId_ == type(IERC2981Upgradeable).interfaceId || super.supportsInterface(interfaceId_);\r\n }\r\n\r\n /// @dev returns the token uri\r\n function uri(uint256 tokenId_) public view override (ERC1155) returns (string memory) {\r\n bytes memory dataURI = generateDataURI(tokenId_);\r\n return string(abi.encodePacked(\"data:application/json;base64,\", Base64.encode(dataURI)));\r\n }\r\n\r\n /*//////////////////////////////////////////////////////////////\r\n INTERNAL VIEW\r\n //////////////////////////////////////////////////////////////*/\r\n\r\n /// @dev returns the data uri in json format\r\n function generateDataURI(uint256 tokenId_) internal view virtual returns (bytes memory) {\r\n // solhint-disable quotes\r\n bytes memory dataURI = abi.encodePacked(\r\n \"{\",\r\n '\"name\": \"',\r\n getNameForToken(tokenId_),\r\n '\",',\r\n '\"description\": \"',\r\n getDescriptionForToken(tokenId_),\r\n '\",',\r\n '\"image\": \"',\r\n makeIPFSUrl(getImageCidForToken(tokenId_)),\r\n '\",',\r\n '\"animation_url\": \"',\r\n makeIPFSUrl(getAnimationCidForToken(tokenId_)),\r\n '\"',\r\n \"}\"\r\n );\r\n // solhint-enable quotes\r\n return dataURI;\r\n }\r\n\r\n function getNameForToken(uint256 tokenId_) internal view virtual returns (string memory) {\r\n if(tokenId_ == 2) {\r\n return \"2023 RabbitHole Holiday Reward\";\r\n } else {\r\n return \"RabbitHole Ticket\";\r\n }\r\n }\r\n\r\n function getDescriptionForToken(uint256 tokenId_) internal view virtual returns (string memory) {\r\n if(tokenId_ == 2) {\r\n return \"You unwrapped a Christmas gift from RabbitHole for being a loyal member and completing our 2023 Holiday campaign\";\r\n } else {\r\n return \"RabbitHole Tickets\";\r\n }\r\n }\r\n\r\n function getAnimationCidForToken(uint256 tokenId_) internal view virtual returns (string memory) {\r\n if(tokenId_ == 2) {\r\n return \"bafybeig7sfklww3qsd2yah4tottv6ewvroad5cqidvxswtdrblzvd7gf64\";\r\n } else {\r\n return animationUrlIPFSCID;\r\n }\r\n }\r\n\r\n function getImageCidForToken(uint256 tokenId_) internal view virtual returns (string memory) {\r\n if(tokenId_ == 2) {\r\n return \"bafybeigoo4rnwlmeyyq2rgcteqb3srxaida24jpiedxsoqa7cvpbjhnzni\";\r\n } else {\r\n return imageIPFSCID;\r\n }\r\n }\r\n\r\n function makeIPFSUrl(string memory ipfsCid_) internal view virtual returns (string memory) {\r\n if (bytes(ipfsCid_).length == 0) {\r\n return \"\";\r\n }\r\n return string(abi.encodePacked(\"ipfs://\", ipfsCid_));\r\n }\r\n}\r\n"},"lib/solady/src/auth/Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\r\npragma solidity ^0.8.4;\r\n\r\n/// @notice Simple single owner authorization mixin.\r\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)\r\n///\r\n/// @dev Note:\r\n/// This implementation does NOT auto-initialize the owner to `msg.sender`.\r\n/// You MUST call the `_initializeOwner` in the constructor / initializer.\r\n///\r\n/// While the ownable portion follows\r\n/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,\r\n/// the nomenclature for the 2-step ownership handover may be unique to this codebase.\r\nabstract contract Ownable {\r\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\r\n /* CUSTOM ERRORS */\r\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\r\n\r\n /// @dev The caller is not authorized to call the function.\r\n error Unauthorized();\r\n\r\n /// @dev The `newOwner` cannot be the zero address.\r\n error NewOwnerIsZeroAddress();\r\n\r\n /// @dev The `pendingOwner` does not have a valid handover request.\r\n error NoHandoverRequest();\r\n\r\n /// @dev Cannot double-initialize.\r\n error AlreadyInitialized();\r\n\r\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\r\n /* EVENTS */\r\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\r\n\r\n /// @dev The ownership is transferred from `oldOwner` to `newOwner`.\r\n /// This event is intentionally kept the same as OpenZeppelin's Ownable to be\r\n /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),\r\n /// despite it not being as lightweight as a single argument event.\r\n event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);\r\n\r\n /// @dev An ownership handover to `pendingOwner` has been requested.\r\n event OwnershipHandoverRequested(address indexed pendingOwner);\r\n\r\n /// @dev The ownership handover to `pendingOwner` has been canceled.\r\n event OwnershipHandoverCanceled(address indexed pendingOwner);\r\n\r\n /// @dev `keccak256(bytes(\"OwnershipTransferred(address,address)\"))`.\r\n uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =\r\n 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;\r\n\r\n /// @dev `keccak256(bytes(\"OwnershipHandoverRequested(address)\"))`.\r\n uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =\r\n 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;\r\n\r\n /// @dev `keccak256(bytes(\"OwnershipHandoverCanceled(address)\"))`.\r\n uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =\r\n 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;\r\n\r\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\r\n /* STORAGE */\r\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\r\n\r\n /// @dev The owner slot is given by:\r\n /// `bytes32(~uint256(uint32(bytes4(keccak256(\"_OWNER_SLOT_NOT\")))))`.\r\n /// It is intentionally chosen to be a high value\r\n /// to avoid collision with lower slots.\r\n /// The choice of manual storage layout is to enable compatibility\r\n /// with both regular and upgradeable contracts.\r\n bytes32 internal constant _OWNER_SLOT =\r\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;\r\n\r\n /// The ownership handover slot of `newOwner` is given by:\r\n /// ```\r\n /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))\r\n /// let handoverSlot := keccak256(0x00, 0x20)\r\n /// ```\r\n /// It stores the expiry timestamp of the two-step ownership handover.\r\n uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;\r\n\r\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\r\n /* INTERNAL FUNCTIONS */\r\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\r\n\r\n /// @dev Override to return true to make `_initializeOwner` prevent double-initialization.\r\n function _guardInitializeOwner() internal pure virtual returns (bool guard) {}\r\n\r\n /// @dev Initializes the owner directly without authorization guard.\r\n /// This function must be called upon initialization,\r\n /// regardless of whether the contract is upgradeable or not.\r\n /// This is to enable generalization to both regular and upgradeable contracts,\r\n /// and to save gas in case the initial owner is not the caller.\r\n /// For performance reasons, this function will not check if there\r\n /// is an existing owner.\r\n function _initializeOwner(address newOwner) internal virtual {\r\n if (_guardInitializeOwner()) {\r\n /// @solidity memory-safe-assembly\r\n assembly {\r\n let ownerSlot := _OWNER_SLOT\r\n if sload(ownerSlot) {\r\n mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.\r\n revert(0x1c, 0x04)\r\n }\r\n // Clean the upper 96 bits.\r\n newOwner := shr(96, shl(96, newOwner))\r\n // Store the new value.\r\n sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))\r\n // Emit the {OwnershipTransferred} event.\r\n log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)\r\n }\r\n } else {\r\n /// @solidity memory-safe-assembly\r\n assembly {\r\n // Clean the upper 96 bits.\r\n newOwner := shr(96, shl(96, newOwner))\r\n // Store the new value.\r\n sstore(_OWNER_SLOT, newOwner)\r\n // Emit the {OwnershipTransferred} event.\r\n log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)\r\n }\r\n }\r\n }\r\n\r\n /// @dev Sets the owner directly without authorization guard.\r\n function _setOwner(address newOwner) internal virtual {\r\n if (_guardInitializeOwner()) {\r\n /// @solidity memory-safe-assembly\r\n assembly {\r\n let ownerSlot := _OWNER_SLOT\r\n // Clean the upper 96 bits.\r\n newOwner := shr(96, shl(96, newOwner))\r\n // Emit the {OwnershipTransferred} event.\r\n log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)\r\n // Store the new value.\r\n sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))\r\n }\r\n } else {\r\n /// @solidity memory-safe-assembly\r\n assembly {\r\n let ownerSlot := _OWNER_SLOT\r\n // Clean the upper 96 bits.\r\n newOwner := shr(96, shl(96, newOwner))\r\n // Emit the {OwnershipTransferred} event.\r\n log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)\r\n // Store the new value.\r\n sstore(ownerSlot, newOwner)\r\n }\r\n }\r\n }\r\n\r\n /// @dev Throws if the sender is not the owner.\r\n function _checkOwner() internal view virtual {\r\n /// @solidity memory-safe-assembly\r\n assembly {\r\n // If the caller is not the stored owner, revert.\r\n if iszero(eq(caller(), sload(_OWNER_SLOT))) {\r\n mstore(0x00, 0x82b42900) // `Unauthorized()`.\r\n revert(0x1c, 0x04)\r\n }\r\n }\r\n }\r\n\r\n /// @dev Returns how long a two-step ownership handover is valid for in seconds.\r\n /// Override to return a different value if needed.\r\n /// Made internal to conserve bytecode. Wrap it in a public function if needed.\r\n function _ownershipHandoverValidFor() internal view virtual returns (uint64) {\r\n return 48 * 3600;\r\n }\r\n\r\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\r\n /* PUBLIC UPDATE FUNCTIONS */\r\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\r\n\r\n /// @dev Allows the owner to transfer the ownership to `newOwner`.\r\n function transferOwnership(address newOwner) public payable virtual onlyOwner {\r\n /// @solidity memory-safe-assembly\r\n assembly {\r\n if iszero(shl(96, newOwner)) {\r\n mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.\r\n revert(0x1c, 0x04)\r\n }\r\n }\r\n _setOwner(newOwner);\r\n }\r\n\r\n /// @dev Allows the owner to renounce their ownership.\r\n function renounceOwnership() public payable virtual onlyOwner {\r\n _setOwner(address(0));\r\n }\r\n\r\n /// @dev Request a two-step ownership handover to the caller.\r\n /// The request will automatically expire in 48 hours (172800 seconds) by default.\r\n function requestOwnershipHandover() public payable virtual {\r\n unchecked {\r\n uint256 expires = block.timestamp + _ownershipHandoverValidFor();\r\n /// @solidity memory-safe-assembly\r\n assembly {\r\n // Compute and set the handover slot to `expires`.\r\n mstore(0x0c, _HANDOVER_SLOT_SEED)\r\n mstore(0x00, caller())\r\n sstore(keccak256(0x0c, 0x20), expires)\r\n // Emit the {OwnershipHandoverRequested} event.\r\n log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())\r\n }\r\n }\r\n }\r\n\r\n /// @dev Cancels the two-step ownership handover to the caller, if any.\r\n function cancelOwnershipHandover() public payable virtual {\r\n /// @solidity memory-safe-assembly\r\n assembly {\r\n // Compute and set the handover slot to 0.\r\n mstore(0x0c, _HANDOVER_SLOT_SEED)\r\n mstore(0x00, caller())\r\n sstore(keccak256(0x0c, 0x20), 0)\r\n // Emit the {OwnershipHandoverCanceled} event.\r\n log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())\r\n }\r\n }\r\n\r\n /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.\r\n /// Reverts if there is no existing ownership handover requested by `pendingOwner`.\r\n function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {\r\n /// @solidity memory-safe-assembly\r\n assembly {\r\n // Compute and set the handover slot to 0.\r\n mstore(0x0c, _HANDOVER_SLOT_SEED)\r\n mstore(0x00, pendingOwner)\r\n let handoverSlot := keccak256(0x0c, 0x20)\r\n // If the handover does not exist, or has expired.\r\n if gt(timestamp(), sload(handoverSlot)) {\r\n mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.\r\n revert(0x1c, 0x04)\r\n }\r\n // Set the handover slot to 0.\r\n sstore(handoverSlot, 0)\r\n }\r\n _setOwner(pendingOwner);\r\n }\r\n\r\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\r\n /* PUBLIC READ FUNCTIONS */\r\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\r\n\r\n /// @dev Returns the owner of the contract.\r\n function owner() public view virtual returns (address result) {\r\n /// @solidity memory-safe-assembly\r\n assembly {\r\n result := sload(_OWNER_SLOT)\r\n }\r\n }\r\n\r\n /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.\r\n function ownershipHandoverExpiresAt(address pendingOwner)\r\n public\r\n view\r\n virtual\r\n returns (uint256 result)\r\n {\r\n /// @solidity memory-safe-assembly\r\n assembly {\r\n // Compute the handover slot.\r\n mstore(0x0c, _HANDOVER_SLOT_SEED)\r\n mstore(0x00, pendingOwner)\r\n // Load the handover slot.\r\n result := sload(keccak256(0x0c, 0x20))\r\n }\r\n }\r\n\r\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\r\n /* MODIFIERS */\r\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\r\n\r\n /// @dev Marks a function as only callable by the owner.\r\n modifier onlyOwner() virtual {\r\n _checkOwner();\r\n _;\r\n }\r\n}\r\n"},"lib/solady/src/tokens/ERC1155.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Simple ERC1155 implementation.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC1155.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol)\n/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC1155/ERC1155.sol)\n///\n/// @dev Note:\n/// - The ERC1155 standard allows for self-approvals.\n/// For performance, this implementation WILL NOT revert for such actions.\n/// Please add any checks with overrides if desired.\n/// - The transfer functions use the identity precompile (0x4)\n/// to copy memory internally.\n///\n/// If you are overriding:\n/// - Make sure all variables written to storage are properly cleaned\n// (e.g. the bool value for `isApprovedForAll` MUST be either 1 or 0 under the hood).\n/// - Check that the overridden function is actually used in the function you want to\n/// change the behavior of. Much of the code has been manually inlined for performance.\nabstract contract ERC1155 {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The lengths of the input arrays are not the same.\n error ArrayLengthsMismatch();\n\n /// @dev Cannot mint or transfer to the zero address.\n error TransferToZeroAddress();\n\n /// @dev The recipient's balance has overflowed.\n error AccountBalanceOverflow();\n\n /// @dev Insufficient balance.\n error InsufficientBalance();\n\n /// @dev Only the token owner or an approved account can manage the tokens.\n error NotOwnerNorApproved();\n\n /// @dev Cannot safely transfer to a contract that does not implement\n /// the ERC1155Receiver interface.\n error TransferToNonERC1155ReceiverImplementer();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* EVENTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Emitted when `amount` of token `id` is transferred\n /// from `from` to `to` by `operator`.\n event TransferSingle(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256 id,\n uint256 amount\n );\n\n /// @dev Emitted when `amounts` of token `ids` are transferred\n /// from `from` to `to` by `operator`.\n event TransferBatch(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256[] ids,\n uint256[] amounts\n );\n\n /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens.\n event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved);\n\n /// @dev Emitted when the Uniform Resource Identifier (URI) for token `id`\n /// is updated to `value`. This event is not used in the base contract.\n /// You may need to emit this event depending on your URI logic.\n ///\n /// See: https://eips.ethereum.org/EIPS/eip-1155#metadata\n event URI(string value, uint256 indexed id);\n\n /// @dev `keccak256(bytes(\"TransferSingle(address,address,address,uint256,uint256)\"))`.\n uint256 private constant _TRANSFER_SINGLE_EVENT_SIGNATURE =\n 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62;\n\n /// @dev `keccak256(bytes(\"TransferBatch(address,address,address,uint256[],uint256[])\"))`.\n uint256 private constant _TRANSFER_BATCH_EVENT_SIGNATURE =\n 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb;\n\n /// @dev `keccak256(bytes(\"ApprovalForAll(address,address,bool)\"))`.\n uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE =\n 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* STORAGE */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The `ownerSlotSeed` of a given owner is given by.\n /// ```\n /// let ownerSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner))\n /// ```\n ///\n /// The balance slot of `owner` is given by.\n /// ```\n /// mstore(0x20, ownerSlotSeed)\n /// mstore(0x00, id)\n /// let balanceSlot := keccak256(0x00, 0x40)\n /// ```\n ///\n /// The operator approval slot of `owner` is given by.\n /// ```\n /// mstore(0x20, ownerSlotSeed)\n /// mstore(0x00, operator)\n /// let operatorApprovalSlot := keccak256(0x0c, 0x34)\n /// ```\n uint256 private constant _ERC1155_MASTER_SLOT_SEED = 0x9a31110384e0b0c9;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* ERC1155 METADATA */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the URI for token `id`.\n ///\n /// You can either return the same templated URI for all token IDs,\n /// (e.g. \"https://example.com/api/{id}.json\"),\n /// or return a unique URI for each `id`.\n ///\n /// See: https://eips.ethereum.org/EIPS/eip-1155#metadata\n function uri(uint256 id) public view virtual returns (string memory);\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* ERC1155 */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the amount of `id` owned by `owner`.\n function balanceOf(address owner, uint256 id) public view virtual returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x20, _ERC1155_MASTER_SLOT_SEED)\n mstore(0x14, owner)\n mstore(0x00, id)\n result := sload(keccak256(0x00, 0x40))\n }\n }\n\n /// @dev Returns whether `operator` is approved to manage the tokens of `owner`.\n function isApprovedForAll(address owner, address operator)\n public\n view\n virtual\n returns (bool result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x20, _ERC1155_MASTER_SLOT_SEED)\n mstore(0x14, owner)\n mstore(0x00, operator)\n result := sload(keccak256(0x0c, 0x34))\n }\n }\n\n /// @dev Sets whether `operator` is approved to manage the tokens of the caller.\n ///\n /// Emits a {ApprovalForAll} event.\n function setApprovalForAll(address operator, bool isApproved) public virtual {\n /// @solidity memory-safe-assembly\n assembly {\n // Convert to 0 or 1.\n isApproved := iszero(iszero(isApproved))\n // Update the `isApproved` for (`msg.sender`, `operator`).\n mstore(0x20, _ERC1155_MASTER_SLOT_SEED)\n mstore(0x14, caller())\n mstore(0x00, operator)\n sstore(keccak256(0x0c, 0x34), isApproved)\n // Emit the {ApprovalForAll} event.\n mstore(0x00, isApproved)\n // forgefmt: disable-next-line\n log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator)))\n }\n }\n\n /// @dev Transfers `amount` of `id` from `from` to `to`.\n ///\n /// Requirements:\n /// - `to` cannot be the zero address.\n /// - `from` must have at least `amount` of `id`.\n /// - If the caller is not `from`,\n /// it must be approved to manage the tokens of `from`.\n /// - If `to` refers to a smart contract, it must implement\n /// {ERC1155-onERC1155Reveived}, which is called upon a batch transfer.\n ///\n /// Emits a {Transfer} event.\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n uint256 amount,\n bytes calldata data\n ) public virtual {\n if (_useBeforeTokenTransfer()) {\n _beforeTokenTransfer(from, to, _single(id), _single(amount), data);\n }\n /// @solidity memory-safe-assembly\n assembly {\n let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from))\n let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to))\n mstore(0x20, fromSlotSeed)\n // Clear the upper 96 bits.\n from := shr(96, fromSlotSeed)\n to := shr(96, toSlotSeed)\n // Revert if `to` is the zero address.\n if iszero(to) {\n mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.\n revert(0x1c, 0x04)\n }\n // If the caller is not `from`, do the authorization check.\n if iszero(eq(caller(), from)) {\n mstore(0x00, caller())\n if iszero(sload(keccak256(0x0c, 0x34))) {\n mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.\n revert(0x1c, 0x04)\n }\n }\n // Subtract and store the updated balance of `from`.\n {\n mstore(0x00, id)\n let fromBalanceSlot := keccak256(0x00, 0x40)\n let fromBalance := sload(fromBalanceSlot)\n if gt(amount, fromBalance) {\n mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.\n revert(0x1c, 0x04)\n }\n sstore(fromBalanceSlot, sub(fromBalance, amount))\n }\n // Increase and store the updated balance of `to`.\n {\n mstore(0x20, toSlotSeed)\n let toBalanceSlot := keccak256(0x00, 0x40)\n let toBalanceBefore := sload(toBalanceSlot)\n let toBalanceAfter := add(toBalanceBefore, amount)\n if lt(toBalanceAfter, toBalanceBefore) {\n mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.\n revert(0x1c, 0x04)\n }\n sstore(toBalanceSlot, toBalanceAfter)\n }\n // Emit a {TransferSingle} event.\n mstore(0x20, amount)\n log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), from, to)\n }\n if (_useAfterTokenTransfer()) {\n _afterTokenTransfer(from, to, _single(id), _single(amount), data);\n }\n /// @solidity memory-safe-assembly\n assembly {\n // Do the {onERC1155Received} check if `to` is a smart contract.\n if extcodesize(to) {\n // Prepare the calldata.\n let m := mload(0x40)\n // `onERC1155Received(address,address,uint256,uint256,bytes)`.\n mstore(m, 0xf23a6e61)\n mstore(add(m, 0x20), caller())\n mstore(add(m, 0x40), from)\n mstore(add(m, 0x60), id)\n mstore(add(m, 0x80), amount)\n mstore(add(m, 0xa0), 0xa0)\n calldatacopy(add(m, 0xc0), sub(data.offset, 0x20), add(0x20, data.length))\n // Revert if the call reverts.\n if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, data.length), m, 0x20)) {\n if returndatasize() {\n // Bubble up the revert if the call reverts.\n returndatacopy(m, 0x00, returndatasize())\n revert(m, returndatasize())\n }\n }\n // Load the returndata and compare it with the function selector.\n if iszero(eq(mload(m), shl(224, 0xf23a6e61))) {\n mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`.\n revert(0x1c, 0x04)\n }\n }\n }\n }\n\n /// @dev Transfers `amounts` of `ids` from `from` to `to`.\n ///\n /// Requirements:\n /// - `to` cannot be the zero address.\n /// - `from` must have at least `amount` of `id`.\n /// - `ids` and `amounts` must have the same length.\n /// - If the caller is not `from`,\n /// it must be approved to manage the tokens of `from`.\n /// - If `to` refers to a smart contract, it must implement\n /// {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer.\n ///\n /// Emits a {TransferBatch} event.\n function safeBatchTransferFrom(\n address from,\n address to,\n uint256[] calldata ids,\n uint256[] calldata amounts,\n bytes calldata data\n ) public virtual {\n if (_useBeforeTokenTransfer()) {\n _beforeTokenTransfer(from, to, ids, amounts, data);\n }\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(eq(ids.length, amounts.length)) {\n mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.\n revert(0x1c, 0x04)\n }\n let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from))\n let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to))\n mstore(0x20, fromSlotSeed)\n // Clear the upper 96 bits.\n from := shr(96, fromSlotSeed)\n to := shr(96, toSlotSeed)\n // Revert if `to` is the zero address.\n if iszero(to) {\n mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.\n revert(0x1c, 0x04)\n }\n // If the caller is not `from`, do the authorization check.\n if iszero(eq(caller(), from)) {\n mstore(0x00, caller())\n if iszero(sload(keccak256(0x0c, 0x34))) {\n mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.\n revert(0x1c, 0x04)\n }\n }\n // Loop through all the `ids` and update the balances.\n {\n for { let i := shl(5, ids.length) } i {} {\n i := sub(i, 0x20)\n let amount := calldataload(add(amounts.offset, i))\n // Subtract and store the updated balance of `from`.\n {\n mstore(0x20, fromSlotSeed)\n mstore(0x00, calldataload(add(ids.offset, i)))\n let fromBalanceSlot := keccak256(0x00, 0x40)\n let fromBalance := sload(fromBalanceSlot)\n if gt(amount, fromBalance) {\n mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.\n revert(0x1c, 0x04)\n }\n sstore(fromBalanceSlot, sub(fromBalance, amount))\n }\n // Increase and store the updated balance of `to`.\n {\n mstore(0x20, toSlotSeed)\n let toBalanceSlot := keccak256(0x00, 0x40)\n let toBalanceBefore := sload(toBalanceSlot)\n let toBalanceAfter := add(toBalanceBefore, amount)\n if lt(toBalanceAfter, toBalanceBefore) {\n mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.\n revert(0x1c, 0x04)\n }\n sstore(toBalanceSlot, toBalanceAfter)\n }\n }\n }\n // Emit a {TransferBatch} event.\n {\n let m := mload(0x40)\n // Copy the `ids`.\n mstore(m, 0x40)\n let n := add(0x20, shl(5, ids.length))\n let o := add(m, 0x40)\n calldatacopy(o, sub(ids.offset, 0x20), n)\n // Copy the `amounts`.\n mstore(add(m, 0x20), add(0x40, n))\n calldatacopy(add(o, n), sub(amounts.offset, 0x20), n)\n // Do the emit.\n log4(m, add(add(n, n), 0x40), _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), from, to)\n }\n }\n if (_useAfterTokenTransfer()) {\n _afterTokenTransferCalldata(from, to, ids, amounts, data);\n }\n /// @solidity memory-safe-assembly\n assembly {\n // Do the {onERC1155BatchReceived} check if `to` is a smart contract.\n if extcodesize(to) {\n mstore(0x00, to) // Cache `to` to prevent stack too deep.\n let m := mload(0x40)\n // Prepare the calldata.\n // `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`.\n mstore(m, 0xbc197c81)\n mstore(add(m, 0x20), caller())\n mstore(add(m, 0x40), from)\n // Copy the `ids`.\n mstore(add(m, 0x60), 0xa0)\n let n := add(0x20, shl(5, ids.length))\n let o := add(m, 0xc0)\n calldatacopy(o, sub(ids.offset, 0x20), n)\n // Copy the `amounts`.\n let s := add(0xa0, n)\n mstore(add(m, 0x80), s)\n calldatacopy(add(o, n), sub(amounts.offset, 0x20), n)\n // Copy the `data`.\n mstore(add(m, 0xa0), add(s, n))\n calldatacopy(add(o, add(n, n)), sub(data.offset, 0x20), add(0x20, data.length))\n let nAll := add(0xc4, add(data.length, add(n, n)))\n // Revert if the call reverts.\n if iszero(call(gas(), mload(0x00), 0, add(m, 0x1c), nAll, m, 0x20)) {\n if returndatasize() {\n // Bubble up the revert if the call reverts.\n returndatacopy(m, 0x00, returndatasize())\n revert(m, returndatasize())\n }\n }\n // Load the returndata and compare it with the function selector.\n if iszero(eq(mload(m), shl(224, 0xbc197c81))) {\n mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`.\n revert(0x1c, 0x04)\n }\n }\n }\n }\n\n /// @dev Returns the amounts of `ids` for `owners.\n ///\n /// Requirements:\n /// - `owners` and `ids` must have the same length.\n function balanceOfBatch(address[] calldata owners, uint256[] calldata ids)\n public\n view\n virtual\n returns (uint256[] memory balances)\n {\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(eq(ids.length, owners.length)) {\n mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.\n revert(0x1c, 0x04)\n }\n balances := mload(0x40)\n mstore(balances, ids.length)\n let o := add(balances, 0x20)\n let i := shl(5, ids.length)\n mstore(0x40, add(i, o))\n // Loop through all the `ids` and load the balances.\n for {} i {} {\n i := sub(i, 0x20)\n let owner := calldataload(add(owners.offset, i))\n mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner)))\n mstore(0x00, calldataload(add(ids.offset, i)))\n mstore(add(o, i), sload(keccak256(0x00, 0x40)))\n }\n }\n }\n\n /// @dev Returns true if this contract implements the interface defined by `interfaceId`.\n /// See: https://eips.ethereum.org/EIPS/eip-165\n /// This function call must use less than 30000 gas.\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n let s := shr(224, interfaceId)\n // ERC165: 0x01ffc9a7, ERC1155: 0xd9b67a26, ERC1155MetadataURI: 0x0e89341c.\n result := or(or(eq(s, 0x01ffc9a7), eq(s, 0xd9b67a26)), eq(s, 0x0e89341c))\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* INTERNAL MINT FUNCTIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Mints `amount` of `id` to `to`.\n ///\n /// Requirements:\n /// - `to` cannot be the zero address.\n /// - If `to` refers to a smart contract, it must implement\n /// {ERC1155-onERC1155Reveived}, which is called upon a batch transfer.\n ///\n /// Emits a {Transfer} event.\n function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual {\n if (_useBeforeTokenTransfer()) {\n _beforeTokenTransfer(address(0), to, _single(id), _single(amount), data);\n }\n /// @solidity memory-safe-assembly\n assembly {\n let to_ := shl(96, to)\n // Revert if `to` is the zero address.\n if iszero(to_) {\n mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.\n revert(0x1c, 0x04)\n }\n // Increase and store the updated balance of `to`.\n {\n mstore(0x20, _ERC1155_MASTER_SLOT_SEED)\n mstore(0x14, to)\n mstore(0x00, id)\n let toBalanceSlot := keccak256(0x00, 0x40)\n let toBalanceBefore := sload(toBalanceSlot)\n let toBalanceAfter := add(toBalanceBefore, amount)\n if lt(toBalanceAfter, toBalanceBefore) {\n mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.\n revert(0x1c, 0x04)\n }\n sstore(toBalanceSlot, toBalanceAfter)\n }\n // Emit a {TransferSingle} event.\n mstore(0x20, amount)\n log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), 0, shr(96, to_))\n }\n if (_useAfterTokenTransfer()) {\n _afterTokenTransfer(address(0), to, _single(id), _single(amount), data);\n }\n if (_hasCode(to)) _checkOnERC1155Received(address(0), to, id, amount, data);\n }\n\n /// @dev Mints `amounts` of `ids` to `to`.\n ///\n /// Requirements:\n /// - `to` cannot be the zero address.\n /// - `ids` and `amounts` must have the same length.\n /// - If `to` refers to a smart contract, it must implement\n /// {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer.\n ///\n /// Emits a {TransferBatch} event.\n function _batchMint(\n address to,\n uint256[] memory ids,\n uint256[] memory amounts,\n bytes memory data\n ) internal virtual {\n if (_useBeforeTokenTransfer()) {\n _beforeTokenTransfer(address(0), to, ids, amounts, data);\n }\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(eq(mload(ids), mload(amounts))) {\n mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.\n revert(0x1c, 0x04)\n }\n let to_ := shl(96, to)\n // Revert if `to` is the zero address.\n if iszero(to_) {\n mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.\n revert(0x1c, 0x04)\n }\n // Loop through all the `ids` and update the balances.\n {\n mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_))\n for { let i := shl(5, mload(ids)) } i { i := sub(i, 0x20) } {\n let amount := mload(add(amounts, i))\n // Increase and store the updated balance of `to`.\n {\n mstore(0x00, mload(add(ids, i)))\n let toBalanceSlot := keccak256(0x00, 0x40)\n let toBalanceBefore := sload(toBalanceSlot)\n let toBalanceAfter := add(toBalanceBefore, amount)\n if lt(toBalanceAfter, toBalanceBefore) {\n mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.\n revert(0x1c, 0x04)\n }\n sstore(toBalanceSlot, toBalanceAfter)\n }\n }\n }\n // Emit a {TransferBatch} event.\n {\n let m := mload(0x40)\n // Copy the `ids`.\n mstore(m, 0x40)\n let n := add(0x20, shl(5, mload(ids)))\n let o := add(m, 0x40)\n pop(staticcall(gas(), 4, ids, n, o, n))\n // Copy the `amounts`.\n mstore(add(m, 0x20), add(0x40, returndatasize()))\n o := add(o, returndatasize())\n n := add(0x20, shl(5, mload(amounts)))\n pop(staticcall(gas(), 4, amounts, n, o, n))\n n := sub(add(o, returndatasize()), m)\n // Do the emit.\n log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), 0, shr(96, to_))\n }\n }\n if (_useAfterTokenTransfer()) {\n _afterTokenTransfer(address(0), to, ids, amounts, data);\n }\n if (_hasCode(to)) _checkOnERC1155BatchReceived(address(0), to, ids, amounts, data);\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* INTERNAL BURN FUNCTIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Equivalent to `_burn(address(0), from, id, amount)`.\n function _burn(address from, uint256 id, uint256 amount) internal virtual {\n _burn(address(0), from, id, amount);\n }\n\n /// @dev Destroys `amount` of `id` from `from`.\n ///\n /// Requirements:\n /// - `from` must have at least `amount` of `id`.\n /// - If `by` is not the zero address, it must be either `from`,\n /// or approved to manage the tokens of `from`.\n ///\n /// Emits a {Transfer} event.\n function _burn(address by, address from, uint256 id, uint256 amount) internal virtual {\n if (_useBeforeTokenTransfer()) {\n _beforeTokenTransfer(from, address(0), _single(id), _single(amount), \"\");\n }\n /// @solidity memory-safe-assembly\n assembly {\n let from_ := shl(96, from)\n mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_))\n // If `by` is not the zero address, and not equal to `from`,\n // check if it is approved to manage all the tokens of `from`.\n if iszero(or(iszero(shl(96, by)), eq(shl(96, by), from_))) {\n mstore(0x00, by)\n if iszero(sload(keccak256(0x0c, 0x34))) {\n mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.\n revert(0x1c, 0x04)\n }\n }\n // Decrease and store the updated balance of `from`.\n {\n mstore(0x00, id)\n let fromBalanceSlot := keccak256(0x00, 0x40)\n let fromBalance := sload(fromBalanceSlot)\n if gt(amount, fromBalance) {\n mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.\n revert(0x1c, 0x04)\n }\n sstore(fromBalanceSlot, sub(fromBalance, amount))\n }\n // Emit a {TransferSingle} event.\n mstore(0x20, amount)\n log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), 0)\n }\n if (_useAfterTokenTransfer()) {\n _afterTokenTransfer(from, address(0), _single(id), _single(amount), \"\");\n }\n }\n\n /// @dev Equivalent to `_batchBurn(address(0), from, ids, amounts)`.\n function _batchBurn(address from, uint256[] memory ids, uint256[] memory amounts)\n internal\n virtual\n {\n _batchBurn(address(0), from, ids, amounts);\n }\n\n /// @dev Destroys `amounts` of `ids` from `from`.\n ///\n /// Requirements:\n /// - `ids` and `amounts` must have the same length.\n /// - `from` must have at least `amounts` of `ids`.\n /// - If `by` is not the zero address, it must be either `from`,\n /// or approved to manage the tokens of `from`.\n ///\n /// Emits a {TransferBatch} event.\n function _batchBurn(address by, address from, uint256[] memory ids, uint256[] memory amounts)\n internal\n virtual\n {\n if (_useBeforeTokenTransfer()) {\n _beforeTokenTransfer(from, address(0), ids, amounts, \"\");\n }\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(eq(mload(ids), mload(amounts))) {\n mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.\n revert(0x1c, 0x04)\n }\n let from_ := shl(96, from)\n mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_))\n // If `by` is not the zero address, and not equal to `from`,\n // check if it is approved to manage all the tokens of `from`.\n let by_ := shl(96, by)\n if iszero(or(iszero(by_), eq(by_, from_))) {\n mstore(0x00, by)\n if iszero(sload(keccak256(0x0c, 0x34))) {\n mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.\n revert(0x1c, 0x04)\n }\n }\n // Loop through all the `ids` and update the balances.\n {\n for { let i := shl(5, mload(ids)) } i { i := sub(i, 0x20) } {\n let amount := mload(add(amounts, i))\n // Decrease and store the updated balance of `from`.\n {\n mstore(0x00, mload(add(ids, i)))\n let fromBalanceSlot := keccak256(0x00, 0x40)\n let fromBalance := sload(fromBalanceSlot)\n if gt(amount, fromBalance) {\n mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.\n revert(0x1c, 0x04)\n }\n sstore(fromBalanceSlot, sub(fromBalance, amount))\n }\n }\n }\n // Emit a {TransferBatch} event.\n {\n let m := mload(0x40)\n // Copy the `ids`.\n mstore(m, 0x40)\n let n := add(0x20, shl(5, mload(ids)))\n let o := add(m, 0x40)\n pop(staticcall(gas(), 4, ids, n, o, n))\n // Copy the `amounts`.\n mstore(add(m, 0x20), add(0x40, returndatasize()))\n o := add(o, returndatasize())\n n := add(0x20, shl(5, mload(amounts)))\n pop(staticcall(gas(), 4, amounts, n, o, n))\n n := sub(add(o, returndatasize()), m)\n // Do the emit.\n log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), 0)\n }\n }\n if (_useAfterTokenTransfer()) {\n _afterTokenTransfer(from, address(0), ids, amounts, \"\");\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* INTERNAL APPROVAL FUNCTIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Approve or remove the `operator` as an operator for `by`,\n /// without authorization checks.\n ///\n /// Emits a {ApprovalForAll} event.\n function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual {\n /// @solidity memory-safe-assembly\n assembly {\n // Convert to 0 or 1.\n isApproved := iszero(iszero(isApproved))\n // Update the `isApproved` for (`by`, `operator`).\n mstore(0x20, _ERC1155_MASTER_SLOT_SEED)\n mstore(0x14, by)\n mstore(0x00, operator)\n sstore(keccak256(0x0c, 0x34), isApproved)\n // Emit the {ApprovalForAll} event.\n mstore(0x00, isApproved)\n let m := shr(96, not(0))\n log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, and(m, by), and(m, operator))\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* INTERNAL TRANSFER FUNCTIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Equivalent to `_safeTransfer(address(0), from, to, id, amount, data)`.\n function _safeTransfer(address from, address to, uint256 id, uint256 amount, bytes memory data)\n internal\n virtual\n {\n _safeTransfer(address(0), from, to, id, amount, data);\n }\n\n /// @dev Transfers `amount` of `id` from `from` to `to`.\n ///\n /// Requirements:\n /// - `to` cannot be the zero address.\n /// - `from` must have at least `amount` of `id`.\n /// - If `by` is not the zero address, it must be either `from`,\n /// or approved to manage the tokens of `from`.\n /// - If `to` refers to a smart contract, it must implement\n /// {ERC1155-onERC1155Reveived}, which is called upon a batch transfer.\n ///\n /// Emits a {Transfer} event.\n function _safeTransfer(\n address by,\n address from,\n address to,\n uint256 id,\n uint256 amount,\n bytes memory data\n ) internal virtual {\n if (_useBeforeTokenTransfer()) {\n _beforeTokenTransfer(from, to, _single(id), _single(amount), data);\n }\n /// @solidity memory-safe-assembly\n assembly {\n let from_ := shl(96, from)\n let to_ := shl(96, to)\n // Revert if `to` is the zero address.\n if iszero(to_) {\n mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.\n revert(0x1c, 0x04)\n }\n mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_))\n // If `by` is not the zero address, and not equal to `from`,\n // check if it is approved to manage all the tokens of `from`.\n let by_ := shl(96, by)\n if iszero(or(iszero(by_), eq(by_, from_))) {\n mstore(0x00, by)\n if iszero(sload(keccak256(0x0c, 0x34))) {\n mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.\n revert(0x1c, 0x04)\n }\n }\n // Subtract and store the updated balance of `from`.\n {\n mstore(0x00, id)\n let fromBalanceSlot := keccak256(0x00, 0x40)\n let fromBalance := sload(fromBalanceSlot)\n if gt(amount, fromBalance) {\n mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.\n revert(0x1c, 0x04)\n }\n sstore(fromBalanceSlot, sub(fromBalance, amount))\n }\n // Increase and store the updated balance of `to`.\n {\n mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_))\n let toBalanceSlot := keccak256(0x00, 0x40)\n let toBalanceBefore := sload(toBalanceSlot)\n let toBalanceAfter := add(toBalanceBefore, amount)\n if lt(toBalanceAfter, toBalanceBefore) {\n mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.\n revert(0x1c, 0x04)\n }\n sstore(toBalanceSlot, toBalanceAfter)\n }\n // Emit a {TransferSingle} event.\n mstore(0x20, amount)\n // forgefmt: disable-next-line\n log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_))\n }\n if (_useAfterTokenTransfer()) {\n _afterTokenTransfer(from, to, _single(id), _single(amount), data);\n }\n if (_hasCode(to)) _checkOnERC1155Received(from, to, id, amount, data);\n }\n\n /// @dev Equivalent to `_safeBatchTransfer(address(0), from, to, ids, amounts, data)`.\n function _safeBatchTransfer(\n address from,\n address to,\n uint256[] memory ids,\n uint256[] memory amounts,\n bytes memory data\n ) internal virtual {\n _safeBatchTransfer(address(0), from, to, ids, amounts, data);\n }\n\n /// @dev Transfers `amounts` of `ids` from `from` to `to`.\n ///\n /// Requirements:\n /// - `to` cannot be the zero address.\n /// - `ids` and `amounts` must have the same length.\n /// - `from` must have at least `amounts` of `ids`.\n /// - If `by` is not the zero address, it must be either `from`,\n /// or approved to manage the tokens of `from`.\n /// - If `to` refers to a smart contract, it must implement\n /// {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer.\n ///\n /// Emits a {TransferBatch} event.\n function _safeBatchTransfer(\n address by,\n address from,\n address to,\n uint256[] memory ids,\n uint256[] memory amounts,\n bytes memory data\n ) internal virtual {\n if (_useBeforeTokenTransfer()) {\n _beforeTokenTransfer(from, to, ids, amounts, data);\n }\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(eq(mload(ids), mload(amounts))) {\n mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.\n revert(0x1c, 0x04)\n }\n let from_ := shl(96, from)\n let to_ := shl(96, to)\n // Revert if `to` is the zero address.\n if iszero(to_) {\n mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.\n revert(0x1c, 0x04)\n }\n let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, from_)\n let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, to_)\n mstore(0x20, fromSlotSeed)\n // If `by` is not the zero address, and not equal to `from`,\n // check if it is approved to manage all the tokens of `from`.\n let by_ := shl(96, by)\n if iszero(or(iszero(by_), eq(by_, from_))) {\n mstore(0x00, by)\n if iszero(sload(keccak256(0x0c, 0x34))) {\n mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.\n revert(0x1c, 0x04)\n }\n }\n // Loop through all the `ids` and update the balances.\n {\n for { let i := shl(5, mload(ids)) } i { i := sub(i, 0x20) } {\n let amount := mload(add(amounts, i))\n // Subtract and store the updated balance of `from`.\n {\n mstore(0x20, fromSlotSeed)\n mstore(0x00, mload(add(ids, i)))\n let fromBalanceSlot := keccak256(0x00, 0x40)\n let fromBalance := sload(fromBalanceSlot)\n if gt(amount, fromBalance) {\n mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.\n revert(0x1c, 0x04)\n }\n sstore(fromBalanceSlot, sub(fromBalance, amount))\n }\n // Increase and store the updated balance of `to`.\n {\n mstore(0x20, toSlotSeed)\n let toBalanceSlot := keccak256(0x00, 0x40)\n let toBalanceBefore := sload(toBalanceSlot)\n let toBalanceAfter := add(toBalanceBefore, amount)\n if lt(toBalanceAfter, toBalanceBefore) {\n mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.\n revert(0x1c, 0x04)\n }\n sstore(toBalanceSlot, toBalanceAfter)\n }\n }\n }\n // Emit a {TransferBatch} event.\n {\n let m := mload(0x40)\n // Copy the `ids`.\n mstore(m, 0x40)\n let n := add(0x20, shl(5, mload(ids)))\n let o := add(m, 0x40)\n pop(staticcall(gas(), 4, ids, n, o, n))\n // Copy the `amounts`.\n mstore(add(m, 0x20), add(0x40, returndatasize()))\n o := add(o, returndatasize())\n n := add(0x20, shl(5, mload(amounts)))\n pop(staticcall(gas(), 4, amounts, n, o, n))\n n := sub(add(o, returndatasize()), m)\n // Do the emit.\n log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_))\n }\n }\n if (_useAfterTokenTransfer()) {\n _afterTokenTransfer(from, to, ids, amounts, data);\n }\n if (_hasCode(to)) _checkOnERC1155BatchReceived(from, to, ids, amounts, data);\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* HOOKS FOR OVERRIDING */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Override this function to return true if `_beforeTokenTransfer` is used.\n /// This is to help the compiler avoid producing dead bytecode.\n function _useBeforeTokenTransfer() internal view virtual returns (bool) {\n return false;\n }\n\n /// @dev Hook that is called before any token transfer.\n /// This includes minting and burning, as well as batched variants.\n ///\n /// The same hook is called on both single and batched variants.\n /// For single transfers, the length of the `id` and `amount` arrays are 1.\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256[] memory ids,\n uint256[] memory amounts,\n bytes memory data\n ) internal virtual {}\n\n /// @dev Override this function to return true if `_afterTokenTransfer` is used.\n /// This is to help the compiler avoid producing dead bytecode.\n function _useAfterTokenTransfer() internal view virtual returns (bool) {\n return false;\n }\n\n /// @dev Hook that is called after any token transfer.\n /// This includes minting and burning, as well as batched variants.\n ///\n /// The same hook is called on both single and batched variants.\n /// For single transfers, the length of the `id` and `amount` arrays are 1.\n function _afterTokenTransfer(\n address from,\n address to,\n uint256[] memory ids,\n uint256[] memory amounts,\n bytes memory data\n ) internal virtual {}\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* PRIVATE HELPERS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Helper for calling the `_afterTokenTransfer` hook.\n /// This is to help the compiler avoid producing dead bytecode.\n function _afterTokenTransferCalldata(\n address from,\n address to,\n uint256[] calldata ids,\n uint256[] calldata amounts,\n bytes calldata data\n ) private {\n if (_useAfterTokenTransfer()) {\n _afterTokenTransfer(from, to, ids, amounts, data);\n }\n }\n\n /// @dev Returns if `a` has bytecode of non-zero length.\n function _hasCode(address a) private view returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := extcodesize(a) // Can handle dirty upper bits.\n }\n }\n\n /// @dev Perform a call to invoke {IERC1155Receiver-onERC1155Received} on `to`.\n /// Reverts if the target does not support the function correctly.\n function _checkOnERC1155Received(\n address from,\n address to,\n uint256 id,\n uint256 amount,\n bytes memory data\n ) private {\n /// @solidity memory-safe-assembly\n assembly {\n // Prepare the calldata.\n let m := mload(0x40)\n // `onERC1155Received(address,address,uint256,uint256,bytes)`.\n mstore(m, 0xf23a6e61)\n mstore(add(m, 0x20), caller())\n mstore(add(m, 0x40), shr(96, shl(96, from)))\n mstore(add(m, 0x60), id)\n mstore(add(m, 0x80), amount)\n mstore(add(m, 0xa0), 0xa0)\n let n := mload(data)\n mstore(add(m, 0xc0), n)\n if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xe0), n)) }\n // Revert if the call reverts.\n if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, n), m, 0x20)) {\n if returndatasize() {\n // Bubble up the revert if the call reverts.\n returndatacopy(m, 0x00, returndatasize())\n revert(m, returndatasize())\n }\n }\n // Load the returndata and compare it with the function selector.\n if iszero(eq(mload(m), shl(224, 0xf23a6e61))) {\n mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Perform a call to invoke {IERC1155Receiver-onERC1155BatchReceived} on `to`.\n /// Reverts if the target does not support the function correctly.\n function _checkOnERC1155BatchReceived(\n address from,\n address to,\n uint256[] memory ids,\n uint256[] memory amounts,\n bytes memory data\n ) private {\n /// @solidity memory-safe-assembly\n assembly {\n // Prepare the calldata.\n let m := mload(0x40)\n // `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`.\n mstore(m, 0xbc197c81)\n mstore(add(m, 0x20), caller())\n mstore(add(m, 0x40), shr(96, shl(96, from)))\n // Copy the `ids`.\n mstore(add(m, 0x60), 0xa0)\n let n := add(0x20, shl(5, mload(ids)))\n let o := add(m, 0xc0)\n pop(staticcall(gas(), 4, ids, n, o, n))\n // Copy the `amounts`.\n let s := add(0xa0, returndatasize())\n mstore(add(m, 0x80), s)\n o := add(o, returndatasize())\n n := add(0x20, shl(5, mload(amounts)))\n pop(staticcall(gas(), 4, amounts, n, o, n))\n // Copy the `data`.\n mstore(add(m, 0xa0), add(s, returndatasize()))\n o := add(o, returndatasize())\n n := add(0x20, mload(data))\n pop(staticcall(gas(), 4, data, n, o, n))\n n := sub(add(o, returndatasize()), add(m, 0x1c))\n // Revert if the call reverts.\n if iszero(call(gas(), to, 0, add(m, 0x1c), n, m, 0x20)) {\n if returndatasize() {\n // Bubble up the revert if the call reverts.\n returndatacopy(m, 0x00, returndatasize())\n revert(m, returndatasize())\n }\n }\n // Load the returndata and compare it with the function selector.\n if iszero(eq(mload(m), shl(224, 0xbc197c81))) {\n mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Returns `x` in an array with a single element.\n function _single(uint256 x) private pure returns (uint256[] memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(0x40)\n mstore(0x40, add(result, 0x40))\n mstore(result, 1)\n mstore(add(result, 0x20), x)\n }\n }\n}\n"},"lib/solady/src/utils/Base64.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library to encode strings in Base64.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol)\n/// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - <brecht@loopring.org>.\nlibrary Base64 {\n /// @dev Encodes `data` using the base64 encoding described in RFC 4648.\n /// See: https://datatracker.ietf.org/doc/html/rfc4648\n /// @param fileSafe Whether to replace '+' with '-' and '/' with '_'.\n /// @param noPadding Whether to strip away the padding.\n function encode(bytes memory data, bool fileSafe, bool noPadding)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let dataLength := mload(data)\n\n if dataLength {\n // Multiply by 4/3 rounded up.\n // The `shl(2, ...)` is equivalent to multiplying by 4.\n let encodedLength := shl(2, div(add(dataLength, 2), 3))\n\n // Set `result` to point to the start of the free memory.\n result := mload(0x40)\n\n // Store the table into the scratch space.\n // Offsetted by -1 byte so that the `mload` will load the character.\n // We will rewrite the free memory pointer at `0x40` later with\n // the allocated size.\n // The magic constant 0x0670 will turn \"-_\" into \"+/\".\n mstore(0x1f, \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef\")\n mstore(0x3f, xor(\"ghijklmnopqrstuvwxyz0123456789-_\", mul(iszero(fileSafe), 0x0670)))\n\n // Skip the first slot, which stores the length.\n let ptr := add(result, 0x20)\n let end := add(ptr, encodedLength)\n\n // Run over the input, 3 bytes at a time.\n for {} 1 {} {\n data := add(data, 3) // Advance 3 bytes.\n let input := mload(data)\n\n // Write 4 bytes. Optimized for fewer stack operations.\n mstore8(0, mload(and(shr(18, input), 0x3F)))\n mstore8(1, mload(and(shr(12, input), 0x3F)))\n mstore8(2, mload(and(shr(6, input), 0x3F)))\n mstore8(3, mload(and(input, 0x3F)))\n mstore(ptr, mload(0x00))\n\n ptr := add(ptr, 4) // Advance 4 bytes.\n if iszero(lt(ptr, end)) { break }\n }\n mstore(0x40, add(end, 0x20)) // Allocate the memory.\n // Equivalent to `o = [0, 2, 1][dataLength % 3]`.\n let o := div(2, mod(dataLength, 3))\n // Offset `ptr` and pad with '='. We can simply write over the end.\n mstore(sub(ptr, o), shl(240, 0x3d3d))\n // Set `o` to zero if there is padding.\n o := mul(iszero(iszero(noPadding)), o)\n mstore(sub(ptr, o), 0) // Zeroize the slot after the string.\n mstore(result, sub(encodedLength, o)) // Store the length.\n }\n }\n }\n\n /// @dev Encodes `data` using the base64 encoding described in RFC 4648.\n /// Equivalent to `encode(data, false, false)`.\n function encode(bytes memory data) internal pure returns (string memory result) {\n result = encode(data, false, false);\n }\n\n /// @dev Encodes `data` using the base64 encoding described in RFC 4648.\n /// Equivalent to `encode(data, fileSafe, false)`.\n function encode(bytes memory data, bool fileSafe)\n internal\n pure\n returns (string memory result)\n {\n result = encode(data, fileSafe, false);\n }\n\n /// @dev Decodes base64 encoded `data`.\n ///\n /// Supports:\n /// - RFC 4648 (both standard and file-safe mode).\n /// - RFC 3501 (63: ',').\n ///\n /// Does not support:\n /// - Line breaks.\n ///\n /// Note: For performance reasons,\n /// this function will NOT revert on invalid `data` inputs.\n /// Outputs for invalid inputs will simply be undefined behaviour.\n /// It is the user's responsibility to ensure that the `data`\n /// is a valid base64 encoded string.\n function decode(string memory data) internal pure returns (bytes memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n let dataLength := mload(data)\n\n if dataLength {\n let decodedLength := mul(shr(2, dataLength), 3)\n\n for {} 1 {} {\n // If padded.\n if iszero(and(dataLength, 3)) {\n let t := xor(mload(add(data, dataLength)), 0x3d3d)\n // forgefmt: disable-next-item\n decodedLength := sub(\n decodedLength,\n add(iszero(byte(30, t)), iszero(byte(31, t)))\n )\n break\n }\n // If non-padded.\n decodedLength := add(decodedLength, sub(and(dataLength, 3), 1))\n break\n }\n result := mload(0x40)\n\n // Write the length of the bytes.\n mstore(result, decodedLength)\n\n // Skip the first slot, which stores the length.\n let ptr := add(result, 0x20)\n let end := add(ptr, decodedLength)\n\n // Load the table into the scratch space.\n // Constants are optimized for smaller bytecode with zero gas overhead.\n // `m` also doubles as the mask of the upper 6 bits.\n let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc\n mstore(0x5b, m)\n mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064)\n mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4)\n\n for {} 1 {} {\n // Read 4 bytes.\n data := add(data, 4)\n let input := mload(data)\n\n // Write 3 bytes.\n // forgefmt: disable-next-item\n mstore(ptr, or(\n and(m, mload(byte(28, input))),\n shr(6, or(\n and(m, mload(byte(29, input))),\n shr(6, or(\n and(m, mload(byte(30, input))),\n shr(6, mload(byte(31, input)))\n ))\n ))\n ))\n ptr := add(ptr, 3)\n if iszero(lt(ptr, end)) { break }\n }\n mstore(0x40, add(end, 0x20)) // Allocate the memory.\n mstore(end, 0) // Zeroize the slot after the bytes.\n mstore(0x60, 0) // Restore the zero slot.\n }\n }\n }\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n * @custom:oz-retyped-from bool\n */\n uint8 private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint8 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n * constructor.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n bool isTopLevelCall = !_initializing;\n require(\n (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n \"Initializable: contract is already initialized\"\n );\n _initialized = 1;\n if (isTopLevelCall) {\n _initializing = true;\n }\n _;\n if (isTopLevelCall) {\n _initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: setting the version to 255 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint8 version) {\n require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n _initialized = version;\n _initializing = true;\n _;\n _initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n require(_initializing, \"Initializable: contract is not initializing\");\n _;\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n require(!_initializing, \"Initializable: contract is initializing\");\n if (_initialized != type(uint8).max) {\n _initialized = type(uint8).max;\n emit Initialized(type(uint8).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint8) {\n return _initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _initializing;\n }\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC2981Upgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/introspection/IERC165Upgradeable.sol\";\n\n/**\n * @dev Interface for the NFT Royalty Standard.\n *\n * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal\n * support for royalty payments across all NFT marketplaces and ecosystem participants.\n *\n * _Available since v4.5._\n */\ninterface IERC2981Upgradeable is IERC165Upgradeable {\n /**\n * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of\n * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.\n */\n function royaltyInfo(\n uint256 tokenId,\n uint256 salePrice\n ) external view returns (address receiver, uint256 royaltyAmount);\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/utils/AddressUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n *\n * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/utils/introspection/IERC165Upgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165Upgradeable {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"}},"settings":{"remappings":["ds-test/=lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/","openzeppelin/=lib/openzeppelin-contracts/contracts/","solady/=lib/solady/src/"],"optimizer":{"enabled":true,"runs":1000},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata","storageLayout"]}},"evmVersion":"paris","viaIR":true,"libraries":{}}}