Sound Protocol
Core Contracts
SoundEditionV2

SoundEditionV2

contracts/core/SoundEditionV2.sol (opens in a new tab)

The Sound Protocol NFT contract.

Overview:

  • Inherits ERC721A (opens in a new tab).
  • 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 (opens in a new tab) 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 (opens in a new tab).
  • Supports per-token tier.

Tiers:

  • The zeroth tier is called the GA_TIER (short for General Admission). This is a special tier that uses default settings on the SoundEdition, as well as platform default settings on minters.
  • Tiers can range from 0 to 255 inclusive.
  • Each tier contains its own max mintable range, cutoff time, and mint randomness.

Inherits:

Structs

TierInfo

struct TierInfo {
    // The tier.
    uint8 tier;
    // The current max mintable amount.
    uint32 maxMintable;
    // The lower bound of the maximum number of tokens that can be minted for the tier.
    uint32 maxMintableLower;
    // The upper bound of the maximum number of tokens that can be minted for the tier.
    uint32 maxMintableUpper;
    // The timestamp (in seconds since unix epoch) after which the
    // max amount of tokens mintable for the tier will drop from
    // `maxMintableUpper` to `maxMintableLower`.
    uint32 cutoffTime;
    // The total number of tokens minted for the tier.
    uint32 minted;
    // The mint randomness for the tier.
    uint256 mintRandomness;
    // Whether the tier mints have concluded.
    bool mintConcluded;
    // Whether the tier has mint randomness enabled.
    bool mintRandomnessEnabled;
    // Whether the tier is frozen.
    bool isFrozen;
}

The information pertaining to a tier.

TierCreation

struct TierCreation {
    // The tier.
    uint8 tier;
    // The lower bound of the maximum number of tokens that can be minted for the tier.
    uint32 maxMintableLower;
    // The upper bound of the maximum number of tokens that can be minted for the tier.
    uint32 maxMintableUpper;
    // The timestamp (in seconds since unix epoch) after which the
    // max amount of tokens mintable for the tier will drop from
    // `maxMintableUpper` to `maxMintableLower`.
    uint32 cutoffTime;
    // Whether the tier has mint randomness enabled.
    bool mintRandomnessEnabled;
    // Whether the tier is frozen.
    bool isFrozen;
}

A struct containing the arguments for creating a tier.

EditionInfo

struct EditionInfo {
    // Base URI for the metadata.
    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;
    // Address of the metadata module. Optional.
    address metadataModule;
    // Whether the metadata is frozen.
    bool isMetadataFrozen;
    // Whether the ability to create tiers is frozen.
    bool isCreateTierFrozen;
    // The royalty BPS (basis points).
    uint16 royaltyBPS;
    // 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;
    // An array of tier info. From lowest (0-indexed) to highest.
    TierInfo[] tierInfo;
}

The information pertaining to this edition.

EditionInitialization

struct EditionInitialization {
    // Name of the collection.
    string name;
    // Symbol of the collection.
    string symbol;
    // Address of the metadata module. Optional.
    address metadataModule;
    // Base URI for the metadata.
    string baseURI;
    // Contract URI for OpenSea storefront.
    string contractURI;
    // Address that receives primary and secondary royalties.
    address fundingRecipient;
    // The royalty BPS (basis points).
    uint16 royaltyBPS;
    // Whether the metadata is frozen.
    bool isMetadataFrozen;
    // Whether the ability to create tiers is frozen.
    bool isCreateTierFrozen;
    // An array of tier creation structs. From lowest (0-indexed) to highest.
    TierCreation[] tierCreations;
}

A struct containing the arguments for initialization.

Write Functions

initialize

function initialize(EditionInitialization calldata init) external

Initializes the contract.

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

Params:
initThe initialization struct.

mint

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

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:
tierThe tier.
toAddress to mint to.
quantityNumber of tokens to mint.

Returns the first token ID minted.

airdrop

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

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:
tierThe tier.
toAddresses 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.

freezeCreateTier

function freezeCreateTier() external

Freezes any more new tiers from being added.

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.

createSplit

function createSplit(address splitMain, bytes calldata splitData)
    external
    returns (address split)

Creates a new split wallet via the SplitMain contract, then sets it as the fundingRecipient.

Calling conditions:

  • The caller must be the owner of the contract, or have the ADMIN_ROLE.
Params:
splitMainThe address of the SplitMain contract.
splitDataThe calldata to forward to the SplitMain contract to create a split.

Returns the address of the new split contract.

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.

freezeTier

function freezeTier(uint8 tier) external

Freezes the tier.

Calling conditions:

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

setMaxMintableRange

function setMaxMintableRange(
    uint8 tier,
    uint32 lower, 
    uint32 upper
) external

Sets the edition max mintable range.

Calling conditions:

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

setCutoffTime

function setCutoffTime(uint8 tier, uint32 cutoffTime) external

Sets the timestamp after which, the max mintable amount for the tier drops from the upper limit to the lower limit.

Calling conditions:

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

setMintRandomnessEnabled

function setMintRandomnessEnabled(bool enabled) external

Sets whether the mintRandomness is enabled.

Calling conditions:

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

createTier

function createTier(TierCreation calldata creation) external

Adds a new tier.

Calling conditions:

  • The caller must be the owner of the contract, or have the ADMIN_ROLE.
Params:
creationThe tier creation data.

emitAllMetadataUpdate

function emitAllMetadataUpdate() external

Emits an event to signal to marketplaces to refresh all the metadata.

Read-only Functions

editionInfo

function editionInfo() external view returns (EditionInfo memory)

Returns the edition info.

tierInfo

function tierInfo(uint8 tier) external view returns (TierInfo memory info)
Params:
tierThe tier.

Returns the tier info.

GA_TIER

function GA_TIER() external pure returns (uint8)

Returns the GA tier, which is 0.

BPS_DENOMINATOR

function BPS_DENOMINATOR() external pure returns (uint8)

Returns the basis points denominator used in fee calculations, which is 10000.

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.

tokenTier

function tokenTier(uint256 tokenId) external view returns (uint8)
Params:
tokenIdThe token ID.

Returns the tier of the tokenId.

explicitTokenTier

function explicitTokenTier(uint256 tokenId) external view returns (uint8)
Params:
tokenIdThe token ID.

Returns the tier of the tokenId.

Note: Will NOT revert if any tokenId does not exist.

If the token has not been minted, the tier will be zero.

If the token is burned, the tier will be the tier before it was burned.

tierTokenIds

function tierTokenIds(uint8 tier) external view returns (uint256[] memory tokenIds) 
Params:
tierThe tier.

Returns an array of all the token IDs in the tier.

tierTokenIdsIn

function tierTokenIdsIn(
    uint8 tier,
    uint256 start,
    uint256 stop
) external view returns (uint256[] memory tokenIds)
Params:
tierThe tier.
startThe start of the range. Inclusive.
stopThe stop of the range. Exclusive.

Returns an array of all the token IDs in the tier, within the range [start, stop).

tierTokenIdIndex

function tierTokenIdIndex(uint256 tokenId) external view returns (uint256)
Params:
tokenIdThe token ID to find.

Returns the index of tokenId in it's tier token ID array.

If not found, returns type(uint256).max.

maxMintable

function maxMintable(uint8 tier) external view returns (uint32)
Params:
tierThe tier.

Returns the maximum amount of tokens mintable for the tier.

maxMintableUpper

function maxMintableUpper(uint8 tier) external view returns (uint32)
Params:
tierThe tier.

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

maxMintableLower

function maxMintableLower(uint8 tier) external view returns (uint32)
Params:
tierThe tier.

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

cutoffTime

function cutoffTime(uint8 tier) external view returns (uint32)
Params:
tierThe tier.

Returns the timestamp after which maxMintable drops from maxMintableUpper to maxMintableLower.

tierMinted

function tierMinted(uint8 tier) external view returns (uint32)
Params:
tierThe tier.

Returns the number of tokens minted for the tier.

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 (opens in a new tab) to learn more about how these ids are created.

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

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 (opens in a new tab)

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 the randomness 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 psuedorandom mechanism.

mintRandomnessEnabled

function mintRandomnessEnabled() external view returns (bool)

Returns whether the mintRandomness has been enabled.

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.

CreateTierFrozen

event CreateTierFrozen()

Emitted when the ability to create tier is removed. event CreateTierFrozen();

FundingRecipientSet

event FundingRecipientSet(address recipient)

Emitted when the fundingRecipient is set.

Params:
recipientThe address of the funding recipient.

RoyaltySet

event RoyaltySet(uint16 bps)

Emitted when the royaltyBPS is set.

Params:
bpsThe new royalty, measured in basis points.

MaxMintableRangeSet

event MaxMintableRangeSet(uint8 tier, uint32 lower, uint32 upper)

Emitted when the tier's maximum mintable token quantity range is set.

Params:
tierThe tier.
lowerThe lower limit of the maximum number of tokens that can be minted.
upperThe upper limit of the maximum number of tokens that can be minted.

CutoffTimeSet

event CutoffTimeSet(uint8 tier, uint32 cutoff)

Emitted when the tier's cutoff time set.

Params:
tierThe tier.
cutoffThe timestamp.

MintRandomnessEnabledSet

event MintRandomnessEnabledSet(uint8 tier, bool enabled)

Emitted when the mintRandomnessEnabled for the tier is set.

Params:
tierThe tier.
enabledThe boolean value.

SoundEditionInitialized

event SoundEditionInitialized(EditionInitialization init)

Emitted upon initialization.

Params:
initThe initialization data.

TierCreated

event TierCreated(TierCreation creation)

Emitted when a tier is created.

Params:
creationThe tier creation data.

TierFrozen

event TierFrozen(uint8 tier)

Emitted when a tier is frozen.

Params:
tierThe tier.

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, address[] tokens, uint256[] amounts, address caller)

Emitted upon ERC20 withdrawal.

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

Minted

event Minted(uint8 tier, address to, uint256 quantity, uint256 fromTokenId)

Emitted upon a mint.

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

Airdropped

event Airdropped(uint8 tier, address[] to, uint256 quantity, uint256 fromTokenId)

Emitted upon an airdrop.

Params:
tierThe tier.
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.

to

event BatchMetadataUpdate(uint256 fromTokenId, uint256 toTokenId)

EIP-4906 event to signal marketplaces to refresh the metadata.

Errors

MetadataIsFrozen

error MetadataIsFrozen()

The edition's metadata is frozen (e.g.: baseURI can no longer be changed).

CreateTierIsFrozen

error CreateTierIsFrozen()

The ability to create tiers is frozen.

InvalidRoyaltyBPS

error InvalidRoyaltyBPS()

The given royaltyBPS is invalid.

ZeroTiersProvided

error ZeroTiersProvided()

A minimum of one tier must be provided to initialize a Sound Edition.

ExceedsAvailableSupply

error ExceedsAvailableSupply()

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

InvalidFundingRecipient

error InvalidFundingRecipient()

The given fundingRecipient address is invalid.

InvalidMaxMintableRange

error InvalidMaxMintableRange()

The maxMintableLower must not be greater than maxMintableUpper.

MintHasConcluded

error MintHasConcluded()

The mint has already concluded.

MintNotConcluded

error MintNotConcluded()

The mint has not concluded.

MintsAlreadyExist

error MintsAlreadyExist()

Cannot perform the operation after a token has been minted.

TierMintsAlreadyExist

error TierMintsAlreadyExist()

Cannot perform the operation after a token has been minted in the tier.

TokenIdsNotStrictlyAscending

error TokenIdsNotStrictlyAscending()

The token IDs must be in strictly ascending order.

TierDoesNotExist

error TierDoesNotExist()

The tier does not exist.

TierAlreadyExists

error TierAlreadyExists()

The tier already exists.

TierIsFrozen

error TierIsFrozen()

The tier is frozen.

InvalidTokenTier

error InvalidTokenTier()

One of more of the tokens do not have the correct token tier.

CannotBurnImmediately

error CannotBurnImmediately()

Please wait for a while before you burn.

TierQueryForNonexistentToken

error TierQueryForNonexistentToken()

The token for the tier query doesn't exist.