Building Web3 Wallets (Part 4) - Displaying Curve Liquidity Pools
Congratulations, you’ve arrived at part 4 of this series. This means that not only do you know how to display all your token balances in your wallet app, you also know how to display all your LP tokens from DeFi protocols such as Curve, as well as all your Curve transactions.
What We Will Build
In this final part, you will be creating another useful feature that you can drop into your app: a table of all the liquidity pools on Curve. This table will feature important data points such as the near real-time constituent token balances within the pool, the pool type, the pool addresses, their TVL (Total Value Locked), as well as their supply APY (Annual Percentage Yield).
Your component will look like this:
Prerequisites
Basic familiarity with React.
Some HTML/CSS knowledge.
Fetching data using APIs.
Tutorial: Building a Liquidity Pool Table on Curve
Ready? Let’s get started!
(Estimated time to follow along: 20mins)
1
Figuring out what data you need
- Pool name: tokens within the pool - e.g. ‘ETH / stETH’
- Pool contract address: the contract address of the liquidity pool - e.g. ‘0xdc24…7022’
- Pool type: the type of the pool - e.g. ‘Plain pool’ / ‘Crypto pool’
- APY: the annual percentage yield of the pool (a function of the swap fees earned from the pool)- e.g. ‘0.0003%’
- TVL: Total Value Locked within the pool - e.g. ‘$1694.0M’
- Pool token name - the name of the tokens within the liquidity pool- e.g. ‘Liquid staked Ether 2.0’
- Pool token balance - the balance of the tokens within the liquidity pool e.g. ‘480143 stETH’
- Value of token - the value of the tokens within the liquidity pool, as calculated at the quote rate at time of request e.g. ‘$832.9M’
2
Identifying the right GoldRush API endpoint to use
https://api.covalenthq.com/v1/cq/covalent/app/curve/markets/?key={apiKey}
apiKey
variable, and pop the endpoint into the browser. If you don’t have a GoldRush API key, you can get it for free here.contract_ticker_symbol
(Pool name for one token), pool_address
(Pool address), pool_type
(Pool Type), supply_apy
(APY), tvl_quote
(TVL). However, it only contains the token data for one side of the liquidity pool. pool_address
.3
Clone this starter kit & initialize the project
localhost:3000
in your browser. You should see the following:.env
file. Create a .env
file that specifies your GoldRush API key in this format:REACT_APP_APIKEY='ckey_8bdxxxxxxxxxxxxxxxxxxxxxxxxxx99'
npm start
again.4
Fetching the Curve pool data
components/Pools.js
file. Within it, we have the JSX template for the Pools component. Our goal now is to fetch the relevant data first.console.log
the response.npm start
in your terminal.5
Rendering the response items
contract_ticker_name
fields of the items from the same pool (so that they appear as, say, ’ETH / stETH’). In order to achieve this, we shall group the items with the same pool_address
into an array, much like what we did for part 3. The following function will do trick:var groupedData = Object.values(
res.data.items.reduce((p, c) => {
(p[c.pool_address] = p[c.pool_address] || []).push(c)
return p
}, {})
data
state variable:import { useState, useEffect } from 'react';
import '../App.css';
import PoolTokenBalance from './PoolTokenBalance';
const Pools = () => {
const [data, setData] = useState(null)
const apiKey = process.env.REACT_APP_APIKEY
const poolsEndpoint = `https://api.covalenthq.com/v1/cq/covalent/app/curve/markets/`
useEffect(() => {
fetch(poolsEndpoint, {method: 'GET', headers: {
"Authorization": `Basic ${btoa(apiKey + ':')}`
}})
.then(res => res.json())
.then(res => {
var groupedData = Object.values(
res.data.items.reduce((p, c) => {
(p[c.pool_address] = p[c.pool_address] || []).push(c)
return p
}, {})
)
setData(groupedData)
})
}, [poolsEndpoint, apiKey])
data
state variable, we see that the result is a grouped array:contract_ticker_symbol
fields. Rendering it on the page:Get all markets
endpoint. The pool_type
field of our response takes this list of possible values:- base_pool <> plain_pool
- meta_pool
- crypto_pool
- base_pool <> lending_pool
const cleanPoolType = (poolType) => {
switch (poolType) {
case 'base_pool <> plain_pool':
return 'Plain Pool'
case 'meta_pool':
return 'Meta Pool'
case 'crypto_pool':
return 'Crypto Pool'
case 'base_pool <> lending_pool':
return 'Lending Pool'
default:
return poolType
}
}
...
return (
<>
<div className='rowPool clickable' key={item} onClick={() => toggleDisplay(i)}>
<div className='left'>
<div className='logoContainer'>
<img className='poolTokenLogo' src='<https://res.cloudinary.com/dl4murstw/image/upload/v1678790049/spaces_-MFA0rQI3SzfbVFgp3Ic_uploads_F5ZS9RzAWKZnNxm9F85H_Curve-Logo-HighRez_zzlvug.webp>' alt='tokenlogo'/>
</div>
<div className='pool-left-info-container'>
<div className='poolTokenName'>{item.map(token => token.contract_ticker_symbol).join(' / ')}</div>
<a href={'<https://etherscan.io/address/>' + item[0].pool_address} target='_blank' rel='noreferrer'><div className='poolAddress'>
<div><img className='scroll' src='<https://res.cloudinary.com/dl4murstw/image/upload/v1668495918/scroll_bkmays.png>' alt='scroll' width='12px' /></div>
<div className='poolAddressText'> {truncateEthAddress(item[0].pool_address)}</div>
</div>
</a>
</div>
</div>
<div className='poolType'>{cleanPoolType(item[0].pool_type)}</div>
<div className='apy'>{item[0].supply_apy.toFixed(5) + '%'}</div>
<div className='tvl'>${(item[0].tvl_quote / 1000000).toFixed(1)}M</div>
</div>
</>
)
6
Add-on feature: constituent token balance
balance
and quote
fields of our response:<PoolTokenBalance />
component on a click of the row. This is the onClick handler (toggleDisplay
) that we will add:<PoolTokenBalance />
component gets rendered.<PoolTokenBalance />
component is fairly straightforward. It takes the items of each row as props (the one we grouped earlier) and renders the constituent tokens along with their balances: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 part4-defi-protocols-pools-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
The on-chain data of DeFi protocols can be complex. Without the right tools, you might just end up spending a lot of your time figuring out the nitty gritty of their smart contract architecture, whilst still not getting the high-level overview data that you need. Hopefully, by the end of this series, you will be able to easily retrieve DeFi protocols’ on-chain data for your app, whatever it is you want to build.
Throughout this series, we’ve illustrated how you can get DeFi protocols’ data using the specific example of Curve. The beauty of GoldRush API is that you can get the data of other protocols just as easily: Aave, Balancer, Compound, Dodo, Frax, InstaDapp, Lido, Yearn, and more.
Do sign up for a free API key and try it yourself.
Happy buidling!