Skip to main content

NFT & SFT tokens

Introduction

MultiversX NFTs(non-fungible tokens) are a breed of digital assets that are revolutionizing the world of art, collectibles, and more. These NFTs are unique, one-of-a-kind tokens that are built on blockchain technology, allowing for secure ownership and transfer of these assets. With MultiversX NFTs, every token is assigned a unique identification code(ticker) and metadata that distinguishes it from every other token, making each NFT truly one-of-a-kind. Read the full page for a comprehensive guide on how to brand, issue, transfer, assign roles and many other features, for both NFTs and SFTs.

NFT and SFT

The MultiversX protocol introduces native NFT support by adding metadata and attributes on top of the already existing Fungible tokens. This way, one can issue a semi-fungible token or a non-fungible token which is quite similar to an ESDT, but has a few more attributes, as well as an assignable URI. Once owning a quantity of a NFT/SFT, users will have their data store directly under their account, inside the trie. All the fields available inside a NFT/SFT token can be found here.

The flow of issuing and transferring non-fungible or semi-fungible tokens is:

  • register/issue the token
  • set roles to the address that will create the NFT/SFTs
  • create the NFT/SFT
  • transfer quantity(es)

Meta ESDT

In addition to NFTs and SFTs, MultiversX introduced Meta ESDTs. Meta ESDTs are a special case of semi-fungible-tokens. They can be seen as regular ESDT fungible tokens that also have properties. In a particular example, LKMEX or XMEX are MetaESDTs and their properties help implement the release schedule.

Branding

Anyone can create NFTs and SFTs tokens on MultiversX Network. There are also no limits in tokens names or tickers. For example, one issues an AliceToken with the ticker ALC. Anyone else is free to create a new token with the same token name and the same token ticker. The only difference will be the random sequence of the token identifier. So the "original" token could have received the random sequence 1q2w3e resulting in the ALC-1q2w3e identifier, while the second token could have received the sequence 3e4r5t resulting in ALC-3e4r5t.

In order to differentiate between an original token and other tokens with the same name or ticker, we have introduced a branding mechanism that allows tokens owners to provide a logo, a description, a website, as well as social link for their tokens. MultiversX products such as Explorer, Wallet and so on will display tokens in accordance to their branding, if any.

A token owner can submit a branding request by opening a Pull Request on https://github.com/multiversx/mx-assets.

Submitting a branding request

Token owners can create a PR to the https://github.com/multiversx/mx-assets with the logo in .png and .svg format, as well as a .json file containing all the relevant information.

Here’s a prefilled template for the .json file to get you started:

{
"website": "https://www.multiversxtoken.com",
"description": "MultiversX Token is a collection of 10.000 unique and randomly generated tokens.",
"social": {
"email": "mxt-token@multiversxtoken.com",
"blog": "https://www.multiversxtoken.com/MXT-token-blog",
"twitter": "https://twitter.com/MXT-token-twitter"
},
"status": "active"
}

Issuance of Non-Fungible Tokens

One has to perform an issuance transaction in order to register a non-fungible token. Non-Fungible Tokens are issued via a request to the Metachain, which is a transaction submitted by the Account which will manage the tokens. When issuing a token, one must provide a token name, a ticker and optionally additional properties. This transaction has the form:

IssuanceTransaction {
Sender: <account address of the token manager>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 50000000000000000 # (0.05 EGLD)
GasLimit: 60000000
Data: "issueNonFungible" +
"@" + <token name in hexadecimal encoding> +
"@" + <token ticker in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

Optionally, the properties can be set when issuing a token. Example:

IssuanceTransaction {
Sender: <account address of the token manager>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 50000000000000000 # (0.05 EGLD)
GasLimit: 60000000
Data: "issueNonFungible" +
"@" + <token name in hexadecimal encoding> +
"@" + <token ticker in hexadecimal encoding> +
"@" + <"canFreeze" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canWipe" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canPause" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canTransferNFTCreateRole" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canChangeOwner" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canUpgrade" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canAddSpecialRoles" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
...
}

For more details about how arguments have to be encoded, check here.

The receiver address erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u is a built-in system smart contract (not a VM-executable contract), which only handles token issuance and other token management operations, and does not handle any transfers. The contract will add a random string to the ticker thus creating the token identifier. The random string starts with “-” and has 6 more random characters. For example, a token identifier could look like ALC-6258d2.

Issuance of Semi-Fungible Tokens

One has to perform an issuance transaction in order to register a semi-fungible token. Semi-Fungible Tokens are issued via a request to the Metachain, which is a transaction submitted by the Account which will manage the tokens. When issuing a semi-fungible token, one must provide a token name, a ticker and optionally additional properties. This transaction has the form:

IssuanceTransaction {
Sender: <account address of the token manager>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 50000000000000000 # (0.05 EGLD)
GasLimit: 60000000
Data: "issueSemiFungible" +
"@" + <token name in hexadecimal encoding> +
"@" + <token ticker in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

Optionally, the properties can be set when issuing a token. Example:

IssuanceTransaction {
Sender: <account address of the token manager>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 50000000000000000 # (0.05 EGLD)
GasLimit: 60000000
Data: "issueSemiFungible" +
"@" + <token name in hexadecimal encoding> +
"@" + <token ticker in hexadecimal encoding> +
"@" + <"canFreeze" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canWipe" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canPause" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canTransferNFTCreateRole" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canChangeOwner" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canUpgrade" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canAddSpecialRoles" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
...
}

For more details about how arguments have to be encoded, check here.

The receiver address erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u is a built-in system smart contract (not a VM-executable contract), which only handles token issuance and other token management operations, and does not handle any transfers. The contract will add a random string to the ticker thus creating the token identifier. The random string starts with “-” and has 6 more random characters. For example, a token identifier could look like ALC-6258d2.

Issuance of Meta-ESDT Tokens

One has to perform an issuance transaction in order to register a Meta-ESDT token. Meta-ESDT Tokens are issued via a request to the Metachain, which is a transaction submitted by the Account which will manage the tokens. When issuing a semi-fungible token, one must provide a token name, a ticker and optionally additional properties. This transaction has the form:

IssuanceTransaction {
Sender: <account address of the token manager>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 50000000000000000 # (0.05 EGLD)
GasLimit: 60000000
Data: "registerMetaESDT" +
"@" + <token name in hexadecimal encoding> +
"@" + <token ticker in hexadecimal encoding> +
"@" + <number of decimals in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

Optionally, the properties can be set when issuing a token. Example:

IssuanceTransaction {
Sender: <account address of the token manager>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 50000000000000000 # (0.05 EGLD)
GasLimit: 60000000
Data: "registerMetaESDT" +
"@" + <token name in hexadecimal encoding> +
"@" + <token ticker in hexadecimal encoding> +
"@" + <number of decimals in hexadecimal encoding>
"@" + <"canFreeze" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canWipe" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canPause" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canTransferNFTCreateRole" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canChangeOwner" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canUpgrade" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
"@" + <"canAddSpecialRoles" hexadecimal encoded> + "@" + <"true" or "false" hexadecimal encoded> +
...
}

For more details about how arguments have to be encoded, check here.

The receiver address erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u is a built-in system smart contract (not a VM-executable contract), which only handles token issuance and other token management operations, and does not handle any transfers. The contract will add a random string to the ticker thus creating the token identifier. The random string starts with “-” and has 6 more random characters. For example, a token identifier could look like ALC-6258d2.

Converting an SFT into Meta-ESDT

An already existing semi-fungible token can be converted into a Meta-ESDT token if the owner sends the following transaction:

ConvertSftToMetaESDTTransaction {
Sender: <account address of the token manager>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 0
GasLimit: 60000000
Data: "changeSFTToMetaESDT" +
"@" + <token name in hexadecimal encoding> +
"@" + <number of decimals in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

Parameters format

Token Name:

  • length between 3 and 50 characters
  • alphanumeric characters only

Token Ticker:

  • length between 3 and 10 characters
  • alphanumeric UPPERCASE only

Issuance examples

For example, a user named Alice wants to issue an ESDT called "AliceTokens" with the ticker "ALC". The issuance transaction would be:

IssuanceTransaction {
Sender: erd1sg4u62lzvgkeu4grnlwn7h2s92rqf8a64z48pl9c7us37ajv9u8qj9w8xg
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 50000000000000000 # (0.05 EGLD)
GasLimit: 60000000
Data: "issueSemiFungible" +
"@416c696365546f6b656e73" +
"@414c43" +
}

For more details about how arguments have to be encoded, check here.

Once this transaction is processed by the Metachain, Alice becomes the designated manager of AliceTokens. She can add quantity later using ESDTNFTCreate. For more operations available to ESDT token managers, see Token management.

In that smart contract result, the data field will contain a transfer syntax which is explained below. What is important to note is that the token identifier can be fetched from here in order to use it for transfers. Alternatively, the token identifier can be fetched from the API (explained also in section REST API - Get NFT data ).

Roles

In order to be able to perform actions over a token, one needs to have roles assigned. The existing roles are:

For NFT:

  • ESDTRoleNFTCreate : this role allows one to create a new NFT
  • ESDTRoleNFTBurn : this role allows one to burn a specific NFT
  • ESDTRoleNFTUpdateAttributes : this role allows one to change the attributes of a specific NFT
  • ESDTRoleNFTAddURI : this role allows one add URIs for a specific NFT
  • ESDTTransferRole : this role enables transfer only to specified addresses. The addresses with the transfer role can transfer anywhere.
  • ESDTRoleNFTUpdate : this role allows one to update meta data attributes of a specific NFT
  • ESDTRoleModifyRoyalties : this role allows one to modify royalities of a specific NFT
  • ESDTRoleSetNewURI : this role allows one to set new uris of a specific NFT
  • ESDTRoleModifyCreator : this role allows one to rewrite the creator of a specific token
  • ESDTRoleNFTRecreate : this role allows one to recreate the whole NFT with new attributes

For SFT:

  • ESDTRoleNFTCreate : this role allows one to create a new SFT
  • ESDTRoleNFTBurn : this role allows one to burn quantity of a specific SFT
  • ESDTRoleNFTAddQuantity : this role allows one to add quantity of a specific SFT
  • ESDTTransferRole : this role enables transfer only to specified addresses. The addresses with the transfer role can transfer anywhere.
  • ESDTRoleNFTUpdate : this role allows one to update meta data attributes of a specific SFT
  • ESDTRoleModifyRoyalties : this role allows one to modify royalities of a specific SFT
  • ESDTRoleSetNewURI : this role allows one to set new uris of a specific SFT
  • ESDTRoleModifyCreator : this role allows one to rewrite the creator of a specific token
  • ESDTRoleNFTRecreate : this role allows one to recreate the whole NFT with new attributes

To see how roles can be assigned, please refer to this section.

Assigning roles

Roles can be assigned by sending a transaction to the Metachain from the ESDT manager.

Within a transaction of this kind, any number of roles can be assigned (minimum 1).

RolesAssigningTransaction {
Sender: <address of the ESDT manager>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 0
GasLimit: 60000000
Data: "setSpecialRole" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <address to assign the role(s) in a hexadecimal encoding> +
"@" + <role in hexadecimal encoding> +
"@" + <role in hexadecimal encoding> +
...
}

For more details about how arguments have to be encoded, check here.

For example, ESDTRoleNFTCreate = 45534454526f6c654e4654437265617465

Unset transactions are very similar. You can find an example here.

NFT/SFT fields

Below you can find the fields involved when creating an NFT.

NFT Name

  • The name of the NFT or SFT

Quantity

  • The quantity of the token. If NFT, it must be 1

Royalties

  • Allows the creator to receive royalties for any transaction involving their NFT
  • Base format is a numeric value between 0 an 10000 (0 meaning 0% and 10000 meaning 100%)

Hash

  • Arbitrary field that should contain the hash of the NFT metadata
  • Optional filed, should be left null when building the transaction to create the NFT

Attributes

  • Represents additional information about the NFT or SFT, like picture traits or tags for your NFT/collection
  • The field should follow a metadata:ipfsCID/fileName.json;tags:tag1,tag2,tag3 format
  • Below you can find a sample for the extra metadata format that should be stored on IPFS:
{
"description": "This is a sample description",
"attributes": [
{
"trait_type": "Background",
"value": "Yellow",
"{key}": "{value}",
"{...}": "{...}",
"{key}": "{value}"
},
{
"trait_type": "Headwear",
"value": "BlackBeanie"
},
{
"trait_type": "SampleTrait3",
"value": "SampleValue3"
}
],
"collection": "ipfsCID/fileName.json"
}

URI(s)

  • Mandatory field that represents the URL to a supported media file ending with the file extension as described in the example below
  • Field should contain the Uniform Resource Identifier

Note: As a best practice, we recommend storing the files for media & extra metadata(from attributes field) within same folder on your storage provider, ideally IPFS. Also, in order to have a thumbnail generated for the uploaded file the size of the file should be less or equal to 64MB.

important

Please note that each argument must be encoded in hexadecimal format with an even number of characters.

Supported Media Types

Below you can find a table with the supported media types for NFTs available on MultiversX network.

Media ExtensionMedia Type
.pngimage/png
.jpegimage/jpeg
.jpgimage/jpg
.gifimage/gif
.webpimage/webp
.svgimage/svg
.svgimage/svg+xml
.accaudio/acc
.flacaudio/flac
.m4aaudio/m4a
.mp3audio/mp3
.wavaudio/wav
.movvideo/mov
.quicktimevideo/quicktime
.mp4video/mp4
.webmvideo/webm

Example

Below you can find a table representing an example of the fields for a non-fungible token that resembles a song.

PropertyPlain valueEncoded value
NFT NameBeautiful song42656175746966756c20736f6e67
Quantity101
Royalties7500 =75%1d4c
Hash0000
Attributesmetadata:ipfsCID/song.json;tags:song,beautiful,music6d657461646174613a697066734349442f736f6e672e6a736f6e3b746167733a736f6e672c62656175746966756c2c6d75736963
URIURL_to_decentralized_storage/song.mp355524c5f746f5f646563656e7472616c697a65645f73746f726167652f736f6e672e6d7033

In this example we are creating a NFT representing a song. Hash is left null, we are sharing media location URL and we are also providing the location of the extra metadata within the attributes field.

Creation of an NFT

A single address can own the role of creating an NFT for an ESDT token. This role can be transferred by using the ESDTNFTCreateRoleTransfer function.

An NFT can be created on top of an existing ESDT by sending a transaction to self that contains the function call that triggers the creation. Any number of URIs can be assigned (minimum 1)

NFTCreationTransaction {
Sender: <address with ESDTRoleNFTCreate role>
Receiver: <same as sender>
Value: 0
GasLimit: 3000000 + Additional gas (see below)
Data: "ESDTNFTCreate" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <initial quantity in hexadecimal encoding> +
"@" + <NFT name in hexadecimal encoding> +
"@" + <Royalties in hexadecimal encoding> +
"@" + <Hash in hexadecimal encoding> +
"@" + <Attributes in hexadecimal encoding> +
"@" + <URI in hexadecimal encoding> +
"@" + <URI in hexadecimal encoding> +
...
}

For more details about how arguments have to be encoded, check here.

Additional gas refers to:

  • Transaction payload cost: Data field length * 1500 (GasPerDataByte = 1500)
  • Storage cost: Size of NFT data * 50000 (StorePerByte = 50000)

To see more about the required fields, please refer to this section.

tip

Note that because NFTs are stored in accounts trie, every transaction involving the NFT will require a gas limit depending on NFT data size.

Most of the times you will be able to create the NFTs by issuing one single transaction. This assumes that the metadata file as well as the NFT media is already uploaded to IPFS.

There are times, however, when uploading the metadata file before issuing the NFT is not possible (eg. when issued from a smart contract) In these cases it is possible to update an NFT with the metadata file after it was issued by sending an additional transaction. You can find more information here about how to update the attributes

Other management operations

Managing non-fungible tokens (NFTs) and semi-fungible tokens (SFTs) presents a greater degree of complexity compared to the management of simple fungible tokens. These unique tokens require specialized transactions for proper identification, ownership, and transfer, making the process of managing them more intricate than that of fungible tokens.

Transfer NFT Creation Role

tip

This role can be transferred only if the canTransferNFTCreateRole property of the token is set to true.

The role of creating an NFT can be transferred by a Transaction like this:

TransferCreationRoleTransaction {
Sender: <address of the current creation role owner>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 0
GasLimit: 60000000 + length of Data field in bytes * 1500
Data: "transferNFTCreateRole" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <the address to transfer the role from in hexadecimal encoding> +
"@" + <the address to transfer the role to in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

Stop NFT creation

The ESDT manager can stop the creation of an NFT for the given ESDT forever by removing the only ESDTRoleNFTCreate role available. This is done by performing a transaction like this:

StopNFTCreationTransaction {
Sender: <account address of the token manager>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 0
GasLimit: 60000000
Data: "stopNFTCreate" +
"@" + <token identifier in hexadecimal encoding> +
}

For more details about how arguments have to be encoded, check here.

Change NFT Attributes

An user that has the ESDTRoleNFTUpdateAttributes role set for a given ESDT, can change the attributes of a given NFT/SFT.

tip

ESDTNFTUpdateAttributes will remove the old attributes and add the new ones. Therefore, if you want to keep the old attributes you will have to pass them along with the new ones.

This is done by performing a transaction like this:

ESDTNFTUpdateAttributesTransaction {
Sender: <address of an address that has ESDTRoleNFTUpdateAttributes role>
Receiver: <same as sender>
Value: 0
GasLimit: 10000000
Data: "ESDTNFTUpdateAttributes" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <NFT or SFT nonce in hexadecimal encoding> +
"@" + <Attributes in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

To see how you can assign this role in case it is not set, please refer to this section.

Add URIs to NFT

An user that has the ESDTRoleNFTAddURI role set for a given ESDT, can add uris to a given NFT/SFT. This is done by performing a transaction like this:

ESDTNFTAddURITransaction {
Sender: <address of an address that has ESDTRoleNFTAddURI role>
Receiver: <same as sender>
Value: 0
GasLimit: 10000000
Data: "ESDTNFTAddURI" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <NFT or SFT nonce in hexadecimal encoding> +
"@" + <URI in hexadecimal encoding> +
"@" + <URI in hexadecimal encoding> +
...
}

For more details about how arguments have to be encoded, check here.

To see how you can assign this role in case it is not set, please refer to this section.

Add quantity (SFT only)

A user that has the ESDTRoleNFTAddQuantity role set for a given Semi-Fungible Token, can increase its quantity. This function will not work for NFTs, because in that case the quantity cannot be higher than 1.

AddQuantityTransaction {
Sender: <address of an address that has ESDTRoleNFTAddQuantity role>
Receiver: <same as sender>
Value: 0
GasLimit: 10000000
Data: "ESDTNFTAddQuantity" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <SFT nonce in hexadecimal encoding>
"@" + <quantity to add in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

If successful, the balance of the address for the given SFT will be increased with the number specified in the argument.

Burn quantity

A user that has the ESDTRoleNFTBurn role set for a given semi-fungible Token, can burn some (or all) of the quantity.

BurnQuantityTransaction {
Sender: <address of an address that has ESDTRoleNFTBurn role>
Receiver: <same as sender>
Value: 0
GasLimit: 10000000
Data: "ESDTNFTBurn" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <SFT nonce in hexadecimal encoding>
"@" + <quantity to burn in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

If successful, the quantity from the argument will be decreased from the balance of the address for that given token.

Freezing and Unfreezing a single NFT

The manager of an ESDT token may freeze the NFT held by a specific Account. As a consequence, no NFT can be transferred to or from the frozen Account. Freezing and unfreezing a single NFT of an Account are operations designed to help token managers to comply with regulations. The transaction that freezes a single NFT of an Account has the form:

FreezeTransaction {
Sender: <account address of the token manager>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 0
GasLimit: 60000000
Data: "freezeSingleNFT" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <NFT nonce in hexadecimal encoding>
"@" + <account address to freeze in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

The reverse operation, unfreezing, will allow further transfers to and from the Account:

UnfreezeTransaction {
Sender: <account address of the token manager>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 0
GasLimit: 60000000
Data: "unFreezeSingleNFT" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <NFT nonce in hexadecimal encoding> +
"@" + <account address to unfreeze in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

Wiping a single NFT

The manager of an ESDT token may wipe out a single NFT held by a frozen Account. This operation is similar to burning the quantity, but the Account must have been frozen beforehand, and it must be done by the token manager. Wiping the tokens of an Account is an operation designed to help token managers to comply with regulations. Such a transaction has the form:

WipeTransaction {
Sender: <account address of the token manager>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 0
GasLimit: 60000000
Data: "wipeSingleNFT" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <NFT nonce in hexadecimal encoding> +
"@" + <account address to wipe in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

Modify Royalties

The manager of an ESDT token may want to set new royalities. This operation will rewrite the royalities on the specified token ID. It requires ESDTRoleNFTModifyRoyalties role. This is done by performing a transaction like this:

ModifyRoyalitiesTransaction {
Sender: <account address of the token manager>
Receiver: <same as sender>
Value: 0
GasLimit: 60000000
Data: "ESDTModifyRoyalties" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <token nonce in hexadecimal encoding> +
"@" + <new royalties in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

Set new URIs

The manager of an ESDT token may want to set new URIs. This operation will rewrite the URIs on the specified token ID. It requires ESDTRoleNFTSetNewURIs role. This is done by performing a transaction like this:

SetNewURIsTransaction {
Sender: <account address of the token manager>
Receiver: <same as sender>
Value: 0
GasLimit: 60000000
Data: "ESDTSetNewURIs" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <token nonce in hexadecimal encoding> +
"@" + <new URI1 in hexadecimal encoding> +
"@" + <new URI2 in hexadecimal encoding> +
...
}

For more details about how arguments have to be encoded, check here.

Modify Creator

The creator of a token can be changed. For this, the token has to be moved to the new creator account. The new creator account requires ESDTRoleModifyCreator role. Also, the token has to be of dynamic type in order for this to work.

The creator can be modified using a transaction like this:

ModifyCreatorTransaction {
Sender: <account address of the new creator that has `ESDTRoleModifyCreator` role>
Receiver: <same as sender>
Value: 0
GasLimit: 60000000
Data: "ESDTModifyCreator" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <token nonce in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

MetaData Update

The manager of an ESDT token may want to update token metadata. This operation will update token metadata on the specified token ID. It requires ESDTRoleNFTUpdate role. If nothing is received for a given attribute, the old version of that attribute will be kept.

This is done by performing a transaction like this:

MetaDataUpdateTransaction {
Sender: <account address that has `ESDTRoleNFTUpdate` role>
Receiver: <same as sender>
Value: 0
GasLimit: 60000000
Data: "ESDTMetaDataUpdate" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <token nonce in hexadecimal encoding> +
"@" + <token name in hexadecimal encoding> +
"@" + <royalities in hexadecimal encoding> +
"@" + <hash in hexadecimal encoding> +
"@" + <attributes in hexadecimal encoding> +
"@" + <uris list in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

MetaData Recreate

The whole NFT can be recreated with new attributes using a transaction like this:

The manager of an ESDT token may want to recreate the whole token with new attributes. This operation will recreate token attributes on the specified token ID. It requires ESDTRoleNFTRecreate role. If an argument is not being set, that field is set to zero.

This is done by performing a transaction like this:

MetaDataRecreateTransaction {
Sender: <account address that has `ESDTRoleNFTRecreate` role>
Receiver: <same as sender>
Value: 0
GasLimit: 60000000
Data: "ESDTMetaDataRecreate" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <NFT nonce in hexadecimal encoding> +
"@" + <token name in hexadecimal encoding> +
"@" + <royalities in hexadecimal encoding> +
"@" + <hash in hexadecimal encoding> +
"@" + <attributes in hexadecimal encoding> +
"@" + <uris list in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

Make token dynamic

The ESDT manager can change token type to dynamic using a transaction like this:

ChangeToDynamicTransaction {
Sender: <account address of the token manager>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 0
GasLimit: 60000000
Data: "changeToDynamic" +
"@" + <token identifier in hexadecimal encoding>
}

The following token types cannot be changed to dynamic: FungibleESDT, NonFungibleESDT, NonFungibleESDTv2

For more details about how arguments have to be encoded, check here.

Update token

The token type can be updated to the latest version, which will update token type and propagate it to shard's system account. Currently, token type is correctly saved only on metachain and there is no type related information on shard level, the shard only knows if the token is non fungible with implicit type NonFungibleESDT, but it does not know specifically if it's NonFungibleESDT, MetaESDT or SemiFungibleESDT. So, the update operation will proceed in the following way:

  • if token type is NonFungibleESDT it will be set to NonFungibleESDTv2, and it will be propagated to shard's system account
  • if token type is MetaESDT or SemiFungibleESDT it will be propagated to shard's system account

This can be done using a transaction like this:

UpdateTokenIDTransaction {
Sender: <account address of the token manager>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 0
GasLimit: 60000000
Data: "updateTokenID" +
"@" + <token identifier in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

Register dynamic token

A token can be registered directly as dynamic.

This can be done using a transaction like this:

RegisterDynamicTransaction {
Sender: <account address of the token manager>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 50000000000000000 # (0.05 EGLD)
GasLimit: 60000000
Data: "registerDynamic" +
"@" + <token name in hexadecimal encoding> +
"@" + <token ticker in hexadecimal encoding> +
"@" + <token compressed type (which can be `NFT`, `SFT`, `META`) in hexadecimal encoding>
# For META token type only
"@" + <denominator in hexadecimal encoding>
# (number of decimals)
}

The following token types cannot be registered as dynamic: FungibleESDT

Register and set all roles to dynamic

A token can be registered directly as dynamic together will all roles set for the specific type.

This can be done using a transaction like this:

RegisterAndSetAllRolesDynamicTransaction {
Sender: <account address of the token manager>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 50000000000000000 # (0.05 EGLD)
GasLimit: 60000000
Data: "registerAndSetAllRolesDynamic" +
"@" + <token name in hexadecimal encoding> +
"@" + <token ticker in hexadecimal encoding> +
"@" + <token compressed type (which can be `NFT`, `SFT`, `META`) in hexadecimal encoding> +
# For META token type only
"@" + <denominator in hexadecimal encoding>
# (number of decimals)
}

The following token types cannot be registered as dynamic: FungibleESDT

Transferring token management rights

The manager of an ESDT token can transfer the ownership if the ESDT was created as upgradable. Check the ESDT - Upgrading (changing properties) section for more details.

Upgrading (changing properties)

The manager of an ESDT token may individually change any of the properties of the token, or multiple properties at once, only if the ESDT was created as upgradable. Check the ESDT - Transferring token management rights section for more details.

Transfers

Performing an ESDT NFT transfer is done by specifying the receiver's address inside the Data field, alongside other details. An ESDT NFT transfer transaction has the following form:

TransferTransaction {
Sender: <account address of the sender>
Receiver: <same as sender>
Value: 0
GasLimit: 1000000 + length of Data field in bytes * 1500
Data: "ESDTNFTTransfer" +
"@" + <collection identifier in hexadecimal encoding> +
"@" + <the NFT nonce in hexadecimal encoding> +
"@" + <quantity to transfer in hexadecimal encoding> +
"@" + <destination address in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

tip

Here is an example of an NFT identifier: ABC-1a9c7d-05dc

The collection identifier is ABC-1a9c7d and the NFT nonce is 05dc. Note that the 05dc is hexadecimal encoded, it represents decimal 1500.

Also note that a MultiversX address is in bech32, so you will need to convert the address from bech32 to hexadecimal. This can be done with the hex() method of mx-sdk-js-core for address (all the methods for addresses can be found here) or manually with an external converter which you can find here.

Transfers to a Smart Contract

To perform the transfer from your account to the smart contract, you have to use the following transaction format:

TransferTransaction {
Sender: <account address of the sender>
Receiver: <same as sender>
Value: 0
GasLimit: 1000000 + extra for smart contract call
Data: "ESDTNFTTransfer" +
"@" + <collection identifier in hexadecimal encoding> +
"@" + <the nonce after the NFT creation in hexadecimal encoding> +
"@" + <quantity to transfer in hexadecimal encoding> +
"@" + <destination address in hexadecimal encoding> +
"@" + <name of method to call in hexadecimal encoding> +
"@" + <first argument of the method in hexadecimal encoding> +
"@" + <second argument of the method in hexadecimal encoding> +
<...>
}

For more details about how arguments have to be encoded, check here.

Multiple tokens transfer

Multiple semi-fungible and/or non-fungible tokens can be transferred in a single transaction to a single receiver.

More details can be found here.

Example flow

Let's see a complete flow of creating and transferring a Semi-Fungible Token.

Step 1: Issue/Register a Semi-Fungible Token

{
Sender: <your address>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 50000000000000000 # 0.05 EGLD
GasLimit: 60000000
Data: "issueSemiFungible" +
"@416c696365546f6b656e73" + # AliceTokens
"@414c43" + # ALC
}

For more details about how arguments have to be encoded, check here.

Step 2: Fetch the token identifier

For doing this, one has to check the previously sent transaction and see the Smart Contract Result of it. It will look similar to @ok@414c432d317132773365. The 414c432d317132773365 represents the token identifier in hexadecimal encoding.

Step 3: Set roles

Assign ESDTRoleNFTCreate and ESDTRoleNFTAddQuantity roles to an address. You can set these roles to your very own address.

{
Sender: <your address>
Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
Value: 0
GasLimit: 60000000
Data: "setSpecialRole" +
"@414c432d317132773365" + # previously fetched token identifier
"@" + <address to assign the roles in a hexadecimal encoding> +
"@45534454526f6c654e4654437265617465" + # ESDTRoleNFTCreate
"@45534454526f6c654e46544164645175616e74697479" # ESDTRoleNFTAddQuantity
...
}

For more details about how arguments have to be encoded, check here.

Step 4: Create NFT

Now, the NFT creation transaction for the example case defined here looks like this:

{
Sender: <address with ESDTRoleNFTCreate role>
Receiver: <same as sender>
Value: 0
GasLimit: 3000000
Data: "ESDTNFTCreate" +
"@414c432d317132773365" + # previously fetched token identifier
"@01" + # quantity: 1
"@42656175746966756c20736f6e67" + # NFT name: 'Beautiful song' in hexadecimal encoding
"@1d4c" + # Royalties: 7500 =75%c in hexadecimal encoding
"@00" + # Hash: 00 in hexadecimal encoding
"@6d657461646174613a697066734349442f736f6e672e6a736f6e3b746167733a736f6e672c62656175746966756c2c6d75736963" + # Attributes: metadata:ipfsCID/song.json;tags:song,beautiful,music in hexadecimal encoding> +
"@55524c5f746f5f646563656e7472616c697a65645f73746f726167652f736f6e672e6d7033" + # URI: URL_to_decentralized_storage/song.mp3 in hexadecimal encoding> +
"@" + <additional optional URI in hexadecimal encoding> +
}

For more details about how arguments have to be encoded, check here.

tip

Note that the nonce is very important when creating an NFT. You must save the nonce after NFT creation because you will need it for further actions.

The NFT nonce is different from the creator's nonce.

It can be fetched by viewing all the tokens for the address via API.

Step 5: Transfer

{
Sender: <your address>
Receiver: <same as sender>
Value: 0
GasLimit: 1000000 + length of Data field in bytes * 1500
Data: "ESDTNFTTransfer" +
"@414c432d317132773365" + # previously fetched token identifier
"@" + <the nonce saved above in hexadecimal encoding> +
"@" + <quantity to transfer in hexadecimal encoding> +
"@" + <destination address in hexadecimal encoding>
}

For more details about how arguments have to be encoded, check here.

REST API

There are a number of API endpoints that one can use to interact with ESDT NFT data. These are:

GET Get NFT data for an address

Returns the balance of an address for specific ESDT Tokens.

https://gateway.multiversx.com/address/<bech32Address>/nft/<tokenIdentifier>/nonce/<creation-nonce>
ParamRequiredTypeDescription
bech32AddressREQUIREDstringThe Address to query in bech32 format.
tokenIdentifierREQUIREDstringThe token identifier.
nonceREQUIREDnumericThe nonce after the NFT creation.

GET Get NFTs/SFTs registered by an address

Returns the identifiers of the tokens that have been registered by the provided address.

https://gateway.multiversx.com/address/<bech32Address>/registered-nfts
ParamRequiredTypeDescription
bech32AddressREQUIREDstringThe Address to query in bech32 format.

GET Get tokens where an address has a given role

Returns the identifiers of the tokens where the given address has the given role.

https://gateway.multiversx.com/address/<bech32Address>/esdts-with-role/<role>
ParamRequiredTypeDescription
bech32AddressREQUIREDstringThe Address to query in bech32 format.
roleREQUIREDstringThe role to query for.

The role can be one of the roles specified in the documentation (for example: ESDTRoleNFTCreate)

GET Parse non/semi fungible tokens transfer logs

Each successful nft/sft transfer generates logs and events that can be used to parse all the details about a transfer (token identifier, sent amount and receiver). In order to get the logs and events generated by the transfer, one should know the transaction's hash.

ParamRequiredTypeDescription
txHashREQUIREDstringThe hash of the transaction
https://gateway.multiversx.com/transaction/*txHash*?withResults=true

GET Get all ESDT tokens for an address

One can use get all esdt tokens for an address endpoint used for ESDT.

GET Get all issued ESDT tokens

One can use get all issued esdt tokens endpoint used for ESDT.

POST Get ESDT properties

Properties can be queried via the getTokenProperties function provided by ESDT.

POST Get special roles

Special roles can be queried via the getSpecialRoles function provided by ESDT.