Final repo of this blog.
If you’re diving into the world of decentralized finance (DeFi), you know how important it is to get accurate and comprehensive data. But what if we could get this data not just from one DeFi protocol, but from dozens all at once?
That’s where Messari’s standardized subgraphs come in.
These standardized subgraphs let us query multiple exchanges with a single query, essentially asking the same question of many different DeFi communities all at the same time! Imagine being able to track the Total Value Locked (TVL) across dozens of different protocols or analyzing trade volumes and user metrics - all with a single query!
In this post, we’ll walk you through the advantages of using Messari standardized subgraphs, show you how to query multiple exchanges, and even give you some creative queries to try out. Let’s get started!
Consistent Data Structure: Messari's subgraphs stick to a consistent schema, making it super easy to write queries that work across different exchanges. No more tweaking queries for each platform!
Comprehensive Insights: By querying multiple exchanges at once, you can get a complete view of the DeFi landscape. This is perfect for comparing TVL, spotting market trends, and finding new opportunities.
Efficient and Fast: Standardized subgraphs let you fetch data from various sources in one go. This saves time and cuts down on the hassle of handling multiple data sources.
Go to subgraphs.messari.io and find the Exchanges category. All subgraphs under each category have the same standardized schema for us to query (Exchanges, erc721, Governance, etc).
We will query Messari’s Curve Finance subgraph and their SushiSwap subgraph, however if we wanted to we could send this query to nearly 40(!) Messari-standard Exchange subgraphs. Every Messari Exchange subgraph uses this schema, which will make designing queries simple!
Step 2: Design a Query and Test in the Subgraph’s Playground
Let’s find the TVL of both Curve Finance and SushiSwap on August 20th, 2023.
After analyzing the subgraph’s schema, as well as finding the UNIX timestamp for that specific date, here is our GraphQL query:
{
dailySnapshot8_20_23: financialsDailySnapshots(
where: {timestamp_gte: 1629417600, timestamp_lt: 1629504000},
) {
totalValueLockedUSD
}
}
We can run this query in each subgraph’s playground and see both are returning data:
But now, how do we build this in programmatically into our dapp?
First things first, make sure you have Node.js installed. Then, set up a new project:
mkdir messari-subgraphs
cd messari-subgraphs
npm init -y
Create a file named app.js
and gather both subgraph’s endpoints by pressing the Query button on each of their dashboards.
Save the endpoints as an array inside of a getTVLs()
function:
//app.js
async function getTVLs() {
const urls = [
{
url: "https://gateway.thegraph.com/api/<API_KEY>/subgraphs/id/GAGwGKc4ArNKKq9eFTcwgd1UGymvqhTier9Npqo1YvZB",
name: "Curve Finance",
},
{
url: "https://gateway.thegraph.com/api/<API_KEY>/subgraphs/id/7h1x51fyT5KigAhXd8sdE3kzzxQDJxxz1y66LTFiC3mS",
name: "SushiSwap",
},
];
};
Step 5: Gather API Key
Go to Subgraph Studio and set up an API Key, then drop the API key into the endpoints:
//app.js
async function getTVLs() {
const urls = [
{
url: "https://gateway.thegraph.com/api/0ab7a83b03a36ac8a536cd8fa19a8ad4/subgraphs/id/GAGwGKc4ArNKKq9eFTcwgd1UGymvqhTier9Npqo1YvZB",
name: "Curve Finance",
},
{
url: "https://gateway.thegraph.com/api/0ab7a83b03a36ac8a536cd8fa19a8ad4/subgraphs/id/7h1x51fyT5KigAhXd8sdE3kzzxQDJxxz1y66LTFiC3mS",
name: "SushiSwap",
},
];
};
Step 6: Programmatically Send Query to Endpoints
Next, we will create an array of POST requests to fetch the Total Value Locked (TVL) data for August 20th, 2023, from multiple subgraphs:
//app.js
const requests = urls.map((entry) =>
fetch(entry.url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
query: `
{
dailySnapshot8_20_23: financialsDailySnapshots(
where: { timestamp_gte: 1629417600, timestamp_lt: 1629504000 }
) {
totalValueLockedUSD
}
}
`,
}),
})
);
const results = await Promise.all(requests);
const tvls = await Promise.all(results.map((result) => result.json()));
By using the map
function on the urls
array, we ensure that each subgraph endpoint is queried with the same GraphQL query.
Step 7: Display The Returned Data
Now that we've fetched the data from multiple subgraphs, the next step is to display it on our webpage. We will take the data returned from the subgraphs and dynamically create HTML elements to show this information.
Get the Data Container:
data-container
.Iterate Over the Results:
div
element to display the data.Create HTML Elements:
data-container
.Here is the final app.js
file:
async function getTVLs() {
const urls = [
{
url: "https://gateway.thegraph.com/api/0ab7a83b03a36ac8a536cd8fa19a8ad4/subgraphs/id/GAGwGKc4ArNKKq9eFTcwgd1UGymvqhTier9Npqo1YvZB",
name: "Curve Finance",
},
{
url: "https://gateway.thegraph.com/api/0ab7a83b03a36ac8a536cd8fa19a8ad4/subgraphs/id/7h1x51fyT5KigAhXd8sdE3kzzxQDJxxz1y66LTFiC3mS",
name: "SushiSwap",
},
];
const requests = urls.map((entry) =>
fetch(entry.url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
query: `
{
dailySnapshot8_20_23: financialsDailySnapshots(
where: { timestamp_gte: 1629417600, timestamp_lt: 1629504000 }
) {
totalValueLockedUSD
}
}
`,
}),
})
);
const results = await Promise.all(requests);
const tvls = await Promise.all(results.map((result) => result.json()));
const dataContainer = document.getElementById("data-container");
tvls.forEach((feed, index) => {
const platformName = urls[index].name;
const feedData = feed.data.dailySnapshot8_20_23;
feedData.forEach((snapshot) => {
const snapshotElement = document.createElement("div");
snapshotElement.innerHTML = `
<h3>${platformName}</h3>
<p>Total Value Locked USD: ${snapshot.totalValueLockedUSD}</p>
<hr>
`;
dataContainer.appendChild(snapshotElement);
});
});
}
getTVLs();
Create an HTML file to display the results:
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TVL on Aug 20th, 2023</title>
<link rel="stylesheet" href="styles.css" />
<link
href="https://fonts.googleapis.com/css2?family=Raleway:ital,wght@0,300;1,300&display=swap"
rel="stylesheet"
/>
</head>
<body class="container">
<h1>TVL on Aug 20th, 2023</h1>
<div id="data-container"></div>
<script type="text/javascript" src="app.js"></script>
</body>
</html>
Create a CSS file (styles.css
) to make everything look nice:
// styles.css
body {
font-family: "Raleway", sans-serif;
background-color: #f4f4f9;
color: #333;
margin: 0;
padding: 20px;
}
.container {
max-width: 800px;
margin: auto;
padding: 20px;
background-color: #ffffff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
h1 {
color: #0a4870;
text-align: center;
}
div#data-container {
margin-top: 20px;
}
div#data-container > div {
padding: 10px;
border-bottom: 1px solid #eee;
}
h3 {
color: #0a4870;
margin: 0 0 5px 0;
}
p {
margin: 5px 0;
}
hr {
margin-top: 10px;
border: none;
height: 1px;
background-color: #eee;
}
Once you’ve got the basic setup down, you can start writing more interesting queries to get even more insights about many DeFi protocols. Here are a few ideas:
Number of Daily Active Users Between Jan 1st, 2021 and Feb 1st, 2021
query DailyActiveUsers {
usageMetricsDailySnapshots(
where: {timestamp_gt: "1609480861", timestamp_lt: "1612159261"}
) {
dailyActiveUsers
timestamp
}
}
Daily Trading Volume, Daily Revenue, and TVL Over the Past 10 Days
{
financialsDailySnapshots(
first: 10
orderBy: timestamp
orderDirection: desc
) {
timestamp
dailyVolumeUSD
dailyTotalRevenueUSD
totalValueLockedUSD
}
}
By querying these standardized subgraphs, you can gather valuable insights across multiple exchanges efficiently, helping you stay ahead in the fast-paced DeFi landscape. Happy querying!
Marcus Rein
Developer Relations and Success
Edge & Node - Working on The Graph