Sound Edition
Most of the SDK is defined within the .edition
subcategory that defines read functions and operations relevant for Sound Edition contracts.
Basic Information
.contract.info
Requires either
signer
orprovider
/**
* { symbol: string
editionMaxMintableLower: number
editionMaxMintableUpper: number
baseURI: string
contractURI: string
editionCutoffTime: number
editionMaxMintable: number
fundingRecipient: string
isMetadataFrozen: boolean
metadataModule: string
mintConcluded: boolean
mintRandomness: BigNumber
mintRandomnessEnabled: boolean
name: string
nextTokenId: BigNumber
royaltyBPS: number
totalBurned: BigNumber
totalMinted: BigNumber
totalSupply: BigNumber
}
*/
const editionInfo = await client.edition.info({
contractAddress: '0x...',
}).contract.info
.contract.isVersionAtLeastV1_2
Requires either
signer
orprovider
Check if the sound edition contract is at least v1.2, which has SAM
available
const {
// Promise<boolean>
isVersionAtLeastV1_2,
} = await client.edition.info({
contractAddress: '0x...',
}).contract
.api.info
Requires
SoundAPI
Get Sound.xyz API information relative to the specified Sound Edition
/**
* {
mintStartDate: Date
id: string
contractAddress: string
editionId: string | null
type: ReleaseType
mintStartTime: number
mintStartTimestamp: number
webappUri: string
externalUrl: string | null
marketPlaceUrl: string | null
title: string
behindTheMusic: string
season: string | null
genre: {
id: string
name: string
}
track: {
id: string
duration: number
audio: {
audio128k: {
id: string
url: string
} | null
audio192k: {
id: string
url: string
} | null
audio256k: {
id: string
url: string
} | null
audioOriginal: {
id: string
url: string
}
}
}
artist: {
id: string
webappUri: string
season: string | null
soundHandle: string | null
bannerImage: {
id: string
url: string
} | null
user: {
id: string
publicAddress: string
description: string | null
displayName: string | null
twitterHandle: string | null
avatar: {
id: string
url: string
} | null
}
}
rewards: {
id: string
description: string
title: string
}[]
coverImage: {
id: string
url: string
}
goldenEggImage: {
id: string
url: string
}
eggGame: {
id: string
winningSerialNum: number
} | null
}
*/
const apiInfo = await client.edition.info({
contractAddress: '0x...',
}).api.info
.apiShare
Requires
SoundAPI
Get Sound.xyz API share information, being able to customize embeds and adding referral addresses
/**
* {
mintStartDate: Date
id: string
contractAddress: string
editionId: string | null
type: ReleaseType
mintStartTime: number
mintStartTimestamp: number
webappUri: string
webEmbed: string
coverImage: {
id: string
url: string
}
track: {
id: string
duration: number
audio: {
audio128k: {
id: string
url: string
} | null
audio192k: {
id: string
url: string
} | null
audio256k: {
id: string
url: string
} | null
audioOriginal: {
id: string
url: string
}
}
}
}
*/
const apiShareInfo = await client.edition
.info({
contractAddress: '0x...',
})
.api.apiShare({
// * Optionally customize webapp uri with referral address
// releaseWebappUriInput: {
// referralAddress: '0x...',
// },
// releaseEmbedUriInput: {
// * Optionally customize the html properties of the iframe embed
// html: {
// height: '...',
// style: '...',
// width: '...',
// },
// * Add an optional referral address to the uri within the embed
// referralAddress: '0x...',
// },
})
Mint Schedules
Requires either
signer
orprovider
Get mint schedules of specified edition, you can optionally specifiy scheduleIds
to optimize on-chain calls and improve performance considerably
.mintSchedules
interface MintScheduleBase {
editionAddress: string
minterAddress: string
mintId: number
startTime: number
endTime: number
mintPaused: boolean
price: BigNumber
maxMintablePerAccount: number
totalMinted: number
affiliateFeeBPS: number
}
interface RangeEditionSchedule extends MintScheduleBase {
mintType: 'RangeEdition'
maxMintableLower: number
maxMintableUpper: number
cutoffTime: number
maxMintable: (unixTimestamp?: number) => number
}
interface MerkleDropSchedule extends MintScheduleBase {
mintType: 'MerkleDrop'
maxMintable: number
merkleRoot: string
}
const {
// MintSchedule[]
schedules,
// Get only active schedules relative to given timestamp or when this function is called
// MintSchedule[]
activeSchedules,
} = await client.edition.mintSchedules({
editionAddress: '0x...',
// Specify schedule identifiers to optimize on-chain calls
// scheduleIds: [...]
// Customize the timestamp to be used for "activeSchedules" filtering.
// Optional, by default it uses Math.floor(Date.now() / 1000). It has to be in UNIX timestamp format
// timestamp: ...
})
.scheduleIds
Schedule identifiers that are used to get schedule the information for the specified edition.
It is highly encouraged to pre-compute and persist these values to be given into the .mintSchedules
call in order
to optimize performance.
/**
* {
minterAddress: string;
mintIds: number[];
}[]
*/
const scheduleIds = await client.edition.scheduleIds({
editionAddress: '0x...',
// Specify the starting block to start looking for logs of the schedule identifiers
// fromBlockOrBlockHash: ...
})
.registeredMinters
Lookup the minters addresses associated with the edition, this is automatically called by scheduleIds
and it's very unlikely to be needed to be called explicitly.
// string[]
const minters = await client.edition.registeredMinters({
editionAddress: '0x...',
// Optionally specify the block to start looking for the registed minters
// fromBlockOrBlockHash: ...
})
.minterMintIds
Lookup the mint indentifiers associated with the minters, this is automatically called by scheduleIds
and it's very unlikely to be needed to be called explicitly.
// number[]
const mintIds = await client.edition.minterMintIds({
editionAddress: '0x...',
minterAddress: '0x...',
// Optionally specify the block to start looking for the mint identifiers
// fromBlockOrBlockHash: ...
})
Minting
.eligibleQuantity
Requires either
signer
orprovider
Check how many tokens a wallet should be able to collect for a specific mint schedule
// number
const quantity = await client.edition.eligibleQuantity({
// mintSchedule: MintSchedule;
mintSchedule: activeSchedule,
// Wallet address to be checked
userAddress: '0x...',
// Customize the timestamp to be used for time-based checks.
// Optional, by default it uses Math.floor(Date.now() / 1000). It has to be in UNIX timestamp format
// timestamp: ...
})
.numberMinted
Requires either
signer
orprovider
Get the currently amount of minted NFTs of the given user address in specified edition, only considering primary purchases, and always incremental, value doesn't decrease as tokens are sold or burned.
// number
const userNumberMinted = await client.numberMinted({
editionAddress: '0x...',
userAddress: '0x...',
})
.numberOfTokensOwned
Requires either
signer
orprovider
Returns the number of tokens owned by user for a given edition, considering primary purchases, transfers into the specified address, and decreased by sold and burned tokens.
// number
const tokensOwnedTotal = await client.numberOfTokensOwned({
editionAddress: '0x...',
userAddress: '0x...',
})
.mint
Requires
signer
Mint a edition given the specified schedule and using given signer. If given schedule is a merkle drop, a Merkle Provider
will be required
// Transaction
const mintTransaction = await client.mint({
mintSchedule,
quantity: 1,
// affiliate: ...
// gasLimit: ...
// maxFeePerGas: ...
// maxPriorityFeePerGas: ...
})
SAM
SAM (Sound Automated Market) is the protocol behind Sound Swap (opens in a new tab)
// This will contain all the relevant SAM helpers
const samEdition = client.edition.sam({
editionAddress: '0x...',
})
Contract
.address
Requires either
signer
orprovider
Contract address of SAM module associated with edition if exists
Please use this address nullability as a cheap check before calling any write function into SAM, otherwise functions will fail loudly.
// string | null
const samAddress = await samEdition.contract.samAddress
.info
Requires either
signer
orprovider
Information relative to edition on SAM
This value will be null
if edition doesn't have SAM associated
/**
* {
affiliateMerkleRoot: string
affiliateFeeBPS: number
basePrice: BigNumber
linearPriceSlope: BigNumber
inflectionPrice: BigNumber
inflectionPoint: number
goldenEggFeesAccrued: BigNumber
balance: BigNumber
supply: number
maxSupply: number
buyFreezeTime: number
artistFeeBPS: number
goldenEggFeeBPS: number
}
|
null
*/
const samInfo = await samEdition.contract.info
.totalBuyPrice
Requires either
signer
orprovider
Estimated price for buying tokens from SAM
/**
* {
total: BigNumber;
platformFee: BigNumber;
artistFee: BigNumber;
goldenEggFee: BigNumber;
affiliateFee: BigNumber;
}
|
null
*/
const buyPrice = await samEdition.contract.totalBuyPrice({
// Offset used as buffer for handling concurrent purchases
// and reducing the possibility of failed transactions
offset: 0,
// How many tokens to be estimated for purchase
quantity: 1,
})
.totalSellPrice
Requires either
signer
orprovider
Estimated price for selling tokens for SAM
// BigNumber | null
const sellPrice = await samEdition.contract.totalSellPrice({
// Offset used as buffer for handling concurrent sales
// and reducing the possibility of failed transactions
offset: 0,
// How many tokens to be estimated for sell
quantity: 1,
})
.buy
Requires
signer
Attempt to buy the given amount based on the specified price
// ContractTransaction
const purchaseTransaction = await samEdition.contract.buy({
// How many to be purchased
quantity: 1,
// Price to be attempted
price: '...',
// Optional attribution identifier
// attributonId?: BigNumberish
// Optional affiliate address
// affiliate: string
// Optional affiliate proof
// affiliateProof: BytesLike[]
// Customize contract's call gas-related attributes
// gasLimit: BigNumberish
// maxFeePerGas: BigNumberish
// maxPriorityFeePerGas: BigNumberish
})
.sell
Requires
signer
Attempt to sell the given tokens based on the specified payout.
It is also required for the tokens to be specified ascendingly, this is required to be able to leverage low-level optimizations.
// ContractTransaction
const purchaseTransaction = await samEdition.contract.buy({
// Specify the tokens to be sold
tokenIds: [1, 2],
// How much is the minimum amount expected to be received
minimumPayout: '...',
// Optional attribution identifier
// attributonId: BigNumberish
// Customize contract's call gas-related attributes
// gasLimit: BigNumberish
// maxFeePerGas: BigNumberish
// maxPriorityFeePerGas: BigNumberish
})
API
.availableTokensToSell
Requires
SoundAPI
When selling NFTs through the SAM a normal expectation for an automated logic when choosing which tokens to be sold is that we sell the older tokens first and we should always exclude the golden egg from being sold.
This requires extra indexing and logic so it is required an interaction with Sound API
.
This returns a potentially-empty list of token identifiers sorted ascendingly after the specified quantity limit
// number[]
const tokensAvailableToSell = await samEdition.api.availableTokensToSell({
// How many tokens are expected to be sold
quantity: 1,
// Wallet address of token holder
ownerPublicAddress: '0x...',
})