// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdweb/**
* @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;
/// @dev Mapping from id of a batch of tokens => to whether the base URI for the respective batch of tokens is frozen.mapping(uint256=>bool) public batchFrozen;
/// @dev This event emits when the metadata of all tokens are frozen./// While not currently supported by marketplaces, this event allows/// future indexing if desired.eventMetadataFrozen();
// @dev This event emits when the metadata of a range of tokens is updated./// So that the third-party platforms such as NFT market could/// timely update the images and related attributes of the NFTs.eventBatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
/**
* @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 at the given index.
* @dev See {getBaseURICount}.
* @param _index Index of the desired batch in batchIds array.
*/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 returns the starting tokenId of a given batchId.function_getBatchStartId(uint256 _batchID) internalviewreturns (uint256) {
uint256 numOfTokenBatches = getBaseURICount();
uint256[] memory indices = batchIds;
for (uint256 i =0; i < numOfTokenBatches; i++) {
if (_batchID == indices[i]) {
if (i >0) {
return indices[i -1];
}
return0;
}
}
revert("Invalid batchId");
}
/// @dev Sets the base URI for the batch of tokens with the given batchId.function_setBaseURI(uint256 _batchId, stringmemory _baseURI) internal{
require(!batchFrozen[_batchId], "Batch frozen");
baseURI[_batchId] = _baseURI;
emit BatchMetadataUpdate(_getBatchStartId(_batchId), _batchId);
}
/// @dev Freezes the base URI for the batch of tokens with the given batchId.function_freezeBaseURI(uint256 _batchId) internal{
stringmemory baseURIForBatch = baseURI[_batchId];
require(bytes(baseURIForBatch).length>0, "Invalid batch");
batchFrozen[_batchId] =true;
emit MetadataFrozen();
}
/// @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 2 of 37: ContractMetadata.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"./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);
}
Contract Source Code
File 3 of 37: CurrencyTransferLib.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdweb// Helper interfacesimport { IWETH } from"../infra/interface/IWETH.sol";
import"../external-deps/openzeppelin/token/ERC20/utils/SafeERC20.sol";
libraryCurrencyTransferLib{
usingSafeERC20forIERC20;
/// @dev The address interpreted as native token of the chain.addresspublicconstant NATIVE_TOKEN =0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev Transfers a given amount of currency.functiontransferCurrency(address _currency,
address _from,
address _to,
uint256 _amount
) internal{
if (_amount ==0) {
return;
}
if (_currency == NATIVE_TOKEN) {
safeTransferNativeToken(_to, _amount);
} else {
safeTransferERC20(_currency, _from, _to, _amount);
}
}
/// @dev Transfers a given amount of currency. (With native token wrapping)functiontransferCurrencyWithWrapper(address _currency,
address _from,
address _to,
uint256 _amount,
address _nativeTokenWrapper
) internal{
if (_amount ==0) {
return;
}
if (_currency == NATIVE_TOKEN) {
if (_from ==address(this)) {
// withdraw from weth then transfer withdrawn native token to recipient
IWETH(_nativeTokenWrapper).withdraw(_amount);
safeTransferNativeTokenWithWrapper(_to, _amount, _nativeTokenWrapper);
} elseif (_to ==address(this)) {
// store native currency in wethrequire(_amount ==msg.value, "msg.value != amount");
IWETH(_nativeTokenWrapper).deposit{ value: _amount }();
} else {
safeTransferNativeTokenWithWrapper(_to, _amount, _nativeTokenWrapper);
}
} else {
safeTransferERC20(_currency, _from, _to, _amount);
}
}
/// @dev Transfer `amount` of ERC20 token from `from` to `to`.functionsafeTransferERC20(address _currency,
address _from,
address _to,
uint256 _amount
) internal{
if (_from == _to) {
return;
}
if (_from ==address(this)) {
IERC20(_currency).safeTransfer(_to, _amount);
} else {
IERC20(_currency).safeTransferFrom(_from, _to, _amount);
}
}
/// @dev Transfers `amount` of native token to `to`.functionsafeTransferNativeToken(address to, uint256 value) internal{
// solhint-disable avoid-low-level-calls// slither-disable-next-line low-level-calls
(bool success, ) = to.call{ value: value }("");
require(success, "native token transfer failed");
}
/// @dev Transfers `amount` of native token to `to`. (With native token wrapping)functionsafeTransferNativeTokenWithWrapper(address to,
uint256 value,
address _nativeTokenWrapper
) internal{
// solhint-disable avoid-low-level-calls// slither-disable-next-line low-level-calls
(bool success, ) = to.call{ value: value }("");
if (!success) {
IWETH(_nativeTokenWrapper).deposit{ value: value }();
IERC20(_nativeTokenWrapper).safeTransfer(to, value);
}
}
}
Contract Source Code
File 4 of 37: Drop1155.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"./interface/IDrop1155.sol";
import"../lib/MerkleProof.sol";
abstractcontractDrop1155isIDrop1155{
/*///////////////////////////////////////////////////////////////
State variables
//////////////////////////////////////////////////////////////*//// @dev Mapping from token ID => the set of all claim conditions, at any given moment, for tokens of the token ID.mapping(uint256=> ClaimConditionList) public claimCondition;
/*///////////////////////////////////////////////////////////////
Drop logic
//////////////////////////////////////////////////////////////*//// @dev Lets an account claim tokens.functionclaim(address _receiver,
uint256 _tokenId,
uint256 _quantity,
address _currency,
uint256 _pricePerToken,
AllowlistProof calldata _allowlistProof,
bytesmemory _data
) publicpayablevirtualoverride{
_beforeClaim(_tokenId, _receiver, _quantity, _currency, _pricePerToken, _allowlistProof, _data);
uint256 activeConditionId = getActiveClaimConditionId(_tokenId);
verifyClaim(
activeConditionId,
_dropMsgSender(),
_tokenId,
_quantity,
_currency,
_pricePerToken,
_allowlistProof
);
// Update contract state.
claimCondition[_tokenId].conditions[activeConditionId].supplyClaimed += _quantity;
claimCondition[_tokenId].supplyClaimedByWallet[activeConditionId][_dropMsgSender()] += _quantity;
// If there's a price, collect price.
collectPriceOnClaim(_tokenId, address(0), _quantity, _currency, _pricePerToken);
// Mint the relevant NFTs to claimer.
transferTokensOnClaim(_receiver, _tokenId, _quantity);
emit TokensClaimed(activeConditionId, _dropMsgSender(), _receiver, _tokenId, _quantity);
_afterClaim(_tokenId, _receiver, _quantity, _currency, _pricePerToken, _allowlistProof, _data);
}
/// @dev Lets a contract admin set claim conditions.functionsetClaimConditions(uint256 _tokenId,
ClaimCondition[] calldata _conditions,
bool _resetClaimEligibility
) externalvirtualoverride{
if (!_canSetClaimConditions()) {
revert("Not authorized");
}
ClaimConditionList storage conditionList = claimCondition[_tokenId];
uint256 existingStartIndex = conditionList.currentStartId;
uint256 existingPhaseCount = conditionList.count;
/**
* The mapping `supplyClaimedByWallet` uses a claim condition's UID as a key.
*
* If `_resetClaimEligibility == true`, we assign completely new UIDs to the claim
* conditions in `_conditions`, effectively resetting the restrictions on claims expressed
* by `supplyClaimedByWallet`.
*/uint256 newStartIndex = existingStartIndex;
if (_resetClaimEligibility) {
newStartIndex = existingStartIndex + existingPhaseCount;
}
conditionList.count = _conditions.length;
conditionList.currentStartId = newStartIndex;
uint256 lastConditionStartTimestamp;
for (uint256 i =0; i < _conditions.length; i++) {
require(i ==0|| lastConditionStartTimestamp < _conditions[i].startTimestamp, "ST");
uint256 supplyClaimedAlready = conditionList.conditions[newStartIndex + i].supplyClaimed;
if (supplyClaimedAlready > _conditions[i].maxClaimableSupply) {
revert("max supply claimed");
}
conditionList.conditions[newStartIndex + i] = _conditions[i];
conditionList.conditions[newStartIndex + i].supplyClaimed = supplyClaimedAlready;
lastConditionStartTimestamp = _conditions[i].startTimestamp;
}
/**
* Gas refunds (as much as possible)
*
* If `_resetClaimEligibility == true`, we assign completely new UIDs to the claim
* conditions in `_conditions`. So, we delete claim conditions with UID < `newStartIndex`.
*
* If `_resetClaimEligibility == false`, and there are more existing claim conditions
* than in `_conditions`, we delete the existing claim conditions that don't get replaced
* by the conditions in `_conditions`.
*/if (_resetClaimEligibility) {
for (uint256 i = existingStartIndex; i < newStartIndex; i++) {
delete conditionList.conditions[i];
}
} else {
if (existingPhaseCount > _conditions.length) {
for (uint256 i = _conditions.length; i < existingPhaseCount; i++) {
delete conditionList.conditions[newStartIndex + i];
}
}
}
emit ClaimConditionsUpdated(_tokenId, _conditions, _resetClaimEligibility);
}
/// @dev Checks a request to claim NFTs against the active claim condition's criteria.functionverifyClaim(uint256 _conditionId,
address _claimer,
uint256 _tokenId,
uint256 _quantity,
address _currency,
uint256 _pricePerToken,
AllowlistProof calldata _allowlistProof
) publicviewreturns (bool isOverride) {
ClaimCondition memory currentClaimPhase = claimCondition[_tokenId].conditions[_conditionId];
uint256 claimLimit = currentClaimPhase.quantityLimitPerWallet;
uint256 claimPrice = currentClaimPhase.pricePerToken;
address claimCurrency = currentClaimPhase.currency;
if (currentClaimPhase.merkleRoot !=bytes32(0)) {
(isOverride, ) = MerkleProof.verify(
_allowlistProof.proof,
currentClaimPhase.merkleRoot,
keccak256(
abi.encodePacked(
_claimer,
_allowlistProof.quantityLimitPerWallet,
_allowlistProof.pricePerToken,
_allowlistProof.currency
)
)
);
}
if (isOverride) {
claimLimit = _allowlistProof.quantityLimitPerWallet !=0
? _allowlistProof.quantityLimitPerWallet
: claimLimit;
claimPrice = _allowlistProof.pricePerToken !=type(uint256).max
? _allowlistProof.pricePerToken
: claimPrice;
claimCurrency = _allowlistProof.pricePerToken !=type(uint256).max&& _allowlistProof.currency !=address(0)
? _allowlistProof.currency
: claimCurrency;
}
uint256 supplyClaimedByWallet = claimCondition[_tokenId].supplyClaimedByWallet[_conditionId][_claimer];
if (_currency != claimCurrency || _pricePerToken != claimPrice) {
revert("!PriceOrCurrency");
}
if (_quantity ==0|| (_quantity + supplyClaimedByWallet > claimLimit)) {
revert("!Qty");
}
if (currentClaimPhase.supplyClaimed + _quantity > currentClaimPhase.maxClaimableSupply) {
revert("!MaxSupply");
}
if (currentClaimPhase.startTimestamp >block.timestamp) {
revert("cant claim yet");
}
}
/// @dev At any given moment, returns the uid for the active claim condition.functiongetActiveClaimConditionId(uint256 _tokenId) publicviewreturns (uint256) {
ClaimConditionList storage conditionList = claimCondition[_tokenId];
for (uint256 i = conditionList.currentStartId + conditionList.count; i > conditionList.currentStartId; i--) {
if (block.timestamp>= conditionList.conditions[i -1].startTimestamp) {
return i -1;
}
}
revert("!CONDITION.");
}
/// @dev Returns the claim condition at the given uid.functiongetClaimConditionById(uint256 _tokenId, uint256 _conditionId)
externalviewreturns (ClaimCondition memory condition)
{
condition = claimCondition[_tokenId].conditions[_conditionId];
}
/// @dev Returns the supply claimed by claimer for a given conditionId.functiongetSupplyClaimedByWallet(uint256 _tokenId,
uint256 _conditionId,
address _claimer
) publicviewreturns (uint256 supplyClaimedByWallet) {
supplyClaimedByWallet = claimCondition[_tokenId].supplyClaimedByWallet[_conditionId][_claimer];
}
/*////////////////////////////////////////////////////////////////////
Optional hooks that can be implemented in the derived contract
///////////////////////////////////////////////////////////////////*//// @dev Exposes the ability to override the msg sender.function_dropMsgSender() internalvirtualreturns (address) {
returnmsg.sender;
}
/// @dev Runs before every `claim` function call.function_beforeClaim(uint256 _tokenId,
address _receiver,
uint256 _quantity,
address _currency,
uint256 _pricePerToken,
AllowlistProof calldata _allowlistProof,
bytesmemory _data
) internalvirtual{}
/// @dev Runs after every `claim` function call.function_afterClaim(uint256 _tokenId,
address _receiver,
uint256 _quantity,
address _currency,
uint256 _pricePerToken,
AllowlistProof calldata _allowlistProof,
bytesmemory _data
) internalvirtual{}
/*///////////////////////////////////////////////////////////////
Virtual functions: to be implemented in derived contract
//////////////////////////////////////////////////////////////*//// @dev Collects and distributes the primary sale value of NFTs being claimed.functioncollectPriceOnClaim(uint256 _tokenId,
address _primarySaleRecipient,
uint256 _quantityToClaim,
address _currency,
uint256 _pricePerToken
) internalvirtual;
/// @dev Transfers the NFTs being claimed.functiontransferTokensOnClaim(address _to,
uint256 _tokenId,
uint256 _quantityBeingClaimed
) internalvirtual;
/// @dev Determine what wallet can update claim conditionsfunction_canSetClaimConditions() internalviewvirtualreturns (bool);
}
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport { ERC1155 } from"../eip/ERC1155.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 `ERC1155Base` smart contract implements the ERC1155 NFT standard.
* It includes the following additions to standard ERC1155 logic:
*
* - Ability to mint NFTs via the provided `mintTo` and `batchMintTo` functions.
*
* - 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.
*/contractERC1155BaseisERC1155, ContractMetadata, Ownable, Royalty, Multicall, BatchMintMetadata{
usingTWStringsforuint256;
/*//////////////////////////////////////////////////////////////
State variables
//////////////////////////////////////////////////////////////*//// @dev The tokenId of the next NFT to mint.uint256internal nextTokenIdToMint_;
/*//////////////////////////////////////////////////////////////
Mappings
//////////////////////////////////////////////////////////////*//**
* @notice Returns the total supply of NFTs of a given tokenId
* @dev Mapping from tokenId => total circulating supply of NFTs of that tokenId.
*/mapping(uint256=>uint256) public totalSupply;
/*//////////////////////////////////////////////////////////////
Constructor
//////////////////////////////////////////////////////////////*/constructor(address _defaultAdmin,
stringmemory _name,
stringmemory _symbol,
address _royaltyRecipient,
uint128 _royaltyBps
) ERC1155(_name, _symbol) {
_setupOwner(_defaultAdmin);
_setupDefaultRoyaltyInfo(_royaltyRecipient, _royaltyBps);
}
/*//////////////////////////////////////////////////////////////
Overriden metadata logic
//////////////////////////////////////////////////////////////*//// @notice Returns the metadata URI for the given tokenId./// @param _tokenId The tokenId of the token for which a URI should be returned./// @return The metadata URI for the given tokenId.functionuri(uint256 _tokenId) publicviewvirtualoverridereturns (stringmemory) {
stringmemory uriForToken = _uri[_tokenId];
if (bytes(uriForToken).length>0) {
return uriForToken;
}
stringmemory batchUri = _getBaseURI(_tokenId);
returnstring(abi.encodePacked(batchUri, _tokenId.toString()));
}
/*//////////////////////////////////////////////////////////////
Mint / burn logic
//////////////////////////////////////////////////////////////*//**
* @notice Lets an authorized address mint NFTs to a recipient.
* @dev - The logic in the `_canMint` function determines whether the caller is authorized to mint NFTs.
* - If `_tokenId == type(uint256).max` a new NFT at tokenId `nextTokenIdToMint` is minted. If the given
* `tokenId < nextTokenIdToMint`, then additional supply of an existing NFT is being minted.
*
* @param _to The recipient of the NFTs to mint.
* @param _tokenId The tokenId of the NFT to mint.
* @param _tokenURI The full metadata URI for the NFTs minted (if a new NFT is being minted).
* @param _amount The amount of the same NFT to mint.
*/functionmintTo(address _to,
uint256 _tokenId,
stringmemory _tokenURI,
uint256 _amount
) publicvirtual{
require(_canMint(), "Not authorized to mint.");
uint256 tokenIdToMint;
uint256 nextIdToMint = nextTokenIdToMint();
if (_tokenId ==type(uint256).max) {
tokenIdToMint = nextIdToMint;
nextTokenIdToMint_ +=1;
_setTokenURI(nextIdToMint, _tokenURI);
} else {
require(_tokenId < nextIdToMint, "invalid id");
tokenIdToMint = _tokenId;
}
_mint(_to, tokenIdToMint, _amount, "");
}
/**
* @notice Lets an authorized address mint multiple NEW NFTs at once to a recipient.
* @dev The logic in the `_canMint` function determines whether the caller is authorized to mint NFTs.
* If `_tokenIds[i] == type(uint256).max` a new NFT at tokenId `nextTokenIdToMint` is minted. If the given
* `tokenIds[i] < nextTokenIdToMint`, then additional supply of an existing NFT is minted.
* The metadata for each new NFT is stored at `baseURI/{tokenID of NFT}`
*
* @param _to The recipient of the NFT to mint.
* @param _tokenIds The tokenIds of the NFTs to mint.
* @param _amounts The amounts of each NFT to mint.
* @param _baseURI The baseURI for the `n` number of NFTs minted. The metadata for each NFT is `baseURI/tokenId`
*/functionbatchMintTo(address _to,
uint256[] memory _tokenIds,
uint256[] memory _amounts,
stringmemory _baseURI
) publicvirtual{
require(_canMint(), "Not authorized to mint.");
require(_amounts.length>0, "Minting zero tokens.");
require(_tokenIds.length== _amounts.length, "Length mismatch.");
uint256 nextIdToMint = nextTokenIdToMint();
uint256 startNextIdToMint = nextIdToMint;
uint256 numOfNewNFTs;
for (uint256 i =0; i < _tokenIds.length; i +=1) {
if (_tokenIds[i] ==type(uint256).max) {
_tokenIds[i] = nextIdToMint;
nextIdToMint +=1;
numOfNewNFTs +=1;
} else {
require(_tokenIds[i] < nextIdToMint, "invalid id");
}
}
if (numOfNewNFTs >0) {
_batchMintMetadata(startNextIdToMint, numOfNewNFTs, _baseURI);
}
nextTokenIdToMint_ = nextIdToMint;
_mintBatch(_to, _tokenIds, _amounts, "");
}
/**
* @notice Lets an owner or approved operator burn NFTs of the given tokenId.
*
* @param _owner The owner of the NFT to burn.
* @param _tokenId The tokenId of the NFT to burn.
* @param _amount The amount of the NFT to burn.
*/functionburn(address _owner,
uint256 _tokenId,
uint256 _amount
) externalvirtual{
address caller =msg.sender;
require(caller == _owner || isApprovedForAll[_owner][caller], "Unapproved caller");
require(balanceOf[_owner][_tokenId] >= _amount, "Not enough tokens owned");
_burn(_owner, _tokenId, _amount);
}
/**
* @notice Lets an owner or approved operator burn NFTs of the given tokenIds.
*
* @param _owner The owner of the NFTs to burn.
* @param _tokenIds The tokenIds of the NFTs to burn.
* @param _amounts The amounts of the NFTs to burn.
*/functionburnBatch(address _owner,
uint256[] memory _tokenIds,
uint256[] memory _amounts
) externalvirtual{
address caller =msg.sender;
require(caller == _owner || isApprovedForAll[_owner][caller], "Unapproved caller");
require(_tokenIds.length== _amounts.length, "Length mismatch");
for (uint256 i =0; i < _tokenIds.length; i +=1) {
require(balanceOf[_owner][_tokenIds[i]] >= _amounts[i], "Not enough tokens owned");
}
_burnBatch(_owner, _tokenIds, _amounts);
}
/*//////////////////////////////////////////////////////////////
ERC165 Logic
//////////////////////////////////////////////////////////////*//**
* @dev See ERC165: https://eips.ethereum.org/EIPS/eip-165
* @inheritdoc IERC165
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(ERC1155, IERC165) returns (bool) {
return
interfaceId ==0x01ffc9a7||// ERC165 Interface ID for ERC165
interfaceId ==0xd9b67a26||// ERC165 Interface ID for ERC1155
interfaceId ==0x0e89341c||// ERC165 Interface ID for ERC1155MetadataURI
interfaceId ==type(IERC2981).interfaceId; // ERC165 ID for ERC2981
}
/*//////////////////////////////////////////////////////////////
View functions
//////////////////////////////////////////////////////////////*//// @notice The tokenId assigned to the next new NFT to be minted.functionnextTokenIdToMint() publicviewvirtualreturns (uint256) {
return nextTokenIdToMint_;
}
/*//////////////////////////////////////////////////////////////
Internal (overrideable) functions
//////////////////////////////////////////////////////////////*//// @dev Returns whether contract metadata can be set in the given execution context./// @return 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./// @return 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./// @return 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./// @return Whether royalty info can be set in the given execution context.function_canSetRoyaltyInfo() internalviewvirtualoverridereturns (bool) {
returnmsg.sender== owner();
}
/// @dev Runs before every token transfer / mint / burn./// @param operator The address of the caller./// @param from The address of the sender./// @param to The address of the recipient./// @param ids The tokenIds of the tokens being transferred./// @param amounts The amounts of the tokens being transferred./// @param data Additional data with no specified format.function_beforeTokenTransfer(address operator,
addressfrom,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytesmemory data
) internalvirtualoverride{
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
if (from==address(0)) {
for (uint256 i =0; i < ids.length; ++i) {
totalSupply[ids[i]] += amounts[i];
}
}
if (to ==address(0)) {
for (uint256 i =0; i < ids.length; ++i) {
totalSupply[ids[i]] -= amounts[i];
}
}
}
}
Contract Source Code
File 7 of 37: IClaimCondition.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdweb/**
* The interface `IClaimCondition` is written for thirdweb's 'Drop' contracts, which are distribution mechanisms for tokens.
*
* A claim condition defines criteria under which accounts can mint tokens. Claim conditions can be overwritten
* or added to by the contract admin. At any moment, there is only one active claim condition.
*/interfaceIClaimCondition{
/**
* @notice The criteria that make up a claim condition.
*
* @param startTimestamp The unix timestamp after which the claim condition applies.
* The same claim condition applies until the `startTimestamp`
* of the next claim condition.
*
* @param maxClaimableSupply The maximum total number of tokens that can be claimed under
* the claim condition.
*
* @param supplyClaimed At any given point, the number of tokens that have been claimed
* under the claim condition.
*
* @param quantityLimitPerWallet The maximum number of tokens that can be claimed by a wallet.
*
* @param merkleRoot The allowlist of addresses that can claim tokens under the claim
* condition.
*
* @param pricePerToken The price required to pay per token claimed.
*
* @param currency The currency in which the `pricePerToken` must be paid.
*
* @param metadata Claim condition metadata.
*/structClaimCondition {
uint256 startTimestamp;
uint256 maxClaimableSupply;
uint256 supplyClaimed;
uint256 quantityLimitPerWallet;
bytes32 merkleRoot;
uint256 pricePerToken;
address currency;
string metadata;
}
}
Contract Source Code
File 8 of 37: IClaimConditionMultiPhase.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"./IClaimCondition.sol";
/**
* The interface `IClaimConditionMultiPhase` is written for thirdweb's 'Drop' contracts, which are distribution mechanisms for tokens.
*
* An authorized wallet can set a series of claim conditions, ordered by their respective `startTimestamp`.
* A claim condition defines criteria under which accounts can mint tokens. Claim conditions can be overwritten
* or added to by the contract admin. At any moment, there is only one active claim condition.
*/interfaceIClaimConditionMultiPhaseisIClaimCondition{
/**
* @notice The set of all claim conditions, at any given moment.
* Claim Phase ID = [currentStartId, currentStartId + length - 1];
*
* @param currentStartId The uid for the first claim condition amongst the current set of
* claim conditions. The uid for each next claim condition is one
* more than the previous claim condition's uid.
*
* @param count The total number of phases / claim conditions in the list
* of claim conditions.
*
* @param conditions The claim conditions at a given uid. Claim conditions
* are ordered in an ascending order by their `startTimestamp`.
*
* @param supplyClaimedByWallet Map from a claim condition uid and account to supply claimed by account.
*/structClaimConditionList {
uint256 currentStartId;
uint256 count;
mapping(uint256=> ClaimCondition) conditions;
mapping(uint256=>mapping(address=>uint256)) supplyClaimedByWallet;
}
}
Contract Source Code
File 9 of 37: IContractMetadata.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdweb/**
* 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);
}
Contract Source Code
File 10 of 37: IDrop1155.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"./IClaimConditionMultiPhase.sol";
/**
* The interface `IDrop1155` is written for thirdweb's 'Drop' contracts, which are distribution mechanisms for tokens.
*
* An authorized wallet can set a series of claim conditions, ordered by their respective `startTimestamp`.
* A claim condition defines criteria under which accounts can mint tokens. Claim conditions can be overwritten
* or added to by the contract admin. At any moment, there is only one active claim condition.
*/interfaceIDrop1155isIClaimConditionMultiPhase{
/**
* @param proof Proof of concerned wallet's inclusion in an allowlist.
* @param quantityLimitPerWallet The total quantity of tokens the allowlisted wallet is eligible to claim over time.
* @param pricePerToken The price per token the allowlisted wallet must pay to claim tokens.
* @param currency The currency in which the allowlisted wallet must pay the price for claiming tokens.
*/structAllowlistProof {
bytes32[] proof;
uint256 quantityLimitPerWallet;
uint256 pricePerToken;
address currency;
}
/// @notice Emitted when tokens are claimed.eventTokensClaimed(uint256indexed claimConditionIndex,
addressindexed claimer,
addressindexed receiver,
uint256 tokenId,
uint256 quantityClaimed
);
/// @notice Emitted when the contract's claim conditions are updated.eventClaimConditionsUpdated(uint256indexed tokenId, ClaimCondition[] claimConditions, bool resetEligibility);
/**
* @notice Lets an account claim a given quantity of NFTs.
*
* @param receiver The receiver of the NFTs to claim.
* @param tokenId The tokenId of the NFT to claim.
* @param quantity The quantity of NFTs to claim.
* @param currency The currency in which to pay for the claim.
* @param pricePerToken The price per token to pay for the claim.
* @param allowlistProof The proof of the claimer's inclusion in the merkle root allowlist
* of the claim conditions that apply.
* @param data Arbitrary bytes data that can be leveraged in the implementation of this interface.
*/functionclaim(address receiver,
uint256 tokenId,
uint256 quantity,
address currency,
uint256 pricePerToken,
AllowlistProof calldata allowlistProof,
bytesmemory data
) externalpayable;
/**
* @notice Lets a contract admin (account with `DEFAULT_ADMIN_ROLE`) set claim conditions.
*
* @param tokenId The token ID for which to set mint conditions.
* @param phases Claim conditions in ascending order by `startTimestamp`.
*
* @param resetClaimEligibility Whether to honor the restrictions applied to wallets who have claimed tokens in the current conditions,
* in the new claim conditions being set.
*
*/functionsetClaimConditions(uint256 tokenId,
ClaimCondition[] calldata phases,
bool resetClaimEligibility
) external;
}
Contract Source Code
File 11 of 37: IERC1155.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/**
@title ERC-1155 Multi Token Standard
@dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md
Note: The ERC-165 identifier for this interface is 0xd9b67a26.
*/interfaceIERC1155{
/**
@dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard).
The `_operator` argument MUST be msg.sender.
The `_from` argument MUST be the address of the holder whose balance is decreased.
The `_to` argument MUST be the address of the recipient whose balance is increased.
The `_id` argument MUST be the token type being transferred.
The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by.
When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).
When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).
*/eventTransferSingle(addressindexed _operator,
addressindexed _from,
addressindexed _to,
uint256 _id,
uint256 _value
);
/**
@dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard).
The `_operator` argument MUST be msg.sender.
The `_from` argument MUST be the address of the holder whose balance is decreased.
The `_to` argument MUST be the address of the recipient whose balance is increased.
The `_ids` argument MUST be the list of tokens being transferred.
The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by.
When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).
When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).
*/eventTransferBatch(addressindexed _operator,
addressindexed _from,
addressindexed _to,
uint256[] _ids,
uint256[] _values
);
/**
@dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absense of an event assumes disabled).
*/eventApprovalForAll(addressindexed _owner, addressindexed _operator, bool _approved);
/**
@dev MUST emit when the URI is updated for a token ID.
URIs are defined in RFC 3986.
The URI MUST point a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema".
*/eventURI(string _value, uint256indexed _id);
/**
@notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call).
@dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard).
MUST revert if `_to` is the zero address.
MUST revert if balance of holder for token `_id` is lower than the `_value` sent.
MUST revert on any other error.
MUST emit the `TransferSingle` event to reflect the balance change (see "Safe Transfer Rules" section of the standard).
After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard).
@param _from Source address
@param _to Target address
@param _id ID of the token type
@param _value Transfer amount
@param _data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to`
*/functionsafeTransferFrom(address _from,
address _to,
uint256 _id,
uint256 _value,
bytescalldata _data
) external;
/**
@notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call).
@dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard).
MUST revert if `_to` is the zero address.
MUST revert if length of `_ids` is not the same as length of `_values`.
MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient.
MUST revert on any other error.
MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of the standard).
Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).
After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard).
@param _from Source address
@param _to Target address
@param _ids IDs of each token type (order and length must match _values array)
@param _values Transfer amounts per token type (order and length must match _ids array)
@param _data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to`
*/functionsafeBatchTransferFrom(address _from,
address _to,
uint256[] calldata _ids,
uint256[] calldata _values,
bytescalldata _data
) external;
/**
@notice Get the balance of an account's Tokens.
@param _owner The address of the token holder
@param _id ID of the Token
@return The _owner's balance of the Token type requested
*/functionbalanceOf(address _owner, uint256 _id) externalviewreturns (uint256);
/**
@notice Get the balance of multiple account/token pairs
@param _owners The addresses of the token holders
@param _ids ID of the Tokens
@return The _owner's balance of the Token types requested (i.e. balance for each (owner, id) pair)
*/functionbalanceOfBatch(address[] calldata _owners, uint256[] calldata _ids)
externalviewreturns (uint256[] memory);
/**
@notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens.
@dev MUST emit the ApprovalForAll event on success.
@param _operator Address to add to the set of authorized operators
@param _approved True if the operator is approved, false to revoke approval
*/functionsetApprovalForAll(address _operator, bool _approved) external;
/**
@notice Queries the approval status of an operator for a given owner.
@param _owner The owner of the Tokens
@param _operator Address of authorized operator
@return True if the operator is approved, false if not
*/functionisApprovedForAll(address _owner, address _operator) externalviewreturns (bool);
}
Contract Source Code
File 12 of 37: IERC1155Metadata.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/**
Note: The ERC-165 identifier for this interface is 0x0e89341c.
*/interfaceIERC1155Metadata{
/**
@notice A distinct Uniform Resource Identifier (URI) for a given token.
@dev URIs are defined in RFC 3986.
The URI may point to a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema".
@return URI string
*/functionuri(uint256 _id) externalviewreturns (stringmemory);
}
Contract Source Code
File 13 of 37: IERC1155Receiver.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)pragmasolidity ^0.8.0;import"./IERC165.sol";
/**
* @dev _Available since v3.1._
*/interfaceIERC1155ReceiverisIERC165{
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/functiononERC1155Received(address operator,
addressfrom,
uint256 id,
uint256 value,
bytescalldata data
) externalreturns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/functiononERC1155BatchReceived(address operator,
addressfrom,
uint256[] calldata ids,
uint256[] calldata values,
bytescalldata data
) externalreturns (bytes4);
}
Contract Source Code
File 14 of 37: IERC165.sol
// 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);
}
// 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 17 of 37: ILazyMint.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdweb/**
* Thirdweb's `LazyMint` is a contract extension for any base NFT contract. It lets you 'lazy mint' any number of NFTs
* at once. Here, 'lazy mint' means defining the metadata for particular tokenIds of your NFT contract, without actually
* minting a non-zero balance of NFTs of those tokenIds.
*/interfaceILazyMint{
/// @dev Emitted when tokens are lazy minted.eventTokensLazyMinted(uint256indexed startTokenId, uint256 endTokenId, string baseURI, bytes encryptedBaseURI);
/**
* @notice Lazy mints a given amount of NFTs.
*
* @param amount The number of NFTs to lazy mint.
*
* @param baseURIForTokens The base URI for the 'n' number of NFTs being lazy minted, where the metadata for each
* of those NFTs is `${baseURIForTokens}/${tokenId}`.
*
* @param extraData Additional bytes data to be used at the discretion of the consumer of the contract.
*
* @return batchId A unique integer identifier for the batch of NFTs lazy minted together.
*/functionlazyMint(uint256 amount,
stringcalldata baseURIForTokens,
bytescalldata extraData
) externalreturns (uint256 batchId);
}
Contract Source Code
File 18 of 37: IMulticall.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/// @author thirdweb/**
* @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);
}
Contract Source Code
File 19 of 37: IOwnable.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdweb/**
* 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 20 of 37: IPermissions.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdweb/**
* @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 21 of 37: IPermissionsEnumerable.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"./IPermissions.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/interfaceIPermissionsEnumerableisIPermissions{
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* [forum post](https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296)
* for more information.
*/functiongetRoleMember(bytes32 role, uint256 index) externalviewreturns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/functiongetRoleMemberCount(bytes32 role) externalviewreturns (uint256);
}
Contract Source Code
File 22 of 37: IPrimarySale.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdweb/**
* Thirdweb's `Primary` is a contract extension to be used with any base contract. It exposes functions for setting and reading
* the recipient of primary sales, and lets the inheriting contract perform conditional logic that uses information about
* primary sales, if desired.
*/interfaceIPrimarySale{
/// @dev The adress that receives all primary sales value.functionprimarySaleRecipient() externalviewreturns (address);
/// @dev Lets a module admin set the default recipient of all primary sales.functionsetPrimarySaleRecipient(address _saleRecipient) external;
/// @dev Emitted when a new sale recipient is set.eventPrimarySaleRecipientUpdated(addressindexed recipient);
}
Contract Source Code
File 23 of 37: IRoyalty.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"../../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);
}
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"./interface/ILazyMint.sol";
import"./BatchMintMetadata.sol";
/**
* The `LazyMint` is a contract extension for any base NFT contract. It lets you 'lazy mint' any number of NFTs
* at once. Here, 'lazy mint' means defining the metadata for particular tokenIds of your NFT contract, without actually
* minting a non-zero balance of NFTs of those tokenIds.
*/abstractcontractLazyMintisILazyMint, BatchMintMetadata{
/// @notice The tokenId assigned to the next new NFT to be lazy minted.uint256internal nextTokenIdToLazyMint;
/**
* @notice Lets an authorized address lazy mint a given amount of NFTs.
*
* @param _amount The number of NFTs to lazy mint.
* @param _baseURIForTokens The base URI for the 'n' number of NFTs being lazy minted, where the metadata for each
* of those NFTs is `${baseURIForTokens}/${tokenId}`.
* @param _data Additional bytes data to be used at the discretion of the consumer of the contract.
* @return batchId A unique integer identifier for the batch of NFTs lazy minted together.
*/functionlazyMint(uint256 _amount,
stringcalldata _baseURIForTokens,
bytescalldata _data
) publicvirtualoverridereturns (uint256 batchId) {
if (!_canLazyMint()) {
revert("Not authorized");
}
if (_amount ==0) {
revert("0 amt");
}
uint256 startId = nextTokenIdToLazyMint;
(nextTokenIdToLazyMint, batchId) = _batchMintMetadata(startId, _amount, _baseURIForTokens);
emit TokensLazyMinted(startId, startId + _amount -1, _baseURIForTokens, _data);
return batchId;
}
/// @dev Returns whether lazy minting can be performed in the given execution context.function_canLazyMint() internalviewvirtualreturns (bool);
}
Contract Source Code
File 26 of 37: MerkleProof.sol
// SPDX-License-Identifier: Apache 2.0pragmasolidity ^0.8.0;/// @author thirdweb/**
* @dev These functions deal with verification of Merkle Trees proofs.
*
* The proofs can be generated using the JavaScript library
* https://github.com/miguelmota/merkletreejs[merkletreejs].
* Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.
*
* See `test/utils/cryptography/MerkleProof.test.js` for some examples.
*
* Source: https://github.com/ensdomains/governance/blob/master/contracts/MerkleProof.sol
*/libraryMerkleProof{
/**
* @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
* defined by `root`. For this, a `proof` must be provided, containing
* sibling hashes on the branch from the leaf to the root of the tree. Each
* pair of leaves and each pair of pre-images are assumed to be sorted.
*/functionverify(bytes32[] memory proof,
bytes32 root,
bytes32 leaf
) internalpurereturns (bool, uint256) {
bytes32 computedHash = leaf;
uint256 index =0;
for (uint256 i =0; i < proof.length; i++) {
index *=2;
bytes32 proofElement = proof[i];
if (computedHash <= proofElement) {
// Hash(current computed hash + current element of the proof)
computedHash =keccak256(abi.encodePacked(computedHash, proofElement));
} else {
// Hash(current element of the proof + current computed hash)
computedHash =keccak256(abi.encodePacked(proofElement, computedHash));
index +=1;
}
}
// Check if the computed hash (root) is equal to the provided rootreturn (computedHash == root, index);
}
}
Contract Source Code
File 27 of 37: MintpadERC1155Drop.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"@thirdweb-dev/contracts/base/ERC1155Base.sol";
// ========== External imports ==========// ========== Internal imports ==========import"@thirdweb-dev/contracts/lib/CurrencyTransferLib.sol";
import"@thirdweb-dev/contracts/lib/TWStrings.sol";
// ========== Features ==========import"@thirdweb-dev/contracts/extension/PrimarySale.sol";
import"@thirdweb-dev/contracts/extension/LazyMint.sol";
import"@thirdweb-dev/contracts/extension/PermissionsEnumerable.sol";
import"@thirdweb-dev/contracts/extension/Drop1155.sol";
import"../extension/TransactionFee.sol";
contractMintpadERC1155DropisERC1155Base,
PrimarySale,
LazyMint,
TransactionFee,
PermissionsEnumerable,
Drop1155{
usingTWStringsforuint256;
/*///////////////////////////////////////////////////////////////
State variables
//////////////////////////////////////////////////////////////*//// @dev Only transfers to or from TRANSFER_ROLE holders are valid, when transfers are restricted.bytes32private transferRole;
/// @dev Only MINTER_ROLE holders can sign off on `MintRequest`s and lazy mint tokens.bytes32private minterRole;
/*///////////////////////////////////////////////////////////////
Mappings
//////////////////////////////////////////////////////////////*//// @dev Mapping from token ID => maximum possible total circulating supply of tokens with that ID.mapping(uint256=>uint256) public maxTotalSupply;
/// @dev Mapping from token ID => the address of the recipient of primary sales.mapping(uint256=>address) public saleRecipient;
constructor (address _defaultAdmin,
stringmemory _name,
stringmemory _symbol,
address _saleRecipient,
uint256 _transactionFee,
address _royaltyRecipient,
uint128 _royaltyBps
)
ERC1155Base(
_defaultAdmin,
_name,
_symbol,
_royaltyRecipient,
_royaltyBps
)
{
require(_transactionFee >0, "!TransactionFee");
bytes32 _transferRole =keccak256("TRANSFER_ROLE");
bytes32 _minterRole =keccak256("MINTER_ROLE");
_setupRole(DEFAULT_ADMIN_ROLE, _defaultAdmin);
_setupRole(_minterRole, _defaultAdmin);
_setupRole(_transferRole, _defaultAdmin);
_setupRole(_transferRole, address(0));
_setupPrimarySaleRecipient(_saleRecipient);
transferRole = _transferRole;
minterRole = _minterRole;
transactionFee = _transactionFee;
}
/*///////////////////////////////////////////////////////////////
Contract identifiers
//////////////////////////////////////////////////////////////*/functioncontractType() externalpurereturns (bytes32) {
returnbytes32("ERC1155");
}
/*//////////////////////////////////////////////////////////////
Overriden ERC1155 logic
//////////////////////////////////////////////////////////////*//// @dev Returns the uri for a given tokenId.functionuri(uint256 _tokenId) publicviewoverridereturns (stringmemory) {
stringmemory batchUri = _getBaseURI(_tokenId);
returnstring(abi.encodePacked(batchUri, _tokenId.toString()));
}
/*///////////////////////////////////////////////////////////////
Setter functions
//////////////////////////////////////////////////////////////*//// @dev Lets a module admin set a max total supply for token.functionsetMaxTotalSupply(uint256 _tokenId, uint256 _maxTotalSupply) externalonlyRole(DEFAULT_ADMIN_ROLE) {
maxTotalSupply[_tokenId] = _maxTotalSupply;
}
/// @dev Lets a contract admin set the recipient for all primary sales.functionsetSaleRecipientForToken(uint256 _tokenId, address _saleRecipient) externalonlyRole(DEFAULT_ADMIN_ROLE) {
saleRecipient[_tokenId] = _saleRecipient;
}
/*//////////////////////////////////////////////////////////////
Internal (overrideable) functions
//////////////////////////////////////////////////////////////*//// @dev Runs before every `claim` function call.function_beforeClaim(uint256 _tokenId,
address,
uint256 _quantity,
address,
uint256,
AllowlistProof calldata,
bytesmemory) internalviewoverride{
require(maxTotalSupply[_tokenId] ==0|| totalSupply[_tokenId] + _quantity <= maxTotalSupply[_tokenId], "!Supply");
}
/// @dev Collects and distributes the primary sale value of NFTs being claimed.functioncollectPriceOnClaim(uint256 _tokenId,
address _primarySaleRecipient,
uint256 _quantityToClaim,
address _currency,
uint256 _pricePerToken
) internaloverride{
address _saleRecipient = _primarySaleRecipient ==address(0)
? (saleRecipient[_tokenId] ==address(0) ? primarySaleRecipient() : saleRecipient[_tokenId])
: _primarySaleRecipient;
uint256 totalPrice = _pricePerToken >0 ? _quantityToClaim * _pricePerToken : 0;
if (_currency == CurrencyTransferLib.NATIVE_TOKEN) {
require (msg.value== (totalPrice + transactionFee), "!ClaimPrice");
}
if (_pricePerToken >0) {
CurrencyTransferLib.transferCurrency(_currency, _msgSender(), _saleRecipient, totalPrice);
}
CurrencyTransferLib.transferCurrency(_currency, _msgSender(), platformAddress, transactionFee);
}
/// @dev Transfers the NFTs being claimed.functiontransferTokensOnClaim(address _to,
uint256 _tokenId,
uint256 _quantityBeingClaimed
) internaloverride{
_mint(_to, _tokenId, _quantityBeingClaimed, "");
}
/// @dev Checks whether primary sale recipient can be set in the given execution context.function_canSetPrimarySaleRecipient() internalviewoverridereturns (bool) {
return hasRole(DEFAULT_ADMIN_ROLE, _msgSender());
}
/// @dev Checks whether owner can be set in the given execution context.function_canSetOwner() internalviewoverridereturns (bool) {
return hasRole(DEFAULT_ADMIN_ROLE, _msgSender());
}
/// @dev Checks whether royalty info can be set in the given execution context.function_canSetRoyaltyInfo() internalviewoverridereturns (bool) {
return hasRole(DEFAULT_ADMIN_ROLE, _msgSender());
}
/// @dev Checks whether contract metadata can be set in the given execution context.function_canSetContractURI() internalviewoverridereturns (bool) {
return hasRole(DEFAULT_ADMIN_ROLE, _msgSender());
}
/// @dev Checks whether platform fee info can be set in the given execution context.function_canSetClaimConditions() internalviewoverridereturns (bool) {
return hasRole(DEFAULT_ADMIN_ROLE, _msgSender());
}
/// @dev Returns whether lazy minting can be done in the given execution context.function_canLazyMint() internalviewvirtualoverridereturns (bool) {
return hasRole(minterRole, _msgSender());
}
/*///////////////////////////////////////////////////////////////
Miscellaneous
//////////////////////////////////////////////////////////////*//// @dev The tokenId of the next NFT that will be minted / lazy minted.functionnextTokenIdToMint() publicviewvirtualoverridereturns (uint256) {
return nextTokenIdToLazyMint;
}
function_dropMsgSender() internalviewvirtualoverridereturns (address) {
return _msgSender();
}
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
}
Contract Source Code
File 28 of 37: Multicall.sol
// SPDX-License-Identifier: Apache 2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"../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 29 of 37: Ownable.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"./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 30 of 37: Permissions.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"./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 31 of 37: PermissionsEnumerable.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"./interface/IPermissionsEnumerable.sol";
import"./Permissions.sol";
/**
* @title PermissionsEnumerable
* @dev This contracts provides extending-contracts with role-based access control mechanisms.
* Also provides interfaces to view all members with a given role, and total count of members.
*/contractPermissionsEnumerableisIPermissionsEnumerable, Permissions{
/**
* @notice A data structure to store data of members for a given role.
*
* @param index Current index in the list of accounts that have a role.
* @param members map from index => address of account that has a role
* @param indexOf map from address => index which the account has.
*/structRoleMembers {
uint256 index;
mapping(uint256=>address) members;
mapping(address=>uint256) indexOf;
}
/// @dev map from keccak256 hash of a role to its members' data. See {RoleMembers}.mapping(bytes32=> RoleMembers) private roleMembers;
/**
* @notice Returns the role-member from a list of members for a role,
* at a given index.
* @dev Returns `member` who has `role`, at `index` of role-members list.
* See struct {RoleMembers}, and mapping {roleMembers}
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param index Index in list of current members for the role.
*
* @return member Address of account that has `role`
*/functiongetRoleMember(bytes32 role, uint256 index) externalviewoverridereturns (address member) {
uint256 currentIndex = roleMembers[role].index;
uint256 check;
for (uint256 i =0; i < currentIndex; i +=1) {
if (roleMembers[role].members[i] !=address(0)) {
if (check == index) {
member = roleMembers[role].members[i];
return member;
}
check +=1;
} elseif (hasRole(role, address(0)) && i == roleMembers[role].indexOf[address(0)]) {
check +=1;
}
}
}
/**
* @notice Returns total number of accounts that have a role.
* @dev Returns `count` of accounts that have `role`.
* See struct {RoleMembers}, and mapping {roleMembers}
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
*
* @return count Total number of accounts that have `role`
*/functiongetRoleMemberCount(bytes32 role) externalviewoverridereturns (uint256 count) {
uint256 currentIndex = roleMembers[role].index;
for (uint256 i =0; i < currentIndex; i +=1) {
if (roleMembers[role].members[i] !=address(0)) {
count +=1;
}
}
if (hasRole(role, address(0))) {
count +=1;
}
}
/// @dev Revokes `role` from `account`, and removes `account` from {roleMembers}/// See {_removeMember}function_revokeRole(bytes32 role, address account) internaloverride{
super._revokeRole(role, account);
_removeMember(role, account);
}
/// @dev Grants `role` to `account`, and adds `account` to {roleMembers}/// See {_addMember}function_setupRole(bytes32 role, address account) internaloverride{
super._setupRole(role, account);
_addMember(role, account);
}
/// @dev adds `account` to {roleMembers}, for `role`function_addMember(bytes32 role, address account) internal{
uint256 idx = roleMembers[role].index;
roleMembers[role].index +=1;
roleMembers[role].members[idx] = account;
roleMembers[role].indexOf[account] = idx;
}
/// @dev removes `account` from {roleMembers}, for `role`function_removeMember(bytes32 role, address account) internal{
uint256 idx = roleMembers[role].indexOf[account];
delete roleMembers[role].members[idx];
delete roleMembers[role].indexOf[account];
}
}
Contract Source Code
File 32 of 37: PrimarySale.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"./interface/IPrimarySale.sol";
/**
* @title Primary Sale
* @notice Thirdweb's `PrimarySale` is a contract extension to be used with any base contract. It exposes functions for setting and reading
* the recipient of primary sales, and lets the inheriting contract perform conditional logic that uses information about
* primary sales, if desired.
*/abstractcontractPrimarySaleisIPrimarySale{
/// @dev The address that receives all primary sales value.addressprivate recipient;
/// @dev Returns primary sale recipient address.functionprimarySaleRecipient() publicviewoverridereturns (address) {
return recipient;
}
/**
* @notice Updates primary sale recipient.
* @dev Caller should be authorized to set primary sales info.
* See {_canSetPrimarySaleRecipient}.
* Emits {PrimarySaleRecipientUpdated Event}; See {_setupPrimarySaleRecipient}.
*
* @param _saleRecipient Address to be set as new recipient of primary sales.
*/functionsetPrimarySaleRecipient(address _saleRecipient) externaloverride{
if (!_canSetPrimarySaleRecipient()) {
revert("Not authorized");
}
_setupPrimarySaleRecipient(_saleRecipient);
}
/// @dev Lets a contract admin set the recipient for all primary sales.function_setupPrimarySaleRecipient(address _saleRecipient) internal{
recipient = _saleRecipient;
emit PrimarySaleRecipientUpdated(_saleRecipient);
}
/// @dev Returns whether primary sale recipient can be set in the given execution context.function_canSetPrimarySaleRecipient() internalviewvirtualreturns (bool);
}
Contract Source Code
File 33 of 37: Royalty.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"./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 34 of 37: SafeERC20.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)pragmasolidity ^0.8.0;import"../../../../../eip/interface/IERC20.sol";
import"../../../../../lib/TWAddress.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/librarySafeERC20{
usingTWAddressforaddress;
functionsafeTransfer(
IERC20 token,
address to,
uint256 value
) internal{
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
functionsafeTransferFrom(
IERC20 token,
addressfrom,
address to,
uint256 value
) internal{
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/functionsafeApprove(
IERC20 token,
address spender,
uint256 value
) internal{
// safeApprove should only be called when setting an initial allowance,// or when resetting it to zero. To increase and decrease it, use// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'require(
(value ==0) || (token.allowance(address(this), spender) ==0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
functionsafeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal{
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
functionsafeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal{
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/function_callOptionalReturn(IERC20 token, bytesmemory data) private{
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that// the target address contains contract code and also asserts for success in the low-level call.bytesmemory returndata =address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length>0) {
// Return data is optionalrequire(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
Contract Source Code
File 35 of 37: TWAddress.sol
// SPDX-License-Identifier: Apache 2.0pragmasolidity ^0.8.0;/// @author thirdweb/**
* @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 36 of 37: TWStrings.sol
// SPDX-License-Identifier: Apache 2.0pragmasolidity ^0.8.0;/// @author thirdweb/**
* @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);
}
}
Contract Source Code
File 37 of 37: TransactionFee.sol
// SPDX-License-Identifier: Apache 2.0pragmasolidity ^0.8.0;errorTrxErrorAuth();
errorTrxErrorFee1();
errorTrxErrorFee2();
/// @author MintpadabstractcontractTransactionFee{
/// @dev Platform wallet addressaddresspublic platformAddress =0x4ec431790805909b0D3Dcf5C8dA25FCBF46E93F8;
/// @dev Transaction costuint256public transactionFee;
/// @dev At any given moment, returns the transaction fee.functiongetTransactionFee() publicviewreturns (uint256) {
return transactionFee;
}
/**
* @notice Sets a new transaction fee in case of need.
* @dev This function is only used in rare situations where
* the transaction fee is not set correctly. This value can
* only be lower than the current transaction fee to prevent
* fraud. Only Mintpad can set this transaction fee.
*
* @param _transactionFee The transaction fee to be set.
*/functionsetTransactionFee(uint256 _transactionFee) external{
if (msg.sender!= platformAddress) {
revert TrxErrorAuth();
}
if (_transactionFee > transactionFee) {
revert TrxErrorFee1();
}
if (_transactionFee <=0) {
revert TrxErrorFee2();
}
transactionFee = _transactionFee;
}
}