Comment on page
How to Create and Deploy an XRC721 NFT Using Remix
Use Remix IDE to deploy an XRC721 Token.
Remix IDE is a blockchain development environment, which you can use to create and test smart contracts by levering an Ethereum Virtual Machine.
In this tutorial, you will learn how to set up Remix IDE and use it to build, test and deploy a XRC721 Token on both the XDC Network mainnet and XDC Apothem testnet.
- Setup Remix IDE
- Create an XRC721 token
- Compile the XRC721 token
- Deploy the XRC721 token
- Interact with the XRC721 token
XRC721 is a set of rules to standardize assets on the XDC network. Every XRC721 Token must be able to execute the following methods:
safeTransferFrom(address from, address to, uint256 tokenId)
transferFrom(address from, address to, uint256 tokenId)
approve(address to, uint256 tokenId)
getApproved(uint256 tokenId)
setApprovalForAll(address operator, bool _approved)
isApprovedForAll(address owner, address operator)
These are the minimum required methods that allow an asset on the XDC Network to be called an XRC721 token. Also, an XRC721 token must be able to emit the following
Events
on the blockchain:Approval(address indexed owner, address indexed approved, uint256 indexed tokenId)
Transfer(address indexed from, address indexed to, uint256 indexed tokenId)
ApprovalForAll(address indexed owner, address indexed operator, bool approved)
Events are helpers that come in handy in the exhaustive labor of indexing state changes, and they are essential for off-chain applications to find relevant data on the blockchain. By mapping all
Transfer
events, for example, you can fetch all the historic data on token transfers more easily.A couple of important contract constants that are public are:
name
symbol
Without these public constants, it would be impossible to label tokens on block explorers, for example. Using this tutorial, you will deploy a XRC721 token that have all the
Methods
, Events
and Constants
mentioned above.Remix is an online solidity IDE for compiling and deploying solidity code to EVM compatible blockchains. To begin working on a new smart contract, you must first create a new file in the contracts folder on the left side of the view pane.

In order to get started deploying new contracts on XDC Mainnet and/or Apothem, you need to have XDCPay wallet to sign our transactions and store XDC tokens.

- Open the Chrome extension after it has been successfully installed.
- Agree to the Terms of Service.

- Create a new XDCPay wallet by setting up a strong password or use an existing Seed Phrase
12 or 24-Word Mnemonic Phrase
to recover your existing wallet here.

- Keep the seed phrase safe. 🚨 Do not share the seed phrase with anyone or you can risk losing your assets and/or the ownership of your smart contracts! 🚨

- Verify recovery phrase
- Your XDCPay wallet has been successfully created.
Initially, your account will be empty, and XDC tokens would be required to initiate blockchain transactions. You'll use a faucet to fill our wallet with test XDC tokens for this purpose. These tokens are essentially worthless, but they are used to test your contracts on the testnet to avoid losing anything of value.
- First, make a copy of your wallet address. Your wallet address would look like
xdc057ac7de8ad6f21c7bb0dcc6a389ff9161b3b943
. These account addresses are interchangeable with the Ethereum network. We can access these accounts on the Ethereum network by simply replacing the initialxdc
with0x
.

- Enter your XDC account address and request for Test XDC here.

- If your request is approved, you will be credited with the XDC in your wallet.
- If you can't see the XDC in your wallet, make sure you're connected to the XDC Apothem Testnet or the XDC Mainnet.

- If you are currently connected to the XDC Mainnet, switch to the XDC Apothem Testnet.
The source code for the XRC721 token used in this tutorial is available here: XRC721 Contract Folder. You will address all
Events
, Methods
and Constants
mentioned in the section 📰 About XRC721 Tokens.You can start by creating the
XRC721.sol
file.
Next, write the shell of your smart contract as follows:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract XRC721 {
}
Inside your contract, you will be importing the scripts from
OpenZeppelin
Github repository. These form the foundation for your contract which has code for all of the different functions that need to be implemented in our contract. We are also importing the Counters
from OpenZeppelin
Github repository, which are used to keep account of the counter of the current tokenId.// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Counters.sol";
contract XRC721 is ERC721 {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
}
As mentioned in 📰 About XRC721 Tokens, events are very important part of a Smart Contract logic. Events have
indexed
variables that can be filtered by off-chain interfaces. You might want to index all the variables that are tied to an on-chain event, however Solidity has a maximum of 3 indexed variable limitation for events. Lets see how Transfer
, Approval
and ApprovalForAll
are written in OpenZeppelin in a simpler form.contract IXRC721 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
// Mapping from token ID to owner
mapping(uint256 => address) private _tokenOwner;
// Mapping from owner to number of owned token
mapping(address => Counters.Counter) private _ownedTokensCount;
// Mapping from token ID to approved address
mapping(uint256 => address) private _tokenApprovals;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
/* @dev Returns the number of NFTs in `owner`'s account. */
function balanceOf(address owner) public view returns (uint256) {
require(owner != address(0), "XRC721: balance query for the zero address");
return _ownedTokensCount[owner].current();
}
/* @dev Returns the owner of the NFT specified by `tokenId`.*/
function ownerOf(uint256 tokenId) public view virtual returns (address) {
address owner = _owners[tokenId];
require(owner != address(0), "ERC721: owner query for nonexistent token");
return owner;
}
* - If the caller is not `from`, it must be have been allowed to move this
* NFT by either {approve} or {setApprovalForAll}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
require(_isApprovedOrOwner(_msgSender(), tokenId), "XRC721: transfer caller is not owner nor approved");
_safeTransferFrom(from, to, tokenId, _data);
}
function transferFrom(address from, address to, uint256 tokenId) public {
//solhint-disable-next-line max-line-length
require(_isApprovedOrOwner(_msgSender(), tokenId), "XRC721: transfer caller is not owner nor approved");
_transferFrom(from, to, tokenId);
}
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(ownerOf(tokenId), to, tokenId);
}
function getApproved(uint256 tokenId) public view returns (address operator) {
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
return _tokenApprovals[tokenId];
}
function setApprovalForAll(address to, bool approved) public {
require(to != _msgSender(), "XRC721: approve to caller");
_operatorApprovals[_msgSender()][to] = approved;
emit ApprovalForAll(_msgSender(), to, approved);
}
function isApprovedForAll(address owner, address operator) public view virtual returns (bool) {
return _operatorApprovals[owner][operator];
}
}
You do not need to write this code in your contract. It is already implemented with the OpenZeppelin github repository.
You'll need to create the
constructor
, which is a function called only once, when the contract is deployed. You can attach information such as the token name and symbol. You'll create another function, createToken
, which will take an address and mint
our created XRC721 NFT Token
to that address:// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// import "@openzeppelin/contracts/token/ERC721/ERC721Full.sol";
// import "@openzeppelin/contracts/drafts/Counters.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Counters.sol";
contract XRC721 is ERC721 {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
constructor(string memory name, string memory symbol) ERC721(name, symbol) {
}
function createToken(address tokenOwner) public returns (uint256) {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(tokenOwner, newItemId);
return newItemId;
}
}
You have implemented everything needed to make your token compliant with the XRC721 standard. Of course, there are more features that you can implement to this contract, such as the SafeMath library that replaces naive mathematical operations for methods that will avoid
underflows
and overflows
, and supply management methods such as mint
and burn
.Next, try to compile the
XRC721.sol
contract:- Open the Solidity Compiler in the left side navigation pane.
- From the compiler option, select the compiler version
v0.8.16
. - Choose Language as
Solidity
. - Set the EVM version as the
compiler default
. - Next, select
Compile XRC721.sol
.

- After a successful compilation, it will show
- Once our contract has been compiled, we can deploy it to the Apothem Test Network.
For deployment on the XDC Apothem Testnet. In either case, you need to have enough funds to pay for gas fees on the address that is being used for development.
- Navigate to Deploy and Transactions.

- Choose Injected Web3 as the Environment.

- Confirm the popup to add the account to Remix IDE now.
- Next, choose the account to which you want to deploy the contract.

- Choose the contract you want to use.

- Add Initial values regarding your token.

- Press the "transact" button and a popup will appear. Confirm in order to create the transaction for contract deployment.

- After that you'll need to
flatten
out your smart contract so that it can be easily verified on the block explorer. - To do this, right click on our smart contract file and here we would see an option to
flatten
our smart contracts on the bottom of menu pane.

- Clicking on the flatten button will open a dialog box. Click accept and, a new icon for flatter will be added to your left navigation pane.

- Next, move to the flattener tab where you will see the option to select the smart contract that you need to flatten. Select the XRC721.sol smart contract and it will give an option to save the flattened smart contract.

- After flattening, we will be using the flattened file.
This flattened code would be used further when we are verifying our token.
Once you have successfully deployed your smart contract to the blockchain, it might be interesting to verify your contract on XinFin Block Explorer.
First, check the address to which your contract is deployed. Go to your wallet and get the most recent transaction details, then copy the transaction address.

Next, navigate to the XDC Block explorer and paste the transaction hash there. Note that if you deployed your token to Apothem testnet then you will need to navigate to the Apothem Explorer, and if you deployed your token to XDC mainnet then you will need to navigate to the mainnet explorer.

From there, you'll need to get the transaction details as well as the
To Address
where the contract is deployed.
In our example, we have a
XRC721
contract deployed on XDC Mainnet at the 0x53bA8Cb12EaF09E6B0b671F39ac4798A6DA7d660
. This address is in the Ethereum standard but we can simply swap the 0x
prefix for xdc
and search for our newly deployed contract on XinFin Block Explorer:
Verify 01
Next, click the
Verify And Publish
Option.You will be redirected to the Contract verification page where you will have to fill out:
- Contract Name: XRC721
- Compiler: Check your
Remix IDE
for Compiler Version - Contract Code: Just paste everything from your
flattened contract
file.
Once everything is filled out, press Submit!

Verify 02
If everything is correctly filled out, your contract page on the block explorer should display a new tab called
Contract
:
Verify 03
With your XDCPay wallet, it is possible to interact with verified Smart Contracts on the XinFin Network Block Explorer. You can read from, write to, or simply read the information tied to your Smart Contract on the blockchain.
First, copy the address where our contract is deployed on the network.
Next, go back to the Remix IDE and paste that deployed contract address in the
At Address
button text box and click on that button.
This will fetch the contract and all the functions related to tour deployed contract and we can easily play around with those functions.

Here, you'd be minting a new NFT token to our wallet.
Then you'd be passing on your
wallet address
before clicking on the createToken
button.
After clicking on
createToken
, you'll need to confirm the transaction on the XDCPay wallet:
Verify 05
You can check for the minted token by going to tour XDCPay Wallet and clicking on the
Tokens
tab and click on the Add Token
button.
Verify 05
Now you have to add the deployed contract address on the
Token Address
text field. This will automatically fetch the token symbol. Then click on the Add Token
button.
Verify 05
Add your newly-minted token to your wallet!

Verify 05
For more information about Remix IDE, Please Visit Remix IDE Documentation.
For more information about XinFin Network, Please Visit XDC Network Documentation on GitBook.\