Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/MegaBadgeImplV1.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import {ERC1155Upgradeable} from "@openzeppelin-upgradeable/contracts/token/ERC1155/ERC1155Upgradeable.sol";
import {Initializable} from "@openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol";
import {UUPSUpgradeable} from "@openzeppelin-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin-upgradeable/contracts/utils/PausableUpgradeable.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {MegaBadgeManagement} from "./MegaBadgeManagement.sol";
/*
##########################################
#############################################
#################################################
########## #####
############ #####
################ #####
##################### #####
############################ #####
################################ #####
################################# #####
################################# #####
################################# ###### ###### #####
################################# ###### ####### #####
################################# ###### ####### #####
################################# ###### ####### #####
################################# #### ##### #####
################################# #####
################################# #####
################################# #####
################################ #####
############################ #####
###### #################### #####
###### ################## #####
################ ####################################################
############### ###############################################
############# ##########################################
*/
/**
* @title MegaBadgeImplV1
* @notice Implementation contract for Megaphone Registration Badges.
*/
/// @custom:oz-upgrades-from src/MegaBadgeImplV1.sol:MegaBadgeImplV1
contract MegaBadgeImplV1 is
Initializable,
ERC1155Upgradeable,
UUPSUpgradeable,
PausableUpgradeable,
MegaBadgeManagement
{
// Events
event ContractInitialized(
address indexed owner,
address indexed platform,
address platformTreasury,
uint256 defaultPlatformFee,
string uri
);
event CustomPlatformFeeSet(uint256 indexed tokenId, uint256 fee);
event DefaultPlatformFeeSet(uint256 fee);
event MaxMintCountForTokenIdSet(uint256 indexed tokenId, uint256 maxMintCount);
event MaxMintCountPerAddressSet(uint256 indexed tokenId, uint256 maxMintsAllowed);
event MintLaunched(
uint256 indexed tokenId,
address indexed mintPriceRecipient,
uint256 mintPrice,
uint256 customPlatformFee,
bool isSoulbound
);
event MintPriceSet(uint256 indexed tokenId, uint256 price);
event MintPriceRecipientSet(uint256 indexed tokenId, address recipient);
event PlatformTreasurySet(address indexed platformTreasury);
event SoulboundStatusSet(uint256 indexed tokenId, bool status);
event StartTimeSet(uint256 indexed tokenId, uint256 _startTime);
event EndTimeSet(uint256 indexed tokenId, uint256 _endTime);
event PlatformOwnershipTransferred(address indexed previousPlatform, address indexed newPlatform);
/**
* @notice Initializes the contract setting the platformTreasury, defaultPlatformFee and the URI for the ERC1155 token.
* @param _owner The address to set as the owner. If zero address, defaults to _msgSender().
* @param _platform The address to set as the Megaphone backend admin.
* @param _platformTreasury The address of the Megaphone treasury.
* @param _defaultPlatformFee The default Megaphone service fee.
* @param _uri The URI for the ERC1155 token.
*/
function initialize(
address _owner,
address _platform,
address _platformTreasury,
uint256 _defaultPlatformFee,
string memory _uri
) public initializer {
require(_platformTreasury != address(0), "Platform treasury cannot be zero address");
__ERC1155_init(_uri);
address _o = _owner != address(0) ? _owner : _msgSender();
__Ownable_init(_o);
__UUPSUpgradeable_init();
__Pausable_init();
PlatformManagementStorage storage $P = _getPlatformManagementStorage();
$P.platform = _platform;
$P.platformTreasury = _platformTreasury;
$P.defaultPlatformFee = _defaultPlatformFee;
emit ContractInitialized(_owner, _platform, _platformTreasury, _defaultPlatformFee, _uri);
}
/**
* @notice Throws if the proxy upgrade is called by any account other than the owner.
*/
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
/**
* @notice Transfer Megaphone Platform address to a new address.
* @param newPlatformAddress The new address to transfer the Megaphone platform admin to.
*/
function transferPlatformOwnership(address newPlatformAddress) public onlyOwner {
PlatformManagementStorage storage $P = _getPlatformManagementStorage();
address oldPlatformAddress = $P.platform;
$P.platform = newPlatformAddress;
emit PlatformOwnershipTransferred(oldPlatformAddress, newPlatformAddress);
}
function _processPayment(uint256 _tokenId, uint256 _amount) internal {
require(msg.value >= _totalFee(_tokenId) * _amount, "Wrong amount of ETH sent");
// Transfer mintprice.
uint256 mintprice = mintPrice(_tokenId);
address recipient = mintPriceRecipient(_tokenId);
address platformTreasury = platformTreasury();
uint256 remaining = msg.value;
if (mintprice > 0 && recipient != address(0)) {
remaining -= mintprice;
(bool sent,) = recipient.call{value: mintprice}("");
require(sent, "Failed to send Ether");
}
if (remaining > 0) {
(bool sent,) = platformTreasury.call{value: remaining}("");
require(sent, "Failed to send Ether");
}
}
function _mintTokens(address _to, uint256 _tokenId, uint256 _amount, bytes calldata _data) private {
// Check mint status.
uint256 s = startTime(_tokenId);
require(s != 0 && block.timestamp >= s, "Minting not started");
uint256 e = endTime(_tokenId);
require(e == 0 || block.timestamp <= e, "Minting ended");
// Check max supply per tokenId.
uint256 maxPerToken = maxMintCountPerTokenId(_tokenId);
uint256 currentSupply = totalSupply(_tokenId);
require(maxPerToken == 0 || currentSupply + _amount <= maxPerToken, "Reached max supply for tokenId");
// Check max mints per address.
uint256 currentMintCount = mintCount(_tokenId, _to);
uint256 maxPerAddress = maxMintCountPerAddress(_tokenId);
require(maxPerAddress == 0 || currentMintCount + _amount <= maxPerAddress, "Reached max mints for address");
// Process the mint fee payment.
_processPayment(_tokenId, _amount);
// Increment total supply and mint count.
MintStatusStorage storage $MS = _getMintStatusStorage();
$MS.totalSupply[_tokenId] = currentSupply + _amount;
$MS.mintCount[_tokenId][_to] = currentMintCount + _amount;
// Mint the tokens.
_mint(_to, _tokenId, _amount, _data);
}
/**
* @notice Mints a new token to the caller of the mint function.
* @param _tokenId The ID of the token to mint.
* @param _amount The number of tokens to mint.
* @param _data Additional data with no specified format.
*/
function mint(uint256 _tokenId, uint256 _amount, bytes calldata _data) public payable whenNotPaused {
_mintTokens(_msgSender(), _tokenId, _amount, _data);
}
/**
* @notice Configure an optional max limit on the number of possible mints per
* tokenId. If 0 (default), then we assume no cap.
* @param tokenId The ID of the token to set the max mint count for.
* @param maxMintCount The max mint count to set.
*/
function setMaxMintCountForTokenId(uint256 tokenId, uint256 maxMintCount) public onlyPlatformOrOwner {
MintStatusStorage storage $MS = _getMintStatusStorage();
require(
maxMintCount == 0 || maxMintCount >= $MS.totalSupply[tokenId],
"Max mint count cannot be less than totalSupply"
);
$MS.maxMintCountPerTokenId[tokenId] = maxMintCount;
emit MaxMintCountForTokenIdSet(tokenId, maxMintCount);
}
/**
* @notice Update the max mints allowed for any given address on a token id.
* @param tokenId The ID of the token to set the max mint count for.
* @param maxMintsAllowed The max mint count to set.
*/
function setMaxMintCountForAddress(uint256 tokenId, uint256 maxMintsAllowed) public onlyPlatformOrOwner {
MintStatusStorage storage $MS = _getMintStatusStorage();
if ($MS.totalSupply[tokenId] > 0) {
require(
maxMintsAllowed >= $MS.maxMintCountPerAddress[tokenId],
"Only increases are supported once minting has begun"
);
}
$MS.maxMintCountPerAddress[tokenId] = maxMintsAllowed;
emit MaxMintCountPerAddressSet(tokenId, maxMintsAllowed);
}
/**
* @notice Returns the next tokenId to be launched, and then increments the pointer.
* @return The tokenId to be launched.
*/
function _useNextTokenId() internal returns (uint256) {
MintStatusStorage storage $MS = _getMintStatusStorage();
uint256 currentId = $MS.nextTokenId;
$MS.nextTokenId++;
return currentId;
}
/**
* @notice Launches a new mint.
* @param mintPrice The price of the mint.
* @param mintPriceRecipient The address to receive the mint price.
* @param startTime The start time of the mint.
* @param endTime The end time of the mint.
* @param customPlatformFee The custom platform fee.
* @param isSoulbound The soulbound status of the mint.
* @return The tokenId of the newly launched token.
*/
function launchMint(
uint256 mintPrice,
address mintPriceRecipient,
uint256 startTime,
uint256 endTime,
uint256 customPlatformFee,
bool isSoulbound
) public onlyPlatformOrOwner returns (uint256) {
require(startTime > 0, "startTime must be non-zero");
return _launchMint(mintPrice, mintPriceRecipient, startTime, endTime, customPlatformFee, isSoulbound);
}
function _launchMint(
uint256 mintPrice,
address mintPriceRecipient,
uint256 startTime,
uint256 endTime,
uint256 customPlatformFee,
bool isSoulbound
) internal returns (uint256) {
require(startTime > 0, "startTime must be non-zero");
uint256 id = _useNextTokenId();
// Additional price to charge for the mint beyond the platform fee.
if (mintPrice > 0) _setMintPrice(id, mintPrice);
// Address to receive the mintPrice.
if (mintPriceRecipient != address(0)) _setMintPriceRecipient(id, mintPriceRecipient);
// Start time of the mint.
_setStartTime(id, startTime);
// End time of the mint.
if (endTime > 0) _setEndTime(id, endTime);
// Custom platform fee to charge for the mint.
if (customPlatformFee > 0) _setCustomPlatformFee(id, customPlatformFee);
// Soulbound status of the mint.
if (isSoulbound) _setSoulbound(id, isSoulbound);
emit MintLaunched(id, mintPriceRecipient, mintPrice, customPlatformFee, isSoulbound);
return id;
}
/**
* @notice Sets the mint price for a token ID.
* @param id The ID of the token to set the mint price for.
* @param price The price to set.
*/
function setMintPrice(uint256 id, uint256 price) public onlyPlatformOrOwner {
_setMintPrice(id, price);
}
function _setMintPrice(uint256 id, uint256 price) internal {
MintPriceStorage storage $MP = _getMintPriceStorage();
$MP.mintPrice[id] = price;
emit MintPriceSet(id, price);
}
/**
* @notice Sets the mint price recipient for a token ID.
* @param id The ID of the token to set the mint price recipient for.
* @param recipient The address to set as the mint price recipient.
*/
function setMintPriceRecipient(uint256 id, address recipient) public onlyPlatformOrOwner {
_setMintPriceRecipient(id, recipient);
}
function _setMintPriceRecipient(uint256 id, address recipient) internal {
MintPriceStorage storage $MP = _getMintPriceStorage();
$MP.mintPriceRecipient[id] = recipient;
emit MintPriceRecipientSet(id, recipient);
}
/**
* @notice Returns the platform fee for a token ID. If customPlatformFee is 0, then use default fee.
* @param tokenId The ID of the token to return the platform fee for.
* @return uint256 representing the platform fee.
*/
function getPlatformFee(uint256 tokenId) public view returns (uint256) {
MintPriceStorage storage $MP = _getMintPriceStorage();
return $MP.customPlatformFee[tokenId] != 0 ? $MP.customPlatformFee[tokenId] : defaultPlatformFee();
}
/**
* @notice Sets the platform fee for a token ID.
* @param tokenId The ID of the token to set the platform fee for.
* @param fee The platform fee to set.
*/
function setCustomPlatformFee(uint256 tokenId, uint256 fee) public onlyPlatformOrOwner {
_setCustomPlatformFee(tokenId, fee);
}
function _setCustomPlatformFee(uint256 id, uint256 fee) internal {
MintPriceStorage storage $MP = _getMintPriceStorage();
$MP.customPlatformFee[id] = fee;
emit CustomPlatformFeeSet(id, fee);
}
/**
* @notice Updates the default platform fee for all token IDs.
* @param fee The new default platform fee.
*/
function setDefaultPlatformFee(uint256 fee) public onlyPlatformOrOwner {
PlatformManagementStorage storage $P = _getPlatformManagementStorage();
$P.defaultPlatformFee = fee;
emit DefaultPlatformFeeSet(fee);
}
/**
* @notice Returns the total fee for a token ID.
* @param _id The ID of the token to return the total fee for.
* @param _amount The amount of tokens to return the total fee for.
* @return uint256 representing the total fee.
*/
function totalFee(uint256 _id, uint256 _amount) public view returns (uint256) {
return _totalFee(_id) * _amount;
}
function _totalFee(uint256 _tokenId) internal view returns (uint256) {
MintPriceStorage storage $MP = _getMintPriceStorage();
uint256 _mintPrice = $MP.mintPrice[_tokenId];
uint256 _customPlatformFee = $MP.customPlatformFee[_tokenId];
if (_customPlatformFee == 0) {
return _mintPrice + defaultPlatformFee();
}
return _mintPrice + _customPlatformFee;
}
/**
* @notice Sets the platform treasury address.
* @param _platformTreasury The address to set as the platform treasury payout address.
*/
function setPlatformTreasury(address _platformTreasury) public onlyOwner {
require(_platformTreasury != address(0), "Platform treasury cannot be zero address");
PlatformManagementStorage storage $P = _getPlatformManagementStorage();
$P.platformTreasury = _platformTreasury;
emit PlatformTreasurySet(_platformTreasury);
}
function setStartTime(uint256 id, uint256 _startTime) public onlyPlatformOrOwner {
_setStartTime(id, _startTime);
}
function _setStartTime(uint256 id, uint256 _startTime) internal {
MintTimingStorage storage $MT = _getMintTimingStorage();
$MT.startTime[id] = _startTime;
emit StartTimeSet(id, _startTime);
}
function setEndTime(uint256 id, uint256 _endTime) public onlyPlatformOrOwner {
_setEndTime(id, _endTime);
}
function _setEndTime(uint256 id, uint256 _endTime) internal {
MintTimingStorage storage $MT = _getMintTimingStorage();
$MT.endTime[id] = _endTime;
emit EndTimeSet(id, _endTime);
}
/**
* @notice Sets the base URI for the metadata.
*
* We expect base uri to be in a format like this: https://badges.megaphone.xyz/v1/chain/:chainId
* Note: no trailing backslash
*
* @param newuri The new base URI.
*/
function setBaseURI(string memory newuri) public onlyOwner {
_setURI(newuri);
}
/**
* @notice Returns the URI for the contract's metadata: https://badges.megaphone.xyz/v1/chain/:chainId
* @return A string representing the URI.
*/
function contractURI() public view returns (string memory) {
return super.uri(0);
}
/**
* @notice Returns the URI for a token ID: https://badges.megaphone.xyz/v1/chain/:chainId/token/:tokenId
*
* We expect base uri to be in a format like this: https://badges.megaphone.xyz/v1/chain/:chainId
* Note: no trailing backslash
*
* @param id The ID of the token to return the URI for.
* @return A string representing the URI.
*/
function uri(uint256 id) public view override returns (string memory) {
require(id < nextTokenId(), "Unlaunched tokenId");
return string(abi.encodePacked(super.uri(id), "/token/", Strings.toString(id)));
}
/**
* @notice Burns a token. The sender must have enough tokens to burn.
* @param id The ID of the token to burn.
* @param amount The amount of tokens to burn.
*/
function burn(uint256 id, uint256 amount) public {
address account = _msgSender();
// Call the inherited _burn function
super._burn(account, id, amount);
}
/**
* @notice Sets the soulbound status of a token ID.
* @param tokenId The ID of the token to set the soulbound status for.
* @param status The soulbound status to set.
*/
function setSoulbound(uint256 tokenId, bool status) public onlyPlatformOrOwner {
_setSoulbound(tokenId, status);
}
function _setSoulbound(uint256 tokenId, bool status) internal {
MintStatusStorage storage $MS = _getMintStatusStorage();
$MS.isSoulbound[tokenId] = status;
emit SoulboundStatusSet(tokenId, status);
}
/**
* @notice Override the _update function to implement soulbound check based on isSoulbound status per tokenId.
*/
function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal override {
MintStatusStorage storage $MS = _getMintStatusStorage();
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
if ($MS.isSoulbound[id]) {
require(from == address(0) || to == address(0), "Soulbound token id cannot be transferred.");
}
}
super._update(from, to, ids, values);
}
/**
* @notice Triggers stop state on the contract. The main thing we care about
* pausing is all mints across all tokenIds. Useful for emergency situations.
*/
function pause() public onlyOwner {
_pause();
}
/**
* @notice Triggers start state on the contract. The main thing we care about
* unpausing is all mints across all tokenIds.
*/
function unpause() public onlyOwner {
_unpause();
}
struct TokenInfo {
// Minting
uint256 mintPrice;
address mintPriceRecipient;
uint256 customPlatformFee;
uint256 totalFee;
// Timing
uint256 startTime;
uint256 endTime;
// Supply & limits
uint256 totalSupply;
uint256 maxMintCountPerTokenId;
uint256 maxMintCountPerAddress;
// Status
bool isSoulbound;
// computed: tokenId < nextTokenId
bool isLaunched;
}
/**
* @notice Convenience helper to return token info for a single tokenId.
* @param tokenId The ID of the token to return the info for.
* @return TokenInfo struct containing the token info.
*/
function getTokenInfo(uint256 tokenId) external view returns (TokenInfo memory) {
return _getTokenInfo(tokenId);
}
/**
* @notice Convenience helper to return token info for a batch of tokenIds.
* @param tokenIds The IDs of the tokens to return the info for.
* @return TokenInfo[] array of TokenInfo structs containing the token info.
*/
function getTokenInfo(uint256[] calldata tokenIds) external view returns (TokenInfo[] memory) {
TokenInfo[] memory infos = new TokenInfo[](tokenIds.length);
for (uint256 i = 0; i < tokenIds.length; i++) {
infos[i] = _getTokenInfo(tokenIds[i]);
}
return infos;
}
function _getTokenInfo(uint256 tokenId) internal view returns (TokenInfo memory) {
MintPriceStorage storage $MP = _getMintPriceStorage();
MintTimingStorage storage $MT = _getMintTimingStorage();
MintStatusStorage storage $MS = _getMintStatusStorage();
uint256 start = $MT.startTime[tokenId];
uint256 end = $MT.endTime[tokenId];
return TokenInfo({
mintPrice: $MP.mintPrice[tokenId],
mintPriceRecipient: $MP.mintPriceRecipient[tokenId],
customPlatformFee: $MP.customPlatformFee[tokenId],
totalFee: _totalFee(tokenId),
startTime: start,
endTime: end,
totalSupply: $MS.totalSupply[tokenId],
maxMintCountPerTokenId: $MS.maxMintCountPerTokenId[tokenId],
maxMintCountPerAddress: $MS.maxMintCountPerAddress[tokenId],
isSoulbound: $MS.isSoulbound[tokenId],
isLaunched: tokenId < $MS.nextTokenId
});
}
struct UserInfo {
// how many tokens the user currently has for this tokenId
uint256 userCurrentBalance;
// how many times the user has minted this tokenId
uint256 userMintCount;
}
/**
* @notice Convenience helper to return user info for a single tokenId.
* @param tokenId The ID of the token to return the user info for.
* @param user The address of the user to return the info for.
* @return UserInfo struct containing the user info.
*/
function getUserInfo(uint256 tokenId, address user) external view returns (UserInfo memory) {
return _getUserInfo(tokenId, user);
}
function _getUserInfo(uint256 tokenId, address user) internal view returns (UserInfo memory) {
uint256 userMintCount = mintCount(tokenId, user);
uint256 userBalance = balanceOf(user, tokenId);
return UserInfo({userCurrentBalance: userBalance, userMintCount: userMintCount});
}
/**
* @notice Returns the contract name.
*/
function name() public pure returns (string memory) {
return "Megaphone Registration Badge";
}
/**
* @notice Returns the contract symbol.
*/
function symbol() public pure returns (string memory) {
return "MB";
}
}
"
},
"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC1155/ERC1155Upgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/ERC1155.sol)
pragma solidity ^0.8.20;
import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import {IERC1155MetadataURI} from "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol";
import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {ERC165Upgradeable} from "../../utils/introspection/ERC165Upgradeable.sol";
import {Arrays} from "@openzeppelin/contracts/utils/Arrays.sol";
import {IERC1155Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the basic standard multi-token.
* See https://eips.ethereum.org/EIPS/eip-1155
* Originally based on code by Enjin: https://github.com/enjin/erc-1155
*/
abstract contract ERC1155Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC1155, IERC1155MetadataURI, IERC1155Errors {
using Arrays for uint256[];
using Arrays for address[];
/// @custom:storage-location erc7201:openzeppelin.storage.ERC1155
struct ERC1155Storage {
mapping(uint256 id => mapping(address account => uint256)) _balances;
mapping(address account => mapping(address operator => bool)) _operatorApprovals;
// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
string _uri;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC1155")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ERC1155StorageLocation = 0x88be536d5240c274a3b1d3a1be54482fd9caa294f08c62a7cde569f49a3c4500;
function _getERC1155Storage() private pure returns (ERC1155Storage storage $) {
assembly {
$.slot := ERC1155StorageLocation
}
}
/**
* @dev See {_setURI}.
*/
function __ERC1155_init(string memory uri_) internal onlyInitializing {
__ERC1155_init_unchained(uri_);
}
function __ERC1155_init_unchained(string memory uri_) internal onlyInitializing {
_setURI(uri_);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC1155MetadataURI-uri}.
*
* This implementation returns the same URI for *all* token types. It relies
* on the token type ID substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* Clients calling this function must replace the `\{id\}` substring with the
* actual token type ID.
*/
function uri(uint256 /* id */) public view virtual returns (string memory) {
ERC1155Storage storage $ = _getERC1155Storage();
return $._uri;
}
/**
* @dev See {IERC1155-balanceOf}.
*/
function balanceOf(address account, uint256 id) public view virtual returns (uint256) {
ERC1155Storage storage $ = _getERC1155Storage();
return $._balances[id][account];
}
/**
* @dev See {IERC1155-balanceOfBatch}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] memory accounts,
uint256[] memory ids
) public view virtual returns (uint256[] memory) {
if (accounts.length != ids.length) {
revert ERC1155InvalidArrayLength(ids.length, accounts.length);
}
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts.unsafeMemoryAccess(i), ids.unsafeMemoryAccess(i));
}
return batchBalances;
}
/**
* @dev See {IERC1155-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC1155-isApprovedForAll}.
*/
function isApprovedForAll(address account, address operator) public view virtual returns (bool) {
ERC1155Storage storage $ = _getERC1155Storage();
return $._operatorApprovals[account][operator];
}
/**
* @dev See {IERC1155-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) public virtual {
address sender = _msgSender();
if (from != sender && !isApprovedForAll(from, sender)) {
revert ERC1155MissingApprovalForAll(sender, from);
}
_safeTransferFrom(from, to, id, value, data);
}
/**
* @dev See {IERC1155-safeBatchTransferFrom}.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) public virtual {
address sender = _msgSender();
if (from != sender && !isApprovedForAll(from, sender)) {
revert ERC1155MissingApprovalForAll(sender, from);
}
_safeBatchTransferFrom(from, to, ids, values, data);
}
/**
* @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. Will mint (or burn) if `from`
* (or `to`) is the zero address.
*
* Emits a {TransferSingle} event if the arrays contain one element, and {TransferBatch} otherwise.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement either {IERC1155Receiver-onERC1155Received}
* or {IERC1155Receiver-onERC1155BatchReceived} and return the acceptance magic value.
* - `ids` and `values` must have the same length.
*
* NOTE: The ERC-1155 acceptance check is not performed in this function. See {_updateWithAcceptanceCheck} instead.
*/
function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal virtual {
ERC1155Storage storage $ = _getERC1155Storage();
if (ids.length != values.length) {
revert ERC1155InvalidArrayLength(ids.length, values.length);
}
address operator = _msgSender();
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids.unsafeMemoryAccess(i);
uint256 value = values.unsafeMemoryAccess(i);
if (from != address(0)) {
uint256 fromBalance = $._balances[id][from];
if (fromBalance < value) {
revert ERC1155InsufficientBalance(from, fromBalance, value, id);
}
unchecked {
// Overflow not possible: value <= fromBalance
$._balances[id][from] = fromBalance - value;
}
}
if (to != address(0)) {
$._balances[id][to] += value;
}
}
if (ids.length == 1) {
uint256 id = ids.unsafeMemoryAccess(0);
uint256 value = values.unsafeMemoryAccess(0);
emit TransferSingle(operator, from, to, id, value);
} else {
emit TransferBatch(operator, from, to, ids, values);
}
}
/**
* @dev Version of {_update} that performs the token acceptance check by calling
* {IERC1155Receiver-onERC1155Received} or {IERC1155Receiver-onERC1155BatchReceived} on the receiver address if it
* contains code (eg. is a smart contract at the moment of execution).
*
* IMPORTANT: Overriding this function is discouraged because it poses a reentrancy risk from the receiver. So any
* update to the contract state after this function would break the check-effect-interaction pattern. Consider
* overriding {_update} instead.
*/
function _updateWithAcceptanceCheck(
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) internal virtual {
_update(from, to, ids, values);
if (to != address(0)) {
address operator = _msgSender();
if (ids.length == 1) {
uint256 id = ids.unsafeMemoryAccess(0);
uint256 value = values.unsafeMemoryAccess(0);
_doSafeTransferAcceptanceCheck(operator, from, to, id, value, data);
} else {
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, values, data);
}
}
}
/**
* @dev Transfers a `value` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `from` must have a balance of tokens of type `id` of at least `value` amount.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
_updateWithAcceptanceCheck(from, to, ids, values, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
* - `ids` and `values` must have the same length.
*/
function _safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
_updateWithAcceptanceCheck(from, to, ids, values, data);
}
/**
* @dev Sets a new URI for all token types, by relying on the token type ID
* substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* By this mechanism, any occurrence of the `\{id\}` substring in either the
* URI or any of the values in the JSON file at said URI will be replaced by
* clients with the token type ID.
*
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
* interpreted by clients as
* `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
* for token type ID 0x4cce0.
*
* See {uri}.
*
* Because these URIs cannot be meaningfully represented by the {URI} event,
* this function emits no events.
*/
function _setURI(string memory newuri) internal virtual {
ERC1155Storage storage $ = _getERC1155Storage();
$._uri = newuri;
}
/**
* @dev Creates a `value` amount of tokens of type `id`, and assigns them to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _mint(address to, uint256 id, uint256 value, bytes memory data) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
_updateWithAcceptanceCheck(address(0), to, ids, values, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `values` must have the same length.
* - `to` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _mintBatch(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
_updateWithAcceptanceCheck(address(0), to, ids, values, data);
}
/**
* @dev Destroys a `value` amount of tokens of type `id` from `from`
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have at least `value` amount of tokens of type `id`.
*/
function _burn(address from, uint256 id, uint256 value) internal {
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
_updateWithAcceptanceCheck(from, address(0), ids, values, "");
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have at least `value` amount of tokens of type `id`.
* - `ids` and `values` must have the same length.
*/
function _burnBatch(address from, uint256[] memory ids, uint256[] memory values) internal {
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
_updateWithAcceptanceCheck(from, address(0), ids, values, "");
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the zero address.
*/
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
ERC1155Storage storage $ = _getERC1155Storage();
if (operator == address(0)) {
revert ERC1155InvalidOperator(address(0));
}
$._operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Performs an acceptance check by calling {IERC1155-onERC1155Received} on the `to` address
* if it contains code at the moment of execution.
*/
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 value,
bytes memory data
) private {
if (to.code.length > 0) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, value, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
// Tokens rejected
revert ERC1155InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
// non-ERC1155Receiver implementer
revert ERC1155InvalidReceiver(to);
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
/**
* @dev Performs a batch acceptance check by calling {IERC1155-onERC1155BatchReceived} on the `to` address
* if it contains code at the moment of execution.
*/
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) private {
if (to.code.length > 0) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, values, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
// Tokens rejected
revert ERC1155InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
// non-ERC1155Receiver implementer
revert ERC1155InvalidReceiver(to);
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
/**
* @dev Creates an array in memory with only one value for each of the elements provided.
*/
function _asSingletonArrays(
uint256 element1,
uint256 element2
) private pure returns (uint256[] memory array1, uint256[] memory array2) {
/// @solidity memory-safe-assembly
assembly {
// Load the free memory pointer
array1 := mload(0x40)
// Set array length to 1
mstore(array1, 1)
// Store the single element at the next word after the length (where content starts)
mstore(add(array1, 0x20), element1)
// Repeat for next array locating it right after the first array
array2 := add(array1, 0x40)
mstore(array2, 1)
mstore(add(array2, 0x20), element2)
// Update the free memory pointer by pointing after the second array
mstore(0x40, add(array2, 0x40))
}
}
}
"
},
"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @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 Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 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 in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._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 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._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() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @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 {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}
"
},
"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.20;
import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Initializable} from "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable __self = address(this);
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
* and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev The call is from an unauthorized context.
*/
error UUPSUnauthorizedCallContext();
/**
* @dev The storage `slot` is unsupported as a UUID.
*/
error UUPSUnsupportedProxiableUUID(bytes32 slot);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_checkProxy();
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
_checkNotDelegated();
_;
}
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual notDelegated returns (bytes32) {
return ERC1967Utils.IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data);
}
/**
* @dev Reverts if the execution is not performed via delegatecall or the execution
* context is not of a proxy with an ERC1967-compliant implementation pointing to self.
* See {_onlyProxy}.
*/
function _checkProxy() internal view virtual {
if (
address(this) == __self || // Must be called through delegatecall
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Reverts if the execution is performed via delegatecall.
* See {notDelegated}.
*/
function _checkNotDelegated() internal view virtual {
if (address(this) != __self) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
*
* As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
* is expected to be the implementation slot in ERC1967.
*
* Emits an {IERC1967-Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
revert UUPSUnsupportedProxiableUUID(slot);
}
ERC1967Utils.upgradeToAndCall(newImplementation, data);
} catch {
// The implementation is not UUPS
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
}
}
}
"
},
"lib/openzeppelin-contracts-upgradeable/contracts/utils/PausableUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Pausable
struct PausableStorage {
bool _paused;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;
function _getPausableStorage() private pure returns (PausableStorage storage $) {
assembly {
$.slot := PausableStorageLocation
}
}
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
PausableStorage storage $ = _getPausableStorage();
$._paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
PausableStorage storage $ = _getPausableStorage();
return $._paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = false;
emit Unpaused(_msgSender());
}
}
"
},
"lib/openzeppelin-contracts/contracts/utils/Strings.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}\
Submitted on: 2025-10-24 09:44:44
Comments
Log in to comment.
No comments yet.