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.
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 Extension | Media Type |
---|---|
.png | image/png |
.jpeg | image/jpeg |
.jpg | image/jpg |
.gif | image/gif |
.webp | image/webp |
.svg | image/svg |
.svg | image/svg+xml |
.acc | audio/acc |
.flac | audio/flac |
.m4a | audio/m4a |
.mp3 | audio/mp3 |
.wav | audio/wav |
.mov | video/mov |
.quicktime | video/quicktime |
.mp4 | video/mp4 |
.webm | video/webm |
Example
Below you can find a table representing an example of the fields for a non-fungible token that resembles a song.
Property | Plain value | Encoded value |
---|---|---|
NFT Name | Beautiful song | 42656175746966756c20736f6e67 |
Quantity | 1 | 01 |
Royalties | 7500 =75% | 1d4c |
Hash | 00 | 00 |
Attributes | metadata:ipfsCID/song.json;tags:song,beautiful,music | 6d657461646174613a697066734349442f736f6e672e6a736f6e3b746167733a736f6e672c62656175746966756c2c6d75736963 |
URI | URL_to_decentralized_storage/song.mp3 | 55524c5f746f5f646563656e7472616c697a65645f73746f726167652f736f6e672e6d7033 |
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.
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
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.
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 toNonFungibleESDTv2
, and it will be propagated to shard's system account - if token type is
MetaESDT
orSemiFungibleESDT
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.
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.
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
- Request
- Response
Returns the balance of an address for specific ESDT Tokens.
https://gateway.multiversx.com/address/<bech32Address>/nft/<tokenIdentifier>/nonce/<creation-nonce>
Param | Required | Type | Description |
---|---|---|---|
bech32Address | REQUIRED | string | The Address to query in bech32 format. |
tokenIdentifier | REQUIRED | string | The token identifier. |
nonce | REQUIRED | numeric | The nonce after the NFT creation. |
{
"data": {
"tokenData": {
"attributes": "YXR0cmlidXRl",
"balance": "2",
"creator": "erd1ukn0tukrdhuv0zzxn0zlr53g7h0fr68dz9dd56mkksev59nwuvnswnlyuy",
"hash": "aGFzaA==",
"name": "H",
"nonce": 1,
"properties": "",
"royalties": "9000",
"tokenIdentifier": "4W97C-32b5ce",
"uris": ["bmZ0IHVyaQ=="]
}
},
"error": "",
"code": "successful"
}
GET Get NFTs/SFTs registered by an address
- Request
- Response
Returns the identifiers of the tokens that have been registered by the provided address.
https://gateway.multiversx.com/address/<bech32Address>/registered-nfts
Param | Required | Type | Description |
---|---|---|---|
bech32Address | REQUIRED | string | The Address to query in bech32 format. |
{
"data": {
"tokens": ["ABC-36tg72"]
},
"error": "",
"code": "successful"
}
GET Get tokens where an address has a given role
- Request
- Response
Returns the identifiers of the tokens where the given address has the given role.
https://gateway.multiversx.com/address/<bech32Address>/esdts-with-role/<role>
Param | Required | Type | Description |
---|---|---|---|
bech32Address | REQUIRED | string | The Address to query in bech32 format. |
role | REQUIRED | string | The role to query for. |
The role can be one of the roles specified in the documentation (for example: ESDTRoleNFTCreate)
{
"data": {
"tokens": ["ABC-36tg72"]
},
"error": "",
"code": "successful"
}
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.
- Request
- Response
Param | Required | Type | Description |
---|---|---|---|
txHash | REQUIRED | string | The hash of the transaction |
https://gateway.multiversx.com/transaction/*txHash*?withResults=true
{
"data": {
"transaction": {
...
"logs": {
"address": "...",
"events": [
{
"address": "...",
"identifier": "ESDTNFTTransfer",
"topics": [
"VFNGVC1jODY3ZzM=", // TSFT-c867g3
"CEI=", // 2114
"Ag==", // 2
"givNK+JiLZ5VA5/dP11QKoYEn7qoqnD8uPchH3ZMLw4=" // erd1sg4u62lzvgkeu4grnlwn7h2s92rqf8a64z48pl9c7us37ajv9u8qj9w8xg
],
"data": null
},
}
}
"error": "",
"code": "successful"
}
The event with the identifier ESDTNFTTransfer
will have the following topics:
- 1st topic: token identifier (decoding: base64 to string)
- 2nd topic: token nonce (decoding: base64 to hex string + hex string to big number / integer)
- 3rd topic: the amount to be sent (decoding: base64 to hex string + hex string to big number)
- 4th topic: the recipient of the tokens (decoding: base64 to hex string + hex string to bech32 address)
In this example, erd1sg4u62lzvgkeu4grnlwn7h2s92rqf8a64z48pl9c7us37ajv9u8qj9w8xg
received 2 tokens of the collection
TSFT-c867g3
with nonce 2114
.
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.