// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.1;/// @author thirdweb, OpenZeppelin Contracts (v4.9.0)/**
* @dev Collection of functions related to the address type
*/libraryAddress{
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/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.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/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 functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/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");
(bool success, bytesmemory returndata) = target.call{ value: value }(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/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) {
(bool success, bytesmemory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/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) {
(bool success, bytesmemory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/functionverifyCallResultFromTarget(address target,
bool success,
bytesmemory returndata,
stringmemory errorMessage
) internalviewreturns (bytesmemory) {
if (success) {
if (returndata.length==0) {
// only check isContract if the call was successful and the return data is empty// otherwise we already know that it was a contractrequire(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/functionverifyCallResult(bool success,
bytesmemory returndata,
stringmemory errorMessage
) internalpurereturns (bytesmemory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function_revert(bytesmemory returndata, stringmemory errorMessage) privatepure{
// 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 assembly/// @solidity memory-safe-assemblyassembly {
let returndata_size :=mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
Contract Source Code
File 2 of 35: BatchMintMetadata.sol
// 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 Invalid index for batcherrorBatchMintInvalidBatchId(uint256 index);
/// @dev Invalid tokenerrorBatchMintInvalidTokenId(uint256 tokenId);
/// @dev Metadata frozenerrorBatchMintMetadataFrozen(uint256 batchId);
/// @dev Largest tokenId of each batch of tokens with the same baseURI + 1 {ex: batchId 100 at position 0 includes tokens 0-99}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 BatchMintInvalidBatchId(_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 BatchMintInvalidTokenId(_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 BatchMintInvalidTokenId(_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 BatchMintInvalidBatchId(_batchID);
}
/// @dev Sets the base URI for the batch of tokens with the given batchId.function_setBaseURI(uint256 _batchId, stringmemory _baseURI) internal{
if (batchFrozen[_batchId]) {
revert BatchMintMetadataFrozen(_batchId);
}
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];
if (bytes(baseURIForBatch).length==0) {
revert BatchMintInvalidBatchId(_batchId);
}
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 3 of 35: 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{
/// @dev The sender is not authorized to perform the actionerrorContractMetadataUnauthorized();
/// @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 ContractMetadataUnauthorized();
}
_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 4 of 35: CurrencyTransferLib.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdweb// Helper interfacesimport { IWETH } from"../infra/interface/IWETH.sol";
import { SafeERC20, IERC20 } from"../external-deps/openzeppelin/token/ERC20/utils/SafeERC20.sol";
libraryCurrencyTransferLib{
usingSafeERC20forIERC20;
errorCurrencyTransferLibMismatchedValue(uint256 expected, uint256 actual);
errorCurrencyTransferLibFailedNativeTransfer(address recipient, uint256 value);
/// @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 wethif (_amount !=msg.value) {
revert CurrencyTransferLibMismatchedValue(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 }("");
if (!success) {
revert CurrencyTransferLibFailedNativeTransfer(to, value);
}
}
/// @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 5 of 35: DelayedReveal.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"./interface/IDelayedReveal.sol";
/**
* @title Delayed Reveal
* @notice Thirdweb's `DelayedReveal` is a contract extension for base NFT contracts. It lets you create batches of
* 'delayed-reveal' NFTs. You can learn more about the usage of delayed reveal NFTs here - https://blog.thirdweb.com/delayed-reveal-nfts
*/abstractcontractDelayedRevealisIDelayedReveal{
/// @dev The contract doesn't have any url to be delayed revealederrorDelayedRevealNothingToReveal();
/// @dev The result of the returned an incorrect hasherrorDelayedRevealIncorrectResultHash(bytes32 expected, bytes32 actual);
/// @dev Mapping from tokenId of a batch of tokens => to delayed reveal data.mapping(uint256=>bytes) public encryptedData;
/// @dev Sets the delayed reveal data for a batchId.function_setEncryptedData(uint256 _batchId, bytesmemory _encryptedData) internal{
encryptedData[_batchId] = _encryptedData;
}
/**
* @notice Returns revealed URI for a batch of NFTs.
* @dev Reveal encrypted base URI for `_batchId` with caller/admin's `_key` used for encryption.
* Reverts if there's no encrypted URI for `_batchId`.
* See {encryptDecrypt}.
*
* @param _batchId ID of the batch for which URI is being revealed.
* @param _key Secure key used by caller/admin for encryption of baseURI.
*
* @return revealedURI Decrypted base URI.
*/functiongetRevealURI(uint256 _batchId, bytescalldata _key) publicviewreturns (stringmemory revealedURI) {
bytesmemory data = encryptedData[_batchId];
if (data.length==0) {
revert DelayedRevealNothingToReveal();
}
(bytesmemory encryptedURI, bytes32 provenanceHash) =abi.decode(data, (bytes, bytes32));
revealedURI =string(encryptDecrypt(encryptedURI, _key));
if (keccak256(abi.encodePacked(revealedURI, _key, block.chainid)) != provenanceHash) {
revert DelayedRevealIncorrectResultHash(
provenanceHash,
keccak256(abi.encodePacked(revealedURI, _key, block.chainid))
);
}
}
/**
* @notice Encrypt/decrypt data on chain.
* @dev Encrypt/decrypt given `data` with `key`. Uses inline assembly.
* See: https://ethereum.stackexchange.com/questions/69825/decrypt-message-on-chain
*
* @param data Bytes of data to encrypt/decrypt.
* @param key Secure key used by caller for encryption/decryption.
*
* @return result Output after encryption/decryption of given data.
*/functionencryptDecrypt(bytesmemory data, bytescalldata key) publicpureoverridereturns (bytesmemory result) {
// Store data length on stack for later useuint256 length = data.length;
// solhint-disable-next-line no-inline-assemblyassembly {
// Set result to free memory pointer
result :=mload(0x40)
// Increase free memory pointer by lenght + 32mstore(0x40, add(add(result, length), 32))
// Set result lengthmstore(result, length)
}
// Iterate over the data stepping by 32 bytesfor (uint256 i =0; i < length; i +=32) {
// Generate hash of the key and offsetbytes32 hash =keccak256(abi.encodePacked(key, i));
bytes32 chunk;
// solhint-disable-next-line no-inline-assemblyassembly {
// Read 32-bytes data chunk
chunk :=mload(add(data, add(i, 32)))
}
// XOR the chunk with hash
chunk ^= hash;
// solhint-disable-next-line no-inline-assemblyassembly {
// Write 32-byte encrypted chunkmstore(add(result, add(i, 32)), chunk)
}
}
}
/**
* @notice Returns whether the relvant batch of NFTs is subject to a delayed reveal.
* @dev Returns `true` if `_batchId`'s base URI is encrypted.
* @param _batchId ID of a batch of NFTs.
*/functionisEncryptedBatch(uint256 _batchId) publicviewreturns (bool) {
return encryptedData[_batchId].length>0;
}
}
Contract Source Code
File 6 of 35: DropSinglePhase1155.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"./interface/IDropSinglePhase1155.sol";
import"../lib/MerkleProof.sol";
abstractcontractDropSinglePhase1155isIDropSinglePhase1155{
/*///////////////////////////////////////////////////////////////
Mappings
//////////////////////////////////////////////////////////////*//// @dev Mapping from tokenId => active claim condition for the tokenId.mapping(uint256=> ClaimCondition) public claimCondition;
/// @dev Mapping from tokenId => active claim condition's UID.mapping(uint256=>bytes32) private conditionId;
/**
* @dev Map from a claim condition uid and account to supply claimed by account.
*/mapping(bytes32=>mapping(address=>uint256)) private supplyClaimedByWallet;
/*///////////////////////////////////////////////////////////////
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);
ClaimCondition memory condition = claimCondition[_tokenId];
bytes32 activeConditionId = conditionId[_tokenId];
verifyClaim(_tokenId, _dropMsgSender(), _quantity, _currency, _pricePerToken, _allowlistProof);
// Update contract state.
condition.supplyClaimed += _quantity;
supplyClaimedByWallet[activeConditionId][_dropMsgSender()] += _quantity;
claimCondition[_tokenId] = condition;
// If there's a price, collect price.
_collectPriceOnClaim(address(0), _quantity, _currency, _pricePerToken);
// Mint the relevant NFTs to claimer.
_transferTokensOnClaim(_receiver, _tokenId, _quantity);
emit TokensClaimed(_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 _condition,
bool _resetClaimEligibility
) externaloverride{
if (!_canSetClaimConditions()) {
revert("Not authorized");
}
ClaimCondition memory condition = claimCondition[_tokenId];
bytes32 targetConditionId = conditionId[_tokenId];
uint256 supplyClaimedAlready = condition.supplyClaimed;
if (targetConditionId ==bytes32(0) || _resetClaimEligibility) {
supplyClaimedAlready =0;
targetConditionId =keccak256(abi.encodePacked(_dropMsgSender(), block.number, _tokenId));
}
if (supplyClaimedAlready > _condition.maxClaimableSupply) {
revert("max supply claimed");
}
ClaimCondition memory updatedCondition = ClaimCondition({
startTimestamp: _condition.startTimestamp,
maxClaimableSupply: _condition.maxClaimableSupply,
supplyClaimed: supplyClaimedAlready,
quantityLimitPerWallet: _condition.quantityLimitPerWallet,
merkleRoot: _condition.merkleRoot,
pricePerToken: _condition.pricePerToken,
currency: _condition.currency,
metadata: _condition.metadata
});
claimCondition[_tokenId] = updatedCondition;
conditionId[_tokenId] = targetConditionId;
emit ClaimConditionUpdated(_tokenId, _condition, _resetClaimEligibility);
}
/// @dev Checks a request to claim NFTs against the active claim condition's criteria.functionverifyClaim(uint256 _tokenId,
address _claimer,
uint256 _quantity,
address _currency,
uint256 _pricePerToken,
AllowlistProof calldata _allowlistProof
) publicviewvirtualreturns (bool isOverride) {
ClaimCondition memory currentClaimPhase = claimCondition[_tokenId];
uint256 claimLimit = currentClaimPhase.quantityLimitPerWallet;
uint256 claimPrice = currentClaimPhase.pricePerToken;
address claimCurrency = currentClaimPhase.currency;
/*
* Here `isOverride` implies that if the merkle proof verification fails,
* the claimer would claim through open claim limit instead of allowlisted limit.
*/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 = supplyClaimedByWallet[conditionId[_tokenId]][_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 Returns the supply claimed by claimer for active conditionId.functiongetSupplyClaimedByWallet(uint256 _tokenId, address _claimer) publicviewreturns (uint256) {
return supplyClaimedByWallet[conditionId[_tokenId]][_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{}
/// @dev Collects and distributes the primary sale value of NFTs being claimed.function_collectPriceOnClaim(address _primarySaleRecipient,
uint256 _quantityToClaim,
address _currency,
uint256 _pricePerToken
) internalvirtual;
/// @dev Transfers the NFTs being claimed.function_transferTokensOnClaim(address _to, uint256 _tokenId, uint256 _quantityBeingClaimed) internalvirtual;
function_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"../extension/PrimarySale.sol";
import"../extension/DropSinglePhase1155.sol";
import"../extension/LazyMint.sol";
import"../extension/DelayedReveal.sol";
import { CurrencyTransferLib } from"../lib/CurrencyTransferLib.sol";
import"../lib/Strings.sol";
/**
* BASE: ERC1155Base
* EXTENSION: DropSinglePhase1155
*
* The `ERC1155Base` smart contract implements the ERC1155 NFT standard.
* It includes the following additions to standard ERC1155 logic:
*
* - 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.
*
* The `drop` mechanism in the `DropSinglePhase1155` extension is a distribution mechanism for lazy minted tokens. It lets
* you set restrictions such as a price to charge, an allowlist etc. when an address atttempts to mint lazy minted tokens.
*
* The `ERC721Drop` contract lets you lazy mint tokens, and distribute those lazy minted tokens via the drop mechanism.
*/contractERC1155DropisERC1155,
ContractMetadata,
Ownable,
Royalty,
Multicall,
BatchMintMetadata,
PrimarySale,
LazyMint,
DelayedReveal,
DropSinglePhase1155{
usingStringsforuint256;
/*//////////////////////////////////////////////////////////////
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
//////////////////////////////////////////////////////////////*//**
* @notice Initializes the contract with the given parameters.
*
* @param _defaultAdmin The default admin for the contract.
* @param _name The name of the contract.
* @param _symbol The symbol of the contract.
* @param _royaltyRecipient The address to which royalties should be sent.
* @param _royaltyBps The royalty basis points to be charged. Max = 10000 (10000 = 100%, 1000 = 10%)
* @param _primarySaleRecipient The address to which primary sale revenue should be sent.
*/constructor(address _defaultAdmin,
stringmemory _name,
stringmemory _symbol,
address _royaltyRecipient,
uint128 _royaltyBps,
address _primarySaleRecipient
) ERC1155(_name, _symbol) {
_setupOwner(_defaultAdmin);
_setupDefaultRoyaltyInfo(_royaltyRecipient, _royaltyBps);
_setupPrimarySaleRecipient(_primarySaleRecipient);
}
/*//////////////////////////////////////////////////////////////
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
}
/*//////////////////////////////////////////////////////////////
Minting/burning logic
//////////////////////////////////////////////////////////////*//**
* @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);
}
/*///////////////////////////////////////////////////////////////
Overriden metadata logic
//////////////////////////////////////////////////////////////*//**
* @notice Returns the metadata URI for an NFT.
* @dev See `BatchMintMetadata` for handling of metadata in this contract.
*
* @param _tokenId The tokenId of an NFT.
* @return The metadata URI for the given NFT.
*/functionuri(uint256 _tokenId) publicviewvirtualoverridereturns (stringmemory) {
(uint256 batchId, ) = _getBatchId(_tokenId);
stringmemory batchUri = _getBaseURI(_tokenId);
if (isEncryptedBatch(batchId)) {
returnstring(abi.encodePacked(batchUri, "0"));
} else {
returnstring(abi.encodePacked(batchUri, _tokenId.toString()));
}
}
/*///////////////////////////////////////////////////////////////
Delayed reveal logic
//////////////////////////////////////////////////////////////*//**
* @notice Lets an authorized address reveal a batch of delayed reveal NFTs.
*
* @param _index The ID for the batch of delayed-reveal NFTs to reveal.
* @param _key The key with which the base URI for the relevant batch of NFTs was encrypted.
* @return revealedURI The revealed URI for the batch of NFTs.
*/functionreveal(uint256 _index, bytescalldata _key) publicvirtualoverridereturns (stringmemory revealedURI) {
require(_canReveal(), "Not authorized");
uint256 batchId = getBatchIdAtIndex(_index);
revealedURI = getRevealURI(batchId, _key);
_setEncryptedData(batchId, "");
_setBaseURI(batchId, revealedURI);
emit TokenURIRevealed(_index, revealedURI);
}
/*///////////////////////////////////////////////////////////////
Overriden lazy minting logic
//////////////////////////////////////////////////////////////*//**
* @notice Lets an authorized address lazy mint a given amount of NFTs.
*
* @param _amount The number of NFTs to lazy mint.
* @param _baseURIForTokens The placeholder base URI for the 'n' number of NFTs being lazy minted, where the
* metadata for each of those NFTs is `${baseURIForTokens}/${tokenId}`.
* @param _data The encrypted base URI + provenance hash for the batch of NFTs being lazy minted.
* @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 (_data.length>0) {
(bytesmemory encryptedURI, bytes32 provenanceHash) =abi.decode(_data, (bytes, bytes32));
if (encryptedURI.length!=0&& provenanceHash !="") {
_setEncryptedData(nextTokenIdToLazyMint + _amount, _data);
}
}
return LazyMint.lazyMint(_amount, _baseURIForTokens, _data);
}
/// @notice The tokenId assigned to the next new NFT to be lazy minted.functionnextTokenIdToMint() publicviewvirtualreturns (uint256) {
return nextTokenIdToLazyMint;
}
/*///////////////////////////////////////////////////////////////
Internal functions
//////////////////////////////////////////////////////////////*//**
* @dev Runs before every `claim` function call.
*
* @param _tokenId The tokenId of the NFT being claimed.
*/function_beforeClaim(uint256 _tokenId,
address,
uint256,
address,
uint256,
AllowlistProof calldata,
bytesmemory) internalviewvirtualoverride{
if (_tokenId >= nextTokenIdToLazyMint) {
revert("Not enough minted tokens");
}
}
/**
* @dev Collects and distributes the primary sale value of NFTs being claimed.
*
* @param _primarySaleRecipient The address to which primary sale revenue should be sent.
* @param _quantityToClaim The quantity of NFTs being claimed.
* @param _currency The currency in which the NFTs are being sold.
* @param _pricePerToken The price per NFT being claimed.
*/function_collectPriceOnClaim(address _primarySaleRecipient,
uint256 _quantityToClaim,
address _currency,
uint256 _pricePerToken
) internalvirtualoverride{
if (_pricePerToken ==0) {
require(msg.value==0, "!Value");
return;
}
uint256 totalPrice = _quantityToClaim * _pricePerToken;
bool validMsgValue;
if (_currency == CurrencyTransferLib.NATIVE_TOKEN) {
validMsgValue =msg.value== totalPrice;
} else {
validMsgValue =msg.value==0;
}
require(validMsgValue, "Invalid msg value");
address saleRecipient = _primarySaleRecipient ==address(0) ? primarySaleRecipient() : _primarySaleRecipient;
CurrencyTransferLib.transferCurrency(_currency, msg.sender, saleRecipient, totalPrice);
}
/**
* @dev Transfers the NFTs being claimed.
*
* @param _to The address to which the NFTs are being transferred.
* @param _tokenId The tokenId of the NFTs being claimed.
* @param _quantityBeingClaimed The quantity of NFTs being claimed.
*/function_transferTokensOnClaim(address _to,
uint256 _tokenId,
uint256 _quantityBeingClaimed
) internalvirtualoverride{
_mint(_to, _tokenId, _quantityBeingClaimed, "");
}
/**
* @dev Runs before every token transfer / mint / burn.
*
* @param operator The address performing the token transfer.
* @param from The address from which the token is being transferred.
* @param to The address to which the token is being transferred.
* @param ids The tokenIds of the tokens being transferred.
* @param amounts The amounts of the tokens being transferred.
* @param data Any additional data being passed in the token transfer.
*/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];
}
}
}
/// @dev Checks whether primary sale recipient can be set in the given execution context.function_canSetPrimarySaleRecipient() internalviewvirtualoverridereturns (bool) {
returnmsg.sender== owner();
}
/// @dev Checks whether owner can be set in the given execution context.function_canSetOwner() internalviewvirtualoverridereturns (bool) {
returnmsg.sender== owner();
}
/// @dev Checks whether royalty info can be set in the given execution context.function_canSetRoyaltyInfo() internalviewvirtualoverridereturns (bool) {
returnmsg.sender== owner();
}
/// @dev Checks whether contract metadata can be set in the given execution context.function_canSetContractURI() internalviewvirtualoverridereturns (bool) {
returnmsg.sender== owner();
}
/// @dev Checks whether platform fee info can be set in the given execution context.function_canSetClaimConditions() internalviewvirtualoverridereturns (bool) {
returnmsg.sender== owner();
}
/// @dev Returns whether lazy minting can be done in the given execution context.function_canLazyMint() internalviewvirtualoverridereturns (bool) {
returnmsg.sender== owner();
}
/// @dev Checks whether NFTs can be revealed in the given execution context.function_canReveal() internalviewvirtualreturns (bool) {
returnmsg.sender== owner();
}
}
// 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 11 of 35: 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 12 of 35: IDelayedReveal.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdweb/**
* Thirdweb's `DelayedReveal` is a contract extension for base NFT contracts. It lets you create batches of
* 'delayed-reveal' NFTs. You can learn more about the usage of delayed reveal NFTs here - https://blog.thirdweb.com/delayed-reveal-nfts
*/interfaceIDelayedReveal{
/// @dev Emitted when tokens are revealed.eventTokenURIRevealed(uint256indexed index, string revealedURI);
/**
* @notice Reveals a batch of delayed reveal NFTs.
*
* @param identifier The ID for the batch of delayed-reveal NFTs to reveal.
*
* @param key The key with which the base URI for the relevant batch of NFTs was encrypted.
*/functionreveal(uint256 identifier, bytescalldata key) externalreturns (stringmemory revealedURI);
/**
* @notice Performs XOR encryption/decryption.
*
* @param data The data to encrypt. In the case of delayed-reveal NFTs, this is the "revealed" state
* base URI of the relevant batch of NFTs.
*
* @param key The key with which to encrypt data
*/functionencryptDecrypt(bytesmemory data, bytescalldata key) externalpurereturns (bytesmemory result);
}
Contract Source Code
File 13 of 35: IDropSinglePhase1155.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"./IClaimCondition.sol";
/**
* The interface `IDropSinglePhase1155` is written for thirdweb's 'DropSinglePhase' contracts, which are distribution mechanisms for tokens.
*
* An authorized wallet can set a claim condition for the distribution of the contract's 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.
*/interfaceIDropSinglePhase1155isIClaimCondition{
/**
* @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 via `claim`.eventTokensClaimed(addressindexed claimer,
addressindexed receiver,
uint256indexed tokenId,
uint256 quantityClaimed
);
/// @notice Emitted when the contract's claim conditions are updated.eventClaimConditionUpdated(uint256indexed tokenId, ClaimCondition condition, bool resetEligibility);
/**
* @notice Lets an account claim a given quantity of NFTs.
*
* @param receiver The receiver of the NFT to claim.
* @param tokenId The tokenId of the NFT to claim.
* @param quantity The quantity of the NFT 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 phase Claim condition to set.
*
* @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.
*
* @param tokenId The tokenId for which to set the relevant claim condition.
*/functionsetClaimConditions(uint256 tokenId, ClaimCondition calldata phase, bool resetClaimEligibility) external;
}
Contract Source Code
File 14 of 35: 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 15 of 35: 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 16 of 35: 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 17 of 35: 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 20 of 35: 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 21 of 35: 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 22 of 35: 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 23 of 35: 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 24 of 35: 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 25 of 35: 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{
/// @dev The sender is not authorized to perform the actionerrorLazyMintUnauthorized();
errorLazyMintInvalidAmount();
/// @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 LazyMintUnauthorized();
}
if (_amount ==0) {
revert LazyMintInvalidAmount();
}
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 28 of 35: MerkleProof.sol
// SPDX-License-Identifier: Apache 2.0pragmasolidity ^0.8.0;/// @author OpenZeppelin, thirdweblibraryMerkleProof{
functionverify(bytes32[] calldata 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 = _efficientHash(computedHash, proofElement);
} else {
// Hash(current element of the proof + current computed hash)
computedHash = _efficientHash(proofElement, computedHash);
index +=1;
}
}
// Check if the computed hash (root) is equal to the provided rootreturn (computedHash == root, index);
}
/**
* @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.
*/function_efficientHash(bytes32 a, bytes32 b) privatepurereturns (bytes32 value) {
/// @solidity memory-safe-assemblyassembly {
mstore(0x00, a)
mstore(0x20, b)
value :=keccak256(0x00, 0x40)
}
}
}
Contract Source Code
File 29 of 35: Multicall.sol
// SPDX-License-Identifier: Apache 2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"../lib/Address.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) externalreturns (bytes[] memory results) {
results =newbytes[](data.length);
address sender = _msgSender();
bool isForwarder =msg.sender!= sender;
for (uint256 i =0; i < data.length; i++) {
if (isForwarder) {
results[i] = Address.functionDelegateCall(address(this), abi.encodePacked(data[i], sender));
} else {
results[i] = Address.functionDelegateCall(address(this), data[i]);
}
}
return results;
}
/// @notice Returns the sender in the given execution context.function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
}
Contract Source Code
File 30 of 35: 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 The sender is not authorized to perform the actionerrorOwnableUnauthorized();
/// @dev Owner of the contract (purpose: OpenSea compatibility)addressprivate _owner;
/// @dev Reverts if caller is not the owner.modifieronlyOwner() {
if (msg.sender!= _owner) {
revert OwnableUnauthorized();
}
_;
}
/**
* @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 OwnableUnauthorized();
}
_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 31 of 35: Permissions.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdwebimport"./interface/IPermissions.sol";
import"../lib/Strings.sol";
/**
* @title Permissions
* @dev This contracts provides extending-contracts with role-based access control mechanisms
*/contractPermissionsisIPermissions{
/// @dev The `account` is missing a role.errorPermissionsUnauthorizedAccount(address account, bytes32 neededRole);
/// @dev The `account` already is a holder of `role`errorPermissionsAlreadyGranted(address account, bytes32 role);
/// @dev Invalid priviledge to revokeerrorPermissionsInvalidPermission(address expected, address actual);
/// @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 PermissionsAlreadyGranted(account, role);
}
_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 PermissionsInvalidPermission(msg.sender, account);
}
_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 PermissionsUnauthorizedAccount(account, role);
}
}
/// @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 PermissionsUnauthorizedAccount(account, role);
}
}
}
Contract Source Code
File 32 of 35: 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 sender is not authorized to perform the actionerrorPrimarySaleUnauthorized();
/// @dev The recipient is invaliderrorPrimarySaleInvalidRecipient(address recipient);
/// @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 PrimarySaleUnauthorized();
}
_setupPrimarySaleRecipient(_saleRecipient);
}
/// @dev Lets a contract admin set the recipient for all primary sales.function_setupPrimarySaleRecipient(address _saleRecipient) internal{
if (_saleRecipient ==address(0)) {
revert PrimarySaleInvalidRecipient(_saleRecipient);
}
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 35: 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 sender is not authorized to perform the actionerrorRoyaltyUnauthorized();
/// @dev The recipient is invaliderrorRoyaltyInvalidRecipient(address recipient);
/// @dev The fee bps exceeded the max valueerrorRoyaltyExceededMaxFeeBps(uint256 max, uint256 actual);
/// @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 RoyaltyUnauthorized();
}
_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 RoyaltyExceededMaxFeeBps(10_000, _royaltyBps);
}
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 RoyaltyUnauthorized();
}
_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 RoyaltyExceededMaxFeeBps(10_000, _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 35: 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 { Address } from"../../../../../lib/Address.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{
usingAddressforaddress;
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 35: Strings.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity ^0.8.0;/// @author thirdweb/**
* @dev String operations.
*/libraryStrings{
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);
}
/// @dev Returns the hexadecimal representation of `value`./// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte,/// and the alphabets are capitalized conditionally according to/// https://eips.ethereum.org/EIPS/eip-55functiontoHexStringChecksummed(address value) internalpurereturns (stringmemory str) {
str = toHexString(value);
/// @solidity memory-safe-assemblyassembly {
let mask :=shl(6, div(not(0), 255)) // `0b010000000100000000 ...`let o :=add(str, 0x22)
let hashed :=and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `let t :=shl(240, 136) // `0b10001000 << 240`for {
let i :=0
} 1 {
} {
mstore(add(i, i), mul(t, byte(i, hashed)))
i :=add(i, 1)
ifeq(i, 20) {
break
}
}
mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))
o :=add(o, 0x20)
mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))
}
}
/// @dev Returns the hexadecimal representation of `value`./// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.functiontoHexString(address value) internalpurereturns (stringmemory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assemblyassembly {
let strLength :=add(mload(str), 2) // Compute the length.mstore(str, 0x3078) // Write the "0x" prefix.
str :=sub(str, 2) // Move the pointer.mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hexadecimal representation of `value`./// The output is encoded using 2 hexadecimal digits per byte.functiontoHexStringNoPrefix(address value) internalpurereturns (stringmemory str) {
/// @solidity memory-safe-assemblyassembly {
str :=mload(0x40)
// Allocate the memory.// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,// 0x02 bytes for the prefix, and 0x28 bytes for the digits.// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.mstore(0x40, add(str, 0x80))
// Store "0123456789abcdef" in scratch space.mstore(0x0f, 0x30313233343536373839616263646566)
str :=add(str, 2)
mstore(str, 40)
let o :=add(str, 0x20)
mstore(add(o, 40), 0)
value :=shl(96, value)
// We write the string from rightmost digit to leftmost digit.// The following is essentially a do-while loop that also handles the zero case.for {
let i :=0
} 1 {
} {
let p :=add(o, add(i, i))
let temp :=byte(i, value)
mstore8(add(p, 1), mload(and(temp, 15)))
mstore8(p, mload(shr(4, temp)))
i :=add(i, 1)
ifeq(i, 20) {
break
}
}
}
}
/// @dev Returns the hex encoded string from the raw bytes./// The output is encoded using 2 hexadecimal digits per byte.functiontoHexString(bytesmemory raw) internalpurereturns (stringmemory str) {
str = toHexStringNoPrefix(raw);
/// @solidity memory-safe-assemblyassembly {
let strLength :=add(mload(str), 2) // Compute the length.mstore(str, 0x3078) // Write the "0x" prefix.
str :=sub(str, 2) // Move the pointer.mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hex encoded string from the raw bytes./// The output is encoded using 2 hexadecimal digits per byte.functiontoHexStringNoPrefix(bytesmemory raw) internalpurereturns (stringmemory str) {
/// @solidity memory-safe-assemblyassembly {
let length :=mload(raw)
str :=add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.mstore(str, add(length, length)) // Store the length of the output.// Store "0123456789abcdef" in scratch space.mstore(0x0f, 0x30313233343536373839616263646566)
let o :=add(str, 0x20)
let end :=add(raw, length)
for {
} iszero(eq(raw, end)) {
} {
raw :=add(raw, 1)
mstore8(add(o, 1), mload(and(mload(raw), 15)))
mstore8(o, mload(and(shr(4, mload(raw)), 15)))
o :=add(o, 2)
}
mstore(o, 0) // Zeroize the slot after the string.mstore(0x40, add(o, 0x20)) // Allocate the memory.
}
}
}