Last Wednesday, Sound unveiled the Sound Protocol, a permissionless, open-source, modular smart contract framework for musicians and creators. It was inspired by many protocols in the web3 ecosystem and brought to bear a lot of the things we’ve learned while iterating on the first set of contracts we deployed nearly a year ago. Its main features are:
Permissionless base layer
Previously, artists needed a signed message provided by Sound to sell their music. With the new Protocol, artists can freely deploy their own Sound contracts.
Artist-owned & non-upgradeable contracts
All contracts in the new protocol are non-upgradeable, which we believe will give artists and collectors greater confidence in the security and sovereignty of the communities they’re building on Sound.
Additionally, we are replacing the former artist contracts that were intended to represent an artist’s whole collection, with edition contracts that can atomically represent a song, album, mixtape, etc. We believe this is better aligned with the broader concept of music collecting, and it has the added benefit of smoother integration and composability.
Custom metadata
Artists and developers are free to implement custom metadata modules to suit their needs.
Custom mint formats
Mint formats can now be customized on a per-song basis by utilizing minter module contracts. We built minters for the existing formats on sound.xyz but any conceivable type of auction or distribution can be built into custom minters: open editions, bonding-curves, dutch auctions, and more.
Payments & end-to-end royalties
With each song as its own contract, Sound now supports end-to-end royalties across primary and secondary sales. Any address can be set to receive the edition’s revenue, be it the artist’s wallet or a payment splitter contract.
Gas efficient
A great amount of care was put into making the Sound Protocol contracts very secure and gas efficient. This was achieved primarily thanks to the contributions of Yul & Solidity expert, Vectorized, aka Optimizoor, maintainer of 721-A. Skip to the Optimizations section for details.
This contract is the first point of contact for an artist. It is a simple, non-upgradable factory which only has one job: deploy minimal proxies (clones) of SoundEditionV1
& initialize them with customizable configurations. The function for doing this is createSoundAndMints
, which accepts encoded calldata for initializing the edition, as well as an arbitrary list of contract addresses and calldata used for setting up minter configurations for the edition.
This is the NFT contract that represents songs (or albums, mixtapes, etc). It’s an implementation of the highly gas-optimized ERC721A. The main thing that sets it apart from the typical NFT contract is it can implement optional module contracts that augment or override the base functionality of metadata, minting, and payments (primary & secondary revenue).
Metadata
tokenURI
function that the edition’s tokenURI
function calls, overriding the default response. If an artist wants to guarantee to their collectors that the metadata cannot be changed, they can call freezeMetadata
, which will prevent any changes to the baseURI
or metadataModule
address.Payments
SoundEditionV1.fundingRecipient
. In the case where the artist is the sole recipient, this would be their wallet address. If they are splitting revenue with other parties, it could be an 0xSplits SplitWallet (what we use on sound.xyz) or an alternative splitter contract.Minting
A few minting features are baked directly into SoundEditionV1
:
The artist can airdrop tokens to a list of addresses at any time, if enough supply is available.
Upon each mint event, a pseudo-random number is set, which enables game mechanics like the Sound Golden Egg. While the value isn’t truly random, it is calculated through a gas-efficient mechanism that would be very difficult to game via MEV.
It is possible to implement range editions directly through the edition contract, which enables some market discoverability. The way it works is a lower and upper quantity bound are defined along with a cutoff time. Prior to the cutoff time, tokens can be minted until the upper bound is reached. After the cutoff time, the current total or the lower bound become the final maximum quantity for the edition, whichever is greater.
Authority over minting can be granted to any number of customized minter contracts, the details of which are described further below.
Access control
SoundEditionV1
implements solady OwnableRoles
, a very gas-optimized on-chain contract for gating access to functions.
Roles can be granted & revoked for addresses. ex:
Minter contracts must have MINTER_ROLE
.
Owner-defined admins must have ADMIN_ROLE
.
The only rule for custom metadata modules is that they implement IMetadataModule.sol
. Currently, sound.xyz is using GoldenEggMetadataModule.sol
for our golden egg feature, however there are many other creative possibilities we encourage builders to explore, like on-chain SVG images and dynamic NFTs.
To be able to mint from an edition, an address only needs to have the MINTER_ROLE
granted to it. To ease composability and off-chain integrations, we recommend custom minter contracts implement IMinterModule.sol
, but it is not a strict requirement.
Each minter can define any max token quantity, irrespective of quantities minted by other minters. However, all minters are constrained by the maximum mintable tokens on the edition. It is up to the artist to initialize the edition with a value high enough quantity to accommodate all current & future mints.
An interesting feature of IMinterModule
is the affiliate fee, which is a way of incentivizing third parties to promote an edition by collecting a fee set by the artist. For example, a music blog could expose a UI to mint songs it is curating and be rewarded for it.
The following are the current minter modules built by the Sound protocol team:
PublicSaleMinter
Mints tokens at a fixed price.
The quantity of tokens an address can mint is constrained by maxMintablePerAccount
.
MerkleDropMinter
Enables a predefined list of recipients to mint tokens at any fixed price.
Each whitelisted user can claim their eligible amount in multiple transactions.
The quantity of tokens an address can mint is constrained by maxMintablePerAccount
.
FixedPriceSignatureMinter
Useful for throttling high-demand sales when the list of interested buyers isn’t known ahead of time.
Mints tokens at a fixed price for buyers approved to buy via signature verification.
The quantity of tokens an address can mint is controlled by the off-chain signature granting process.
Each signature can only be used a single time, which is enforced via claim tickets stored in gas-efficient bitmaps.
The signature is unique by edition
address, buyer
address, mintId
, single-use claimTicket
, a signedQuantity
enforcing an upper limit for the transaction, and affiliate
address.
RangeEditionMinter
Mints either a fixed quantity or a quantity within a range based on time bounds.
The quantity of tokens an address can mint is constrained by maxMintablePerAccount
.
Note: While range mints can be implemented natively with the edition contract, the range minter enables multiple range mint schedules
For long term scalability and mass adoption, we have heavily optimized the code.
Storage reads and writes are extremely expensive operations in the EVM, making up the bulk of the gas costs. As such, most of our storage variables are tightly packed to minimize the number of storage words required. This helps us reduce greatly gas for artists deploying contracts and minters.
We have also implemented advanced storage optimizations such as:
Converting Arweave URIs to a single word by base64 decoding.
Packing the SoundEdition's name and symbol into a single word where possible.
Using ERC721A’s _nextTokenId()
as an re-initialization guard to remove reliance on the default implementation (which takes up an extra storage slot).
Additionally, we adopted high level design choices that allow us to combine variables, such as using Solady’s OwnableRoles library which combines the owner and default admin.
Further gas efficiency is achieved by using assembly (Yul).
The SoundCreator uses assembly for efficient forwarding of calldata to the contracts and for bubbling up reverted errors.
We also utilize the Solady library, a collection of highly optimized Solidity assembly snippets for the following:
ETH and ERC20 transfers
ECDSA verification
Merkle proof verification
Contract ownership and access roles management
String operations
Base64 encoding/decoding
The use of low level features requires much heavier testing for certainty of safety and correctness, due to the relinquishment of many default safeguards.
Our code (inclusive of snippets from Solady), have been rigorously tested with fuzz tests, brutalized memory tests, differential tests, and more.
We have also engaged reviewers with extensive low-level Solidity optimization experience to scrutinize the code.
Since Sound launched last year, several amazing third-party projects like Spinamp, FutureTape, and OohLaLa have been building apps using data from our contracts. However, until now there hasn’t been a straightforward and reliable way for them to get the data they need. So to make their lives easier and encourage more builders, we’ve released the public Sound API. You can read more about it on its documentation page.
And finally, what is a shiny new protocol and API without a proper SDK to round out the lineup? The one we just open sourced streamlines the process of creating editions with custom mint configurations using any valid minter contract, as well as facilitating the minting process. We hope to see it receive heavy use in the coming months. Sound.xyz is powered by the Sound SDK so everyone has the same minting experience. You can check out its documentation here.
Have any questions? Interested in building custom modules for the Sound Protocol? We welcome you to reach out to the team on Twitter or make a pull request. We can’t wait to see how the protocol evolves as the Sound community grows.