-
Notifications
You must be signed in to change notification settings - Fork 351
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Problem: Missing ADR draft for NFT transition to the SDK module (#674) (
fixes #673) Solution: Added a draft ADR for transition * Added backwards compatibility details and deprecation plan * Add duplicate messages point in negatives
- Loading branch information
1 parent
dc26c7b
commit 0f99b25
Showing
1 changed file
with
273 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,273 @@ | ||
# Transition to Cosmos SDK's NFT module | ||
|
||
## Changelog | ||
|
||
- 04-11-2021: Initial Draft | ||
|
||
## Context | ||
|
||
Currently, Crypto.org Chain offers support for non-fungible tokens (NFTs) using a custom NFT module in `chain-main`. The | ||
current implementation of NFT module is based on [Irismod's NFT module](https://github.com/irisnet/irismod/tree/master/modules/nft). | ||
Given that different chains are using their custom implementation of NFT module, it is very difficult to achieve | ||
flawless interportability of NFTs across multiple chains using IBC. At the same time, there are more usecases that need | ||
to be supported using NFTs which may require IBC support. So, there is a need of a standardized NFT implementation | ||
which has support for reusing NFTs between modules and chains. | ||
|
||
## Decision | ||
|
||
There are multiple ways to address above mentioned issues. | ||
|
||
1. Use Cosmos SDK's NFT module | ||
|
||
To solve interportablity and standardisation issues, we can adopt [Cosmos SDK's NFT module](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-043-nft-module.md) | ||
which is expected to become standard for implementing NFTs on Cosmos SDK chains and also expected to get support for | ||
transferring NFTs via IBC. | ||
|
||
> More details on interportability of Cosmos SDK's NFT module [here](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-043-nft-module.md#interoperability) | ||
To migrate all the NFTs in current NFT module to new Cosmos SDK NFT module, we can use in-place store migration | ||
(outlined in [ADR 41](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-041-in-place-store-migrations.md)). | ||
|
||
**Advantages** | ||
|
||
- Because this module is a part of Cosmos SDK, it'll get all the future improvement for free. | ||
- Much easier upgrades to newer versions of NFT module as the upgrades will be tested extensively by the community. | ||
|
||
**Drawbacks** | ||
|
||
- It'll become a bit difficult to add custom logic (especially when transferring NFTs) based on our requirements. | ||
|
||
2. Modify current NFT implementation in `chain-main` | ||
|
||
Cosmos SDK's NFT module [ADR](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-043-nft-module.md) | ||
outlines the API contract implemented by NFT module. | ||
|
||
**Advantages** | ||
|
||
- It'll be very easy to add custom logic base on our requirements (for example, https://github.com/irisnet/irismod/issues/183). | ||
|
||
**Drawbacks** | ||
|
||
- Because this module will be developed in isolation, we'll have to work extra hard to make sure that it confirms to | ||
Cosmos SDK's NFT standards. | ||
- Custom logic added to the module may make it impossible to stay in sync with Cosmos SDK's standards. | ||
|
||
This ADR proposes the adoption of **Option 1** to use native Cosmos SDK's NFT module. | ||
|
||
### Cosmos SDK's NFT module | ||
|
||
Cosmos SDK's NFT module provides only one message type that can be used to send NFTs to someone. | ||
|
||
```protobuf | ||
service Msg { | ||
rpc Send(MsgSend) returns (MsgSendResponse); | ||
} | ||
message MsgSend { | ||
string class_id = 1; | ||
string id = 2; | ||
string sender = 3; | ||
string reveiver = 4; | ||
} | ||
message MsgSendResponse {} | ||
``` | ||
|
||
This is similar to `TransferNFT` in current implementation. | ||
|
||
```protobuf | ||
service Msg { | ||
rpc TransferNFT(MsgTransferNFT) returns (MsgTransferNFTResponse); | ||
} | ||
message MsgTransferNFT { | ||
string id = 1; | ||
string denom_id = 2; | ||
string sender = 3; | ||
string recipient = 4; | ||
} | ||
message MsgTransferNFTResponse {} | ||
``` | ||
|
||
`denom_id` in current implementation can directly be mapped to `class_id` and `receipient` can be mapped to `receiver` | ||
of Cosmos SDK's NFT module request. | ||
|
||
Besides this, Cosmos SDK's NFT module specifies multiple message types that should be implemented by wrapper module. | ||
|
||
- `MsgNewClass` - Receive the user's request to create a class, and call the `NewClass` of the `x/nft` module. | ||
- `MsgUpdateClass` - Receive the user's request to update a class, and call the `UpdateClass` of the `x/nft` module. | ||
- `MsgMintNFT` - Receive the user's request to mint a nft, and call the `MintNFT` of the `x/nft` module. | ||
- `BurnNFT` - Receive the user's request to burn a nft, and call the `BurnNFT` of the `x/nft` module. | ||
- `UpdateNFT` - Receive the user's request to update a nft, and call the `UpdateNFT` of the `x/nft` module. | ||
|
||
### Backwards Compatibility | ||
|
||
#### `MsgIssueDenom` | ||
|
||
```protobuf | ||
service Msg { | ||
rpc IssueDenom(MsgIssueDenom) returns (MsgIssueDenomResponse); | ||
} | ||
message MsgIssueDenom { | ||
string id = 1; | ||
string name = 2; | ||
string schema = 3; | ||
string sender = 4; | ||
} | ||
message MsgIssueDenomResponse {} | ||
``` | ||
|
||
To implement `MsgIssueDenom`: | ||
|
||
- `id` can be mapped to `id` field of `Class` | ||
- `name` can be mapped to `name` field of `Class` | ||
- `schema` can be mapped to `data` field of `Class` | ||
- There is no field for storing `sender` information in `Class` so, `sender` information must be injected in `data` | ||
field of `Class` | ||
|
||
Once the `Class` object is prepared, we can call `NewClass` of `x/nft` module. | ||
|
||
#### `MsgMintNFT` | ||
|
||
```protobuf | ||
service Msg { | ||
rpc MintNFT(MsgMintNFT) returns (MsgMintNFTResponse); | ||
} | ||
message MsgMintNFT { | ||
string id = 1; | ||
string denom_id = 2; | ||
string name = 3; | ||
string uri = 4; | ||
string data = 5; | ||
string sender = 6; | ||
string recipient = 7; | ||
} | ||
message MsgMintNFTResponse {} | ||
``` | ||
|
||
To implement `MsgMintNFT`: | ||
|
||
- `id` can be mapped to `id` field of `NFT` | ||
- `denom_id` can be mapped to `class_id` field of `NFT` | ||
- `uri` can be mapped to `uri` field of `NFT` | ||
- Since there is no field for `name` in `NFT`, we'll have to inject name in `data` field of `NFT` | ||
- Owners in Cosmos SDK's NFT module are tracked differently. So, we do not have to set `owner` (it does not exist) field | ||
in `NFT` | ||
- `data` can be mapped to `data` field in `NFT` | ||
|
||
Once the `NFT` object is prepared, we can call `MintNFT` of `x/nft` module. | ||
|
||
#### `MsgEditNFT` | ||
|
||
```protobuf | ||
service Msg { | ||
rpc EditNFT(MsgEditNFT) returns (MsgEditNFTResponse); | ||
} | ||
message MsgEditNFT { | ||
string id = 1; | ||
string denom_id = 2; | ||
string name = 3; | ||
string uri = 4; | ||
string data = 5; | ||
string sender = 6; | ||
} | ||
message MsgEditNFTResponse {} | ||
``` | ||
|
||
To implement `MsgEditNFT`: | ||
|
||
- `id` can be mapped to `id` field of `NFT` | ||
- `denom_id` can be mapped to `class_id` field of `NFT` | ||
- `uri` can be mapped to `uri` field of `NFT` | ||
- Since there is no field for `name` in `NFT`, we'll have to inject name in `data` field of `NFT` | ||
- `data` can be mapped to `data` field in `NFT` | ||
|
||
Once the `NFT` object is prepared, we can call the `UpdateNFT` of `x/nft` module. | ||
|
||
#### `MsgTransferNFT` | ||
|
||
```protobuf | ||
service Msg { | ||
rpc TransferNFT(MsgTransferNFT) returns (MsgTransferNFTResponse); | ||
} | ||
message MsgTransferNFT { | ||
string id = 1; | ||
string denom_id = 2; | ||
string sender = 3; | ||
string recipient = 4; | ||
} | ||
message MsgTransferNFTResponse {} | ||
``` | ||
|
||
Message to transfer the ownership of NFT is directly provided by Cosmos SDK's NFT module using `MsgSend`. To implement | ||
`MsgTransferNFT`: | ||
|
||
- `id` can be mapped to `id` of `MsgSend` | ||
- `denom_id` can be mapped to `class_id` of `MsgSend` | ||
- `sender` can be mapped to `sender` of `MsgSend` | ||
- `recipient` can be mapped to `receiver` of `MsgSend` | ||
|
||
Once `MsgSend` object is created, we can call the `Send` of `x/nft` module. | ||
|
||
#### `MsgBurnNFT` | ||
|
||
```protobuf | ||
service Msg { | ||
rpc BurnNFT(MsgBurnNFT) returns (MsgBurnNFTResponse); | ||
} | ||
message MsgBurnNFT { | ||
string id = 1; | ||
string denom_id = 2; | ||
string sender = 3; | ||
} | ||
message MsgBurnNFTResponse {} | ||
``` | ||
|
||
To implement `MsgBurnNFT`, we can directly call the `BurnNFT` of `x/nft` (after performing validations). | ||
|
||
### Deprecation Plan | ||
|
||
On the release of new wrapper NFT module on Crypto.org chain, all the above messages should be considered as deprecated | ||
and will be removed in approx. 3 months via an upgrade. After the upgrade, the messages specified by Cosmos SDK's NFT | ||
module will handle all the operations. | ||
|
||
## Status | ||
|
||
Draft | ||
|
||
## Consequences | ||
|
||
### Positive | ||
|
||
Cosmos SDK's module will have support from multiple members of the community and will get all the future improvements | ||
for free (for example, IBC support, inter-module asset support using [ADR-33](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-033-protobuf-inter-module-comm.md)) | ||
|
||
### Negative | ||
|
||
- Our current implementation is slightly different from Cosmos SDK's NFT module which can result in backwards | ||
incompatibility. This can be temporarily avoided by creating a wrapper module (which we anyway need to create for | ||
minting and burning NFTs) and adding same messages as the current module along with the sandard message types mentioned | ||
[here](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-043-nft-module.md#abstract). But, it is | ||
necessary to have a deprecation plan for old message types and transition all the downstream services to new | ||
standardized message types. | ||
- There'll be a lot of duplicate message types until legacy messages are removed. | ||
|
||
### Neutral | ||
|
||
Our current implementation is very similar to Cosmos SDK's NFT module implementation and all the usecases currently | ||
supported by Crypto.org Chain can easily be supported using new module. | ||
|
||
## References | ||
|
||
- [Cosmos SDK's NFT Module ADR](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-043-nft-module.md) | ||
- [Current NFT Module specs](https://github.com/crypto-org-chain/chain-main/tree/master/x/nft/spec) |