Sound Protocol
Core Contracts
SoundEdition

SoundEdition

contracts/core/SoundEditionV1_1.sol

The Sound Protocol NFT contract.

Overview:

  • An implementation of ERC721A.
  • Enables the owner, authorized minter contracts or administrators to batch mint NFTs. Authorization is granted by the owner via the grantRoles function inherited from OwnableRoles.
  • Token IDs are minted sequentially (e.g. 1, 2, 3…) starting from 1.
  • Can optionally implement a metadataModule that effectively overrides the default tokenURI function.
  • Can natively support range editions via a dynamic maximum mintable supply (based on a editionCutoffTime),
  • Has a pseudorandom mintRandomness number optionally set on each mint call, which can be used for game mechanics.
  • Implements EIP-2981 Royalty Standard.

Inherits:

Structs

EditionInfo

struct EditionInfo {
    // Base URI for the tokenId.
    string baseURI;
    // Contract URI for OpenSea storefront.
    string contractURI;
    // Name of the collection.
    string name;
    // Symbol of the collection.
    string symbol;
    // Address that receives primary and secondary royalties.
    address fundingRecipient;
    // The current max mintable amount;
    uint32 editionMaxMintable;
    // The lower limit of the maximum number of tokens that can be minted.
    uint32 editionMaxMintableUpper;
    // The upper limit of the maximum number of tokens that can be minted.
    uint32 editionMaxMintableLower;
    // The timestamp (in seconds since unix epoch) after which the
    // max amount of tokens mintable will drop from
    // `maxMintableUpper` to `maxMintableLower`.
    uint32 editionCutoffTime;
    // Address of metadata module, address(0x00) if not used.
    address metadataModule;
    // The current mint randomness value.
    uint256 mintRandomness;
    // The royalty BPS (basis points).
    uint16 royaltyBPS;
    // Whether the mint randomness is enabled.
    bool mintRandomnessEnabled;
    // Whether the mint has concluded.
    bool mintConcluded;
    // Whether the metadata has been frozen.
    bool isMetadataFrozen;
    // Next token ID to be minted.
    uint256 nextTokenId;
    // Total number of tokens burned.
    uint256 totalBurned;
    // Total number of tokens minted.
    uint256 totalMinted;
    // Total number of tokens currently in existence.
    uint256 totalSupply;
}

Holds information pertaining to the SoundEdition.

This struct is intended for off-chain queries, and can be retrieved via the editionInfo function.

Write Functions

initialize

function initialize(
    string memory name_,
    string memory symbol_,
    address metadataModule_,
    string memory baseURI_,
    string memory contractURI_,
    address fundingRecipient_,
    uint16 royaltyBPS_,
    uint32 editionMaxMintableLower_,
    uint32 editionMaxMintableUpper_,
    uint32 editionCutoffTime_,
    uint8 flags_
) external

Initializes the contract.

This function is called in the createSoundAndMints function of SoundCreatorV1, right after the creation of the SoundEdtion, within the same transaction.

Params:
name_Name of the collection.
symbol_Symbol of the collection.
metadataModule_Address of metadata module, address(0x00) if not used.
baseURI_Base URI.
contractURI_Contract URI for OpenSea storefront.
fundingRecipient_Address that receives primary and secondary royalties.
royaltyBPS_Royalty amount in bps (basis points).
editionMaxMintableLower_The lower bound of the max mintable quantity for the edition.
editionMaxMintableUpper_The upper bound of the max mintable quantity for the edition.
editionCutoffTime_The timestamp after which editionMaxMintable drops from editionMaxMintableUpper to max(_totalMinted(), editionMaxMintableLower).
flags_The bitwise OR result of the initialization flags.
See: METADATA_IS_FROZEN_FLAG
See: MINT_RANDOMNESS_ENABLED_FLAG

mint

function mint(address to, uint256 quantity) external payable returns (uint256)

Mints quantity tokens to addrress to

Each token will be assigned a token ID that is consecutively increasing.

Calling conditions:

  • The caller must be the owner of the contract, or have either the ADMIN_ROLE, MINTER_ROLE, which can be granted via grantRoles. Multiple minters, such as different minter contracts, can be authorized simultaneously.
Params:
toAddress to mint to.
quantityNumber of tokens to mint.

Returns the first token ID minted.

airdrop

function airdrop(address[] calldata to, uint256 quantity) external returns (uint256)

Mints quantity tokens to each of the addresses in to.

Calling conditions:

  • The caller must be the owner of the contract, or have the ADMIN_ROLE, which can be granted via grantRoles.
Params:
toAddress to mint to.
quantityNumber of tokens to mint.

Returns the first token ID minted.

withdrawETH

function withdrawETH() external

Withdraws collected ETH royalties to the fundingRecipient.

withdrawERC20

function withdrawERC20(address[] calldata tokens) external

Withdraws collected ERC20 royalties to the fundingRecipient.

Params:
tokensarray of ERC20 tokens to withdraw

setMetadataModule

function setMetadataModule(address metadataModule) external

Sets metadata module.

Calling conditions:

  • The caller must be the owner of the contract, or have the ADMIN_ROLE.
Params:
metadataModuleAddress of metadata module.

setBaseURI

function setBaseURI(string memory baseURI) external

Sets global base URI.

Calling conditions:

  • The caller must be the owner of the contract, or have the ADMIN_ROLE.
Params:
baseURIThe base URI to be set.

setContractURI

function setContractURI(string memory contractURI) external

Sets contract URI.

Calling conditions:

  • The caller must be the owner of the contract, or have the ADMIN_ROLE.
Params:
contractURIThe contract URI to be set.

freezeMetadata

function freezeMetadata() external

Freezes metadata by preventing any more changes to base URI.

Calling conditions:

  • The caller must be the owner of the contract, or have the ADMIN_ROLE.

setFundingRecipient

function setFundingRecipient(address fundingRecipient) external

Sets funding recipient address.

Calling conditions:

  • The caller must be the owner of the contract, or have the ADMIN_ROLE.
Params:
fundingRecipientAddress to be set as the new funding recipient.

setRoyalty

function setRoyalty(uint16 bps) external

Sets royalty amount in bps (basis points).

Calling conditions:

  • The caller must be the owner of the contract, or have the ADMIN_ROLE.
Params:
bpsThe new royalty basis points to be set.

setEditionMaxMintableRange

function setEditionMaxMintableRange(
    uint32 editionMaxMintableLower_,
    uint32 editionMaxMintableUpper_
) external

Sets the edition max mintable range.

Calling conditions:

  • The caller must be the owner of the contract, or have the ADMIN_ROLE.
Params:
editionMaxMintableLower_The lower limit of the maximum number of tokens that can be minted.
editionMaxMintableUpper_The upper limit of the maximum number of tokens that can be minted.

setEditionCutoffTime

function setEditionCutoffTime(uint32 editionCutoffTime_) external

Sets the timestamp after which, the editionMaxMintable drops from editionMaxMintableUpper to editionMaxMintableLower.

Calling conditions:

  • The caller must be the owner of the contract, or have the ADMIN_ROLE.
Params:
editionCutoffTime_The timestamp.

setMintRandomnessEnabled

function setMintRandomnessEnabled(bool mintRandomnessEnabled_) external

Sets whether the mintRandomness is enabled.

Calling conditions:

  • The caller must be the owner of the contract, or have the ADMIN_ROLE.
Params:
mintRandomnessEnabled_The boolean value.

setOperatorFilteringEnabled

function setOperatorFilteringEnabled(bool operatorFilteringEnabled_) external

Sets whether OpenSea’s OperatorFilter registry is enabled.

Calling conditions:

  • The caller must be the owner of the contract, or have the ADMIN_ROLE.
Params:
operatorFilteringEnabled_The boolean value.

setApprovalForAll

function setApprovalForAll(address operator, bool approved) external

Approves or removes operator as an operator for the caller. Operators can call transferFrom or safeTransferFrom for any token owned by the caller. If the OPERATOR_FILTERING_ENABLED_FLAG is set, this function will revert if the operator is not approved by the OperatorFilter registry.

Calling conditions:

  • The operator cannot be the caller.
Params:
operatorThe operator address.
approvedWhether or not the operator is approved.

approve

function approve(address operator, bool approved) external

Gives permission to to to transfer tokenId token to another account. The approval is cleared when the token is transferred. Gives permission to to to transfer tokenId token to another account. The approval is cleared when the token is transferred. If the OPERATOR_FILTERING_ENABLED_FLAG is set, this function will revert if the operator is not approved by the OperatorFilter registry.

Calling conditions:

  • The operator cannot be the caller.
Params:
toThe permissioned operator.
tokenIdThe permissioned token.

transferFrom

 function transferFrom(address from, address to, uint256 tokenId) external payable

Transfers tokenId token from from to to.

WARNING: Usage of this method is discouraged, use safeTransferFrom whenever possible.

Calling conditions:

  • from cannot be the zero address.
  • from can only be approved operators (if OPERATOR_FILTERING_ENABLED_FLAG is set)
  • to cannot be the zero address.
  • tokenId token must be owned by from.
  • If the caller is not from, it must be approved to move this token by either approve or setApprovalForAll.
Params:
fromThe sender.
toThe receiver.
tokenIdThe permissioned token.

safeTransferFrom

 function safeTransferFrom(address from, address to, bytes calldata data) external payable

Safely transfers tokenId token from from to to, checking first that contract recipients are aware of the ERC721 protocol to prevent tokens from being forever locked.

Calling conditions:

  • from cannot be the zero address.
  • from can only be approved operators (if OPERATOR_FILTERING_ENABLED_FLAG is set) to cannot be the zero address. tokenId token must exist and be owned by from. If the caller is not from, it must be have been allowed to move this token by either approve or setApprovalForAll. If to refers to a smart contract, it must implement IERC721Receiver-onERC721Received, which is called upon a safe transfer.
Params:
fromThe sender.
toThe receiver.
tokenIdThe permissioned token.
dataOptional data to be used by receiver if receiver is a smart contract.

Read-only Functions

editionInfo

function editionInfo() external view returns (EditionInfo memory)

Returns the edition info.

supportsInterface

IERC165-supportsInterface

function supportsInterface(bytes4 interfaceId) public view virtual returns (bool)

Returns true if this contract implements the interface defined by interfaceId.

See the corresponding EIP section to learn more about how these ids are created.

Params:
interfaceIdThe 4 byte interface ID.
Supported Interface IDs:
IERC1650x01ffc9a7
ERC7210x80ac58cd
ERC721Metadata0x5b5e139f
ISoundEditionV10x50899e54
ISoundEditionV1_10x425aac3d

MINTER_ROLE

function MINTER_ROLE() external view returns (uint256)

Returns the minter role flag.

ADMIN_ROLE

function ADMIN_ROLE() external view returns (uint256)

Returns the admin role flag.

ADDRESS_BATCH_MINT_LIMIT

function ADDRESS_BATCH_MINT_LIMIT() external pure returns (uint256)

Returns the maximum limit for the mint or airdrop quantity.

Prevents the first-time transfer costs for tokens near the end of large mint batches via ERC721A from becoming too expensive due to the need to scan many storage slots.

See: https://chiru-labs.github.io/ERC721A/#/tips?id=batch-size

Initialization flags

Each flag is a bit in the uint256 _flags passed to the initialze function.

  • METADATA_IS_FROZEN_FLAG - If set, the metadata is frozen and cannot be changed.
  • MINT_RANDOMNESS_ENABLED_FLAG - If set, the mintRandomness function is enabled.
  • OPERATOR_FILTERING_ENABLED_FLAG - If set, the edition will be compatible with OpenSea’s OperatorFilter registry for creator fees.

Each flag’s base-10 value can be retrieved by calling its name as a function.

function METADATA_IS_FROZEN_FLAG() external pure returns (uint8);
function MINT_RANDOMNESS_ENABLED_FLAG() external pure returns (uint8);
function OPERATOR_FILTERING_ENABLED_FLAG() external pure returns (uint8);

baseURI

function baseURI() external view returns (string memory)

Returns the base token URI for the collection.

contractURI

function contractURI() external view returns (string memory)

Returns the contract URI to be used by Opensea.

See: https://docs.opensea.io/docs/contract-level-metadata

fundingRecipient

function fundingRecipient() external view returns (address)

Returns the address of the funding recipient.

editionMaxMintable

function editionMaxMintable() external view returns (uint32)

Returns the maximum amount of tokens mintable for this edition.

editionMaxMintableUpper

function editionMaxMintableUpper() external view returns (uint32)

Returns the upper bound for the maximum tokens that can be minted for this edition.

editionMaxMintableLower

function editionMaxMintableLower() external view returns (uint32)

Returns the lower bound for the maximum tokens that can be minted for this edition.

editionCutoffTime

function editionCutoffTime() external view returns (uint32)

Returns the timestamp after which editionMaxMintable drops from editionMaxMintableUpper to editionMaxMintableLower.

metadataModule

function metadataModule() external view returns (address)

Returns the address of the metadata module.

mintRandomness

function mintRandomness() external view returns (uint256)

Returns a pseudorandom number based on latest block hash, which is stored upon each mint unless mintConcluded is true. Used for game mechanics like the Sound Golden Egg. Returns 0 before revealed.

WARNING This value should NOT be used for any reward of significant monetary value, due to it being computed via a purely on-chain pseudorandom mechanism.

mintRandomnessEnabled

function mintRandomnessEnabled() external view returns (bool)

Returns whether the mintRandomness has been enabled.

operatorFilteringEnabled

function operatorFilteringEnabled() external view returns (bool)

Returns whether the edition implements OpenSea’s OperatorFilter registry

mintConcluded

function mintConcluded() external view returns (bool)

Returns whether the mint has been concluded.

royaltyBPS

function royaltyBPS() external view returns (uint16)

Returns the royalty basis points.

isMetadataFrozen

function isMetadataFrozen() external view returns (bool)

Returns whether the metadata module is frozen.

nextTokenId

function nextTokenId() external view returns (uint256)

Returns the next token ID to be minted.

numberMinted

function numberMinted(address owner) external view returns (uint256)

Returns the number of tokens minted by owner.

Params:
ownerAddress to query for number minted.

numberBurned

function numberBurned(address owner) external view returns (uint256)

Returns the number of tokens burned by owner.

Params:
ownerAddress to query for number burned.

totalMinted

function totalMinted() external view returns (uint256)

Returns the total amount of tokens minted.

totalBurned

function totalBurned() external view returns (uint256);

Returns the total amount of tokens burned.

Events

MetadataModuleSet

event MetadataModuleSet(address metadataModule);

Emitted when the metadata module is set.

Params:
metadataModulethe address of the metadata module.

BaseURISet

event BaseURISet(string baseURI);

Emitted when the baseURI is set.

Params:
baseURIThe base URI of the edition.

ContractURISet

event ContractURISet(string contractURI);

Emitted when the contractURI is set.

Params:
contractURIThe contract URI of the edition.

MetadataFrozen

event MetadataFrozen(address metadataModule, string baseURI, string contractURI)

Emitted when the metadata is frozen (e.g.: baseURI can no longer be changed).

Params:
metadataModuleThe address of the metadata module.
baseURIThe base URI of the edition.
contractURIThe contract URI of the edition.

FundingRecipientSet

event FundingRecipientSet(address fundingRecipient)

Emitted when the fundingRecipient is set.

Params:
fundingRecipientThe address of the funding recipient.

RoyaltySet

event RoyaltySet(uint16 bps)

Emitted when the royaltyBPS is set.

Params:
bpsThe new royalty, measured in basis points.

EditionMaxMintableRangeSet

event EditionMaxMintableRangeSet(
    uint32 editionMaxMintableLower_,
    uint32 editionMaxMintableUpper_
)

Emitted when the edition’s maximum mintable token quantity range is set.

Params:
editionMaxMintableLower_The lower limit of the maximum number of tokens that can be minted.
editionMaxMintableUpper_The upper limit of the maximum number of tokens that can be minted.

EditionCutoffTimeSet

event EditionCutoffTimeSet(uint32 editionCutoffTime_)

Emitted when the edition’s cutoff time set.

Params:
editionCutoffTime_The timestamp.

MintRandomnessEnabledSet

event MintRandomnessEnabledSet(bool mintRandomnessEnabled_)

Emitted when the mintRandomnessEnabled is set.

Params:
mintRandomnessEnabled_The boolean value.

SoundEditionInitialized

event SoundEditionInitialized(
    address indexed edition_,
    string name_,
    string symbol_,
    address metadataModule_,
    string baseURI_,
    string contractURI_,
    address fundingRecipient_,
    uint16 royaltyBPS_,
    uint32 editionMaxMintableLower_,
    uint32 editionMaxMintableUpper_,
    uint32 editionCutoffTime_,
    uint8 flags_
    )

Emitted upon initialization.

Params:
edition_The address of the edition.
name_Name of the collection.
symbol_Symbol of the collection.
metadataModule_Address of metadata module, address(0) if not used.
baseURI_Base URI.
contractURI_Contract URI for OpenSea storefront.
fundingRecipient_Address that receives primary and secondary royalties.
royaltyBPS_Royalty amount in bps (basis points).
editionMaxMintableLower_The lower bound of the max mintable quantity for the edition.
editionMaxMintableUpper_The upper bound of the max mintable quantity for the edition.
editionCutoffTime_The timestamp after which editionMaxMintable drops from editionMaxMintableUpper to max(_totalMinted(), editionMaxMintableLower).
flags_The bitwise OR result of the initialization flags.
See: METADATA_IS_FROZEN_FLAG
See: MINT_RANDOMNESS_ENABLED_FLAG

ETHWithdrawn

event ETHWithdrawn(address recipient, uint256 amount, address caller)

Emitted upon ETH withdrawal.

Params:
recipientThe recipient of the withdrawal..
amountThe amount withdrawn.
callerThe account that initiated the withdrawal.

ERC20Withdrawn

event ERC20Withdrawn(address recipient, uint256 amount, address caller)

Emitted upon ERC20 withdrawal.

Params:
recipientThe recipient of the withdrawal..
tokensThe addresses of the ERC20 tokens.
amountThe amount of each token withdrawn.
callerThe account that initiated the withdrawal.

Minted

event Minted(address to, uint256 quantity, uint256 fromTokenId);

Emitted upon a mint.

Params:
toThe address to mint to.
quantityThe number of minted.
fromTokenIdThe first token ID minted.

Airdropped

event Minted(address to, uint256 quantity, uint256 fromTokenId);

Emitted upon an airdrop.

Params:
toThe recipients of the airdrop.
quantityThe number of tokens airdropped to each address in to.
fromTokenIdThe first token ID minted to the first address in to.

Errors

MetadataIsFrozen

error MetadataIsFrozen()

The edition’s metadata is frozen.

InvalidRoyaltyBPS

error InvalidRoyaltyBPS()

The given royaltyBPS is invalid.

InvalidRandomnessLock

error InvalidRandomnessLock()

The given randomnessLockedAfterMinted value is invalid.

ExceedsEditionAvailableSupply

error ExceedsEditionAvailableSupply(uint32 available)

The requested quantity exceeds the edition’s remaining mintable token quantity.

Params:
availableThe number of tokens remaining available for mint.

InvalidAmount

error InvalidAmount()

The given amount is invalid.

InvalidFundingRecipient

error InvalidFundingRecipient()

The given fundingRecipient address is invalid.

InvalidEditionMaxMintableRange

error InvalidEditionMaxMintableRange()

The editionMaxMintableLower must not be greater than editionMaxMintableUpper.

MaximumHasAlreadyBeenReached

error MaximumHasAlreadyBeenReached()

The editionMaxMintable has already been reached.

ExceedsAddressBatchMintLimit

error ExceedsAddressBatchMintLimit()

The mint quantity cannot exceed ADDRESS_BATCH_MINT_LIMIT tokens.

MintRandomnessAlreadyRevealed

error MintRandomnessAlreadyRevealed()

The mint randomness has already been revealed.

NoAddressesToAirdrop

error NoAddressesToAirdrop()

No addresses to airdrop.

MintHasConcluded

error MintHasConcluded()

The mint has already concluded.

MintsAlreadyExist

error MintsAlreadyExist()

Cannot perform the operation after a token has been minted.