Frontend dApp

In this section, you will create a frontend dApp that allows users to deposit native tokens on connected chains to mint NFTs on ZetaChain, view their collection, burn NFTs to withdraw native tokens from ZetaChain and transfer NFTs to other addresses on ZetaChain.

This UI is built as part of the example frontend project (opens in a new tab), but you can replicate it in your own project.

Frontend dApp

  • Complete the NFT Omnichain Contract tutorial. Make sure that you've configured Goldsky to index events from your contract.

The entry point of the frontend dApp is the NFTPage component. It is responsible for rendering the page layout and the widgets that trigger broadcasting of transactions.

The NFTPage component uses the useNFT hook to access the state of the frontend dApp. The useNFT hook is responsible for managing the state of the frontend dApp and for broadcasting transactions.

On component load the NFTPage component calls the fetchNFTs function to fetch the NFTs owned by the connected address.


useNFT is a simple component that stores the state of the frontend dApp.


The hook is responsible for fetching NFTs owned by the connected address.

Set the constant to store the URL of the subgraph that you deployed in the previous section.

Goldsky is a subgraph indexer that uses GraphQL to query events from your contract. Write a query that fetches all Transfer events. You're interested in transfers that were sent to or from a specific address. In the body of the query specify the fields your're interested in.

The function to fetch NFT makes a GraphQL request to the subgraph to fetch the transfer events. The function then filters the events to find the NFTs that are currently owned by the address by checking which NFTs were sent to the addres and which NFTs were sent from the address.

Since you're using the default ERC-721 Transfer event, you only have the tokenId field that contains the ID of the NFT. You will need to query the contract to get the chain ID and the amount of the NFT.

To correctly format the amount of tokens in NFTs, you to know the number of decimals of the corresponding ZRC-20 token. Query the foreign coins endpoints to find the decimals and use to correctly format the amounts.

Finally, sort NFTs by ID in descending order.


To mint an NFT on ZetaChain you need to deposit native tokens on a connected chain to the TSS address.

For Bitcoin use the supported XDEFI wallet. Format the request correctly with the recipient (TSS address), amount (in sats) and memo (the address that will receive the NFT on ZetaChain), and call the request method.

For EVM chains, just use sendTransaction to send a token transfer transaction to the TSS address with the amount of tokens that you want to deposit and the recipient address in the data field.

Next, if the transaction was successful, use the transaction hash to track the progress of the cross-chain transaction.


Burning NFTs happens on ZetaChain. To burn an NFT, you need to approve an NFT first, then call the burn method on the omnichain contract. The burn method takes the ID of the NFT as an argument.

Due to fluctuating gas prices, a transaction might fail. To make sure that the user has best experience possible, implement a recursive check for approval. This function will check if a user has approved the omnichain contract to burn an NFT. If the user has not approved the contract, the function will ask for an approval. Implement a similar function to check for ownership of the NFT.

In the body of the function call the approval function, once the approval is received, call burn the NFT and start checking for ownership. As soon as the user is no longer the owner of the NFT, update the frontend dApp state.


Transferring NFTS happens on ZetaChain and does not invlove any cross-chain interactions. Simple call the contract's transfer method and pass the recipient, the sender and the ID of the NFT.


You've successfully created a frontend dApp that allows users to mint, burn and transfer NFTs on ZetaChain.