Building Web3 Wallets (Part 2) - Curve LP Token Balances
Now, let us move on to the fun part. In the previous section, we focused on building a simple component that displays all your token holdings. We learned that getting all the tokens for your address is super simple: all it took was one GoldRush API call. In this part, we are going to expand the functionality of your wallet to return the wallet activities from your favorite DeFi protocols, such as Aave, Curve, Balancer, Frax, InstaDapp, Yearn, and more.
Getting Web3 Wallet Data from DeFi Protocols
Part of what makes Web3 wallets exciting is that they are composable. While Web2 applications and their data function mostly in silos (Instagram would never interface with Tiktok, for instance), Web3 data is public, and all write functionalities with the DeFi protocols’ smart contracts are public as well. This means that our wallet is not ‘just’ a wallet - it is a portal for us to engage with the rest of the Web3 world. But how do we hook our wallets to the Web3 world at large?
Well, again, two parts: first, we need to read on-chain data from those protocols, and second, we need to write on-chain data to those protocols’ smart contracts by executing their functions. This section, like the last one, focuses on reading the data. With these data, we can quickly get a sense of what Liquidity Provider (LP) tokens we have and how much they’re worth (these are the tokens you receive when you supply liquidity to a liquidity pool). We can even get all recent transactions we have made with the protocol, along with the APY (Annual Percentage Yield) of the pools. All this enables your wallet to function almost like an app store, with the DeFi protocols themselves being the individual apps.
What We Will Build
In this guide, we will build the following Curve LP Token Balances component:
On the left, you get each LP token’s name, amount, and ticker. On the right, you get their values in USD, as well as the rewards you accrue from the swap fees for holding them. Beneath each row, you get their underlying redeemable tokens.
Pretty slick, right?
Before we begin, let’s dive into a bit of background about Curve first.
What is Curve Finance?
Curve Finance (https://curve.fi) is one of the top protocols in DeFi. It allows you to swap between stablecoins with low fees and slippage. Let’s say I want to swap $8000 USDC to USDT. Instead of going through a centralized service like Binance, I can do it purely on-chain using Curve. That is the utility part. (In version 2, Curve has added support for more volatile assets such as the tricrypto pool - wBTC, ETH, and fUSDT - but it is still mainly known as a stableswap protocol.)
Behind the scenes, Curve enables us to swap stablecoins by using liquidity pools. Liquidity providers inject stablecoins into these pools, enabling other traders to trade against them. In return, liquidity providers get pool rewards accrued against LP tokens that they receive.
What is unique about Curve is simply its niche in the stableswaps space (swapping stablecoins). For everyday DeFi users, this has proven to be a vital use case. For liquidity providers, it gives them an opportunity to earn yield on a stable asset.
What Kind of On-Chain Data is Generated by Transactions on Curve?
To understand the kinds of data produced by Curve, we need to understand first what are the common user actions you see on Curve.
Swaps: This is the most common action performed on Curve. When I want to exchange USDT to USDC, I perform a Swap, which is a type of transaction event containing details such as how much of token A is swapped for token B at what rates and with what fees. We’ll be adding these transaction events into our Curve LP Token Balances component.
Adding/Removing Liquidity: How do the pools hold any liquidity in the first place? They come from Liquidity providers injecting their tokens into the pools. When a liquidity provider injects USDC into, say, 3Pools, they will receive 3Crv LP tokens. At any future point, they can swap their LP tokens back for USDC. This action generates on-chain data such as:
the value of the LP tokens
swap fee rewards of each LP token.
Pools: Lastly, the liquidity pools themselves also have certain attributes such as the pool token balances, APY, TVL, and so on. We’ll build a section to see those as well.
Prerequisites
Basic familiarity with React.
Some HTML/CSS knowledge.
Fetching data using APIs.
Tutorial: Building a Curve LP Token Balances Component
Let’s get started!
(Estimated time to follow along: 20mins)
1
Clone this starter kit and initialize the project
localhost:3000
in your browser. You should see the following:src/App.js
, you’ll see that there are three simple components (<Tokens />
, <Transactions />
, and <Pools />
) that correspond to the sections you see on this page in the components
folder.<Tokens />
component, and let’s begin.2
Fetching the LP tokens data
.env
file that specifies your GoldRush API key in this format:REACT_APP_APIKEY='ckey_8bdxxxxxxxxxxxxxxxxxxxxxxxxxx99'
<Tokens.js>
component to fetch the data:3
Understanding the data response
4
Rendering the live token data
<Token.js>
component:5
New feature: redeemable tokens
Get Redeemable token balance
endpoint, we’ll be able to get the pool proportion easily. It even returns the balance of the underlying token we are getting.npm start
, and click on one of the rows:<RedeemableTokens />
component, we find that it has the same familiar structure to what we’ve done before. First, we fetch the data in an effect hook, and then we display it. This time, I’ve already fetched it for you, but you’ll need to fill up the placeholder values:// RedeemableTokens.js
import { useState, useEffect } from 'react';
import '../App.css';
const RedeemableTokens = ({ address, poolAddress }) => {
const [tokenData, setTokenData] = useState(null)
const [loading, setLoading] = useState(false)
const apiKey = process.env.REACT_APP_APIKEY
const protocol = 'curve'
const redeemableTokenBalanceEndpoint = `https://api.covalenthq.com/v1/cq/covalent/app/${protocol}/tokens/?key=${apiKey}&pool-address=${poolAddress}&address=${address}`
useEffect(() => {
setLoading(true)
fetch(redeemableTokenBalanceEndpoint, {method: 'GET', headers: {
"Authorization": `Basic ${btoa(apiKey + ':')}`
}})
.then(res => res.json())
.then(res => {
setLoading(false)
setTokenData(res.data.items)
})
}, [redeemableTokenBalanceEndpoint])
if (loading) {
return (
<div className='loading'>Loading redeemable tokens...</div>
)
} else if (!loading && tokenData) {
return (
<>
<div className='rowHeadersRedeem'>
<div className='rowHeaderPool'>Tokens</div>
<div className='rowHeaderAPY'> Redeemable Value (USD)</div>
</div>
<div className='redeemTokenContainer'>
{tokenData.map(token => {
return (
<div className='redeemTokenRow'>
<div className='redeem-left'>
<div className='poolTokenName'>token0</div>
<div className='poolTokenBalance'>000 USDC</div>
</div>
<div className='redeem-right tvl'> $00 </div>
</div>
)
})}
</div>
</>
)
}
}
export default RedeemableTokens
Get Redeemable token balance
endpoint has this query format:https://api.covalenthq.com/v1/cq/covalent/app/${protocol}/tokens/?key=${apiKey}&pool-address=${poolAddress}&address=${address}
- protocol - string: the name of the protocol. Currently, we support Aave, Balancer, Compound, Curve, Dodo, Frax, Instadapp, Lido, and Yearn.
- apiKey - string: your API key. Note: passing the API key via the query string is not advised, and is used here for mainly demonstration purposes. Use basic auth instead for all other cases.
- poolAddress - string: the address of the liquidity pool on Curve.
- address - string: the wallet address you’re querying.
tokenData
state to see what values you’ll need to fill!npm start
...If you have not been following along and would just like the end state, you can do the following to see this app locally:
git clone https://github.com/xiaogit00/building-wallets.git
cd building-wallets
npm i
git checkout part2-defi-protocols-end
npm start
Just be sure to add your API key in a .env
file, like so:
REACT_APP_APIKEY='ckey_8bdxxxxxxxxxxxxxxxxxxxxxxxxxx99'
All in a Day’s Work
Good job, you’ve successfully reached the end of this tutorial. Hopefully, you can see that displaying a user’s LP token holdings, along with their redeemable token value, is super simple with the help of the GoldRush API.
You have probably seen at the start that the LP token balances is only one part of the protocol data a user might be interested in. What’s very important as well is the list of transactions we’ve done with the protocol. In the next part, we’ll be building the protocol transactions component. Stay tuned!