Given the resounding positive feedback to last week’s release of ETH Carbon Footprint, we thought it would be helpful to new Terminal users if we released instances of advanced usage for API studio on a consistent basis. If you’ve never used Terminal before, be sure to check us out at www.terminal.co.

This week we are following up ETH Carbon Footprint with a protocol-specific API.  Given the open-source and community focused ethos that Uniswap has managed to instill within its developer community, we thought it would be fitting to build an API that helps developers working with Uniswap fetch historical exchange data in novel and interesting ways with Terminal.

This week’s project is called Unistats. Unistats fetches historical fees accrued for any Uniswap exchange.  Simply pass in the exchange address and the UniStats api will fetch historical fees accrued by all liquidity providers in terms of ETH and the ERC20 token pair.  Check out the UniStats app here.  If you’re interested in how it works internally, check out the public API resource on Terminal HexHub here or the frontend repo on Github here.

Our goal for the Unistats API was to build minimum viable logic for doing historical data fetching on Uniswap exchanges alongside a fancy UI to show it off.  The API itself is publicly available on HexHub, click here to check it out.  Our hope is that Uniswap's community of developers can use this API as a basis for implementing more complex logic in their own APIs on Terminal.  

We came up with a few additional initiatives that we hope the Uniswap community can spearhead using Terminal, such as getting fees accrued for a specific liquidity provider, getting historical fees in terms of Dai, and more.  Come join our Discord if you’re interested in working on one of these projects.  We would be happy to work with you on the project, provide support, highlight your work in our newsletter, and integrate your API directly into the Unistats website!

API Overview

The Unistats API is composed of two promises, referenced by the variable names "eth" and "token" (See code snippet below). The queries inside the promises are both relatively similar.  They begin by joining the public_transactions and public_logs table to settle the valid transaction hashes for the exchange in question.  The strings ‘0xcd60aa75' and '0x7f4091b4' match the first ten characters of the event topics against the event signatures of EthPurchase and TokenPurchcase. ‘Topics’ can be thought of as representing the data that is emitted from the event. The query uses these strings to determine the input type for the transaction, i.e. whether the fee is taken off of ETH or the ERC20 token pair.

The input value for each swap is stored in hex format from index 66 to 135 in topics as a 32 byte integer. Handling the conversion from hex to numeric types is a little tricky as postgresql does not offer native support for this conversion, so we baked in the "public_hex_to_dec" function, which is now available for anyone using API Studio. Once we successfully parse the hex values to decimal, we can simply multiply the transaction values by .003 or .3% in order to determine the total amount of fees accrued for a given transaction. Since both of the queries are wrapped in Javascript promises, we to force both to resolve successfully before returning using promise.all().

const eth = new Promise((resolve, reject) => {
    db.raw(
      `
        SELECT  sum(public_hex_to_dec(substr(l."topics", 135, 66)) * 0.003)
        FROM public_transactions t
        LEFT JOIN public_logs l ON t."hash" = l."transactionHash"
        WHERE t."to"=lower(?)
        AND l."topics" LIKE '0xcd60aa75%'
        AND t."blockNumber" > 0
        AND t."blockNumber" < ?
        AND t."network"='ethereum_main'
        AND l."network"='ethereum_main'
        `,
      [address, blockNumber],
    ).then(res => resolve(res));
  });

  const token = new Promise((resolve, reject) => {
    db.raw(
      `
        SELECT sum(public_hex_to_dec(substr(l."topics", 135, 66)) * 0.003)
        FROM public_transactions t
        LEFT JOIN public_logs l ON t."hash" = l."transactionHash"
        WHERE t."to"=lower(?)
        AND l."topics" LIKE '0x7f4091b4%'
        AND t."blockNumber" > 0
        AND t."blockNumber" < ?
        AND t."network"='ethereum_main'
        AND l."network"='ethereum_main'
        `,
      [address, blockNumber],
    ).then(res => resolve(res));
  });
  
  const tokenAddress = await factoryContract.methods.getToken(address)

  
if (tokenAddress != ZERO) {
    Promise.all([token, eth]).then(vals => {
    const tokenFees = vals[0].rows[0].sum;
    const ethFees = vals[1].rows[0].sum;

    res.send({
      tokenFees,
      ethFees,
    });
  });

*Note how the second argument to the ‘db.raw’ method is an array.  The elements of the array are derived from the post params.  These elements replace the “?’s” in the query body in the order in which they appear.  For example, the question mark in `WHERE t.”from”=lower(?)` is replaced by the value of the first element in the array (address).


Read our Docs to get started, be a part of the community by joining our Discord, follow us on Twitter for all the updates and subscribe to our Blog for all the insights.