// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol)pragmasolidity ^0.8.0;/**
* @dev Provides a set of functions to operate with Base64 strings.
*
* _Available since v4.5._
*/libraryBase64{
/**
* @dev Base64 Encoding/Decoding Table
*/stringinternalconstant _TABLE ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* @dev Converts a `bytes` to its Bytes64 `string` representation.
*/functionencode(bytesmemory data) internalpurereturns (stringmemory) {
/**
* Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
* https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
*/if (data.length==0) return"";
// Loads the table into memorystringmemory table = _TABLE;
// Encoding takes 3 bytes chunks of binary data from `bytes` data parameter// and split into 4 numbers of 6 bits.// The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up// - `data.length + 2` -> Round up// - `/ 3` -> Number of 3-bytes chunks// - `4 *` -> 4 characters for each chunkstringmemory result =newstring(4* ((data.length+2) /3));
/// @solidity memory-safe-assemblyassembly {
// Prepare the lookup table (skip the first "length" byte)let tablePtr :=add(table, 1)
// Prepare result pointer, jump over lengthlet resultPtr :=add(result, 32)
// Run over the input, 3 bytes at a timefor {
let dataPtr := data
let endPtr :=add(data, mload(data))
} lt(dataPtr, endPtr) {
} {
// Advance 3 bytes
dataPtr :=add(dataPtr, 3)
let input :=mload(dataPtr)
// To write each character, shift the 3 bytes (18 bits) chunk// 4 times in blocks of 6 bits for each character (18, 12, 6, 0)// and apply logical AND with 0x3F which is the number of// the previous character in the ASCII table prior to the Base64 Table// The result is then added to the table to get the character to write,// and finally write it in the result pointer but with a left shift// of 256 (1 byte) - 8 (1 ASCII char) = 248 bitsmstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr :=add(resultPtr, 1) // Advancemstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr :=add(resultPtr, 1) // Advancemstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
resultPtr :=add(resultPtr, 1) // Advancemstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
resultPtr :=add(resultPtr, 1) // Advance
}
// When data `bytes` is not exactly 3 bytes long// it is padded with `=` characters at the endswitchmod(mload(data), 3)
case1 {
mstore8(sub(resultPtr, 1), 0x3d)
mstore8(sub(resultPtr, 2), 0x3d)
}
case2 {
mstore8(sub(resultPtr, 1), 0x3d)
}
}
return result;
}
}
Contract Source Code
File 2 of 31: BatchMintMetadata.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/**
* @title Batch-mint Metadata
* @notice The `BatchMintMetadata` is a contract extension for any base NFT contract. It lets the smart contract
* using this extension set metadata for `n` number of NFTs all at once. This is enabled by storing a single
* base URI for a batch of `n` NFTs, where the metadata for each NFT in a relevant batch is `baseURI/tokenId`.
*/contractBatchMintMetadata{
/// @dev Largest tokenId of each batch of tokens with the same baseURI.uint256[] private batchIds;
/// @dev Mapping from id of a batch of tokens => to base URI for the respective batch of tokens.mapping(uint256=>string) private baseURI;
/**
* @notice Returns the count of batches of NFTs.
* @dev Each batch of tokens has an in ID and an associated `baseURI`.
* See {batchIds}.
*/functiongetBaseURICount() publicviewreturns (uint256) {
return batchIds.length;
}
/**
* @notice Returns the ID for the batch of tokens the given tokenId belongs to.
* @dev See {getBaseURICount}.
* @param _index ID of a token.
*/functiongetBatchIdAtIndex(uint256 _index) publicviewreturns (uint256) {
if (_index >= getBaseURICount()) {
revert("Invalid index");
}
return batchIds[_index];
}
/// @dev Returns the id for the batch of tokens the given tokenId belongs to.function_getBatchId(uint256 _tokenId) internalviewreturns (uint256 batchId, uint256 index) {
uint256 numOfTokenBatches = getBaseURICount();
uint256[] memory indices = batchIds;
for (uint256 i =0; i < numOfTokenBatches; i +=1) {
if (_tokenId < indices[i]) {
index = i;
batchId = indices[i];
return (batchId, index);
}
}
revert("Invalid tokenId");
}
/// @dev Returns the baseURI for a token. The intended metadata URI for the token is baseURI + tokenId.function_getBaseURI(uint256 _tokenId) internalviewreturns (stringmemory) {
uint256 numOfTokenBatches = getBaseURICount();
uint256[] memory indices = batchIds;
for (uint256 i =0; i < numOfTokenBatches; i +=1) {
if (_tokenId < indices[i]) {
return baseURI[indices[i]];
}
}
revert("Invalid tokenId");
}
/// @dev Sets the base URI for the batch of tokens with the given batchId.function_setBaseURI(uint256 _batchId, stringmemory _baseURI) internal{
baseURI[_batchId] = _baseURI;
}
/// @dev Mints a batch of tokenIds and associates a common baseURI to all those Ids.function_batchMintMetadata(uint256 _startId,
uint256 _amountToMint,
stringmemory _baseURIForTokens
) internalreturns (uint256 nextTokenIdToMint, uint256 batchId) {
batchId = _startId + _amountToMint;
nextTokenIdToMint = batchId;
batchIds.push(batchId);
baseURI[batchId] = _baseURIForTokens;
}
}
Contract Source Code
File 3 of 31: Context.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)pragmasolidity ^0.8.0;/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
}
Contract Source Code
File 4 of 31: ContractMetadata.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;import"./interface/IContractMetadata.sol";
/**
* @title Contract Metadata
* @notice Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI
* for you contract.
* Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea.
*/abstractcontractContractMetadataisIContractMetadata{
/// @notice Returns the contract metadata URI.stringpublicoverride contractURI;
/**
* @notice Lets a contract admin set the URI for contract-level metadata.
* @dev Caller should be authorized to setup contractURI, e.g. contract admin.
* See {_canSetContractURI}.
* Emits {ContractURIUpdated Event}.
*
* @param _uri keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
*/functionsetContractURI(stringmemory _uri) externaloverride{
if (!_canSetContractURI()) {
revert("Not authorized");
}
_setupContractURI(_uri);
}
/// @dev Lets a contract admin set the URI for contract-level metadata.function_setupContractURI(stringmemory _uri) internal{
stringmemory prevURI = contractURI;
contractURI = _uri;
emit ContractURIUpdated(prevURI, _uri);
}
/// @dev Returns whether contract metadata can be set in the given execution context.function_canSetContractURI() internalviewvirtualreturns (bool);
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"./interfaces/IDiceNFT.sol";
import"@thirdweb-dev/contracts/base/ERC721Base.sol";
import"@thirdweb-dev/contracts/extension/Permissions.sol";
import"@thirdweb-dev/contracts/extension/DefaultOperatorFilterer.sol";
import"@openzeppelin/contracts/utils/Base64.sol";
import"@openzeppelin/contracts/utils/Strings.sol";
contractDiceNFTisIDiceNFT, ERC721Base, Permissions, DefaultOperatorFilterer{
usingMaterialUtilforMaterial;
usingDiceTypeUtilforDieType;
usingElementalTypeUtilforElementalType;
usingStringsforuint256;
usingStringsforuint8;
bytes32publicconstant BOOST_ADMIN_ROLE =keccak256("BOOST_ADMIN_ROLE");
bytes32publicconstant BOOST_USER_ROLE =keccak256("BOOST_USER_ROLE");
bytes32publicconstant MINTER_ROLE =keccak256("MINTER_ROLE");
uint256public maxTotalSupply;
uint256public defaultBoostCount;
stringpublic imageDirURI;
mapping(uint256=>uint256) private _boosts;
mapping(uint256=> DiceMetadata) private _oldTokenIdToMetadata;
mapping(uint256=>uint256) private _newTokenIdToOldTokenId;
mapping(uint256=>bool) private _oldTokenIdBurned;
modifiertokenExists(uint256 _tokenId) {
if (!_exists(_tokenId)) revert URIQueryForNonexistentToken();
_;
}
constructor(stringmemory _name,
stringmemory _symbol,
stringmemory _imageDirURI,
stringmemory _contractURI,
uint256 _defaultBoostCount,
uint256 _maxSupply,
address _royaltyRecipient,
uint128 _royaltyBps
) ERC721Base(_name, _symbol, _royaltyRecipient, _royaltyBps) {
_setupContractURI(_contractURI);
_setupDefaultRoyaltyInfo(_royaltyRecipient, _royaltyBps);
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(MINTER_ROLE, msg.sender);
_setupRole(BOOST_USER_ROLE, msg.sender);
_setupRole(BOOST_ADMIN_ROLE, msg.sender);
maxTotalSupply = _maxSupply;
imageDirURI = _imageDirURI;
defaultBoostCount = _defaultBoostCount;
}
functionsetOriginalMetadata(
DiceMetadata[] calldata originalMetadata,
uint128 _startIndex,
uint128 _endIndex
) publiconlyRole(DEFAULT_ADMIN_ROLE) {
require(
_startIndex <= _endIndex,
"Start index should be less than or equal to end index"
);
uint128 numberOfItems = _endIndex - _startIndex;
require(
originalMetadata.length== numberOfItems,
"Metadata length does not match index range"
);
for (uint256 i =0; i < numberOfItems; ) {
_oldTokenIdToMetadata[_startIndex + i] = originalMetadata[i];
unchecked {
++i;
}
}
}
functionresetBoosts(uint256 _newDefaultBoostCount)
publiconlyRole(BOOST_ADMIN_ROLE)
{
defaultBoostCount = _newDefaultBoostCount;
for (uint256 i =0; i < _totalMinted(); i++) {
_boosts[i] = defaultBoostCount;
}
}
functionuseBoost(uint256 tokenId, uint256 count)
publictokenExists(tokenId)
onlyRole(BOOST_USER_ROLE)
{
uint256 totalBoosts = _boosts[tokenId];
require(
totalBoosts >= count,
"Requested boost count exceeds the total"
);
_boosts[tokenId] = totalBoosts - count;
emit BoostUpdated(tokenId, _boosts[tokenId]);
}
functionsetBoostCount(uint256 tokenId, uint16 amount)
publictokenExists(tokenId)
onlyRole(BOOST_ADMIN_ROLE)
{
_boosts[tokenId] = amount;
emit BoostUpdated(tokenId, amount);
}
/*//////////////////////////////////////////////////////////////
Minting logic
//////////////////////////////////////////////////////////////*/functionmintTo(address _to, stringmemory _tokenURI)
publicvirtualoverride{
revert("Not allowed");
}
functionbatchMintTo(address _to,
uint256 _quantity,
stringmemory _baseURI,
bytesmemory _data
) publicvirtualoverride{
revert("Not allowed");
}
/**
* @notice Lets an authorized address mint an NFT to a recipient.
* @dev The logic in the `_canMint` function determines whether the caller is authorized to mint NFTs.
*
* @param _to The recipient of the NFT to mint.
* @param _oldTokenId Old dice token Id
*/functionmint(address _to, uint256 _oldTokenId) publicvirtual{
require(_canMint(), "Not authorized to mint.");
require(
!_oldTokenIdBurned[_oldTokenId],
"Already claimed old token id"
);
uint256 newTokenId = nextTokenIdToMint();
_safeMint(_to, 1, "");
_newTokenIdToOldTokenId[newTokenId] = _oldTokenId;
_boosts[newTokenId] = defaultBoostCount;
_oldTokenIdBurned[_oldTokenId] =true;
}
/**
* @notice Lets an authorized address mint multiple NFTs at once to a recipient.
* @dev The logic in the `_canMint` function determines whether the caller is authorized to mint NFTs.
*
* @param _to The recipient of the NFT to mint.
* @param _oldTokenIds Old dice token Ids
*/functionbatchMint(address _to, uint256[] calldata _oldTokenIds)
publicvirtual{
require(_canMint(), "Not authorized to mint.");
uint256 quantity = _oldTokenIds.length;
uint256 newTokenId = nextTokenIdToMint();
_safeMint(_to, quantity, "");
uint256 oldTokenIndex =0;
for (uint256 i = newTokenId; i < newTokenId + quantity; ++i) {
require(
!_oldTokenIdBurned[_oldTokenIds[oldTokenIndex]],
"Already claimed old token id"
);
_newTokenIdToOldTokenId[i] = _oldTokenIds[oldTokenIndex];
_boosts[i] = defaultBoostCount;
_oldTokenIdBurned[_oldTokenIds[oldTokenIndex]] =true;
oldTokenIndex++;
}
}
/**
* @notice Returns the metadata of an NFT.
*
* @param _tokenId The tokenId of an NFT.
*/functiontokenURI(uint256 _tokenId)
publicviewvirtualoverridetokenExists(_tokenId)
returns (stringmemory)
{
DiceMetadata memory _diceMetadata = _oldTokenIdToMetadata[
_newTokenIdToOldTokenId[_tokenId]
];
stringmemory attributes;
// All dice// Dice 1if (_diceMetadata.amount >=1) {
attributes =string(
abi.encodePacked(
attributes,
'{"trait_type":"dice ',
"1",
' type","value":"',
DiceBitmapUtil.getDiceType(_diceMetadata.bitmap, 0).toString(),
'"},{"trait_type":"dice ',
"1",
' material","value":"',
DiceBitmapUtil.getDiceMaterial(_diceMetadata.bitmap, 0).toString(),
'"},'
)
);
}
// Dice 2if (_diceMetadata.amount >=2) {
attributes =string(
abi.encodePacked(
attributes,
'{"trait_type":"dice ',
"2",
' type","value":"',
DiceBitmapUtil.getDiceType(_diceMetadata.bitmap, 1).toString(),
'"},{"trait_type":"dice ',
"2",
' material","value":"',
DiceBitmapUtil.getDiceMaterial(_diceMetadata.bitmap, 1).toString(),
'"},'
)
);
}
// Dice 3if (_diceMetadata.amount >=3) {
attributes =string(
abi.encodePacked(
attributes,
'{"trait_type":"dice ',
"3",
' type","value":"',
DiceBitmapUtil.getDiceType(_diceMetadata.bitmap, 2).toString(),
'"},{"trait_type":"dice ',
"3",
' material","value":"',
DiceBitmapUtil.getDiceMaterial(_diceMetadata.bitmap, 2).toString(),
'"},'
)
);
}
// Dice 4if (_diceMetadata.amount >=4) {
attributes =string(
abi.encodePacked(
attributes,
'{"trait_type":"dice ',
"4",
' type","value":"',
DiceBitmapUtil.getDiceType(_diceMetadata.bitmap, 3).toString(),
'"},{"trait_type":"dice ',
"4",
' material","value":"',
DiceBitmapUtil.getDiceMaterial(_diceMetadata.bitmap, 3).toString(),
'"},'
)
);
}
// Dice 5if (_diceMetadata.amount >=5) {
attributes =string(
abi.encodePacked(
attributes,
'{"trait_type":"dice ',
"5",
' type","value":"',
DiceBitmapUtil.getDiceType(_diceMetadata.bitmap, 4).toString(),
'"},{"trait_type":"dice ',
"5",
' material","value":"',
DiceBitmapUtil.getDiceMaterial(_diceMetadata.bitmap, 4).toString(),
'"},'
)
);
}
// Dice 6if (_diceMetadata.amount >=6) {
attributes =string(
abi.encodePacked(
attributes,
'{"trait_type":"dice ',
"6",
' type","value":"',
DiceBitmapUtil.getDiceType(_diceMetadata.bitmap, 5).toString(),
'"},{"trait_type":"dice ',
"6",
' material","value":"',
DiceBitmapUtil.getDiceMaterial(_diceMetadata.bitmap, 5).toString(),
'"},'
)
);
}
// Dice 7if (_diceMetadata.amount >=7) {
attributes =string(
abi.encodePacked(
attributes,
'{"trait_type":"dice ',
"7",
' type","value":"',
DiceBitmapUtil.getDiceType(_diceMetadata.bitmap, 6).toString(),
'"},{"trait_type":"dice ',
"7",
' material","value":"',
DiceBitmapUtil.getDiceMaterial(_diceMetadata.bitmap, 6).toString(),
'"},'
)
);
}
//Add power and Boosts attributes
attributes =string(
abi.encodePacked(
attributes,
'{"trait_type":"Power","value":',
_diceMetadata.power.toString(),
'},',
'{"trait_type":"Boosts","value":',
_boosts[_tokenId].toString(),
'},',
'{"trait_type":"Element Type","value":"',
DiceBitmapUtil.getElementType(_diceMetadata.bitmap).toString(),
'"}'
)
);
returnstring(
abi.encodePacked(
"data:application/json;base64,",
Base64.encode(
abi.encodePacked(
'{"name":"',
name(),
'","image":"',
imageDirURI,
"/",
_newTokenIdToOldTokenId[_tokenId].toString(),
'.jpg","animation_url":"',
imageDirURI,
"/",
_newTokenIdToOldTokenId[_tokenId].toString(),
'.mp4","attributes":[',
attributes,
"]}"
)
)
)
);
}
functiongetDiceBoosts(uint256 _tokenId)
publicviewtokenExists(_tokenId)
returns (uint256)
{
return _boosts[_tokenId];
}
functiongetDiceMaterials(uint256 _tokenId)
publicviewtokenExists(_tokenId)
returns (string[] memory)
{
DiceMetadata memory _diceMetadata = _oldTokenIdToMetadata[
_newTokenIdToOldTokenId[_tokenId]
];
string[] memory materials =newstring[](_diceMetadata.amount);
if (_diceMetadata.amount >=1) {
materials[0] = DiceBitmapUtil.getDiceMaterial(_diceMetadata.bitmap, 0).toString();
}
if (_diceMetadata.amount >=2) {
materials[1] = DiceBitmapUtil.getDiceMaterial(_diceMetadata.bitmap, 1).toString();
}
if (_diceMetadata.amount >=3) {
materials[2] = DiceBitmapUtil.getDiceMaterial(_diceMetadata.bitmap, 2).toString();
}
if (_diceMetadata.amount >=4) {
materials[3] = DiceBitmapUtil.getDiceMaterial(_diceMetadata.bitmap, 3).toString();
}
if (_diceMetadata.amount >=5) {
materials[4] = DiceBitmapUtil.getDiceMaterial(_diceMetadata.bitmap, 4).toString();
}
if (_diceMetadata.amount >=6) {
materials[5] = DiceBitmapUtil.getDiceMaterial(_diceMetadata.bitmap, 5).toString();
}
if (_diceMetadata.amount >=7) {
materials[6] = DiceBitmapUtil.getDiceMaterial(_diceMetadata.bitmap, 6).toString();
}
return materials;
}
functiongetDiceMetadata(uint256 _tokenId)
publicviewtokenExists(_tokenId)
returns (DiceMetadata memory)
{
return _oldTokenIdToMetadata[_newTokenIdToOldTokenId[_tokenId]];
}
functionsetImageDirURI(stringcalldata _imageDirURI)
publiconlyRole(DEFAULT_ADMIN_ROLE)
{
imageDirURI = _imageDirURI;
}
functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) publicoverrideonlyAllowedOperator(from) {
super.transferFrom(from, to, tokenId);
}
functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) publicoverrideonlyAllowedOperator(from) {
super.safeTransferFrom(from, to, tokenId);
}
functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytesmemory data
) publicoverrideonlyAllowedOperator(from) {
super.safeTransferFrom(from, to, tokenId, data);
}
function_canMint() internalviewvirtualoverridereturns (bool) {
return hasRole(MINTER_ROLE, msg.sender);
}
}
Contract Source Code
File 7 of 31: ERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)pragmasolidity ^0.8.0;import"./interface/IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/abstractcontractERC165isIERC165{
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverridereturns (bool) {
return interfaceId ==type(IERC165).interfaceId;
}
}
Contract Source Code
File 8 of 31: ERC721A.sol
// SPDX-License-Identifier: MIT// ERC721A Contracts v3.3.0// Creator: Chiru Labspragmasolidity ^0.8.4;import"./interface/IERC721A.sol";
import"../openzeppelin-presets/token/ERC721/IERC721Receiver.sol";
import"../lib/TWAddress.sol";
import"../openzeppelin-presets/utils/Context.sol";
import"../lib/TWStrings.sol";
import"./ERC165.sol";
/**
* @dev Implementation of [ERC721](https://eips.ethereum.org/EIPS/eip-721) Non-Fungible Token Standard, including
* the Metadata extension. Built to optimize for lower gas during batch mints.
*
* Assumes serials are sequentially minted starting at _startTokenId() (defaults to 0, e.g. 0, 1, 2, 3..).
*
* Assumes that an owner cannot have more than 2^64 - 1 (max value of uint64) of supply.
*
* Assumes that the maximum token id cannot exceed 2^256 - 1 (max value of uint256).
*/contractERC721AisContext, ERC165, IERC721A{
usingTWAddressforaddress;
usingTWStringsforuint256;
// The tokenId of the next token to be minted.uint256internal _currentIndex;
// The number of tokens burned.uint256internal _burnCounter;
// Token namestringprivate _name;
// Token symbolstringprivate _symbol;
// Mapping from token ID to ownership details// An empty struct value does not necessarily mean the token is unowned. See _ownershipOf implementation for details.mapping(uint256=> TokenOwnership) internal _ownerships;
// Mapping owner address to address datamapping(address=> AddressData) private _addressData;
// Mapping from token ID to approved addressmapping(uint256=>address) private _tokenApprovals;
// Mapping from owner to operator approvalsmapping(address=>mapping(address=>bool)) private _operatorApprovals;
constructor(stringmemory name_, stringmemory symbol_) {
_name = name_;
_symbol = symbol_;
_currentIndex = _startTokenId();
}
/**
* To change the starting tokenId, please override this function.
*/function_startTokenId() internalviewvirtualreturns (uint256) {
return0;
}
/**
* @dev Burned tokens are calculated here, use _totalMinted() if you want to count just minted tokens.
*/functiontotalSupply() publicviewoverridereturns (uint256) {
// Counter underflow is impossible as _burnCounter cannot be incremented// more than _currentIndex - _startTokenId() timesunchecked {
return _currentIndex - _burnCounter - _startTokenId();
}
}
/**
* Returns the total amount of tokens minted in the contract.
*/function_totalMinted() internalviewreturns (uint256) {
// Counter underflow is impossible as _currentIndex does not decrement,// and it is initialized to _startTokenId()unchecked {
return _currentIndex - _startTokenId();
}
}
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(ERC165) returns (bool) {
return
interfaceId ==type(IERC721).interfaceId||
interfaceId ==type(IERC721Metadata).interfaceId||super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/functionbalanceOf(address owner) publicviewoverridereturns (uint256) {
if (owner ==address(0)) revert BalanceQueryForZeroAddress();
returnuint256(_addressData[owner].balance);
}
/**
* Returns the number of tokens minted by `owner`.
*/function_numberMinted(address owner) internalviewreturns (uint256) {
returnuint256(_addressData[owner].numberMinted);
}
/**
* Returns the number of tokens burned by or on behalf of `owner`.
*/function_numberBurned(address owner) internalviewreturns (uint256) {
returnuint256(_addressData[owner].numberBurned);
}
/**
* Returns the auxillary data for `owner`. (e.g. number of whitelist mint slots used).
*/function_getAux(address owner) internalviewreturns (uint64) {
return _addressData[owner].aux;
}
/**
* Sets the auxillary data for `owner`. (e.g. number of whitelist mint slots used).
* If there are multiple variables, please pack them into a uint64.
*/function_setAux(address owner, uint64 aux) internal{
_addressData[owner].aux = aux;
}
/**
* Gas spent here starts off proportional to the maximum mint batch size.
* It gradually moves to O(1) as tokens get transferred around in the collection over time.
*/function_ownershipOf(uint256 tokenId) internalviewreturns (TokenOwnership memory) {
uint256 curr = tokenId;
unchecked {
if (_startTokenId() <= curr)
if (curr < _currentIndex) {
TokenOwnership memory ownership = _ownerships[curr];
if (!ownership.burned) {
if (ownership.addr !=address(0)) {
return ownership;
}
// Invariant:// There will always be an ownership that has an address and is not burned// before an ownership that does not have an address and is not burned.// Hence, curr will not underflow.while (true) {
curr--;
ownership = _ownerships[curr];
if (ownership.addr !=address(0)) {
return ownership;
}
}
}
}
}
revert OwnerQueryForNonexistentToken();
}
/**
* @dev See {IERC721-ownerOf}.
*/functionownerOf(uint256 tokenId) publicviewoverridereturns (address) {
return _ownershipOf(tokenId).addr;
}
/**
* @dev See {IERC721Metadata-name}.
*/functionname() publicviewvirtualoverridereturns (stringmemory) {
return _name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/functionsymbol() publicviewvirtualoverridereturns (stringmemory) {
return _symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/functiontokenURI(uint256 tokenId) publicviewvirtualoverridereturns (stringmemory) {
if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
stringmemory baseURI = _baseURI();
returnbytes(baseURI).length!=0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overriden in child contracts.
*/function_baseURI() internalviewvirtualreturns (stringmemory) {
return"";
}
/**
* @dev See {IERC721-approve}.
*/functionapprove(address to, uint256 tokenId) publicoverride{
address owner = ERC721A.ownerOf(tokenId);
if (to == owner) revert ApprovalToCurrentOwner();
if (_msgSender() != owner)
if (!isApprovedForAll(owner, _msgSender())) {
revert ApprovalCallerNotOwnerNorApproved();
}
_approve(to, tokenId, owner);
}
/**
* @dev See {IERC721-getApproved}.
*/functiongetApproved(uint256 tokenId) publicviewoverridereturns (address) {
if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();
return _tokenApprovals[tokenId];
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/functionsetApprovalForAll(address operator, bool approved) publicvirtualoverride{
if (operator == _msgSender()) revert ApproveToCaller();
_operatorApprovals[_msgSender()][operator] = approved;
emit ApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/functionisApprovedForAll(address owner, address operator) publicviewvirtualoverridereturns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) publicvirtualoverride{
_transfer(from, to, tokenId);
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) publicvirtualoverride{
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytesmemory _data
) publicvirtualoverride{
_transfer(from, to, tokenId);
if (to.isContract())
if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted (`_mint`),
*/function_exists(uint256 tokenId) internalviewreturns (bool) {
return _startTokenId() <= tokenId && tokenId < _currentIndex &&!_ownerships[tokenId].burned;
}
/**
* @dev Equivalent to `_safeMint(to, quantity, '')`.
*/function_safeMint(address to, uint256 quantity) internal{
_safeMint(to, quantity, "");
}
/**
* @dev Safely mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
* - `quantity` must be greater than 0.
*
* Emits a {Transfer} event.
*/function_safeMint(address to,
uint256 quantity,
bytesmemory _data
) internal{
uint256 startTokenId = _currentIndex;
if (to ==address(0)) revert MintToZeroAddress();
if (quantity ==0) revert MintZeroQuantity();
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are incredibly unrealistic.// balance or numberMinted overflow if current value of either + quantity > 1.8e19 (2**64) - 1// updatedIndex overflows if _currentIndex + quantity > 1.2e77 (2**256) - 1unchecked {
_addressData[to].balance+=uint64(quantity);
_addressData[to].numberMinted +=uint64(quantity);
_ownerships[startTokenId].addr = to;
_ownerships[startTokenId].startTimestamp =uint64(block.timestamp);
uint256 updatedIndex = startTokenId;
uint256 end = updatedIndex + quantity;
if (to.isContract()) {
do {
emit Transfer(address(0), to, updatedIndex);
if (!_checkContractOnERC721Received(address(0), to, updatedIndex++, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
} while (updatedIndex < end);
// Reentrancy protectionif (_currentIndex != startTokenId) revert();
} else {
do {
emit Transfer(address(0), to, updatedIndex++);
} while (updatedIndex < end);
}
_currentIndex = updatedIndex;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` must be greater than 0.
*
* Emits a {Transfer} event.
*/function_mint(address to, uint256 quantity) internal{
uint256 startTokenId = _currentIndex;
if (to ==address(0)) revert MintToZeroAddress();
if (quantity ==0) revert MintZeroQuantity();
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are incredibly unrealistic.// balance or numberMinted overflow if current value of either + quantity > 1.8e19 (2**64) - 1// updatedIndex overflows if _currentIndex + quantity > 1.2e77 (2**256) - 1unchecked {
_addressData[to].balance+=uint64(quantity);
_addressData[to].numberMinted +=uint64(quantity);
_ownerships[startTokenId].addr = to;
_ownerships[startTokenId].startTimestamp =uint64(block.timestamp);
uint256 updatedIndex = startTokenId;
uint256 end = updatedIndex + quantity;
do {
emit Transfer(address(0), to, updatedIndex++);
} while (updatedIndex < end);
_currentIndex = updatedIndex;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/function_transfer(addressfrom,
address to,
uint256 tokenId
) private{
TokenOwnership memory prevOwnership = _ownershipOf(tokenId);
if (prevOwnership.addr !=from) revert TransferFromIncorrectOwner();
bool isApprovedOrOwner = (_msgSender() ==from||
isApprovedForAll(from, _msgSender()) ||
getApproved(tokenId) == _msgSender());
if (!isApprovedOrOwner) revert TransferCallerNotOwnerNorApproved();
if (to ==address(0)) revert TransferToZeroAddress();
_beforeTokenTransfers(from, to, tokenId, 1);
// Clear approvals from the previous owner
_approve(address(0), tokenId, from);
// Underflow of the sender's balance is impossible because we check for// ownership above and the recipient's balance can't realistically overflow.// Counter overflow is incredibly unrealistic as tokenId would have to be 2**256.unchecked {
_addressData[from].balance-=1;
_addressData[to].balance+=1;
TokenOwnership storage currSlot = _ownerships[tokenId];
currSlot.addr = to;
currSlot.startTimestamp =uint64(block.timestamp);
// If the ownership slot of tokenId+1 is not explicitly set, that means the transfer initiator owns it.// Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls.uint256 nextTokenId = tokenId +1;
TokenOwnership storage nextSlot = _ownerships[nextTokenId];
if (nextSlot.addr ==address(0)) {
// This will suffice for checking _exists(nextTokenId),// as a burned slot cannot contain the zero address.if (nextTokenId != _currentIndex) {
nextSlot.addr =from;
nextSlot.startTimestamp = prevOwnership.startTimestamp;
}
}
}
emit Transfer(from, to, tokenId);
_afterTokenTransfers(from, to, tokenId, 1);
}
/**
* @dev Equivalent to `_burn(tokenId, false)`.
*/function_burn(uint256 tokenId) internalvirtual{
_burn(tokenId, false);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/function_burn(uint256 tokenId, bool approvalCheck) internalvirtual{
TokenOwnership memory prevOwnership = _ownershipOf(tokenId);
addressfrom= prevOwnership.addr;
if (approvalCheck) {
bool isApprovedOrOwner = (_msgSender() ==from||
isApprovedForAll(from, _msgSender()) ||
getApproved(tokenId) == _msgSender());
if (!isApprovedOrOwner) revert TransferCallerNotOwnerNorApproved();
}
_beforeTokenTransfers(from, address(0), tokenId, 1);
// Clear approvals from the previous owner
_approve(address(0), tokenId, from);
// Underflow of the sender's balance is impossible because we check for// ownership above and the recipient's balance can't realistically overflow.// Counter overflow is incredibly unrealistic as tokenId would have to be 2**256.unchecked {
AddressData storage addressData = _addressData[from];
addressData.balance-=1;
addressData.numberBurned +=1;
// Keep track of who burned the token, and the timestamp of burning.
TokenOwnership storage currSlot = _ownerships[tokenId];
currSlot.addr =from;
currSlot.startTimestamp =uint64(block.timestamp);
currSlot.burned =true;
// If the ownership slot of tokenId+1 is not explicitly set, that means the burn initiator owns it.// Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls.uint256 nextTokenId = tokenId +1;
TokenOwnership storage nextSlot = _ownerships[nextTokenId];
if (nextSlot.addr ==address(0)) {
// This will suffice for checking _exists(nextTokenId),// as a burned slot cannot contain the zero address.if (nextTokenId != _currentIndex) {
nextSlot.addr =from;
nextSlot.startTimestamp = prevOwnership.startTimestamp;
}
}
}
emit Transfer(from, address(0), tokenId);
_afterTokenTransfers(from, address(0), tokenId, 1);
// Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.unchecked {
_burnCounter++;
}
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* Emits a {Approval} event.
*/function_approve(address to,
uint256 tokenId,
address owner
) private{
_tokenApprovals[tokenId] = to;
emit Approval(owner, to, tokenId);
}
/**
* @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target contract.
*
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param _data bytes optional data to send along with the call
* @return bool whether the call correctly returned the expected magic value
*/function_checkContractOnERC721Received(addressfrom,
address to,
uint256 tokenId,
bytesmemory _data
) privatereturns (bool) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
return retval == IERC721Receiver(to).onERC721Received.selector;
} catch (bytesmemory reason) {
if (reason.length==0) {
revert TransferToNonERC721ReceiverImplementer();
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
/**
* @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. This includes minting.
* And also called before burning one token.
*
* startTokenId - the first token id to be transferred
* quantity - the amount to be transferred
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, `tokenId` will be burned by `from`.
* - `from` and `to` are never both zero.
*/function_beforeTokenTransfers(addressfrom,
address to,
uint256 startTokenId,
uint256 quantity
) internalvirtual{}
/**
* @dev Hook that is called after a set of serially-ordered token ids have been transferred. This includes
* minting.
* And also called after one token has been burned.
*
* startTokenId - the first token id to be transferred
* quantity - the amount to be transferred
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
* transferred to `to`.
* - When `from` is zero, `tokenId` has been minted for `to`.
* - When `to` is zero, `tokenId` has been burned by `from`.
* - `from` and `to` are never both zero.
*/function_afterTokenTransfers(addressfrom,
address to,
uint256 startTokenId,
uint256 quantity
) internalvirtual{}
}
Contract Source Code
File 9 of 31: ERC721Base.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;import { ERC721A } from"../eip/ERC721A.sol";
import"../extension/ContractMetadata.sol";
import"../extension/Multicall.sol";
import"../extension/Ownable.sol";
import"../extension/Royalty.sol";
import"../extension/BatchMintMetadata.sol";
import"../lib/TWStrings.sol";
/**
* The `ERC721Base` smart contract implements the ERC721 NFT standard, along with the ERC721A optimization to the standard.
* It includes the following additions to standard ERC721 logic:
*
* - Ability to mint NFTs via the provided `mint` function.
*
* - Contract metadata for royalty support on platforms such as OpenSea that use
* off-chain information to distribute roaylties.
*
* - Ownership of the contract, with the ability to restrict certain functions to
* only be called by the contract's owner.
*
* - Multicall capability to perform multiple actions atomically
*
* - EIP 2981 compliance for royalty support on NFT marketplaces.
*/contractERC721BaseisERC721A, ContractMetadata, Multicall, Ownable, Royalty, BatchMintMetadata{
usingTWStringsforuint256;
/*//////////////////////////////////////////////////////////////
Mappings
//////////////////////////////////////////////////////////////*/mapping(uint256=>string) private fullURI;
/*//////////////////////////////////////////////////////////////
Constructor
//////////////////////////////////////////////////////////////*/constructor(stringmemory _name,
stringmemory _symbol,
address _royaltyRecipient,
uint128 _royaltyBps
) ERC721A(_name, _symbol) {
_setupOwner(msg.sender);
_setupDefaultRoyaltyInfo(_royaltyRecipient, _royaltyBps);
}
/*//////////////////////////////////////////////////////////////
ERC165 Logic
//////////////////////////////////////////////////////////////*//// @dev See ERC165: https://eips.ethereum.org/EIPS/eip-165functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(ERC721A, IERC165) returns (bool) {
return
interfaceId ==0x01ffc9a7||// ERC165 Interface ID for ERC165
interfaceId ==0x80ac58cd||// ERC165 Interface ID for ERC721
interfaceId ==0x5b5e139f||// ERC165 Interface ID for ERC721Metadata
interfaceId ==type(IERC2981).interfaceId; // ERC165 ID for ERC2981
}
/*//////////////////////////////////////////////////////////////
Overriden ERC721 logic
//////////////////////////////////////////////////////////////*//**
* @notice Returns the metadata URI for an NFT.
* @dev See `BatchMintMetadata` for handling of metadata in this contract.
*
* @param _tokenId The tokenId of an NFT.
*/functiontokenURI(uint256 _tokenId) publicviewvirtualoverridereturns (stringmemory) {
stringmemory fullUriForToken = fullURI[_tokenId];
if (bytes(fullUriForToken).length>0) {
return fullUriForToken;
}
stringmemory batchUri = _getBaseURI(_tokenId);
returnstring(abi.encodePacked(batchUri, _tokenId.toString()));
}
/*//////////////////////////////////////////////////////////////
Minting logic
//////////////////////////////////////////////////////////////*//**
* @notice Lets an authorized address mint an NFT to a recipient.
* @dev The logic in the `_canMint` function determines whether the caller is authorized to mint NFTs.
*
* @param _to The recipient of the NFT to mint.
* @param _tokenURI The full metadata URI for the NFT minted.
*/functionmintTo(address _to, stringmemory _tokenURI) publicvirtual{
require(_canMint(), "Not authorized to mint.");
_setTokenURI(nextTokenIdToMint(), _tokenURI);
_safeMint(_to, 1, "");
}
/**
* @notice Lets an authorized address mint multiple NFTs at once to a recipient.
* @dev The logic in the `_canMint` function determines whether the caller is authorized to mint NFTs.
*
* @param _to The recipient of the NFT to mint.
* @param _quantity The number of NFTs to mint.
* @param _baseURI The baseURI for the `n` number of NFTs minted. The metadata for each NFT is `baseURI/tokenId`
* @param _data Additional data to pass along during the minting of the NFT.
*/functionbatchMintTo(address _to,
uint256 _quantity,
stringmemory _baseURI,
bytesmemory _data
) publicvirtual{
require(_canMint(), "Not authorized to mint.");
_batchMintMetadata(nextTokenIdToMint(), _quantity, _baseURI);
_safeMint(_to, _quantity, _data);
}
/**
* @notice Lets an owner or approved operator burn the NFT of the given tokenId.
* @dev ERC721A's `_burn(uint256,bool)` internally checks for token approvals.
*
* @param _tokenId The tokenId of the NFT to burn.
*/functionburn(uint256 _tokenId) externalvirtual{
_burn(_tokenId, true);
}
/*//////////////////////////////////////////////////////////////
Public getters
//////////////////////////////////////////////////////////////*//// @notice The tokenId assigned to the next new NFT to be minted.functionnextTokenIdToMint() publicviewvirtualreturns (uint256) {
return _currentIndex;
}
/// @notice Returns whether a given address is the owner, or approved to transfer an NFT.functionisApprovedOrOwner(address _operator, uint256 _tokenId)
publicviewvirtualreturns (bool isApprovedOrOwnerOf)
{
address owner = ownerOf(_tokenId);
isApprovedOrOwnerOf = (_operator == owner ||
isApprovedForAll(owner, _operator) ||
getApproved(_tokenId) == _operator);
}
/*//////////////////////////////////////////////////////////////
Internal (overrideable) functions
//////////////////////////////////////////////////////////////*/function_setTokenURI(uint256 _tokenId, stringmemory _tokenURI) internalvirtual{
require(bytes(fullURI[_tokenId]).length==0, "URI already set");
fullURI[_tokenId] = _tokenURI;
}
/// @dev Returns whether contract metadata can be set in the given execution context.function_canSetContractURI() internalviewvirtualoverridereturns (bool) {
returnmsg.sender== owner();
}
/// @dev Returns whether a token can be minted in the given execution context.function_canMint() internalviewvirtualreturns (bool) {
returnmsg.sender== owner();
}
/// @dev Returns whether owner can be set in the given execution context.function_canSetOwner() internalviewvirtualoverridereturns (bool) {
returnmsg.sender== owner();
}
/// @dev Returns whether royalty info can be set in the given execution context.function_canSetRoyaltyInfo() internalviewvirtualoverridereturns (bool) {
returnmsg.sender== owner();
}
}
Contract Source Code
File 10 of 31: IContractMetadata.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/**
* Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI
* for you contract.
*
* Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea.
*/interfaceIContractMetadata{
/// @dev Returns the metadata URI of the contract.functioncontractURI() externalviewreturns (stringmemory);
/**
* @dev Sets contract URI for the storefront-level metadata of the contract.
* Only module admin can call this function.
*/functionsetContractURI(stringcalldata _uri) external;
/// @dev Emitted when the contract URI is updated.eventContractURIUpdated(string prevURI, string newURI);
}
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)pragmasolidity ^0.8.0;/**
* @dev Interface of the ERC165 standard, as defined in the
* [EIP](https://eips.ethereum.org/EIPS/eip-165).
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/interfaceIERC165{
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
Contract Source Code
File 13 of 31: IERC2981.sol
// SPDX-License-Identifier: Apache 2.0pragmasolidity ^0.8.0;import"./IERC165.sol";
/**
* @dev Interface for the NFT Royalty Standard.
*
* A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
* support for royalty payments across all NFT marketplaces and ecosystem participants.
*
* _Available since v4.5._
*/interfaceIERC2981isIERC165{
/**
* @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
* exchange. The royalty amount is denominated and should be payed in that same unit of exchange.
*/functionroyaltyInfo(uint256 tokenId, uint256 salePrice)
externalviewreturns (address receiver, uint256 royaltyAmount);
}
Contract Source Code
File 14 of 31: IERC721.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)pragmasolidity ^0.8.0;/**
* @dev Required interface of an ERC721 compliant contract.
*/interfaceIERC721{
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/eventApproval(addressindexed owner, addressindexed approved, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/eventApprovalForAll(addressindexed owner, addressindexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/functionbalanceOf(address owner) externalviewreturns (uint256);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functionownerOf(uint256 tokenId) externalviewreturns (address);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/functionapprove(address to, uint256 tokenId) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functiongetApproved(uint256 tokenId) externalviewreturns (address);
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/functionsetApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/functionisApprovedForAll(address owner, address operator) externalviewreturns (bool);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytescalldata data
) external;
}
Contract Source Code
File 15 of 31: IERC721A.sol
// SPDX-License-Identifier: MIT// ERC721A Contracts v3.3.0// Creator: Chiru Labspragmasolidity ^0.8.4;import"./IERC721.sol";
import"./IERC721Metadata.sol";
/**
* @dev Interface of an ERC721A compliant contract.
*/interfaceIERC721AisIERC721, IERC721Metadata{
/**
* The caller must own the token or be an approved operator.
*/errorApprovalCallerNotOwnerNorApproved();
/**
* The token does not exist.
*/errorApprovalQueryForNonexistentToken();
/**
* The caller cannot approve to their own address.
*/errorApproveToCaller();
/**
* The caller cannot approve to the current owner.
*/errorApprovalToCurrentOwner();
/**
* Cannot query the balance for the zero address.
*/errorBalanceQueryForZeroAddress();
/**
* Cannot mint to the zero address.
*/errorMintToZeroAddress();
/**
* The quantity of tokens minted must be more than zero.
*/errorMintZeroQuantity();
/**
* The token does not exist.
*/errorOwnerQueryForNonexistentToken();
/**
* The caller must own the token or be an approved operator.
*/errorTransferCallerNotOwnerNorApproved();
/**
* The token must be owned by `from`.
*/errorTransferFromIncorrectOwner();
/**
* Cannot safely transfer to a contract that does not implement the ERC721Receiver interface.
*/errorTransferToNonERC721ReceiverImplementer();
/**
* Cannot transfer to the zero address.
*/errorTransferToZeroAddress();
/**
* The token does not exist.
*/errorURIQueryForNonexistentToken();
// Compiler will pack this into a single 256bit word.structTokenOwnership {
// The address of the owner.address addr;
// Keeps track of the start time of ownership with minimal overhead for tokenomics.uint64 startTimestamp;
// Whether the token has been burned.bool burned;
}
// Compiler will pack this into a single 256bit word.structAddressData {
// Realistically, 2**64-1 is more than enough.uint64 balance;
// Keeps track of mint count with minimal overhead for tokenomics.uint64 numberMinted;
// Keeps track of burn count with minimal overhead for tokenomics.uint64 numberBurned;
// For miscellaneous variable(s) pertaining to the address// (e.g. number of whitelist mint slots used).// If there are multiple variables, please pack them into a uint64.uint64 aux;
}
/**
* @dev Returns the total amount of tokens stored by the contract.
*
* Burned tokens are calculated here, use `_totalMinted()` if you want to count just minted tokens.
*/functiontotalSupply() externalviewreturns (uint256);
}
Contract Source Code
File 16 of 31: IERC721Metadata.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension/// @dev See https://eips.ethereum.org/EIPS/eip-721/// Note: the ERC-165 identifier for this interface is 0x5b5e139f./* is ERC721 */interfaceIERC721Metadata{
/// @notice A descriptive name for a collection of NFTs in this contractfunctionname() externalviewreturns (stringmemory);
/// @notice An abbreviated name for NFTs in this contractfunctionsymbol() externalviewreturns (stringmemory);
/// @notice A distinct Uniform Resource Identifier (URI) for a given asset./// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC/// 3986. The URI may point to a JSON file that conforms to the "ERC721/// Metadata JSON Schema".functiontokenURI(uint256 _tokenId) externalviewreturns (stringmemory);
}
Contract Source Code
File 17 of 31: IERC721Receiver.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)pragmasolidity ^0.8.0;/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/interfaceIERC721Receiver{
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
*/functiononERC721Received(address operator,
addressfrom,
uint256 tokenId,
bytescalldata data
) externalreturns (bytes4);
}
Contract Source Code
File 18 of 31: IMulticall.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.5.0) (utils/Multicall.sol)pragmasolidity ^0.8.0;/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* _Available since v4.1._
*/interfaceIMulticall{
/**
* @dev Receives and executes a batch of function calls on this contract.
*/functionmulticall(bytes[] calldata data) externalreturns (bytes[] memory results);
}
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/**
* Thirdweb's `Ownable` is a contract extension to be used with any base contract. It exposes functions for setting and reading
* who the 'owner' of the inheriting smart contract is, and lets the inheriting contract perform conditional logic that uses
* information about who the contract's owner is.
*/interfaceIOwnable{
/// @dev Returns the owner of the contract.functionowner() externalviewreturns (address);
/// @dev Lets a module admin set a new owner for the contract. The new owner must be a module admin.functionsetOwner(address _newOwner) external;
/// @dev Emitted when a new Owner is set.eventOwnerUpdated(addressindexed prevOwner, addressindexed newOwner);
}
Contract Source Code
File 21 of 31: IPermissions.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/interfaceIPermissions{
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/eventRoleAdminChanged(bytes32indexed role, bytes32indexed previousAdminRole, bytes32indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/eventRoleGranted(bytes32indexed role, addressindexed account, addressindexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/eventRoleRevoked(bytes32indexed role, addressindexed account, addressindexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/functionhasRole(bytes32 role, address account) externalviewreturns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/functiongetRoleAdmin(bytes32 role) externalviewreturns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/functiongrantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/functionrevokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/functionrenounceRole(bytes32 role, address account) external;
}
Contract Source Code
File 22 of 31: IRoyalty.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;import"../../eip/interface/IERC2981.sol";
/**
* Thirdweb's `Royalty` is a contract extension to be used with any base contract. It exposes functions for setting and reading
* the recipient of royalty fee and the royalty fee basis points, and lets the inheriting contract perform conditional logic
* that uses information about royalty fees, if desired.
*
* The `Royalty` contract is ERC2981 compliant.
*/interfaceIRoyaltyisIERC2981{
structRoyaltyInfo {
address recipient;
uint256 bps;
}
/// @dev Returns the royalty recipient and fee bps.functiongetDefaultRoyaltyInfo() externalviewreturns (address, uint16);
/// @dev Lets a module admin update the royalty bps and recipient.functionsetDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps) external;
/// @dev Lets a module admin set the royalty recipient for a particular token Id.functionsetRoyaltyInfoForToken(uint256 tokenId,
address recipient,
uint256 bps
) external;
/// @dev Returns the royalty recipient for a particular token Id.functiongetRoyaltyInfoForToken(uint256 tokenId) externalviewreturns (address, uint16);
/// @dev Emitted when royalty info is updated.eventDefaultRoyalty(addressindexed newRoyaltyRecipient, uint256 newRoyaltyBps);
/// @dev Emitted when royalty recipient for tokenId is seteventRoyaltyForToken(uint256indexed tokenId, addressindexed royaltyRecipient, uint256 royaltyBps);
}
Contract Source Code
File 23 of 31: Math.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)pragmasolidity ^0.8.0;/**
* @dev Standard math utilities missing in the Solidity language.
*/libraryMath{
enumRounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/functionmax(uint256 a, uint256 b) internalpurereturns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/functionmin(uint256 a, uint256 b) internalpurereturns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/functionaverage(uint256 a, uint256 b) internalpurereturns (uint256) {
// (a + b) / 2 can overflow.return (a & b) + (a ^ b) /2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/functionceilDiv(uint256 a, uint256 b) internalpurereturns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.return a ==0 ? 0 : (a -1) / b +1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/functionmulDiv(uint256 x,
uint256 y,
uint256 denominator
) internalpurereturns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256// variables such that product = prod1 * 2^256 + prod0.uint256 prod0; // Least significant 256 bits of the productuint256 prod1; // Most significant 256 bits of the productassembly {
let mm :=mulmod(x, y, not(0))
prod0 :=mul(x, y)
prod1 :=sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.if (prod1 ==0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.require(denominator > prod1);
///////////////////////////////////////////////// 512 by 256 division.///////////////////////////////////////////////// Make division exact by subtracting the remainder from [prod1 prod0].uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder :=mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 :=sub(prod1, gt(remainder, prod0))
prod0 :=sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.// See https://cs.stackexchange.com/q/138556/92363.// Does not overflow because the denominator cannot be zero at this stage in the function.uint256 twos = denominator & (~denominator +1);
assembly {
// Divide denominator by twos.
denominator :=div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 :=div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos :=add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for// four bits. That is, denominator * inv = 1 mod 2^4.uint256 inverse = (3* denominator) ^2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works// in modular arithmetic, doubling the correct bits in each step.
inverse *=2- denominator * inverse; // inverse mod 2^8
inverse *=2- denominator * inverse; // inverse mod 2^16
inverse *=2- denominator * inverse; // inverse mod 2^32
inverse *=2- denominator * inverse; // inverse mod 2^64
inverse *=2- denominator * inverse; // inverse mod 2^128
inverse *=2- denominator * inverse; // inverse mod 2^256// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/functionmulDiv(uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internalpurereturns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up &&mulmod(x, y, denominator) >0) {
result +=1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/functionsqrt(uint256 a) internalpurereturns (uint256) {
if (a ==0) {
return0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.//// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.//// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`//// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.uint256 result =1<< (log2(a) >>1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision// into the expected uint128 result.unchecked {
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/functionsqrt(uint256 a, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/functionlog2(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >>128>0) {
value >>=128;
result +=128;
}
if (value >>64>0) {
value >>=64;
result +=64;
}
if (value >>32>0) {
value >>=32;
result +=32;
}
if (value >>16>0) {
value >>=16;
result +=16;
}
if (value >>8>0) {
value >>=8;
result +=8;
}
if (value >>4>0) {
value >>=4;
result +=4;
}
if (value >>2>0) {
value >>=2;
result +=2;
}
if (value >>1>0) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog2(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result =log2(value);
return result + (rounding == Rounding.Up &&1<< result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/functionlog10(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >=10**64) {
value /=10**64;
result +=64;
}
if (value >=10**32) {
value /=10**32;
result +=32;
}
if (value >=10**16) {
value /=10**16;
result +=16;
}
if (value >=10**8) {
value /=10**8;
result +=8;
}
if (value >=10**4) {
value /=10**4;
result +=4;
}
if (value >=10**2) {
value /=10**2;
result +=2;
}
if (value >=10**1) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog10(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up &&10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/functionlog256(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >>128>0) {
value >>=128;
result +=16;
}
if (value >>64>0) {
value >>=64;
result +=8;
}
if (value >>32>0) {
value >>=32;
result +=4;
}
if (value >>16>0) {
value >>=16;
result +=2;
}
if (value >>8>0) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog256(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up &&1<< (result *8) < value ? 1 : 0);
}
}
}
Contract Source Code
File 24 of 31: Multicall.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.5.0) (utils/Multicall.sol)pragmasolidity ^0.8.0;import"../lib/TWAddress.sol";
import"./interface/IMulticall.sol";
/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* _Available since v4.1._
*/contractMulticallisIMulticall{
/**
* @notice Receives and executes a batch of function calls on this contract.
* @dev Receives and executes a batch of function calls on this contract.
*
* @param data The bytes data that makes up the batch of function calls to execute.
* @return results The bytes data that makes up the result of the batch of function calls executed.
*/functionmulticall(bytes[] calldata data) externalvirtualoverridereturns (bytes[] memory results) {
results =newbytes[](data.length);
for (uint256 i =0; i < data.length; i++) {
results[i] = TWAddress.functionDelegateCall(address(this), data[i]);
}
return results;
}
}
Contract Source Code
File 25 of 31: OperatorFilterer.sol
// SPDX-License-Identifier: Apache 2.0// Credit: OpenSeapragmasolidity ^0.8.0;import { IOperatorFilterRegistry } from"./interface/IOperatorFilterRegistry.sol";
abstractcontractOperatorFilterer{
errorOperatorNotAllowed(address operator);
// solhint-disable-next-line
IOperatorFilterRegistry constant operatorFilterRegistry =
IOperatorFilterRegistry(0x000000000000AAeB6D7670E522A718067333cd4E);
constructor(address subscriptionOrRegistrantToCopy, bool subscribe) {
// If an inheriting token contract is deployed to a network without the registry deployed, the modifier// will not revert, but the contract will need to be registered with the registry once it is deployed in// order for the modifier to filter addresses.if (address(operatorFilterRegistry).code.length>0) {
if (subscribe) {
operatorFilterRegistry.registerAndSubscribe(address(this), subscriptionOrRegistrantToCopy);
} else {
if (subscriptionOrRegistrantToCopy !=address(0)) {
operatorFilterRegistry.registerAndCopyEntries(address(this), subscriptionOrRegistrantToCopy);
} else {
operatorFilterRegistry.register(address(this));
}
}
}
}
modifieronlyAllowedOperator(addressfrom) virtual{
// Check registry code length to facilitate testing in environments without a deployed registry.if (address(operatorFilterRegistry).code.length>0) {
// Allow spending tokens from addresses with balance// Note that this still allows listings and marketplaces with escrow to transfer tokens if transferred// from an EOA.if (from==msg.sender) {
_;
return;
}
if (
!(operatorFilterRegistry.isOperatorAllowed(address(this), msg.sender) &&
operatorFilterRegistry.isOperatorAllowed(address(this), from))
) {
revert OperatorNotAllowed(msg.sender);
}
}
_;
}
}
Contract Source Code
File 26 of 31: Ownable.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;import"./interface/IOwnable.sol";
/**
* @title Ownable
* @notice Thirdweb's `Ownable` is a contract extension to be used with any base contract. It exposes functions for setting and reading
* who the 'owner' of the inheriting smart contract is, and lets the inheriting contract perform conditional logic that uses
* information about who the contract's owner is.
*/abstractcontractOwnableisIOwnable{
/// @dev Owner of the contract (purpose: OpenSea compatibility)addressprivate _owner;
/// @dev Reverts if caller is not the owner.modifieronlyOwner() {
if (msg.sender!= _owner) {
revert("Not authorized");
}
_;
}
/**
* @notice Returns the owner of the contract.
*/functionowner() publicviewoverridereturns (address) {
return _owner;
}
/**
* @notice Lets an authorized wallet set a new owner for the contract.
* @param _newOwner The address to set as the new owner of the contract.
*/functionsetOwner(address _newOwner) externaloverride{
if (!_canSetOwner()) {
revert("Not authorized");
}
_setupOwner(_newOwner);
}
/// @dev Lets a contract admin set a new owner for the contract. The new owner must be a contract admin.function_setupOwner(address _newOwner) internal{
address _prevOwner = _owner;
_owner = _newOwner;
emit OwnerUpdated(_prevOwner, _newOwner);
}
/// @dev Returns whether owner can be set in the given execution context.function_canSetOwner() internalviewvirtualreturns (bool);
}
Contract Source Code
File 27 of 31: Permissions.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;import"./interface/IPermissions.sol";
import"../lib/TWStrings.sol";
/**
* @title Permissions
* @dev This contracts provides extending-contracts with role-based access control mechanisms
*/contractPermissionsisIPermissions{
/// @dev Map from keccak256 hash of a role => a map from address => whether address has role.mapping(bytes32=>mapping(address=>bool)) private _hasRole;
/// @dev Map from keccak256 hash of a role to role admin. See {getRoleAdmin}.mapping(bytes32=>bytes32) private _getRoleAdmin;
/// @dev Default admin role for all roles. Only accounts with this role can grant/revoke other roles.bytes32publicconstant DEFAULT_ADMIN_ROLE =0x00;
/// @dev Modifier that checks if an account has the specified role; reverts otherwise.modifieronlyRole(bytes32 role) {
_checkRole(role, msg.sender);
_;
}
/**
* @notice Checks whether an account has a particular role.
* @dev Returns `true` if `account` has been granted `role`.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account for which the role is being checked.
*/functionhasRole(bytes32 role, address account) publicviewoverridereturns (bool) {
return _hasRole[role][account];
}
/**
* @notice Checks whether an account has a particular role;
* role restrictions can be swtiched on and off.
*
* @dev Returns `true` if `account` has been granted `role`.
* Role restrictions can be swtiched on and off:
* - If address(0) has ROLE, then the ROLE restrictions
* don't apply.
* - If address(0) does not have ROLE, then the ROLE
* restrictions will apply.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account for which the role is being checked.
*/functionhasRoleWithSwitch(bytes32 role, address account) publicviewreturns (bool) {
if (!_hasRole[role][address(0)]) {
return _hasRole[role][account];
}
returntrue;
}
/**
* @notice Returns the admin role that controls the specified role.
* @dev See {grantRole} and {revokeRole}.
* To change a role's admin, use {_setRoleAdmin}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
*/functiongetRoleAdmin(bytes32 role) externalviewoverridereturns (bytes32) {
return _getRoleAdmin[role];
}
/**
* @notice Grants a role to an account, if not previously granted.
* @dev Caller must have admin role for the `role`.
* Emits {RoleGranted Event}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account to which the role is being granted.
*/functiongrantRole(bytes32 role, address account) publicvirtualoverride{
_checkRole(_getRoleAdmin[role], msg.sender);
if (_hasRole[role][account]) {
revert("Can only grant to non holders");
}
_setupRole(role, account);
}
/**
* @notice Revokes role from an account.
* @dev Caller must have admin role for the `role`.
* Emits {RoleRevoked Event}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account from which the role is being revoked.
*/functionrevokeRole(bytes32 role, address account) publicvirtualoverride{
_checkRole(_getRoleAdmin[role], msg.sender);
_revokeRole(role, account);
}
/**
* @notice Revokes role from the account.
* @dev Caller must have the `role`, with caller being the same as `account`.
* Emits {RoleRevoked Event}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account from which the role is being revoked.
*/functionrenounceRole(bytes32 role, address account) publicvirtualoverride{
if (msg.sender!= account) {
revert("Can only renounce for self");
}
_revokeRole(role, account);
}
/// @dev Sets `adminRole` as `role`'s admin role.function_setRoleAdmin(bytes32 role, bytes32 adminRole) internalvirtual{
bytes32 previousAdminRole = _getRoleAdmin[role];
_getRoleAdmin[role] = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/// @dev Sets up `role` for `account`function_setupRole(bytes32 role, address account) internalvirtual{
_hasRole[role][account] =true;
emit RoleGranted(role, account, msg.sender);
}
/// @dev Revokes `role` from `account`function_revokeRole(bytes32 role, address account) internalvirtual{
_checkRole(role, account);
delete _hasRole[role][account];
emit RoleRevoked(role, account, msg.sender);
}
/// @dev Checks `role` for `account`. Reverts with a message including the required role.function_checkRole(bytes32 role, address account) internalviewvirtual{
if (!_hasRole[role][account]) {
revert(
string(
abi.encodePacked(
"Permissions: account ",
TWStrings.toHexString(uint160(account), 20),
" is missing role ",
TWStrings.toHexString(uint256(role), 32)
)
)
);
}
}
/// @dev Checks `role` for `account`. Reverts with a message including the required role.function_checkRoleWithSwitch(bytes32 role, address account) internalviewvirtual{
if (!hasRoleWithSwitch(role, account)) {
revert(
string(
abi.encodePacked(
"Permissions: account ",
TWStrings.toHexString(uint160(account), 20),
" is missing role ",
TWStrings.toHexString(uint256(role), 32)
)
)
);
}
}
}
Contract Source Code
File 28 of 31: Royalty.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;import"./interface/IRoyalty.sol";
/**
* @title Royalty
* @notice Thirdweb's `Royalty` is a contract extension to be used with any base contract. It exposes functions for setting and reading
* the recipient of royalty fee and the royalty fee basis points, and lets the inheriting contract perform conditional logic
* that uses information about royalty fees, if desired.
*
* @dev The `Royalty` contract is ERC2981 compliant.
*/abstractcontractRoyaltyisIRoyalty{
/// @dev The (default) address that receives all royalty value.addressprivate royaltyRecipient;
/// @dev The (default) % of a sale to take as royalty (in basis points).uint16private royaltyBps;
/// @dev Token ID => royalty recipient and bps for tokenmapping(uint256=> RoyaltyInfo) private royaltyInfoForToken;
/**
* @notice View royalty info for a given token and sale price.
* @dev Returns royalty amount and recipient for `tokenId` and `salePrice`.
* @param tokenId The tokenID of the NFT for which to query royalty info.
* @param salePrice Sale price of the token.
*
* @return receiver Address of royalty recipient account.
* @return royaltyAmount Royalty amount calculated at current royaltyBps value.
*/functionroyaltyInfo(uint256 tokenId, uint256 salePrice)
externalviewvirtualoverridereturns (address receiver, uint256 royaltyAmount)
{
(address recipient, uint256 bps) = getRoyaltyInfoForToken(tokenId);
receiver = recipient;
royaltyAmount = (salePrice * bps) /10_000;
}
/**
* @notice View royalty info for a given token.
* @dev Returns royalty recipient and bps for `_tokenId`.
* @param _tokenId The tokenID of the NFT for which to query royalty info.
*/functiongetRoyaltyInfoForToken(uint256 _tokenId) publicviewoverridereturns (address, uint16) {
RoyaltyInfo memory royaltyForToken = royaltyInfoForToken[_tokenId];
return
royaltyForToken.recipient ==address(0)
? (royaltyRecipient, uint16(royaltyBps))
: (royaltyForToken.recipient, uint16(royaltyForToken.bps));
}
/**
* @notice Returns the defualt royalty recipient and BPS for this contract's NFTs.
*/functiongetDefaultRoyaltyInfo() externalviewoverridereturns (address, uint16) {
return (royaltyRecipient, uint16(royaltyBps));
}
/**
* @notice Updates default royalty recipient and bps.
* @dev Caller should be authorized to set royalty info.
* See {_canSetRoyaltyInfo}.
* Emits {DefaultRoyalty Event}; See {_setupDefaultRoyaltyInfo}.
*
* @param _royaltyRecipient Address to be set as default royalty recipient.
* @param _royaltyBps Updated royalty bps.
*/functionsetDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps) externaloverride{
if (!_canSetRoyaltyInfo()) {
revert("Not authorized");
}
_setupDefaultRoyaltyInfo(_royaltyRecipient, _royaltyBps);
}
/// @dev Lets a contract admin update the default royalty recipient and bps.function_setupDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps) internal{
if (_royaltyBps >10_000) {
revert("Exceeds max bps");
}
royaltyRecipient = _royaltyRecipient;
royaltyBps =uint16(_royaltyBps);
emit DefaultRoyalty(_royaltyRecipient, _royaltyBps);
}
/**
* @notice Updates default royalty recipient and bps for a particular token.
* @dev Sets royalty info for `_tokenId`. Caller should be authorized to set royalty info.
* See {_canSetRoyaltyInfo}.
* Emits {RoyaltyForToken Event}; See {_setupRoyaltyInfoForToken}.
*
* @param _recipient Address to be set as royalty recipient for given token Id.
* @param _bps Updated royalty bps for the token Id.
*/functionsetRoyaltyInfoForToken(uint256 _tokenId,
address _recipient,
uint256 _bps
) externaloverride{
if (!_canSetRoyaltyInfo()) {
revert("Not authorized");
}
_setupRoyaltyInfoForToken(_tokenId, _recipient, _bps);
}
/// @dev Lets a contract admin set the royalty recipient and bps for a particular token Id.function_setupRoyaltyInfoForToken(uint256 _tokenId,
address _recipient,
uint256 _bps
) internal{
if (_bps >10_000) {
revert("Exceeds max bps");
}
royaltyInfoForToken[_tokenId] = RoyaltyInfo({ recipient: _recipient, bps: _bps });
emit RoyaltyForToken(_tokenId, _recipient, _bps);
}
/// @dev Returns whether royalty info can be set in the given execution context.function_canSetRoyaltyInfo() internalviewvirtualreturns (bool);
}
Contract Source Code
File 29 of 31: Strings.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)pragmasolidity ^0.8.0;import"./math/Math.sol";
/**
* @dev String operations.
*/libraryStrings{
bytes16privateconstant _SYMBOLS ="0123456789abcdef";
uint8privateconstant _ADDRESS_LENGTH =20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/functiontoString(uint256 value) internalpurereturns (stringmemory) {
unchecked {
uint256 length = Math.log10(value) +1;
stringmemory buffer =newstring(length);
uint256 ptr;
/// @solidity memory-safe-assemblyassembly {
ptr :=add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assemblyassembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /=10;
if (value ==0) break;
}
return buffer;
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/functiontoHexString(uint256 value) internalpurereturns (stringmemory) {
unchecked {
return toHexString(value, Math.log256(value) +1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/functiontoHexString(uint256 value, uint256 length) internalpurereturns (stringmemory) {
bytesmemory buffer =newbytes(2* length +2);
buffer[0] ="0";
buffer[1] ="x";
for (uint256 i =2* length +1; i >1; --i) {
buffer[i] = _SYMBOLS[value &0xf];
value >>=4;
}
require(value ==0, "Strings: hex length insufficient");
returnstring(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/functiontoHexString(address addr) internalpurereturns (stringmemory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
Contract Source Code
File 30 of 31: TWAddress.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)pragmasolidity ^0.8.0;/**
* @dev Collection of functions related to the address type
*/libraryTWAddress{
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/functionisContract(address account) internalviewreturns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0// for contracts in construction, since the code is only stored at the end// of the constructor execution.return account.code.length>0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* [EIP1884](https://eips.ethereum.org/EIPS/eip-1884) increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/functionsendValue(addresspayable recipient, uint256 amount) internal{
require(address(this).balance>= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/functionfunctionCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(address(this).balance>= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytesmemory returndata) = target.call{ value: value }(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target, bytesmemory data) internalviewreturns (bytesmemory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalviewreturns (bytesmemory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytesmemory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytesmemory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/functionverifyCallResult(bool success,
bytesmemory returndata,
stringmemory errorMessage
) internalpurereturns (bytesmemory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if presentif (returndata.length>0) {
// The easiest way to bubble the revert reason is using memory via assemblyassembly {
let returndata_size :=mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
Contract Source Code
File 31 of 31: TWStrings.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)pragmasolidity ^0.8.0;/**
* @dev String operations.
*/libraryTWStrings{
bytes16privateconstant _HEX_SYMBOLS ="0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/functiontoString(uint256 value) internalpurereturns (stringmemory) {
// Inspired by OraclizeAPI's implementation - MIT licence// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.solif (value ==0) {
return"0";
}
uint256 temp = value;
uint256 digits;
while (temp !=0) {
digits++;
temp /=10;
}
bytesmemory buffer =newbytes(digits);
while (value !=0) {
digits -=1;
buffer[digits] =bytes1(uint8(48+uint256(value %10)));
value /=10;
}
returnstring(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/functiontoHexString(uint256 value) internalpurereturns (stringmemory) {
if (value ==0) {
return"0x00";
}
uint256 temp = value;
uint256 length =0;
while (temp !=0) {
length++;
temp >>=8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/functiontoHexString(uint256 value, uint256 length) internalpurereturns (stringmemory) {
bytesmemory buffer =newbytes(2* length +2);
buffer[0] ="0";
buffer[1] ="x";
for (uint256 i =2* length +1; i >1; --i) {
buffer[i] = _HEX_SYMBOLS[value &0xf];
value >>=4;
}
require(value ==0, "Strings: hex length insufficient");
returnstring(buffer);
}
}