Avalanche is a proof-of-stake (PoS), Layer 1 chain that supports Solidity-compatible dapps running on an Ethereum Virtual Machine (EVM). Infura supports the Contract Chain (C-Chain), which is an instance of the EVM. It enables the creation of smart contracts using the C-Chain’s API. Developers can write decentralized applications (dapps) that use Infura to call Avalanche C-Chain via JSON-RPC endpoints.
This tutorial shows how developers can use Avalanche to deploy an ERC721 smart contract and then mint a series of NFTs with links to metadata that represent double-entry accounting transactions.
In an example use case, a company wants to create a decentralized record of its financial performance for a given year. At the start of that year, and again at the end of every quarter, the company mints a series of NFTs whose metadata shows changes to its balance sheet. Those changes are a permanent record that can be accessed by a bank in support of a loan package.
Prerequisites
Node.js (version 16 or later), and npm or yarn installed
An IDE such as Microsoft Visual Studio Code
- Prepare your MetaMask wallet
We will use the Avalanche FUJI C-Chain testnet, so we need to fund our wallet with test AVAX tokens. Our first step is to add the FUJI C-Chain to MetaMask by defining a custom network:
Log into MetaMask, click the network dropdown, and select “Add a network” and fill in the following information:
Network Name: Avalanche FUJI C-Chain
New RPC URL: https://api.avax-test.network/ext/bc/C/rpc
ChainID: 43113
Symbol: AVAX
Explorer: https://testnet.snowtrace.io/
2. Add wallet address to config file
Copy the wallet address to clipboard.
As described below, paste the wallet address into the WALLET_ADDRESS field in src/config.tsx, replacing the placeholder string (“xxxxxxx”).
3. Add private key to config file
Click “Export private key,” and then enter browser password to enable copying.
As described below, paste the private key into the PRIVATE_KEY field in src/config.tsx, replacing the placeholder string (“xxxxxxx”).
NOTE: As described below, DO NOT commit config.tsx to the repo after you have filled in actual values. The private key is most critical because exposure completely removes your protection against hacking.
4. Get AVAX tokens from the Avalanche Fuji Faucet
Next, we visit https://faucet.avax.network/ to request 2 AVAX, the maximum available in any 24-hour period. Click the Connect button to copy the address of your MetaMask wallet into the form, then press REQUEST 2 AVAX. Given the speed of the Avalanche chain, the balance should quickly appear in your wallet.
5. Create an ERC721 contract with the Open Zeppelin wizard
We use the Open Zeppelin wizard to create our ECR721 contract. Visit https://wizard.openzeppelin.com/ and select the ERC721 tab.
Create a name and symbol. We will leave the Base URI field blank for this example.
Choose Mintable and Auto increment ids, Burnable and URI Storage.
When you have done this, click the “Open in Remix” button. Your browser will open a tab with this view of the code.
Click the “Compile Contract” button to compile the contract in Remix, which should display the correct compiler version.
Click the “ABI” icon to copy the ABI from Remix. As described below, paste it into the empty file src/abi.json” in the GitHub repo referenced below.
Deploy the contract to the Avalanche Fuji C-Chain. On the left side of the Remix panel, go to the first dropdown “Environment,” and be sure the Injected Provider is set to Metamask, which should already be set to the Fuji C-Chain.
Copy the contract address from Remix.
Visit the Fuji Snowtrace block explorer at https://testnet.snowtrace.io/.
Paste the contract address into the search bar and you will see the deployed contract.
As described below, paste the contract address into the CONTRACT_ADDRESS field in src/config.tsx, replacing the placeholder string (“xxxxxxx”).
6. Create an Avalanche project in Infura
Go to your Infura dashboard and click the “Create New Key” button.
Choose “Web3 API” in order to see the Avalanche endpoints.
Choose the Avalanche C-Chain Fuji testnet endpoint.
Copy the endpoint. This is your project’s URL, which will display in this format:
https://avalanche-fuji.infura.io/v3/xxxxxxxxxxxxxxxxxxxxxxx
As described below, paste this into the INFURA_FUJI_PROVIDER field in src/config.tsx, replacing the placeholder string (“xxxxxxx”).
7. Create an IPFS project in Infura
An NFT contains metadata that describe images and other related resources that are stored off-chain, typically on the IPFS decentralized file storage network. In order to mint Avalanche NFTs, we need to create an IPFS project in your Infura account.
Under “Create an IPFS Project”, click “Get Started”
Name your IPFS project.
Enable dedicated gateways.
As described below, paste PROJECT ID and API KEY SECRET into the INFURA_IPFS_PROJECT_ID and INFURA_IPFS_API_KEY_SECRET fields in src/config.tsx, replacing the placeholder strings (“xxxxxxx”).
Create a subdomain name that is unique to your project.
Add the string “/ipfs/” to the Subdomain Name that you have created, then paste the entire name (https://your-name.infura-ipfs.io/ipfs/) into the INFURA_IPFS_GATEWAY field in src/config.tsx, replacing the placeholder string (“xxxxxxx”).
8. Visit the GitHub repo to clone this project
https://github.com/ConsenSys/avalanche-tutorial-accounting
Before building and running the application, you need to finish these two steps:
- As described above, copy the contents of the ABI from Remix intp the src/abi.json file.
- Fill in the values contained in src/config.tsx, replacing the placeholder strings (“xxxxx”)”
const config = {
INFURA_FUJI_PROVIDER: "xxxxxxxxxx",
INFURA_IPFS_PROJECT_ID: "xxxxxxxxxx",
INFURA_IPFS_API_KEY_SECRET: "xxxxxxxxxx",
INFURA_IPFS_GATEWAY: "xxxxxxxxxx",
CONTRACT_ADDRESS: "xxxxxxxxxx",
WALLET_ADDRESS: "xxxxxxxxxx",
PRIVATE_KEY:"xxxxxxxxxx",
};
NOTE: If you are doing additional commits, instead of writing these values directly to config.tsx, create a file called “config_local.tsx” in the src directory. You can store these values there, and then copy the entire config structure into config.tsx before running the application. Since the .gitignore file has an entry for config_local.tsx, you should avoid accidentally committing the actual values for everyone to see. Before any additional commits, remove the changes to config.tsx, so the file reverts to the placeholder strings.
To build the application, run npm install or yarn install.
To run the application, run npm start or yarn start.
Summary
This application enables a user to mint a group of NFTs containing metadata that represent a series of double entries in an accounting system. Starting with an empty balance sheet, we follow three steps to record each double entry:
- Entry - Show the changes in each account affected by the double entry.
- IPFS - Upload a JSON object representing those changes to IPFS.
- Mint - Mint an NFT with a URI containing the IPFS file identifier
The application roadmap below shows the steps to connect your MetaMask wallet, and four transactions that generate entries:
- Initial equity investment
- Purchase manufacturing equipment
- Purchase inventory from supplier
- Sell the product to customer
For each step, we show changes in the accounts, based on mock data included in the application. As each NFT is minted, the balance of AVAX test tokens in our MetaMask wallet decreases by the amount of the transaction fee. The 2 tokens you get from the Avalanche C-Chain Fuji test faucet should be enough to run this application many times.
The Entry, IPFS and Mint buttons are disabled after the fourth NFT is minted.
The user can reset the application to start another series of four entries by reloading the page.
After launching the application
Click the Entry button to post the first accounting entry.
After Entry 1
Click the “IPFS” button to upload a JSON object representing the entry.
After IPFS 1
Click the “Mint” button to begin minting the NFT.
Minting 1
Wait for the progress indicator to indicate that minting has finished.
After Entry 2
Click the “Entry” button when it is enabled again to repeat the process for the second entry.
After Entry 3
Click the “Entry” button when it is enabled again to repeat the process for the third entry.
After Entry 4
Click the “Entry” button when it is enabled again to repeat the process for the fourth entry.
After Minting 4
The “Entry”, “IPFS” and “Mint” buttons will be disabled after minting the fourth NFT.
Snowtrace Block Explorer - Contract
After each series of entries, the transactions will appear in the contract shown in the Snowtrace Block Explorer. https://testnet.snowtrace.io/
Snowtrace Block Explorer - Transaction
In this view of Transaction Details, we see that the most recently minted NFT has a TokenID of 74. The metadata for this NFT should show the state of the accounts after the fourth entry.
Remix - call tokenURI
In Remix, we can enter that TokenID in the field for the tokenURI call. Clicking the “call” button will show the IPFS URL under which the metadata is stored.
tokenURI output in browser
Pasting that URL into a browser displays the JSON object that represents the fourth entry.
Using external data feeds
In this tutorial, we used placeholder data to mint a series of NFTs that represent changes in a company’s financial state. Live data from a company’s accounting systems can be fed into a decentralized oracle network like Chainlink to provide a deterministic view of its performance. This can provide an end-to-end audit solution that companies can share with financial institutions and other interested parties.