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": {
"contracts/Pixels.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {ERC721SeaDrop} from "./ERC721SeaDrop.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {Base64} from "@openzeppelin/contracts/utils/Base64.sol";
error TokenDoesNotExist();
error MintQuantityExceedsMaxSupply(uint256 requested, uint256 maxSupply);
error TokenAlreadyMinted();
error TokenIdTooLarge();
/// @title Pixels
/// @author Parker Thompson
/// @notice Pixels are simple test NFTs for OpenSea integration
/// @dev Integrates with OpenSea SeaDrop
contract Pixels is ERC721SeaDrop {
using Strings for uint256;
uint256 public constant OS_START_ID = 100;
uint256 public nextMintId = OS_START_ID;
// Track SeaDrop mints separately from manual mints
uint256 public seaDropMinted = 0;
// Track SeaDrop mints per address (what should count toward limits)
mapping(address => uint256) public seaDropMintsByAddress;
constructor(
address[] memory allowedSeaDrop
) ERC721SeaDrop("Pixels", "PIXELS", allowedSeaDrop) {}
function _startTokenId() internal view virtual override returns (uint256) {
return 0;
}
function _sequentialUpTo()
internal
view
virtual
override
returns (uint256)
{
return 0;
}
function mintViaContract(uint256 tokenId) public onlyOwner {
if (_exists(tokenId)) revert TokenAlreadyMinted();
if (tokenId >= OS_START_ID) revert TokenIdTooLarge();
_mintSpot(msg.sender, tokenId);
}
function bulkMintViaContract(uint256[] memory tokenIds) public onlyOwner {
for (uint256 i = 0; i < tokenIds.length; i++) {
mintViaContract(tokenIds[i]);
}
}
function mintSeaDrop(
address minter,
uint256 quantity
) external override nonReentrant {
_onlyAllowedSeaDrop(msg.sender);
// Check against SeaDrop-specific supply limit
if (seaDropMinted + quantity > maxSupply()) {
revert MintQuantityExceedsMaxSupply(
seaDropMinted + quantity,
maxSupply()
);
}
for (uint256 i = 0; i < quantity; ++i) {
_mintSpot(minter, nextMintId);
unchecked {
++nextMintId;
++seaDropMinted;
++seaDropMintsByAddress[minter];
}
}
}
function _totalMintedSuper() public view returns (uint256) {
return super._totalMinted();
}
function _totalMinted() internal view override returns (uint256) {
return seaDropMinted;
}
function totalSupply() public view override returns (uint256) {
return _totalMintedSuper() - _totalBurned();
}
/**
* @dev Override _numberMinted to return only SeaDrop mints.
* This ensures only SeaDrop tokens count toward OpenSea's per-wallet limits.
*/
function _numberMinted(address owner) internal view override returns (uint256) {
return seaDropMintsByAddress[owner];
}
/**
* @dev Helper function for testing - exposes _numberMinted
*/
function numberMinted(address owner) public view returns (uint256) {
return _numberMinted(owner);
}
function tokenURI(
uint256 tokenId
) public view override returns (string memory) {
if (!_exists(tokenId)) revert TokenDoesNotExist();
// Simple pixel art as base64 encoded PNG
string
memory imageUri = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAB2SURBVHgB7doxAQAwDIAwOv+eOxk9IBK4GWARe8gVALkCIFcA5AqAXAGQKwByBUCuAMgVALkCIFcA5AqAXAGQKwByBUDuPMDu7Z4wNEi4FQC5AiBXAOQKgFwBkCsAcgVArgDIFQC5AiBXAOQKgFwBkCsAcvoAH6/zBXr/PpazAAAAAElFTkSuQmCC";
string memory svgString = string(
abi.encodePacked(
'<svg width="1200" height="1200" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg" style="background-image:url(',
imageUri,
');background-repeat:no-repeat;background-size:contain;background-position:center;image-rendering:-webkit-optimize-contrast;-ms-interpolation-mode:nearest-neighbor;image-rendering:-moz-crisp-edges;image-rendering:pixelated;"></svg>'
)
);
string memory json = string(
abi.encodePacked(
'{"name":"',
"Pixel ",
tokenId.toString(),
'", "description":"Testing OpenSea with spot minting - Simple pixel art NFT"',
', "image":"data:image/svg+xml;base64,',
Base64.encode(bytes(svgString)),
'", "attributes":[{"trait_type":"Token ID","value":"',
tokenId.toString(),
'"},{"trait_type":"Collection","value":"Pixels Test"}]}'
)
);
return
string(
abi.encodePacked(
"data:application/json;base64,",
Base64.encode(bytes(json))
)
);
}
}
"
},
"contracts/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/openzeppelin-contracts/contracts/utils/Strings.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
"
},
"lib/openzeppelin-contracts/contracts/utils/Base64.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides a set of functions to operate with Base64 strings.
*
* _Available since v4.5._
*/
library Base64 {
/**
* @dev Base64 Encoding/Decoding Table
*/
string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* @dev Converts a `bytes` to its Bytes64 `string` representation.
*/
function encode(bytes memory data) internal pure returns (string memory) {
/**
* Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
* https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
*/
if (data.length == 0) return "";
// Loads the table into memory
string memory table = _TABLE;
// Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
// and split into 4 numbers of 6 bits.
// The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
// - `data.length + 2` -> Round up
// - `/ 3` -> Number of 3-bytes chunks
// - `4 *` -> 4 characters for each chunk
string memory result = new string(4 * ((data.length + 2) / 3));
/// @solidity memory-safe-assembly
assembly {
// Prepare the lookup table (skip the first "length" byte)
let tablePtr := add(table, 1)
// Prepare result pointer, jump over length
let resultPtr := add(result, 32)
// Run over the input, 3 bytes at a time
for {
let dataPtr := data
let endPtr := add(data, mload(data))
} lt(dataPtr, endPtr) {
} {
// Advance 3 bytes
dataPtr := add(dataPtr, 3)
let input := mload(dataPtr)
// To write each character, shift the 3 bytes (18 bits) chunk
// 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
// and apply logical AND with 0x3F which is the number of
// the previous character in the ASCII table prior to the Base64 Table
// The result is then added to the table to get the character to write,
// and finally write it in the result pointer but with a left shift
// of 256 (1 byte) - 8 (1 ASCII char) = 248 bits
mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
}
// When data `bytes` is not exactly 3 bytes long
// it is padded with `=` characters at the end
switch mod(mload(data), 3)
case 1 {
mstore8(sub(resultPtr, 1), 0x3d)
mstore8(sub(resultPtr, 2), 0x3d)
}
case 2 {
mstore8(sub(resultPtr, 1), 0x3d)
}
}
return result;
}
}
"
},
"contracts/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 {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IERC2981} from "@openzeppelin/contracts/interfaces/IERC2981.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
error OnlyOwner();
error CannotExceedMaxSupplyOfUint64(uint256 newMaxSupply);
error NewMaxSupplyCannotBeLessThenTotalMinted(
uint256 newMaxSupply,
uint256 totalMinted
);
error ProvenanceHashCannotBeSetAfterMintStarted();
error RoyaltyAddressCannotBeZeroAddress();
error InvalidRoyaltyBasisPoints(uint256 bps);
struct RoyaltyInfo {
address royaltyAddress;
uint96 royaltyBps;
}
/**
* @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,
Ownable,
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
}
}
}
"
},
"contracts/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;
}
"
},
"contracts/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);
}
"
},
"contracts/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 storag
Submitted on: 2025-10-23 18:32:05
Comments
Log in to comment.
No comments yet.