Docs

Docs

  • Develop
  • Validate
  • Integrate
  • Learn

›Developers

Welcome to Elrond

  • Welcome to Elrond

Technology

  • Architecture Overview
  • Entities
  • Chronology
  • Secure Proof of Stake
  • Adaptive State Sharding
  • The Arwen WASM VM
  • Cross Shard Transactions

Wallet

  • Web Wallet
  • Ledger

Validators

  • Overview
  • System Requirements
  • Install a Mainnet Node

    • Scripts & User config
    • Installing a Validator Node
    • Optional Configurations
    • How to use the Docker Image

    Install a Testnet Node

    • Scripts & User config
    • Installing & updating
    • Manage your testnet node

    Install a Devnet Node

    • Scripts & User config
    • Installing & updating
    • Manage your devnet node

    Manage your keys

    • Validator Keys
    • Wallet Keys
    • Protecting your keys

    Staking, Unstaking, Unjailing

    • Staking, unstaking and unjailing
    • Staking
    • Unjailing
    • The Staking Smart Contract
  • The Delegation Manager
  • Rating
  • Node redundancy
  • Node CLI
  • Useful Links & Tools
  • FAQs

Developers

    Tutorials

    • The Counter Smart Contract
    • Start Building - Crowdfunding Tutorial
    • The Crowdfunding Smart Contract (part 2)

    Signing Transactions

    • Signing Transactions
    • Tools for signing
    • Signing programmatically

    Developer reference

    • Mandos tests reference
    • The Elrond Serialization Format
  • ESDT tokens
  • NFT tokens
  • Setup a Local Testnet
  • Setup a Local Testnet (advanced)
  • Creating Wallets

SDK and Tools

    REST API

    • REST API
    • Addresses
    • Transactions
    • Network
    • Nodes
    • Blocks
    • Virtual Machine
    • Versions and Changelog
  • Proxy
  • erdpy

    • erdpy
    • Installing erdpy
    • Configuring erdpy
    • erdpy CLI
    • Deriving the Wallet PEM file
    • Sending bulk transactions
    • Writing and running erdpy scripts
  • erdjs
  • erdgo
  • erdjava
  • erdwalletjs-cli

Integrators

  • Observing Squad
  • Accounts Management
  • Creating Transactions
  • Querying the Blockchain

Detailed comparison

  • Overview
  • Elrond vs. Ethereum Serenity
  • Elrond vs. Zilliqa
  • Elrond vs. Dfinity
  • Elrond vs. Algorand
  • Elrond vs. Harmony

NFT tokens

important

NFTs aren't enabled yet on Elrond Mainnet. See testnet or devnet

Introduction

The Elrond protocol introduces native NFT support by adding metadata and attributes on top of the already existing ESDT. 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, such as a changeable 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 are:

  • attributes
  • balance
  • creator
  • hash
  • name
  • properties
  • royalties
  • tokenIdentifier
  • URIs

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)

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: 5000000000000000000 (5 eGLD)
    GasLimit: 60000000
    Data: "issueNonFungible" +
          "@" + <token name in hexadecimal encoding> +
          "@" + <token ticker in hexadecimal encoding>
}

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

IssuanceTransaction {
    Sender: <account address of the token manager>
    Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
    Value: 5000000000000000000 (5 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>
}

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, the initial quantity and optionally additional properties. This transaction has the form:

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

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

IssuanceTransaction {
    Sender: <account address of the token manager>
    Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u
    Value: 5000000000000000000 (5 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>
}

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.

Parameters format

Token Name:

  • length between 3 and 20 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: 5000000000000000000
    GasLimit: 60000000
    Data: "issueSemiFungible" +
          "@416c696365546f6b656e73" +
          "@414c43" +
}

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:

  • ESDTRoleNFTCreate : this role allows one to create a new NFT/SFT
  • ESDTRoleNFTAddQuantity : this role allows one to add quantity of a specific NFT/SFT
  • ESDTRoleNFTBurn : this role allows one to burn quantity of a specific NFT/SFT

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 example, ESDTRoleNFTCreate = 45534454526f6c654e4654437265617465

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: 60000000
    Data: "ESDTNFTCreate" +
          "@" + <token identifier in hexadecimal encoding> +
          "@" + <initial quantity in hexadecimal encoding> +
          "@" + <NFT name in hexadecimal econding> +
          "@" + <Royalties in hexadecimal encoding> +
          "@" + <Hash in hexadecimal encoding> +
          "@" + <Attributes in hexadecimal encoding> +
          "@" + <URI in hexadecimal encoding> +
          "@" + <URI in hexadecimal encoding> +
          ...
}

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: 500000 + length of Data field in bytes * 1500
    Data: "ESDTNFTCreateRoleTransfer" +
          "@" + <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> 
}

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: 500000 + length of Data field in bytes * 1500
    Data: "ESDTNFTTransfer" +
          "@" + <token identifier in hexadecimal encoding> +
          "@" + <the nonce after the NFT creation in hexadecimal encoding> + 
          "@" + <quantity to transfer in hexadecimal encoding> +
          "@" + <destination address in hexadecimal encoding>
}

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: 500000 + extra for smart contract call
    Data: "ESDTNFTTransfer" +
          "@" + <token 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> + 
          <...>
}

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: 5000000000000000000  # 5 eGLD
    GasLimit: 60000000
    Data: "issueSemiFungible" +
          "@416c696365546f6b656e73" + # AliceTokens
          "@414c43" +                 # ALC
}

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
          ...
}

Step 4: Create NFT

Fill all the attributes as you think.

{
    Sender: <address with ESDTRoleNFTCreate role>
    Receiver: <same as sender>
    Value: 0
    GasLimit: 60000000
    Data: "ESDTNFTCreate" +
          "@414c432d317132773365" +   # previously fetched token identifier
          "@" + <initial quantity in hexadecimal encoding> +
          "@" + <NFT name in hexadecimal econding> +
          "@" + <Royalties in hexadecimal encoding> +
          "@" + <Hash in hexadecimal encoding> +
          "@" + <Attributes in hexadecimal encoding> +
          "@" + <URI in hexadecimal encoding> +
          "@" + <URI in hexadecimal encoding> +
}
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. For example, if Alice has nonce 5 before sending the nft creation transaction, nonce 6 must be used in further actions.

Also, the nonce 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: 500000 + 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>
}

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://api.elrond.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.
{
"data": {
"tokenData": {
"attributes": "YXR0cmlidXRl",
"balance": "2",
"creator": "erd1ukn0tukrdhuv0zzxn0zlr53g7h0fr68dz9dd56mkksev59nwuvnswnlyuy",
"hash": "aGFzaA==",
"name": "H",
"properties": "",
"royalties": "9000",
"tokenIdentifier": "4W97C-32b5ce",
"uris": [
"bmZ0IHVyaQ=="
]
}
},
"error": "",
"code": "successful"
}

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

One can use get esdt properties endpoint used for ESDT.

← ESDT tokensSetup a Local Testnet →
  • Introduction
  • Issuance of Non Fungible Tokens
  • Issuance of Semi Fungible Tokens
  • Parameters format
  • Issuance examples
  • Roles
  • Assigning roles
  • Creation of an NFT
    • Transfer NFT Creation Role
  • Transfers
  • Transfers to a Smart Contract
  • Example flow
  • Rest API
    • GET Get NFT data for an address
    • GET Get all ESDT tokens for an address
    • GET Get all issued ESDT tokens
    • POST Get ESDT properties
Made withby the Elrond team.
GithubChat
Main siteWalletExplorerBridgeDocsGrowthMaiar