Skip to main content

ADR-005: Non-Fungible Token Standard for Objects


Define the implementation of Non-Fungible Tokens on the Sonr Network and the developmental resources needed to create the x/nft module. Non-Fungible Tokens will allow developers to create digital assets on the Sonr Network.


1. What is a Non-Fungible Token​

A Non-Fungible Token NFT is a digital asset that is commonly expressed with art, in-game items, music videos, and tickets although it is not limited to these specific items. NFT's can be can be understood as a verifiable purchase.

1.1 How Non-Fungible Tokens will Work on the Sonr Ecosystem​

The Non-Fungible Tokens will be owned, transferred and sold on a basic level. For example, let's say that User-A purchases an NFT that is a picture of User-B's cat. User-A now owns that specific NFT photo of User-B's cat and can hold it, sell it to another user (via marketplace), or transfer the NFT to another user.

1.2 How Non-Fungible Tokens will be utilized to create a consumer-focused Market​

NFT will allow users of the Sonr ecosystem to buy and sell art, music, tickets, in-game items, and videos. These specific examples will allow B2-B and B2-C projects to come onto the market in a cost-effective way due to Sonr's low gas fees.

1.3 How Non-Fungible Tokens can interact with the ecosystem​

Non-Fungible Tokens will allow the Sonr Network to obtain Gas Fess from the purchase, sale and transfer of NFTs as well as the creation of CW721 Smart Contracts and messages sent to the smart contracts on the blockchain.

  • Minting of Non-Fungible Tokens
    • Mint Price (will be stored in the smart contract which the owner can withdrawl) + gas fee
  • Purchase of Non-Fungible Tokens
    • Set Price (by Owner of NFT) + gas fee
  • Sale of Non-Fungible Tokens
    • Gas fee (to set the NFT for sale with set price by Owner)
  • Transfer of Non-Fungible Tokens
    • Gas fee (to transfer the NFT from the Owner to another address)
  • Smart Contract Creation
    • Gas fee (to publish the smart contract on the blockchain)

2. How will Non-Fungible Tokens be purchased, sold & transferred on the Sonr blockchain​

The Sonr Blockchain will accept smart contracts that are in the Cosmos WebAssembly (CosmWasm) which is a smart contracting platform built for the Cosmos Ecosystem. The CW721 Specification will allow developers to utilize Sonr's specific NFT implementation and have a specific set of rules to follow and allow developers to add custom logic.

2.1 Base of the CW721 Specification​

The Base will handle ownership, transfers, and allowances. Allowances pertain to users allowing a portion of their wallet to be spent to purchase NFTs as well as sell and transfer them.

2.2 Metadata with the Non-Fungible Smart Contracts (CW721)​

Metadata is used to give Non-Fungible Tokens the ability to show specific data on a blockchain. For Example, User-A's cat NFTs would all have metadata with an on-chain or off-chain metadata with the picture of the cat. Metadata can have assocaited cost depending on the developers choice of storage. For example, you can utilize IPFS or Arweave storage at a cost to the developer, or utilize the Sonr Buckets that incurs a small fee.

2.3 How Gas Fees will allow the Blockchain & Validators to receive more token​

Along with the purchase, sale, or transfer of an NFT is an associated gas fee. These gas fees can be thought of as a reward for the computationally difficult process of verifying the purchase, sale, or transfer of an NFT. These gas fees will be utilized to give the validators on the network incentive to stay on the network as validators.

2.4 How Non-Fungible Tokens can be Purchased, Sold, & Transferred​

Purchasing NFTs will be on an NFT marketplace. These marketplaces can be made by any developer on the network and don’t necessarily need to be owned by Sonr itself. Although Sonr may not own the majority (or any) of the marketplaces, gas fees spoken about above will still go to the Sonr blockchain and its validators.

3. Who will be using, creating, and purchasing Non-Fungible Tokens​

Sonr users from all walks of life will be utilizing Non-Fungible tokens for various reasons. Developers will be able to create elaborate smart contracts for various artistic expressions, online games, music, videos, and tickets that are all digitally verifiable by the blockchain. Users can play online games, purchase music, videos, art,Β  and purchase tickets with verifiable digital ownership to get into a multitude of events. Digital verified ownership of documents is available for most contracts, letting developers and users to be able to send and receive documents securely. Through the Sonr Blockchain, individuals will be empowered to share their art, data, documents, etc. as Non-Fungible Tokens with the rest of the world!

3.1 What is an NFT Marketplace​

An NFT Marketplace consists of all Non-Fungible Tokens on a specific blockchain. These NFTs can be purchased and sold on the marketplace by the owners of the NFT or the Smart Contract that owns the Non-Fungible Token in a minting process. As all of these transactions are on the blockchain, the purchase and sale are verifiable and recorded.

Specification for Non-Fungible Tokens on the Blockchain​

Implementation of Non-Fungible Tokens into Blockchain

The implementation of the NFT module into our blockchain will provide the ability to create smart contracts based on the CW-721 specification. This specification will allow developers to create smart contracts based on types that can be called upon by developers with their own set of logic. Not all of the functionality may be used in the CW-721 specification but is available to be used by all developers.

Goals of Implementation are as follows​

  • Store Non-Fungible Tokens and track their ownership via the blockchain
  • Expose Keeper interface for composing modules to transfer, mint, and burn Non-Fungible tokens.
  • Expose an external Message interface for users to purchase, sell and transfer ownership of their Non-Fungible Tokens.
  • Query Non-Fungible Tokens for their supply information, ownership of a given NFT, and a list of operators that can access a specific owners tokens.

x/nft Module Required Functions​

  • 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 an NFT, and call the MintNFT of the x/nft module.
  • BurnNFT - Receive the user's request to burn an NFT, and call the BurnNFT of the x/nft module.
  • UpdateNFT - Receive the user's request to update an NFT, and call the UpdateNFT of the x/nft module.

Keeper Interface​

type Keeper interface {
NewClass(class Class)
UpdateClass(class Class)

Mint(nft NFT,receiver sdk.AccAddress) // updates totalSupply
Burn(classId string, nftId string) // updates totalSupply
Update(nft NFT)
Transfer(classId string, nftId string, receiver sdk.AccAddress)

GetClass(classId string) Class
GetClasses() []Class

GetNFT(classId string, nftId string) NFT
GetNFTsOfClassByOwner(classId string, owner sdk.AccAddress) []NFT
GetNFTsOfClass(classId string) []NFT

GetOwner(classId string, nftId string) sdk.AccAddress
GetBalance(classId string, owner sdk.AccAddress) uint64
GetTotalSupply(classId string) uint64

Types for x/nft Module​

  • Class - describes the NFT class. Can be thought of as the smart contract address
  • NFT - an object representing unique non-fungible assets. Each NFT is associated with a Class

Class Example:

message Class {
string id = 1;
string name = 2;
string symbol = 3;
string description = 4;
string uri = 5;
string uri_hash = 6;
google.protobuf.Any data = 7;

NFT Example:

message NFT {
string class_id = 1;
string id = 2;
string uri = 3;
string uri_hash = 4;
google.protobuf.Any data = 10;

Msg Service for x/nft Module​

service Msg {
rpc Send(MsgSend) returns (MsgSendResponse);

message MsgSend {
string class_id = 1;
string id = 2;
string sender = 3;
string reveiver = 4;
message MsgSendResponse {}

MsgSend can be used to transfer ownership of an NFT to another address.

type msgServer struct{
k Keeper

func (m msgServer) Send(ctx context.Context, msg *types.MsgSend) (*types.MsgSendResponse, error) {
// check current ownership
assertEqual(msg.Sender, m.k.GetOwner(msg.ClassId, msg.Id))

// transfer ownership
m.k.Transfer(msg.ClassId, msg.Id, msg.Receiver)

return &types.MsgSendResponse{}, nil

CW721 Specification In Detail​

The CW721 Specification will allow developers to create smart contracts based on CosmWasm. Keep in mind all Messages will have a gas cost associated

CW721-base Specfication​

InitMsg : Takes the name and symbol for metadata, as well as the minter address. This is a special address that has full power to mint new NFTs but does not modify existing NFTs.

HandleMsg::Mint{token_id, owner, name, description, image} : Creates a new token with given owner and metadata. It can only be called by the Minter set in init.

QueryMsg::Minter{} : Returns the minter address for this contract.

Base Messages​

TransferNFT{recipient, token_id} : Transfers ownership of the token to the recipient account. Designed to send to an address and does not trigger any actions to the recipient.

SendNFT{contract, token_id, msg} : This transfers ownership of the token to the contract account specified in the message. The contract must be an address controlled by the contract, which implements the cw721Reciever interface. The msg will be passed along to the recipient contract along with the token_id.

Approve{spender, token_id, expires} : Grants permission to spender to transfer or send the given token_id.

Revoke{spender, token_id} : This revokes a previously granted permission to transfer the given token_id.

ApproveAll{operator, expires} : Grants operator the permission to transfer or send all tokens owned by env.sender. This approval is tied to the owner, not the tokens, and applies to any future token that the owner receives as well.

RevokeAll{operator} : Revokes the previous ApproveAll permission granted to the given operator.

Base Queries​

OwnerOf{token_id} : Returns the owner of a given token, as well as anyone with approval on the particular token.

ApprovedForAll{owner, include_expired} : List all operators that can access all of the owner's tokens.

NumToken{} : Total number of tokens issued.

Base Receiver​

ReceiveNft{sender, token_id, msg} : This is designed to handle SendNFT messages.

Metadata Queries​

ContractInfo{} : This returns top-level metadata about the contract. Namely the Name & symbol.

NftInfo{token_id} : This returns metadata about one particular token. The return value is based on the ERC721 Metadata JSON Schema, but directly from the contract, not as a URI. Only the image link is a URI.

AllNftInfo{token_id} : This returns the result of both NftInfo and OwnerOf as one query as an optimization for clients, which may want both info to display one NFT.