Analysing GraphQL Data

The Graph and GraphQL

The Graph is a decentralized protocol for indexing and querying data from blockchains, starting with Ethereum. What that means: it is an easier way to retrieve specific data from the blockchain, within the ethos of web3, with the advantages of decentralization and reliability.

GraphQL is the underlying query language utilised in The Graph. What is the difference between standard RESTFUL API calls and GraphQL calls? The difference is that traditional APIs require the developers to create specific endpoints for users that return specific data. If the user requires more information, they may need to make multiple API calls, sometimes hundreds of API calls, to get the information they require. With The Graph (which uses GraphQL), only one call is needed to a subgraph, as long as the developer has created a flexible schema.

For more information on The Graph and the underlying GraphQL, see this GraphQL primer.

If you are consuming GraphQL data in your app, we'd recommend using Apollo.

Aave's Subgraphs

To view the source of our subgraphs, see our Github repo.

Mainnet
Kovan
Ropsten
Mainnet

Return Data Types

Subgraph Address

Multi-pools subgraph

https://thegraph.com/explorer/subgraph/aave/protocol-multy-raw

Governance subgraph

https://thegraph.com/explorer/subgraph/aave/governance-v1

Kovan
Ropsten

Return Data Types

Subgraph Address

Multi-pools subgraph

https://thegraph.com/explorer/subgraph/aave/protocol-multy-ropsten-raw

How to use the playground

If you visit the above playground links in your browser, you will be taken to The Graph’s playground, where you can easily construct and test GraphQL queries.

  • To execute your query, select the purple play button.

  • The query results will be returned in the middle column.

  • To find out what data is available, use the ‘Schema’ column on the right, which can be explored to discover the underlying data.

  • You can also type in the left column and use the auto-complete to find the correct query/types.

Common 'Gotchas'

  • All address values (e.g. when used for id) must be in lower case format.

  • The ID of reserves is the address of the asset and the address of the market's LendingPoolAddressProvider, in lower case.

  • When using the raw endpoints, depending on the type of numeric value queried, it will be returned either in wei units (i.e. 10^18), the decimals of the asset itself (i.e. 10^6 for USDC), or ray units (i.e. 10^27).

  • Each results 'page' returns 100 entries by default. This can be increased to a maximum of 1000 entries per page.

    • E.g. to list the next 1000 entries, append something similar to: (skip:1000, first: 1000) to your query's parameters.

    • This also applies to nested entries, such as arrays.

  • All data on our Graph endpoint is static. Therefore to get the latest balancer of a user (which includes the interest earned up to that second), you would need to either calculate it yourself or make a balanceOf() call to the aToken contract.

Accessing GraphQL data from your app

The recommended way is to use a client library that can take care of the 'plumbing' to ensure you have up to date data (with caching sometimes included). Internally we use Apollo, but there are many options depending on your programming language, see the official GraphQL page.

If for some reason you cannot use a client library (e.g. querying via Postman), then you can create a POST request to our subgraph's HTTP endpoint, with header: Content-Type: application/json and the body consisting of your query on one line in quotations. For example:

{"query": "{ reserves (where: {usageAsCollateralEnabled: true}) { id name price {id} liquidityRate variableBorrowRate stableBorrowRate}}" }

Example Queries

In the below queries, we'll be using the mainnet Big uints GraphQL endpoints. You can copy and paste these queries into the Graph playground links.

Reserve data

If we want to get a list of all the reserves that are able to be used as collateral, along with each reserve's interest rate details , our query would look like:

{
reserves (where: {
usageAsCollateralEnabled: true
}) {
id
name
price {
id
}
liquidityRate
variableBorrowRate
stableBorrowRate
}
}

If we want to fetch data for a specific reserve, then we would use the reserves ERC20 token address. E.g. for the Chainlink reserve:

{
reserve(id: "0x514910771af9ca656af840dff83e8264ecf986ca0x24a42fd28c976a61df5d00d0599c34c4f90748c8") { // LINK
symbol
price
aToken {
id
}
}
}

If we want to fetch historic interest rate data for a particular reserve and paginate through the records, our query could look something like:

{
reserve (id: "0x0000000000085d4780b73119b644ae5ecd22b3760x24a42fd28c976a61df5d00d0599c34c4f90748c8") { // TUSD
id
paramsHistory(skip:1000, first: 1000) {
id
variableBorrowRate
utilizationRate
liquidityRate
timestamp
}
}
}

User data

When an address interacts with the Aave Protocol, a UserReserve is created with the user ID being the user's address + the reserve's ID (which is the ERC20 token address).

To fetch the details of a particular UserReserve:

{
userReserve(id: "USER_ADDRESS_AND_RESERVE_ADDRESS") {
reserve {
id
symbol
}
user {
id
}
}
}

To fetch all the reserves (i.e. positions) that a specific user has (note that user address must be lower case):

{
userReserves(where: { user: "USER_ADDRESS"}) {
id
reserve{
id
symbol
}
user {
id
}
}
}

Deposit data

To get recent deposits for a particular asset:

{
deposits (orderBy: timestamp, orderDirection: desc, where: {
reserve: "0xdac17f958d2ee523a2206206994597c13d831ec70x24a42fd28c976a61df5d00d0599c34c4f90748c8" // USDT
}) {
id
amount
timestamp
}
}

Borrow data

To get recent borrows for a particular asset:

{
borrows (orderBy: timestamp, orderDirection: desc, where: {
reserve: "0xdac17f958d2ee523a2206206994597c13d831ec70x24a42fd28c976a61df5d00d0599c34c4f90748c8" // USDT
}) {
id
amount
timestamp
}
}

Flash loan data

An example query for analysing the 5 most recent Flash Loans would be:

{
flashLoans(
first: 5
orderBy: timestamp
orderDirection: desc
) {
id
reserve {
id
name
symbol
}
amount
totalFee
timestamp
}
}