Current Implementation: - https://github.com/paritytech/substrate/tree/bg/nfts-royalty/frame/nfts-royalty ### Important Notes ```rust pub fn set_collection_royalty ``` - The royalty can be set on the NFT collection and applies for all items in the collection - There can be multiple royalty recipients for the collection **Questions** - Should we only allow for a royalty to be set as long as there are not items minted? - Should we explicitly make the collection owner a royalty recipient? - Does it make sense for us to set multiple recipients here or should we only set the collection owner recipient here and allow for multiple recipients in the `set_item_royalty`? - I am thinking we should make multiple recipients optional in `set_collection_royalty` - Example 1, collection owner will generate thousands of NFTs via AI with 3 known recipients for all NFTs in the collection - Example 2, collection owner creates the collection, artists come and decide they want to mint their artwork in that collection so each NFT has a different recipient(s) - Should we allow for the collection issuer to set the royalty? - Should we allow for the collection admin to set the royalty? - Why do we need `ForceOrigin` - still not convinced. - ***Research where it is being used in NFTs pallet*** **Nice-to-haves** - Optional feature, collection owner sets a maximum accummulated royalty that is allowed for recipients ## ```rust pub fn set_item_royalty ``` - The royalty can also be set on the NFT item. This would override the royalty (and recipients) set on the collection for that specific item - There can be multiple royalty recipients for the item - **TODO** - Only allow for royalty to be set if the sender is the one that minted the item and currently owns the item - Make it so that `set_item_royalty` is enabled or disabled on the pallet - A team can decide that the royalty can only be set on the collection and not be overridden per item ## ```rust pub fn transfer_collection_royalty_recipient ``` - An existing collection royalty recipient can transfer their royalty percentage to another account - Make this an optional feature in the pallet that can be enabled/disabled ## ```rust pub fn transfer_item_royalty_recipient ``` - An existing item royalty recipient can transfer their royalty percentage to another account - Make this an optional feature in the pallet that can be enabled/disabled ## ```rust pub fn buy ``` - The idea is that we override the buy logic in the NFTs pallet with our buy logic which includes payment of royalties. ### Issues that need to be solved **Problem #1** There are two `buy` dispatchable calls. One `buy` dispatchable call in the NFTs pallet, the other in the Royalty pallet. The royalty pallet's `buy` includes royalty payment as part of the buy logic where as the NFTs pallet's `buy` does not include royalty payment logic. The problem is that the user could bypass royalties by calling the NFTs `buy` instead of the royalty pallet's `buy`. A few possible solutions: 1. disable `buy` in NFTs pallet - If user tries to call it they get the error: `disabledBuy` - Problem: Subtrate/FRAME - there is no overriding on dispatchable calls 2. disable transfer so `buy` in NFTs pallet does not work - if user tries calling the NFTs pallet `buy`, they will get a `disabledTransfer` error - this is not an elegant solution, more of a hack 4. use an `on_buy` hook - pay royalties `on_intitialize` - create an `on_buy` trait in NFTs pallet - implement the trait in the royalty pallet - with this solution, there is no need to create a `buy` dispatchable call in the royalty pallet - this was also proposed here: https://github.com/paritytech/substrate/pull/11676#issuecomment-1159946189 **Problem #2**: Users can bypass royalties by using `transfer` or `swap` Possible Solution: Disabling transfers (and swaps) - We would like to optionally disable transfers (and swapping) so that the royalty payment cannot be bypassed. This would help solve the issue of bypassing royalty payment as stated here: - https://github.com/paritytech/substrate/pull/11676#issuecomment-1165578321 - This should be an optional pallet feature (perhaps the default feature?) as some teams would rather have the ability to transfer knowing that the royalty could be bypassed - Similar to soul bound NFTs - cannot be transferred, different in the sense that it can be sold - we need a new name for this? - This is not a 100% solution for bypassing royalties as the NFT can still be sold for $1 but it is not a bad solution because it is far easier to solve the issue of selling an NFT for $1 to bypass the royalty vs "selling the NFT offchain and transferring to bypass the royalty" issue **Technical Solution for disabling transfers** We could lock the NFT collection/item when the royalty is set, then when the NFT is bought, we unlock in the `buy` dispatchable call logic of our pallet, make the purchase, pay the royalties, then lock the NFT again. Something similar was implemented in the [NFT-fractionalization](https://github.com/paritytech/substrate/tree/master/frame/nft-fractionalization) pallet. It allows a user to lock an NFT they own, create a new fungible asset, and mint a set amount of tokens. The pallet manages all the assets and if needed the pallet can unify and unlock the NFT. Example of disabling transfer (by setting an attribute): ```rust fn disable_transfer(collection: &Self::CollectionId, item: &Self::ItemId) -> DispatchResult { <Self as Mutate<T::AccountId, ItemConfig>>::set_attribute( collection, item, &PalletAttributes::<Self::CollectionId>::TransferDisabled.encode(), &[], ) } ``` ```rust pub fn remove_collection_royalty ``` - This can only be called if the collection no longer exists - This would return the deposit and clear storage ```rust pub fn remove_item_royalty ``` - This can only be called if the item no longer exists - This would return the deposit and clear storage **Post-MVP** - Allow for buying royalty rights