DEXDeFiWeb3

Retrieving Uniswap trades using The Graph

With the rise of Uniswap, Messari was presented with the challenge of providing real-time and historical data for this thriving AMM (automated market-maker). While data reporting infrastructure around centralized exchanges is relatively mature, the same is not the case for decentralized exchanges.

To solve this issue, we turned to The Graph, which is a decentralized querying protocol that interfaces with Ethereum. Here's how we did it.

Background

Retrieving real-time and historical trade data from Uniswap can be challenging. One way to retrieve trade data is parse out the Swap events emitted from the ERC20 contract:

event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);

A trade event like this DAI-ETH swap looks as follows:

Notice amount0In is 35000000000000000000, that is a whole lot of DAI! Similarly amount1Out of 103496165542782070 wETH? Am I rich?!

Actually, parsing DAI and wETH smart contracts we find that both ERC20 tokens are specified using 18 decimals:

This means we have to divide by 10^18 in order to retrieve the actual amount0In of 35 DAI swapped for amount1Out 0.1034 ETH, dang I’m not rich!

Hence in order to retrieve a single trade on the Uniswap contract, we performed the following:

  1. connect to an Ethereum node and listen to the Swap event from the Uniswap contract
  2. retrieve the raw amount0In, amount1Out values from the event
  3. retrieve the DAI and wETH smart contracts associated to In and Out and parse out the decimal values
  4. convert raw amounts into actual DAI and wETH token amounts by dividing the decimal values

Now imagine we needed to retrieve all DAI-ETH trades since the inception of Uniswap, we’d have to replay all Ethereum blocks from the start of Uniswap’s inception and perform the above steps on all DAI-ETH swap events.

This requires an in-depth ETL infrastructure investment.

The Graph

The Graph provides a GraphQL abstraction on top of the Ethereum network, allowing consumers to retrieve normalized trades from Uniswap.

The same DAI-ETH pair can be retrieved using the following query inside the playground:

query swaps{
swaps(where:{transaction:"0x5ed0ee8ff25e0a368519ba10822d2f1d4261ca8cf3fe42b4f5806a515865d88f"}) {
id
timestamp
amount0In
amount1In
amount0Out
amount1Out
sender
to
pair {
token0 {
id
symbol
}
token1 {
id
symbol
}
}
}
}

Notice the normalized amount0In of 35 DAI swapped for amount1Out 0.1034 ETH gets returned!

This means we no longer have to retrieve the individual Swap events and extrapolate the relevant with the referencing DAI and wETH smart contracts.

Additionally, the above query returns the id and symbol of the tokens that have been swapped, within the pair sub-object. This provides a handy visual reference and allows us to audit the normalization process.

Under the hood

As mentioned earlier, The Graph uses GraphQL to interface with the Ethereum network. For folks who aren’t familiar, GraphQL is a query framework mapping a user query to one or more backend queries, allowing the user to work on a higher level of abstraction without knowing the internals of the underlying system.

Contrast the above single GraphQL query swaps(where:{transaction:"..."}) to the four step process in monitoring the on-chain Swap (index_topic_1 address sender, uint256 amount0In, ...) event.

This mapping is maintained within the Uniswap V2 Subgraph repository by the Uniswap team. Where the mapping dictates which events from the ERC20 contract should be extracted, transformed, and stored. It also provides a clear and concise abstraction for the user to query the stored data and consume it in a useful way.

In fact, https://info.uniswap.org/ is powered by this subgraph using this exact abstraction.

Historical Data

To retrieve historical DAI-ETH data, we can specify the number of historical trades we want via first: 150, starting at a given block via block: {number:11009390} ordered descending by the time traded via orderBy: timestamp, orderDirection: desc

query trades{
swaps(where:{pair: "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11"}, orderBy: timestamp, orderDirection: desc, first:150, block: {number:11009390}) {
id
timestamp
amount0In
amount1In
amount0Out
amount1Out
pair {
token0 {
id
symbol
}
token1 {
id
symbol
}
}
transaction {
blockNumber
}
}
}

Real-Time Data

To get real-time DAI-ETH trades, change query to subscription. Under the hood this uses a websocket connection to push new trades to the consumer when a swap has happened on-chain:

subscription swaps{
swaps(orderBy: timestamp, orderDirection: desc, where:{pair: "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11"}) {
id
timestamp
amount0In
amount1In
amount0Out
amount1Out
pair {
token0 {
id
symbol
}
token1 {
id
symbol
}
}
}
}

Messari

At Messari we use The Graph extensively to populate Uniswap markets like this one.

If you would like to build with us, visit us at https://messari.io/careers or shoot us an email at careers@messari.io

Let us know what you loved about the report, what may be missing, or share any other feedback by filling out this short form. All responses are subject to our Privacy Policy and Terms of Service.

Diran is the CTO at Messari. His domain of expertise ranges between AI, crypto, and enterprise software.

Mentioned Assets

Suggested Research Based on your Watchlists

Create a new watchlist
Outline
  • Background
  • The Graph
  • Under the hood
  • Historical Data
  • Real-Time Data
  • Messari
Author
Diran is the CTO at Messari. His domain of expertise ranges between AI, crypto, and enterprise software.
Mentioned Assets