Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/ERC721SeaDropSoulboundExtended.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import { ERC721SeaDropSoulbound } from "seadrop/extensions/ERC721SeaDropSoulbound.sol";
/**
* @title ERC721SeaDropSoulboundExtended
* @notice Extension of ERC721SeaDropSoulbound that adds admin minting functionality
* while maintaining full SeaDrop compatibility and soulbound properties.
* @dev Admin minting bypasses SeaDrop restrictions and payment requirements.
*/
contract ERC721SeaDropSoulboundExtended is ERC721SeaDropSoulbound {
/// @notice Mapping of addresses with admin minting privileges
mapping(address => bool) public admins;
/// @notice Total number of tokens minted by admins (for tracking)
uint256 public totalAdminMinted;
/// @notice Event emitted when admin status is updated
event AdminStatusUpdated(address indexed admin, bool status);
/// @notice Event emitted when tokens are admin minted
event AdminMinted(address indexed to, uint256 quantity, address indexed mintedBy);
/// @notice Event emitted when batch admin mint occurs
event AdminBatchMinted(address indexed mintedBy, uint256 totalQuantity);
/// @notice Modifier to restrict function access to admins or owner
modifier onlyAdminOrOwner() {
if (msg.sender != owner() && !admins[msg.sender]) {
revert("Not authorized");
}
_;
}
/**
* @notice Deploy the token contract with its name, symbol,
* and allowed SeaDrop addresses.
*/
constructor(
string memory name,
string memory symbol,
address[] memory allowedSeaDrop
) ERC721SeaDropSoulbound(name, symbol, allowedSeaDrop) {}
/**
* @notice Set or revoke admin status for an address.
* Only the owner can call this function.
*
* @param admin The address to update admin status for
* @param status True to grant admin privileges, false to revoke
*/
function setAdmin(address admin, bool status) external onlyOwner {
if (admin == address(0)) revert("Invalid address");
admins[admin] = status;
emit AdminStatusUpdated(admin, status);
}
/**
* @notice Admin mint tokens to a specific address without payment.
* This function bypasses all SeaDrop restrictions.
*
* @param to The address to mint tokens to
* @param quantity The number of tokens to mint
*/
function adminMint(address to, uint256 quantity) external onlyAdminOrOwner {
if (to == address(0)) revert("Cannot mint to zero address");
if (quantity == 0) revert("Quantity must be greater than 0");
// Check max supply if configured
uint256 maxSupply_ = maxSupply();
if (maxSupply_ != 0) {
if (_totalMinted() + quantity > maxSupply_) {
revert("Exceeds max supply");
}
}
// Track admin mints
totalAdminMinted += quantity;
// Mint tokens directly, bypassing SeaDrop
_safeMint(to, quantity);
emit AdminMinted(to, quantity, msg.sender);
}
/**
* @notice Admin batch mint tokens to multiple addresses without payment.
* This function bypasses all SeaDrop restrictions.
*
* @param recipients Array of addresses to mint tokens to
* @param quantities Array of quantities for each recipient
*/
function adminBatchMint(
address[] calldata recipients,
uint256[] calldata quantities
) external onlyAdminOrOwner {
uint256 length = recipients.length;
if (length != quantities.length) revert("Array length mismatch");
if (length == 0) revert("Empty arrays");
// Calculate total quantity
uint256 totalQuantity = 0;
for (uint256 i = 0; i < length;) {
if (recipients[i] == address(0)) revert("Cannot mint to zero address");
if (quantities[i] == 0) revert("Quantity must be greater than 0");
totalQuantity += quantities[i];
unchecked { ++i; }
}
// Check max supply if configured
uint256 maxSupply_ = maxSupply();
if (maxSupply_ != 0) {
if (_totalMinted() + totalQuantity > maxSupply_) {
revert("Exceeds max supply");
}
}
// Track admin mints
totalAdminMinted += totalQuantity;
// Mint tokens to each recipient
for (uint256 i = 0; i < length;) {
_safeMint(recipients[i], quantities[i]);
emit AdminMinted(recipients[i], quantities[i], msg.sender);
unchecked { ++i; }
}
emit AdminBatchMinted(msg.sender, totalQuantity);
}
/**
* @notice Get the total number of tokens minted through admin functions
* @return The total number of admin minted tokens
*/
function getAdminMintedCount() external view returns (uint256) {
return totalAdminMinted;
}
/**
* @notice Check if an address has admin privileges
* @param account The address to check
* @return True if the address is an admin, false otherwise
*/
function isAdmin(address account) external view returns (bool) {
return admins[account];
}
}
"
},
"../lib/seadrop/src/extensions/ERC721SeaDropSoulbound.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import { ERC721SeaDrop } from "../ERC721SeaDrop.sol";
/**
* @title ERC721SeaDropSoulbound
* @notice A token contract that extends ERC721SeaDrop to be soulbound,
* meaning it cannot be transferred after minting.
*/
contract ERC721SeaDropSoulbound is ERC721SeaDrop {
/// @notice Revert on approvals and transfers since the token is soulbound.
error SoulboundNotTransferable();
/**
* @notice Deploy the token contract with its name, symbol,
* and allowed SeaDrop addresses.
*/
constructor(
string memory name,
string memory symbol,
address[] memory allowedSeaDrop
) ERC721SeaDrop(name, symbol, allowedSeaDrop) {}
/**
* @notice This token is soulbound, so approvals cannot be set.
*/
function setApprovalForAll(
address, /* operator */
bool /* approved */
) public virtual override {
revert SoulboundNotTransferable();
}
/**
* @notice This token is soulbound, so approvals cannot be set.
*/
function approve(
address, /* to */
uint256 /* tokenId */
) public virtual override {
revert SoulboundNotTransferable();
}
/**
* @notice This token is soulbound, so transfers are not allowed.
*/
function _beforeTokenTransfers(
address from,
address, /* to */
uint256, /* startTokenId */
uint256 /* quantity */
) internal virtual override {
if (from != address(0)) {
revert SoulboundNotTransferable();
}
}
}
"
},
"../lib/seadrop/src/ERC721SeaDrop.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {
ERC721ContractMetadata,
ISeaDropTokenContractMetadata
} from "./ERC721ContractMetadata.sol";
import {
INonFungibleSeaDropToken
} from "./interfaces/INonFungibleSeaDropToken.sol";
import { ISeaDrop } from "./interfaces/ISeaDrop.sol";
import {
AllowListData,
PublicDrop,
TokenGatedDropStage,
SignedMintValidationParams
} from "./lib/SeaDropStructs.sol";
import {
ERC721SeaDropStructsErrorsAndEvents
} from "./lib/ERC721SeaDropStructsErrorsAndEvents.sol";
import { ERC721A } from "ERC721A/ERC721A.sol";
import { ReentrancyGuard } from "solmate/utils/ReentrancyGuard.sol";
import {
IERC165
} from "openzeppelin-contracts/utils/introspection/IERC165.sol";
/**
* @title ERC721SeaDrop
* @author James Wenzel (emo.eth)
* @author Ryan Ghods (ralxz.eth)
* @author Stephan Min (stephanm.eth)
* @author Michael Cohen (notmichael.eth)
* @custom:contributor Limit Break (@limitbreak)
* @notice ERC721SeaDrop is a token contract that contains methods
* to properly interact with SeaDrop.
* Implements Limit Break's Creator Token Standards transfer
* validation for royalty enforcement.
*/
contract ERC721SeaDrop is
ERC721ContractMetadata,
INonFungibleSeaDropToken,
ERC721SeaDropStructsErrorsAndEvents,
ReentrancyGuard
{
/// @notice Track the allowed SeaDrop addresses.
mapping(address => bool) internal _allowedSeaDrop;
/// @notice Track the enumerated allowed SeaDrop addresses.
address[] internal _enumeratedAllowedSeaDrop;
/**
* @dev Reverts if not an allowed SeaDrop contract.
* This function is inlined instead of being a modifier
* to save contract space from being inlined N times.
*
* @param seaDrop The SeaDrop address to check if allowed.
*/
function _onlyAllowedSeaDrop(address seaDrop) internal view {
if (_allowedSeaDrop[seaDrop] != true) {
revert OnlyAllowedSeaDrop();
}
}
/**
* @notice Deploy the token contract with its name, symbol,
* and allowed SeaDrop addresses.
*/
constructor(
string memory name,
string memory symbol,
address[] memory allowedSeaDrop
) ERC721ContractMetadata(name, symbol) {
// Put the length on the stack for more efficient access.
uint256 allowedSeaDropLength = allowedSeaDrop.length;
// Set the mapping for allowed SeaDrop contracts.
for (uint256 i = 0; i < allowedSeaDropLength; ) {
_allowedSeaDrop[allowedSeaDrop[i]] = true;
unchecked {
++i;
}
}
// Set the enumeration.
_enumeratedAllowedSeaDrop = allowedSeaDrop;
// Emit an event noting the contract deployment.
emit SeaDropTokenDeployed();
}
/**
* @notice Update the allowed SeaDrop contracts.
* Only the owner can use this function.
*
* @param allowedSeaDrop The allowed SeaDrop addresses.
*/
function updateAllowedSeaDrop(address[] calldata allowedSeaDrop)
external
virtual
override
onlyOwner
{
_updateAllowedSeaDrop(allowedSeaDrop);
}
/**
* @notice Internal function to update the allowed SeaDrop contracts.
*
* @param allowedSeaDrop The allowed SeaDrop addresses.
*/
function _updateAllowedSeaDrop(address[] calldata allowedSeaDrop) internal {
// Put the length on the stack for more efficient access.
uint256 enumeratedAllowedSeaDropLength = _enumeratedAllowedSeaDrop
.length;
uint256 allowedSeaDropLength = allowedSeaDrop.length;
// Reset the old mapping.
for (uint256 i = 0; i < enumeratedAllowedSeaDropLength; ) {
_allowedSeaDrop[_enumeratedAllowedSeaDrop[i]] = false;
unchecked {
++i;
}
}
// Set the new mapping for allowed SeaDrop contracts.
for (uint256 i = 0; i < allowedSeaDropLength; ) {
_allowedSeaDrop[allowedSeaDrop[i]] = true;
unchecked {
++i;
}
}
// Set the enumeration.
_enumeratedAllowedSeaDrop = allowedSeaDrop;
// Emit an event for the update.
emit AllowedSeaDropUpdated(allowedSeaDrop);
}
/**
* @notice Burns `tokenId`. The caller must own `tokenId` or be an
* approved operator.
*
* @param tokenId The token id to burn.
*/
// solhint-disable-next-line comprehensive-interface
function burn(uint256 tokenId) external {
_burn(tokenId, true);
}
/**
* @dev Overrides the `_startTokenId` function from ERC721A
* to start at token id `1`.
*
* This is to avoid future possible problems since `0` is usually
* used to signal values that have not been set or have been removed.
*/
function _startTokenId() internal view virtual override returns (uint256) {
return 1;
}
/**
* @dev Overrides the `tokenURI()` function from ERC721A
* to return just the base URI if it is implied to not be a directory.
*
* This is to help with ERC721 contracts in which the same token URI
* is desired for each token, such as when the tokenURI is 'unrevealed'.
*/
function tokenURI(uint256 tokenId)
public
view
virtual
override
returns (string memory)
{
if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
string memory baseURI = _baseURI();
// Exit early if the baseURI is empty.
if (bytes(baseURI).length == 0) {
return "";
}
// Check if the last character in baseURI is a slash.
if (bytes(baseURI)[bytes(baseURI).length - 1] != bytes("/")[0]) {
return baseURI;
}
return string(abi.encodePacked(baseURI, _toString(tokenId)));
}
/**
* @notice Mint tokens, restricted to the SeaDrop contract.
*
* @dev NOTE: If a token registers itself with multiple SeaDrop
* contracts, the implementation of this function should guard
* against reentrancy. If the implementing token uses
* _safeMint(), or a feeRecipient with a malicious receive() hook
* is specified, the token or fee recipients may be able to execute
* another mint in the same transaction via a separate SeaDrop
* contract.
* This is dangerous if an implementing token does not correctly
* update the minterNumMinted and currentTotalSupply values before
* transferring minted tokens, as SeaDrop references these values
* to enforce token limits on a per-wallet and per-stage basis.
*
* ERC721A tracks these values automatically, but this note and
* nonReentrant modifier are left here to encourage best-practices
* when referencing this contract.
*
* @param minter The address to mint to.
* @param quantity The number of tokens to mint.
*/
function mintSeaDrop(address minter, uint256 quantity)
external
virtual
override
nonReentrant
{
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(msg.sender);
// Extra safety check to ensure the max supply is not exceeded.
if (_totalMinted() + quantity > maxSupply()) {
revert MintQuantityExceedsMaxSupply(
_totalMinted() + quantity,
maxSupply()
);
}
// Mint the quantity of tokens to the minter.
_safeMint(minter, quantity);
}
/**
* @notice Update the public drop data for this nft contract on SeaDrop.
* Only the owner can use this function.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param publicDrop The public drop data.
*/
function updatePublicDrop(
address seaDropImpl,
PublicDrop calldata publicDrop
) external virtual override {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(seaDropImpl);
// Update the public drop data on SeaDrop.
ISeaDrop(seaDropImpl).updatePublicDrop(publicDrop);
}
/**
* @notice Update the allow list data for this nft contract on SeaDrop.
* Only the owner can use this function.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param allowListData The allow list data.
*/
function updateAllowList(
address seaDropImpl,
AllowListData calldata allowListData
) external virtual override {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(seaDropImpl);
// Update the allow list on SeaDrop.
ISeaDrop(seaDropImpl).updateAllowList(allowListData);
}
/**
* @notice Update the token gated drop stage data for this nft contract
* on SeaDrop.
* Only the owner can use this function.
*
* Note: If two INonFungibleSeaDropToken tokens are doing
* simultaneous token gated drop promotions for each other,
* they can be minted by the same actor until
* `maxTokenSupplyForStage` is reached. Please ensure the
* `allowedNftToken` is not running an active drop during the
* `dropStage` time period.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param allowedNftToken The allowed nft token.
* @param dropStage The token gated drop stage data.
*/
function updateTokenGatedDrop(
address seaDropImpl,
address allowedNftToken,
TokenGatedDropStage calldata dropStage
) external virtual override {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(seaDropImpl);
// Update the token gated drop stage.
ISeaDrop(seaDropImpl).updateTokenGatedDrop(allowedNftToken, dropStage);
}
/**
* @notice Update the drop URI for this nft contract on SeaDrop.
* Only the owner can use this function.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param dropURI The new drop URI.
*/
function updateDropURI(address seaDropImpl, string calldata dropURI)
external
virtual
override
{
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(seaDropImpl);
// Update the drop URI.
ISeaDrop(seaDropImpl).updateDropURI(dropURI);
}
/**
* @notice Update the creator payout address for this nft contract on
* SeaDrop.
* Only the owner can set the creator payout address.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param payoutAddress The new payout address.
*/
function updateCreatorPayoutAddress(
address seaDropImpl,
address payoutAddress
) external {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(seaDropImpl);
// Update the creator payout address.
ISeaDrop(seaDropImpl).updateCreatorPayoutAddress(payoutAddress);
}
/**
* @notice Update the allowed fee recipient for this nft contract
* on SeaDrop.
* Only the owner can set the allowed fee recipient.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param feeRecipient The new fee recipient.
* @param allowed If the fee recipient is allowed.
*/
function updateAllowedFeeRecipient(
address seaDropImpl,
address feeRecipient,
bool allowed
) external virtual {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(seaDropImpl);
// Update the allowed fee recipient.
ISeaDrop(seaDropImpl).updateAllowedFeeRecipient(feeRecipient, allowed);
}
/**
* @notice Update the server-side signers for this nft contract
* on SeaDrop.
* Only the owner can use this function.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param signer The signer to update.
* @param signedMintValidationParams Minimum and maximum parameters to
* enforce for signed mints.
*/
function updateSignedMintValidationParams(
address seaDropImpl,
address signer,
SignedMintValidationParams memory signedMintValidationParams
) external virtual override {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(seaDropImpl);
// Update the signer.
ISeaDrop(seaDropImpl).updateSignedMintValidationParams(
signer,
signedMintValidationParams
);
}
/**
* @notice Update the allowed payers for this nft contract on SeaDrop.
* Only the owner can use this function.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param payer The payer to update.
* @param allowed Whether the payer is allowed.
*/
function updatePayer(
address seaDropImpl,
address payer,
bool allowed
) external virtual override {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(seaDropImpl);
// Update the payer.
ISeaDrop(seaDropImpl).updatePayer(payer, allowed);
}
/**
* @notice Returns a set of mint stats for the address.
* This assists SeaDrop in enforcing maxSupply,
* maxTotalMintableByWallet, and maxTokenSupplyForStage checks.
*
* @dev NOTE: Implementing contracts should always update these numbers
* before transferring any tokens with _safeMint() to mitigate
* consequences of malicious onERC721Received() hooks.
*
* @param minter The minter address.
*/
function getMintStats(address minter)
external
view
override
returns (
uint256 minterNumMinted,
uint256 currentTotalSupply,
uint256 maxSupply
)
{
minterNumMinted = _numberMinted(minter);
currentTotalSupply = _totalMinted();
maxSupply = _maxSupply;
}
/**
* @notice Returns whether the interface is supported.
*
* @param interfaceId The interface id to check against.
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(IERC165, ERC721ContractMetadata)
returns (bool)
{
return
interfaceId == type(INonFungibleSeaDropToken).interfaceId ||
interfaceId == type(ISeaDropTokenContractMetadata).interfaceId ||
// ERC721ContractMetadata returns supportsInterface true for
// EIP-2981
// ERC721A returns supportsInterface true for
// ERC165, ERC721, ERC721Metadata
super.supportsInterface(interfaceId);
}
/**
* @notice Configure multiple properties at a time.
*
* Note: The individual configure methods should be used
* to unset or reset any properties to zero, as this method
* will ignore zero-value properties in the config struct.
*
* @param config The configuration struct.
*/
function multiConfigure(MultiConfigureStruct calldata config)
external
onlyOwner
{
if (config.maxSupply > 0) {
this.setMaxSupply(config.maxSupply);
}
if (bytes(config.baseURI).length != 0) {
this.setBaseURI(config.baseURI);
}
if (bytes(config.contractURI).length != 0) {
this.setContractURI(config.contractURI);
}
if (
_cast(config.publicDrop.startTime != 0) |
_cast(config.publicDrop.endTime != 0) ==
1
) {
this.updatePublicDrop(config.seaDropImpl, config.publicDrop);
}
if (bytes(config.dropURI).length != 0) {
this.updateDropURI(config.seaDropImpl, config.dropURI);
}
if (config.allowListData.merkleRoot != bytes32(0)) {
this.updateAllowList(config.seaDropImpl, config.allowListData);
}
if (config.creatorPayoutAddress != address(0)) {
this.updateCreatorPayoutAddress(
config.seaDropImpl,
config.creatorPayoutAddress
);
}
if (config.provenanceHash != bytes32(0)) {
this.setProvenanceHash(config.provenanceHash);
}
if (config.allowedFeeRecipients.length > 0) {
for (uint256 i = 0; i < config.allowedFeeRecipients.length; ) {
this.updateAllowedFeeRecipient(
config.seaDropImpl,
config.allowedFeeRecipients[i],
true
);
unchecked {
++i;
}
}
}
if (config.disallowedFeeRecipients.length > 0) {
for (uint256 i = 0; i < config.disallowedFeeRecipients.length; ) {
this.updateAllowedFeeRecipient(
config.seaDropImpl,
config.disallowedFeeRecipients[i],
false
);
unchecked {
++i;
}
}
}
if (config.allowedPayers.length > 0) {
for (uint256 i = 0; i < config.allowedPayers.length; ) {
this.updatePayer(
config.seaDropImpl,
config.allowedPayers[i],
true
);
unchecked {
++i;
}
}
}
if (config.disallowedPayers.length > 0) {
for (uint256 i = 0; i < config.disallowedPayers.length; ) {
this.updatePayer(
config.seaDropImpl,
config.disallowedPayers[i],
false
);
unchecked {
++i;
}
}
}
if (config.tokenGatedDropStages.length > 0) {
if (
config.tokenGatedDropStages.length !=
config.tokenGatedAllowedNftTokens.length
) {
revert TokenGatedMismatch();
}
for (uint256 i = 0; i < config.tokenGatedDropStages.length; ) {
this.updateTokenGatedDrop(
config.seaDropImpl,
config.tokenGatedAllowedNftTokens[i],
config.tokenGatedDropStages[i]
);
unchecked {
++i;
}
}
}
if (config.disallowedTokenGatedAllowedNftTokens.length > 0) {
for (
uint256 i = 0;
i < config.disallowedTokenGatedAllowedNftTokens.length;
) {
TokenGatedDropStage memory emptyStage;
this.updateTokenGatedDrop(
config.seaDropImpl,
config.disallowedTokenGatedAllowedNftTokens[i],
emptyStage
);
unchecked {
++i;
}
}
}
if (config.signedMintValidationParams.length > 0) {
if (
config.signedMintValidationParams.length !=
config.signers.length
) {
revert SignersMismatch();
}
for (
uint256 i = 0;
i < config.signedMintValidationParams.length;
) {
this.updateSignedMintValidationParams(
config.seaDropImpl,
config.signers[i],
config.signedMintValidationParams[i]
);
unchecked {
++i;
}
}
}
if (config.disallowedSigners.length > 0) {
for (uint256 i = 0; i < config.disallowedSigners.length; ) {
SignedMintValidationParams memory emptyParams;
this.updateSignedMintValidationParams(
config.seaDropImpl,
config.disallowedSigners[i],
emptyParams
);
unchecked {
++i;
}
}
}
}
}
"
},
"../lib/seadrop/src/ERC721ContractMetadata.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {
ISeaDropTokenContractMetadata
} from "./interfaces/ISeaDropTokenContractMetadata.sol";
import { ERC721A } from "ERC721A/ERC721A.sol";
import { ERC721AConduitPreapproved } from "./lib/ERC721AConduitPreapproved.sol";
import { ERC721TransferValidator } from "./lib/ERC721TransferValidator.sol";
import {
ICreatorToken,
ILegacyCreatorToken
} from "./interfaces/ICreatorToken.sol";
import { ITransferValidator721 } from "./interfaces/ITransferValidator.sol";
import { TwoStepOwnable } from "utility-contracts/TwoStepOwnable.sol";
import { IERC2981 } from "openzeppelin-contracts/interfaces/IERC2981.sol";
import {
IERC165
} from "openzeppelin-contracts/utils/introspection/IERC165.sol";
/**
* @title ERC721ContractMetadata
* @author James Wenzel (emo.eth)
* @author Ryan Ghods (ralxz.eth)
* @author Stephan Min (stephanm.eth)
* @notice ERC721ContractMetadata is a token contract that extends ERC721A
* with additional metadata and ownership capabilities.
*/
contract ERC721ContractMetadata is
ERC721AConduitPreapproved,
ERC721TransferValidator,
TwoStepOwnable,
ISeaDropTokenContractMetadata
{
/// @notice Track the max supply.
uint256 _maxSupply;
/// @notice Track the base URI for token metadata.
string _tokenBaseURI;
/// @notice Track the contract URI for contract metadata.
string _contractURI;
/// @notice Track the provenance hash for guaranteeing metadata order
/// for random reveals.
bytes32 _provenanceHash;
/// @notice Track the royalty info: address to receive royalties, and
/// royalty basis points.
RoyaltyInfo _royaltyInfo;
/**
* @dev Reverts if the sender is not the owner or the contract itself.
* This function is inlined instead of being a modifier
* to save contract space from being inlined N times.
*/
function _onlyOwnerOrSelf() internal view {
if (
_cast(msg.sender == owner()) | _cast(msg.sender == address(this)) ==
0
) {
revert OnlyOwner();
}
}
/**
* @notice Deploy the token contract with its name and symbol.
*/
constructor(string memory name, string memory symbol)
ERC721AConduitPreapproved(name, symbol)
{}
/**
* @notice Sets the base URI for the token metadata and emits an event.
*
* @param newBaseURI The new base URI to set.
*/
function setBaseURI(string calldata newBaseURI) external override {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Set the new base URI.
_tokenBaseURI = newBaseURI;
// Emit an event with the update.
if (totalSupply() != 0) {
emit BatchMetadataUpdate(1, _nextTokenId() - 1);
}
}
/**
* @notice Sets the contract URI for contract metadata.
*
* @param newContractURI The new contract URI.
*/
function setContractURI(string calldata newContractURI) external override {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Set the new contract URI.
_contractURI = newContractURI;
// Emit an event with the update.
emit ContractURIUpdated(newContractURI);
}
/**
* @notice Emit an event notifying metadata updates for
* a range of token ids, according to EIP-4906.
*
* @param fromTokenId The start token id.
* @param toTokenId The end token id.
*/
function emitBatchMetadataUpdate(uint256 fromTokenId, uint256 toTokenId)
external
{
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Emit an event with the update.
emit BatchMetadataUpdate(fromTokenId, toTokenId);
}
/**
* @notice Sets the max token supply and emits an event.
*
* @param newMaxSupply The new max supply to set.
*/
function setMaxSupply(uint256 newMaxSupply) external {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the max supply does not exceed the maximum value of uint64.
if (newMaxSupply > 2**64 - 1) {
revert CannotExceedMaxSupplyOfUint64(newMaxSupply);
}
// Ensure the max supply does not exceed the total minted.
if (newMaxSupply < _totalMinted()) {
revert NewMaxSupplyCannotBeLessThenTotalMinted(
newMaxSupply,
_totalMinted()
);
}
// Set the new max supply.
_maxSupply = newMaxSupply;
// Emit an event with the update.
emit MaxSupplyUpdated(newMaxSupply);
}
/**
* @notice Sets the provenance hash and emits an event.
*
* The provenance hash is used for random reveals, which
* is a hash of the ordered metadata to show it has not been
* modified after mint started.
*
* This function will revert after the first item has been minted.
*
* @param newProvenanceHash The new provenance hash to set.
*/
function setProvenanceHash(bytes32 newProvenanceHash) external {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Revert if any items have been minted.
if (_totalMinted() > 0) {
revert ProvenanceHashCannotBeSetAfterMintStarted();
}
// Keep track of the old provenance hash for emitting with the event.
bytes32 oldProvenanceHash = _provenanceHash;
// Set the new provenance hash.
_provenanceHash = newProvenanceHash;
// Emit an event with the update.
emit ProvenanceHashUpdated(oldProvenanceHash, newProvenanceHash);
}
/**
* @notice Sets the address and basis points for royalties.
*
* @param newInfo The struct to configure royalties.
*/
function setRoyaltyInfo(RoyaltyInfo calldata newInfo) external {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Revert if the new royalty address is the zero address.
if (newInfo.royaltyAddress == address(0)) {
revert RoyaltyAddressCannotBeZeroAddress();
}
// Revert if the new basis points is greater than 10_000.
if (newInfo.royaltyBps > 10_000) {
revert InvalidRoyaltyBasisPoints(newInfo.royaltyBps);
}
// Set the new royalty info.
_royaltyInfo = newInfo;
// Emit an event with the updated params.
emit RoyaltyInfoUpdated(newInfo.royaltyAddress, newInfo.royaltyBps);
}
/**
* @notice Returns the base URI for token metadata.
*/
function baseURI() external view override returns (string memory) {
return _baseURI();
}
/**
* @notice Returns the base URI for the contract, which ERC721A uses
* to return tokenURI.
*/
function _baseURI() internal view virtual override returns (string memory) {
return _tokenBaseURI;
}
/**
* @notice Returns the contract URI for contract metadata.
*/
function contractURI() external view override returns (string memory) {
return _contractURI;
}
/**
* @notice Returns the max token supply.
*/
function maxSupply() public view returns (uint256) {
return _maxSupply;
}
/**
* @notice Returns the provenance hash.
* The provenance hash is used for random reveals, which
* is a hash of the ordered metadata to show it is unmodified
* after mint has started.
*/
function provenanceHash() external view override returns (bytes32) {
return _provenanceHash;
}
/**
* @notice Returns the address that receives royalties.
*/
function royaltyAddress() external view returns (address) {
return _royaltyInfo.royaltyAddress;
}
/**
* @notice Returns the royalty basis points out of 10_000.
*/
function royaltyBasisPoints() external view returns (uint256) {
return _royaltyInfo.royaltyBps;
}
/**
* @notice Called with the sale price to determine how much royalty
* is owed and to whom.
*
* @ param _tokenId The NFT asset queried for royalty information.
* @param _salePrice The sale price of the NFT asset specified by
* _tokenId.
*
* @return receiver Address of who should be sent the royalty payment.
* @return royaltyAmount The royalty payment amount for _salePrice.
*/
function royaltyInfo(
uint256,
/* _tokenId */
uint256 _salePrice
) external view returns (address receiver, uint256 royaltyAmount) {
// Put the royalty info on the stack for more efficient access.
RoyaltyInfo storage info = _royaltyInfo;
// Set the royalty amount to the sale price times the royalty basis
// points divided by 10_000.
royaltyAmount = (_salePrice * info.royaltyBps) / 10_000;
// Set the receiver of the royalty.
receiver = info.royaltyAddress;
}
/**
* @notice Returns the transfer validation function used.
*/
function getTransferValidationFunction()
external
pure
returns (bytes4 functionSignature, bool isViewFunction)
{
functionSignature = ITransferValidator721.validateTransfer.selector;
isViewFunction = false;
}
/**
* @notice Set the transfer validator. Only callable by the token owner.
*/
function setTransferValidator(address newValidator) external onlyOwner {
// Set the new transfer validator.
_setTransferValidator(newValidator);
}
/**
* @dev Hook that is called before any token transfer.
* This includes minting and burning.
*/
function _beforeTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 /* quantity */
) internal virtual override {
if (from != address(0) && to != address(0)) {
// Call the transfer validator if one is set.
address transferValidator = _transferValidator;
if (transferValidator != address(0)) {
ITransferValidator721(transferValidator).validateTransfer(
msg.sender,
from,
to,
startTokenId
);
}
}
}
/**
* @notice Returns whether the interface is supported.
*
* @param interfaceId The interface id to check against.
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(IERC165, ERC721A)
returns (bool)
{
return
interfaceId == type(IERC2981).interfaceId ||
interfaceId == type(ICreatorToken).interfaceId ||
interfaceId == type(ILegacyCreatorToken).interfaceId ||
interfaceId == 0x49064906 || // ERC-4906
super.supportsInterface(interfaceId);
}
/**
* @dev Internal pure function to cast a `bool` value to a `uint256` value.
*
* @param b The `bool` value to cast.
*
* @return u The `uint256` value.
*/
function _cast(bool b) internal pure returns (uint256 u) {
assembly {
u := b
}
}
}
"
},
"../lib/seadrop/src/interfaces/INonFungibleSeaDropToken.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {
ISeaDropTokenContractMetadata
} from "./ISeaDropTokenContractMetadata.sol";
import {
AllowListData,
PublicDrop,
TokenGatedDropStage,
SignedMintValidationParams
} from "../lib/SeaDropStructs.sol";
interface INonFungibleSeaDropToken is ISeaDropTokenContractMetadata {
/**
* @dev Revert with an error if a contract is not an allowed
* SeaDrop address.
*/
error OnlyAllowedSeaDrop();
/**
* @dev Emit an event when allowed SeaDrop contracts are updated.
*/
event AllowedSeaDropUpdated(address[] allowedSeaDrop);
/**
* @notice Update the allowed SeaDrop contracts.
* Only the owner can use this function.
*
* @param allowedSeaDrop The allowed SeaDrop addresses.
*/
function updateAllowedSeaDrop(address[] calldata allowedSeaDrop) external;
/**
* @notice Mint tokens, restricted to the SeaDrop contract.
*
* @dev NOTE: If a token registers itself with multiple SeaDrop
* contracts, the implementation of this function should guard
* against reentrancy. If the implementing token uses
* _safeMint(), or a feeRecipient with a malicious receive() hook
* is specified, the token or fee recipients may be able to execute
* another mint in the same transaction via a separate SeaDrop
* contract.
* This is dangerous if an implementing token does not correctly
* update the minterNumMinted and currentTotalSupply values before
* transferring minted tokens, as SeaDrop references these values
* to enforce token limits on a per-wallet and per-stage basis.
*
* @param minter The address to mint to.
* @param quantity The number of tokens to mint.
*/
function mintSeaDrop(address minter, uint256 quantity) external;
/**
* @notice Returns a set of mint stats for the address.
* This assists SeaDrop in enforcing maxSupply,
* maxTotalMintableByWallet, and maxTokenSupplyForStage checks.
*
* @dev NOTE: Implementing contracts should always update these numbers
* before transferring any tokens with _safeMint() to mitigate
* consequences of malicious onERC721Received() hooks.
*
* @param minter The minter address.
*/
function getMintStats(address minter)
external
view
returns (
uint256 minterNumMinted,
uint256 currentTotalSupply,
uint256 maxSupply
);
/**
* @notice Update the public drop data for this nft contract on SeaDrop.
* Only the owner can use this function.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param publicDrop The public drop data.
*/
function updatePublicDrop(
address seaDropImpl,
PublicDrop calldata publicDrop
) external;
/**
* @notice Update the allow list data for this nft contract on SeaDrop.
* Only the owner can use this function.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param allowListData The allow list data.
*/
function updateAllowList(
address seaDropImpl,
AllowListData calldata allowListData
) external;
/**
* @notice Update the token gated drop stage data for this nft contract
* on SeaDrop.
* Only the owner can use this function.
*
* Note: If two INonFungibleSeaDropToken tokens are doing
* simultaneous token gated drop promotions for each other,
* they can be minted by the same actor until
* `maxTokenSupplyForStage` is reached. Please ensure the
* `allowedNftToken` is not running an active drop during the
* `dropStage` time period.
*
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param allowedNftToken The allowed nft token.
* @param dropStage The token gated drop stage data.
*/
function updateTokenGatedDrop(
address seaDropImpl,
address allowedNftToken,
TokenGatedDropStage calldata dropStage
) external;
/**
* @notice Update the drop URI for this nft contract on SeaDrop.
* Only the owner can use this function.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param dropURI The new drop URI.
*/
function updateDropURI(address seaDropImpl, string calldata dropURI)
external;
/**
* @notice Update the creator payout address for this nft contract on
* SeaDrop.
* Only the owner can set the creator payout address.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param payoutAddress The new payout address.
*/
function updateCreatorPayoutAddress(
address seaDropImpl,
address payoutAddress
) external;
/**
* @notice Update the allowed fee recipient for this nft contract
* on SeaDrop.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param feeRecipient The new fee recipient.
*/
function updateAllowedFeeRecipient(
address seaDropImpl,
address feeRecipient,
bool allowed
) external;
/**
* @notice Update the server-side signers for this nft contract
* on SeaDrop.
* Only the owner can use this function.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param signer The signer to update.
* @param signedMintValidationParams Minimum and maximum parameters
* to enforce for signed mints.
*/
function updateSignedMintValidationParams(
address seaDropImpl,
address signer,
SignedMintValidationParams memory signedMintValidationParams
) external;
/**
* @notice Update the allowed payers for this nft contract on SeaDrop.
* Only the owner can use this function.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param payer The payer to update.
* @param allowed Whether the payer is allowed.
*/
function updatePayer(
address seaDropImpl,
address payer,
bool allowed
) external;
}
"
},
"../lib/seadrop/src/interfaces/ISeaDrop.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {
AllowListData,
MintParams,
PublicDrop,
TokenGatedDropStage,
TokenGatedMintParams,
SignedMintValidationParams
} from "../lib/SeaDropStructs.sol";
import { SeaDropErrorsAndEvents } from "../lib/SeaDropErrorsAndEvents.sol";
interface ISeaDrop is SeaDropErrorsAndEvents {
/**
* @notice Mint a public drop.
*
* @param nftContract The nft contract to mint.
* @param feeRecipient The fee recipient.
* @param minterIfNotPayer The mint recipient if different than the payer.
* @param quantity The number of tokens to mint.
*/
function mintPublic(
address nftContract,
address feeRecipient,
address minterIfNotPayer,
uint256 quantity
) external payable;
/**
* @notice Mint from an allow list.
*
* @param nftContract The nft contract to mint.
* @param feeRecipient The fee recipient.
* @param minterIfNotPayer The mint recipient if different than the payer.
* @param quantity The number of tokens to mint.
* @param mintParams The mint parameters.
* @param proof The proof for the leaf of the allow list.
*/
function mintAllowList(
address nftContract,
address feeRecipient,
address minterIfNotPayer,
uint256 quantity,
MintParams calldata mintParams,
bytes32[] calldata proof
) external payable;
/**
* @notice Mint with a server-side signature.
* Note that a signature can only be used once.
*
* @param nftContract The nft contract to mint.
* @param feeRecipient The fee recipient.
* @param minterIfNotPayer The mint recipient if different than the payer.
* @param quantity The number of tokens to mint.
* @param mintParams The mint parameters.
* @param salt The sale for the signed mint.
* @param signature The server-side signature, must be an allowed
* signer.
*/
function mintSigned(
address nftContract,
address feeRecipient,
address minterIfNotPayer,
uint256 quantity,
MintParams calldata mintParams,
uint256 salt,
bytes calldata signature
) external payable;
/**
* @notice Mint as an allowed token holder.
* This will mark the token id as redeemed and will revert if the
* same token id is attempted to be redeemed twice.
*
* @param nftContract The nft contract to mint.
* @param feeRecipient The fee recipient.
* @param minterIfNotPayer The mint recipient if different than the payer.
* @param mintParams The token gated mint params.
*/
function mintAllowedTokenHolder(
address nftContract,
address feeRecipient,
address minterIfNotPayer,
TokenGatedMintParams calldata mintParams
) external payable;
/**
* @notice Emits an event to notify update of the drop URI.
*
* This method assume msg.sender is an nft contract and its
* ERC165 interface id matches INonFungibleSeaDropToken.
*
* Note: Be sure only authorized users can call this from
* token contracts that implement INonFungibleSeaDropToken.
*
* @param dropURI The new drop URI.
*/
function updateDropURI(string calldata dropURI) external;
/**
* @notice Updates the public drop data for the nft contract
* and emits an event.
*
* This method assume msg.sender is an nft contract and its
* ERC165 interface id matches INonFungibleSeaDropToken.
*
* Note: Be sure only authorized users can call this from
* token contracts that implement INonFungibleSeaDropToken.
*
* @param publicDrop The public drop data.
*/
function updatePublicDrop(PublicDrop calldata publicDrop) external;
/**
* @notice Updates the allow list merkle root for the nft contract
* and emits an event.
*
* This method assume msg.sender is an nft contract and its
* ERC165 interface id matches INonFungibleSeaDropToken.
*
* Note: Be sure only authorized users can call this from
* token contracts that implement INonFungibleSeaDropToken.
*
* @param allowListData The allow list data.
*/
function updateAllowList(AllowListData calldata allowListData) external;
/**
* @notice Updates the token gated drop stage for the nft contract
* and emits an event.
*
* This method assume msg.sender is an nft contract and its
* ERC165 interface id matches INonFungibleSeaDropToken.
*
* Note: Be sure only authorized users can call this from
* token contracts that implement INonFungibleSeaDropToken.
*
* Note: If two INonFungibleSeaDropToken tokens are doing
* simultaneous token gated drop promotions for each other,
* they can be minted by the same actor until
* `maxTokenSupplyForStage` is reached. Please ensure the
* `allowedNftToken` is not running an active drop during
* the `dropStage` time period.
*
* @param allowedNftToken The token gated nft token.
* @param dropStage The token gated drop stage data.
*/
function updateTokenGatedDrop(
address allowedNftToken,
TokenGatedDropStage calldata dropStage
) external;
/**
* @notice Updates the creator payout address and emits an event.
*
* This method assume msg.sender is an nft contract and its
* ERC165 interface id matches INonFungibleSeaDropToken.
*
* Note: Be sure only authorized users can call this from
* token contracts that implement INonFungibleSeaDropToken.
*
* @param payoutAddress The creator payout address.
*/
function updateCreatorPayoutAddress(address payoutAddress) external;
/**
* @notice Updates the allowed fee recipient and emits an event.
*
* This method assume msg.sender is an nft contract and its
* ERC165 interface id matches INonFungibleSeaDropToken.
*
* Note: Be sure only authorized users can call this from
* token contracts that implement INonFungibleSeaDropToken.
*
* @param feeRecipient The fee recipient.
* @param allowed If the fee recipient is allowed.
*/
function updateAllowedFeeRecipient(address feeRecipient, bool allowed)
external;
/**
* @notice Updates the allowed server-side signers and emits an event.
*
* This method assume msg.sender is an nft contract and its
* ERC165 interface id matches INonFungibleSeaDropToken.
*
* Note: Be sure only authorized users can call this from
* token contracts that implement INonFungibleSeaDropToken.
*
* @param signer The signer to update.
* @param signedMintValidationParams Minimum and maximum parameters
* to enforce for signed mints.
*/
function updateSignedMintValidationParams(
address signer,
SignedMintValidationParams calldata signedMintValidationParams
) external;
/**
* @notice Updates the allowed payer and emits an event.
*
* This method assume msg.sender is an nft contract and its
* ERC165 interface id matches INonFungibleSeaDropToken.
*
* Note: Be sure only authorized users can call this from
* token contracts that implement INonFungibleSeaDropToken.
*
* @param payer The payer to add or remove.
* @param allowed Whether to add or remove the payer.
*/
function updatePayer(address payer, bool allowed) external;
/**
* @notice Returns the public drop data for the nft contract.
*
* @param nftContract The nft contract.
*/
function getPublicDrop(address nftContract)
external
view
returns (PublicDrop memory);
/**
* @notice Returns the creator payout address for the nft contract.
*
* @param nftContract The nft contract.
*/
function getCreatorPayoutAddress(address nftContract)
external
view
returns (address);
/**
* @notice Returns the allow list merkle root for the nft contract.
*
* @param nftContract The nft contract.
*/
function getAllowListMerkleRoot(address nftContract)
external
view
returns (bytes32);
/**
* @notice Returns if the specified fee recipient is allowed
* for the nft contract.
*
* @param nftContract The nft contract.
* @param feeRecipient The fee recipient.
*/
function getFeeRecipientIsAllowed(address nftContract, address feeRecipient)
external
view
returns (bool);
/**
* @notice Returns an enumeration of allowed fee recipients for an
* nft contract when fee recipients are enforced
*
* @param nftContract The nft contract.
*/
function getAllowedFeeRecipients(address nftContract)
external
view
returns (address[] memory);
/**
* @notice Returns the server-side signers for the nft contract.
*
* @param nftContract The nft contract.
*/
function getSigners(address nftContract)
external
view
returns (address[] memory);
/**
* @notice Returns the struct of SignedMintValidationParams for a signer.
*
* @param nftContract The nft contract.
* @param signer The signer.
*/
function getSignedMintValidationParams(address nftContract, address signer)
external
view
returns (SignedMintValidationParams memory);
/**
* @notice Returns the payers for the nft contract.
*
* @param nftContract The nft contract.
*/
function getPayers(address nftContract)
external
view
returns (address[] memory);
/**
* @notice Returns if the specified payer is allowed
* for the nft contract.
*
* @param nftContract The nft contract.
* @param payer The payer.
*/
function getPayerIsAllowed(address nftContract, address payer)
external
view
returns (bool);
/**
* @notice Returns the allowed token gated drop tokens for the nft contract.
*
* @param nftContract The nft contract.
*/
function getTokenGatedAllowedTokens(address nftContract)
external
view
returns (address[] memory);
/**
* @notice Returns the token gated drop data for the nft contract
* and token gated nft.
*
* @param nftContract The nft contract.
* @param allowedNftToken The token gated nft token.
*/
function getTokenGatedDrop(address nftContract, address allowedNftToken)
external
view
returns (TokenGatedDropStage memory);
/**
* @notice Returns whether the token id for a token gated drop has been
* redeemed.
*
* @param nftContract The nft contract.
* @param allowedNftToken The token gated nft token.
* @param allowedNftTokenId The token gated nft token id to check.
*/
function getAllowedNftTokenIdIsRedeemed(
address nftContract,
address allowedNftToken,
uint256 allowedNftTokenId
) external view returns (bool);
}
"
},
"../lib/seadrop/src/lib/SeaDropStructs.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
/**
* @notice A struct defining public drop data.
* Designed to fit efficiently in one storage slot.
*
* @param mintPrice The mint price per token. (Up to 1.2m
* of native token, e.g. ETH, MATIC)
* @param startTime The start time, ensure this is not zero.
* @param endTIme The end time, ensure this is not zero.
* @param maxTotalMintableByWallet Maximum total number of mints a user is
* allowed. (The limit for this field is
* 2^16 - 1)
* @param feeBps Fee out of 10_000 basis points to be
* collected.
* @param restrictFeeRecipients If false, allow any fee recipient;
* if true, check fee recipient is allowed.
*/
struct PublicDrop {
uint80 mintPrice; // 80/256 bits
uint48 startTime; // 128/256 bits
uint48 endTime; // 176/256 bits
uint16 maxTotalMintableByWallet; // 224/256 bits
uint16 feeBps; // 240/256 bits
bool restrictFeeRecipients; // 248/256 bits
}
/**
* @notice A struct defining token gated drop stage data.
* Designed to fit efficiently in one storage slot.
*
* @param mintPrice The mint price per token. (Up to 1.2m
* of native token, e.g.: ETH, MATIC)
* @param maxTotalMintableByWallet Maximum total number of mints a user is
* allowed. (The limit for this field is
* 2^16 - 1)
* @param startTime The start time, ensure this is not zero.
* @param endTime The end time, ensure this is not zero.
* @param dropStageIndex The drop stage index to emit with the event
* for analytical purposes. This should be
* non-zero since the public mint emits
* with index zero.
* @param maxTokenSupplyForStage The limit of token supply this stage can
* mint within. (The limit for this field is
* 2^16 - 1)
* @param feeBps Fee out of 10_000 basis points to be
* collected.
* @param restrictFeeRecipients If false, allow any fee recipient;
* if true, check fee recipient is allowed.
*/
struct TokenGatedDropStage {
uint80 mintPrice; // 80/256 bits
uint16 maxTotalMintableByWallet; // 96/256 bits
uint48 startTime; // 144/256 bits
uint48 endTime; // 192/256 bits
uint8 dropStageIndex; // non-zero. 200/256 bits
uint32 maxTokenSupplyForStage; // 232/256 bits
uint16 feeBps; // 248/256 bits
bool restrictFeeRecipients; // 256/256 bits
}
/**
* @notice A struct defining mint params for an allow list.
* An allow list leaf will be composed of `msg.sender` and
* the following params.
*
* Note: Since feeBps is encoded in the leaf, backend should ensure
* that feeBps is acceptable before generating a proof.
*
* @param mintPrice The mint price per token.
* @param maxTotalMintableByWallet Maximum total number of mints a user is
* allowed.
* @param startTime The start time, ensure this is not zero.
* @param endTime The end time, ensure this is not zero.
* @param dropStageIndex The drop stage index to emit with the event
* for analytical purposes. This should be
* non-zero since the public mint emits with
* index zero.
* @param maxTokenSupplyForStage The limit of token supply this stage can
* mint within.
* @param feeBps Fee out of 10_000 basis points to be
* collected.
* @param restrictFeeRecipients If false, allow any fee recipient;
* if true, check fee recipient is allowed.
*/
struct MintParams {
uint256 mintPrice;
uint256 maxTotalMintableByWallet;
uint256 startTime;
uint256 endTime;
uint256 dropStageIndex; // non-zero
uint256 maxTokenSupplyForStage;
uint256 feeBps;
bool restrictFeeRecipients;
}
/**
* @notice A struct defining token gated mint par
Submitted on: 2025-11-06 18:49:38
Comments
Log in to comment.
No comments yet.