Add support for on-chain royalties
psiemens opened this issue · comments
Peter Siemens commented
Users need a way to specify royalty recipients for their NFTs.
At a minimum, we should update the MetadataViews.Royalties view implementation to return values specified by the user rather than an empty list.
Questions
- How does a user specify a single royalty that is applied to all NFTs in a contract?
- How does a user specify multiple royalty receivers and amounts?
- How does a user specify a royalty receiver that changes depending on the NFT?
- How does a user change a royalty receiver for an already minted NFT?
- e.g. What happens if an NFT royalty recipient loses access to their Flow account?
- How does a royalty recipient accept royalties in multiple token types?
- Answer: using the fungible token switchboard contract.
Ideas
- Create a royalty proxy contract that is deployed alongside an NFT contract. This contract will act as a routing table between NFTs and their royalty receivers. The project owner would have freedom to add/remove/update the receivers as needed using a separate set of admin transactions.
Peter Siemens commented
After more thought, the proxy contract is only necessary when a contract needs to be retrofitted to include royalties.
Otherwise, I think it's cleaner to just store the royalty information on the main contract.
Here's what I'm thinking:
pub contract MyNFT: NonFungibleToken {
// Royalty information is stored in a mutable variable on the contract.
//
pub var royalties: [MetadataViews.Royalty]
pub resource NFT {
// The NFT implements the Royalties view.
//
pub fun resolveRoyaltiesView(): MetadataViews.Royalties {
return MetadataViews.Royalties(MyNFT.royalties)
}
}
pub resource Admin {
// The admin has the ability to update the royalty receiver at a later date.
//
// I think this is important given that not all accounts are set up to use the token switchboard.
// An admin may want to update the royalty receiver(s) to an account that can accept more token types.
//
pub fun setRoyalties(royalties: [MetadataViews.Royalty]) {
self.royalties = royalties
}
}
init(royalties: [MetadataViews.Royalty]) {
// Royalties can be set at deploy time,
// but this array can also just be empty (e.g. for local development).
self.royalties = royalties
}
}
The Node.js library would then be updated as follows:
const contract = new StandardNFTContract({ name, address, schema })
// Option 1: set royalties on deployment
contract.deploy({
publicKey,
hashAlgorithm,
royalties: [
{
address: '0xf8d6e0586b0a20c7',
receiverPublicPath: '/public/flowTokenReceiver', // Receive FLOW royalties
cut: '5.0' // Send 5% of sale to this receiver
},
{
address: '0xee82856bf20e2aa6',
receiverPublicPath: '/public/flowTokenReceiver' // Receive FLOW royalties
cut: '3.0' // Send 3% of sale to this receiver
}
]
})
// Option 2: set or update royalties after deployment
contract.setRoyalties([{
address: '0xee82856bf20e2aa6',
receiverPublicPath: '/public/flowTokenReceiver' // Receive FLOW royalties
cut: '3.0' // Send 3% of sale to this receiver
}])
Peter Siemens commented
Reopening this because I still need to add a CLI command to set royalties.
Peter Siemens commented
Added royalties
field to freshmint.yaml
in #166