Building a Web3 Portfolio Tracker with the GoldRush API
As decentralized finance and Web3 applications are rapidly growing in popularity, there is also a rise in investors building their crypto asset portfolios across different blockchains. Keeping track of these assets as they spread across these protocols can be daunting, especially without using the right tools. This is where a Web3 portfolio tracker comes in handy.
In this guide, you’ll learn how to build your own Web3 portfolio tracker using the GoldRush Unified API. You can check out and interact with the Portfolio Tracker application we will build here!
The GoldRush Unified API
GoldRush provides a unified API to easily access on-chain data across multiple blockchains like Ethereum, Binance Chain (BSC), Polygon and many more. We will be using the GoldRush API to build a portfolio tracker that can provide a list of all the assets (ERC-20 tokens and NFTs) a wallet address is holding and also displays the market value of these assets which gives the users a clear overview of how much they have invested across multiple blockchains.
Prerequisites
A good understanding of JavaScript.
Knowledge of React.js.
Knowledge of how to build front-end applications using React.js.
Knowledge of how to interact with APIs.
Have Node.js and NPM or Yarn installed on your computer.
Have VSCode installed.
Get a GoldRush API Key
Interacting with the GoldRush Unified API requires that you have an account on the GoldRush platform which gives you access to generating an API key for interacting with the API endpoints. Use the following guide to generate an API key:
Navigate to the GoldRush Website.
Click on the Signup for a free API key button on the main page to create an account.
On the signup page, fill out the required input fields, check the Terms of Use checkbox, and click the Sign me up button.
After signing up, verify your email and log in to your GoldRush account. You will be asked to provide some information about yourself in the input fields.
Once you have completed all the necessary onboarding/signup steps, go to GoldRush to create your own API key. An API key will be created for you automatically, else, click the dropdown beside the Manage API keys button and click the Create button.
Now you have created an account on GoldRush, and you also have an API key to interact with the GoldRush unified API, let’s proceed to building the Portfolio tracker.
Building the Portfolio Tracker
Let’s start building the portfolio tracker application.
1
Creating a React Application
- Create a folder in your PC named portfolio_tracker.
- Open a terminal on the portfolio_tracker folder and run:
npx create-react-app .
- This above command will create a react application inside the portfolio_tracker folder you have created.
2
Setting up Bootstrap in the React Application
- After opening the portfolio_tracker in your VSCode, navigate to public/index.html.
- Replace everything in your index.html with the attached code.
3
Installing the GoldRush SDK
- Go to the GoldRush platform.
- Scroll down to the SDK installation section.
- Copy the installation command.
- Open up a VSCode terminal in your portfolio_tracker application.
- Paste the command and press enter. This will install the GoldRush SDK.
4
Replace the Code in App.js
- Once you are done installing the SDK, head over to src/App.js.
- Replace everything inside this file with the code below:
import React, { useState, Fragment } from "react";
import { CovalentClient } from "@covalenthq/client-sdk";
import LoadingSpinner from "./UI/LoadingSpinner";
import { ethers } from 'ethers';
function App() {
const [address, setAddress] = useState("");
const [network, setNetwork] = useState("eth-mainnet");
const [tokenData, setTokenData] = useState(null);
const [nftData, setNftData] = useState(null);
const [nativeCurrencyData, setNativeCurrencyData] = useState(null);
const [loading, setLoading] = useState(false);
const client = new CovalentClient(process.env.REACT_APP_API_KEY);
const getWalletTokenBalance = async () => {
try {
const resp = await client.BalanceService.getTokenBalancesForWalletAddress(network, address);
setTokenData(resp.data);
} catch (error) {
console.error(error);
}
}
const getWalletNfts = async () => {
try {
const resp = await client.NftService.getNftsForAddress(network, address);
setNftData(resp.data);
} catch (error) {
console.error(error);
}
}
const getNativeTokenBalance = async () => {
try {
const resp = await client.BalanceService.getNativeTokenBalance(network, address);
setNativeCurrencyData(resp.data);
} catch (error) {
console.error(error);
}
}
const addressChangeHandler = (e) => {
e.preventDefault();
setAddress(e.target.value);
}
const networkChangeHandler = (e) => {
e.preventDefault();
setNetwork(e.target.value);
}
const fetchWalletTokens = async (e) => {
e.preventDefault();
if(address === "" || network === "") {
alert("input an address and select a blockchain network");
} else {
setLoading(true);
await getNativeTokenBalance();
await getWalletTokenBalance();
await getWalletNfts();
setLoading(false);
}
}
return (
<div className="App">
<div className="container">
<nav className="navbar navbar-expand-lg navbar-light bg-primary mb-1">
<a className="navbar-brand text-light font-weight-bold" href="!#">Portfolio Tracker</a>
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation"
>
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarText">
<ul className="navbar-nav mr-auto"></ul>
<span className="navbar-text text-light">
Track your crypto assets across multiple chains
</span>
</div>
</nav>
<div className="row">
<div className="col-md-12">
<form>
<div className="input-group mb-3 input-group-lg">
<input type="text" className="form-control" placeholder="Wallet Address" onChange={addressChangeHandler} />
<select className="form-control" value={network} onChange={networkChangeHandler}>
<option value="eth-mainnet">Ethereum</option>
<option value="bsc-mainnet">Binance</option>
<option value="matic-mainnet">Polygon</option>
<option value="fantom-mainnet">Fantom</option>
</select>
<div className="input-group-append">
<button className="btn btn-primary" onClick={fetchWalletTokens}>Explore</button>
</div>
</div>
</form>
</div>
</div>
{loading ?
<div className="text-center mt-5">
<LoadingSpinner />
<h3 className="text-center text-black mt-3">Loading...</h3>
</div>
:
<Fragment>
<div className="row mt-4">
<div className="col-md-4">
<div className="card bg-primary text-white">
<div className="card-body">
<span>
Currency: {nativeCurrencyData !== null && nativeCurrencyData.items.length > 0 && ethers.utils.formatUnits(nativeCurrencyData.items[0].balance, nativeCurrencyData.items[0].contract_decimals)}
<strong>{nativeCurrencyData !== null && nativeCurrencyData.items.length > 0 && nativeCurrencyData.items[0].contract_ticker_symbol}</strong>
</span>
<h3>{nativeCurrencyData !== null && nativeCurrencyData.items.length > 0 && nativeCurrencyData.items[0].pretty_quote}</h3>
</div>
</div>
</div>
<div className="col-md-4">
<div className="card bg-primary text-white">
<div className="card-body">
<span>Tokens</span>
<h3>{tokenData !== null && tokenData.items.length}</h3>
</div>
</div>
</div>
<div className="col-md-4">
<div className="card bg-primary text-white">
<div className="card-body">
<span>NFTs:</span>
<h3>{nftData !== null && nftData.items.length}</h3>
</div>
</div>
</div>
</div>
<div className="row mt-5">
<div className="col-md-12">
<ul className="nav nav-tabs nav-justified">
<li className="nav-item">
<a className="nav-link active" data-toggle="tab" href="#tokens">Tokens</a>
</li>
<li className="nav-item">
<a className="nav-link" data-toggle="tab" href="#nfts">NFTs</a>
</li>
</ul>
<div className="tab-content">
<div className="tab-pane container active" id="tokens">
<div className="table-responsive my-4">
<table className="table table-striped table-light">
<thead>
<tr>
<th scope="col">SN</th>
<th scope="col">Token</th>
<th scope="col">Symbol</th>
<th scope="col">Amount</th>
<th scope="col">Value</th>
</tr>
</thead>
<tbody>
{tokenData !== null && tokenData.items.length > 0 &&
tokenData.items.map((item, index) => (
<tr key={item.contract_address}>
<th scope="row">{index + 1}</th>
<td><img style={{ width: "30px" }} src={`${item.logo_url}`} alt="" /> {item.contract_name}</td>
<td>{item.contract_ticker_symbol}</td>
<td>{ethers.utils.formatUnits(item.balance_24h, item.contract_decimal)}</td>
<td>{item.pretty_quote_24h === null ? "$0.00" : item.pretty_quote_24h}</td>
</tr>
))
}
</tbody>
</table>
</div>
</div>
<div className="tab-pane container fade" id="nfts">
<div className="table-responsive my-4">
<table className="table table-striped table-light">
<thead>
<tr>
<th scope="col">SN</th>
<th scope="col">NFT</th>
<th scope="col">Symbol</th>
<th scope="col">Contract Address</th>
<th scope="col">Floor Price</th>
</tr>
</thead>
<tbody>
{nftData !== null && nftData.items.length > 0 &&
nftData.items.map((item, index) => (
<tr key={item.contract_address}>
<th scope="row">{index + 1}</th>
<td>{item.contract_name}</td>
<td>{item.contract_ticker_symbol}</td>
<td>{item.contract_address}</td>
<td>{item.pretty_floor_price_quote === null ? "$0.00" : item.pretty_floor_price_quote}</td>
</tr>
))
}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</Fragment>
}
</div>
</div>
);
}
export default App;
5
Create Loading Components
- Create a folder named UI inside the src folder.
- Inside the UI folder, create two files named LoadingSpinner.js, and LoadingSpinner.module.css.
6
Create a .env.local File to Keep API Key
- In the root project directory, create a .env.local file.
- Inside the .env.local file create a variable and set the value to your GoldRush API key.
7
Run the React Application
npm start
. This will open the application on http://localhost:3000.Interacting with the Portfolio Tracker
Let’s now interact with the portfolio tracker application we have created! To interact with the application:
Get any Ethereum wallet address and paste it inside the Wallet Address input field.
Select any blockchain you wish to see the portfolio and click the Explore button.
This will list out all the tokens (ERC-20 and NFTs) that the specified Ethereum address is holding.
The portfolio tracker shows all the ERC-20 tokens the given address is holding on Binance Smart Chain. In our example, it shows that the wallet address has thirty-one (31) ERC-20 tokens and one NFT on the Binance chain while also showing the value of these token assets.
The tracker also shows the NFT a given address is holding on Binance Smart Chain. You can switch chains and click the Explore button to check the wallet assets on other chains. This portfolio tracker supports four different blockchains; Ethereum, Binance, Polygon and Fantom.
Deploying the Portfolio Tracker
The final step of building the portfolio tracker is to deploy the application, making it accessible to every other person on the internet.
We will be deploying this application on Vercel using the following steps:
1
Add a New Project
- Make sure that your application has been pushed to GitHub.
- Go to your Vercel dashboard or create an account if you don’t already have an account.
- On your Vercel dashboard, click on the Add New button and select Project.
2
Import
- After clicking on Project, search for the project name, if you have not added the project to your Vercel, click on the Configure GitHub App button, add the project and save it.
- When you have successfully configured the GitHub application, the project will now appear on your Vercel as shown. Click on the Import button.
3
Deploy
- On clicking the Import button, you will be redirected to the deployment page. Set up the environment variables and click the Deploy button.
Your application will deploy successfully and you will be provided a link to access your own portfolio tracker application. Access the full codebase for the portfolio tracker here.
Conclusion
The portfolio tracker application is a utility application that comes in very handy in the Web3 and DeFi ecosystem, making it easy for investors to keep track of their investments across multiple chains. Of course, the application we have built can be improved, you can explore other options to make it better by adding support for more blockchains and also showing on-chain transactions of a wallet address. Cheers, and Happy Building!