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