Se você já trabalhou em projetos que envolvem integração com exchanges descentralizadas (dex), como Uniswap e outras, sabe o quão sofrido pode ser tentar obter informações para alimentar dashboards, bots, etc. Isso porque uma vez que todos os dados estão nos smart contracts na blockchain e não há uma maneira simples e eficiente de consultá-los, não é incomum ter de fazer chamadas RPC a vários contratos para se ter algo “simples” como a cotação de um par de moedas.
Pensando nisso a equipe de desenvolvimento da Uniswap, a maior exchange descentralizada do mundo, criou uma graph API pública que permite consultar uma série de informações de maneira rápida e prática. Neste tutorial vamos explorar as suas possibilidades e como fazer consultas utilizando JavaScript, seja no frontend ou no backend.
Se preferir, você pode assistir ao vídeo abaixo ao invés de ler este tutorial, apenas atenção à URL que mudou recentemente, pode pegar ela aqui no artigo.
Vamos lá!
O que é uma Graph API?
Uma Graph API, abreviação de “Graph Application Programming Interface” (Interface de Programação de Aplicativos de Grafo), é um tipo de API (Interface de Programação de Aplicativos) que permite que aplicativos interajam com e recuperem dados de um grafo. Um grafo, nesse contexto, refere-se a uma estrutura de dados composta por nós (ou vértices) e arestas (ou conexões) que conectam esses nós.
O termo “Graph API” é frequentemente associado ao Facebook Graph API, lançado por volta de 2010. Era algo bem diferente pra época pois tínhamos saído há pouco do padrão SOAP e estávamos entrando no jeito REST de criar APIs. A Open Graph como foi chamada à época é uma API desenvolvida pelo Facebook para permitir que os desenvolvedores acessem e interajam com os dados do Facebook, como perfis de usuários, páginas, grupos, fotos e outras informações relacionadas à rede social. O Facebook Graph API usa o conceito de um grafo para representar as relações entre os diferentes objetos e entidades dentro do Facebook.
No entanto, além do Facebook, muitas outras plataformas e serviços passaram a oferecer Graph APIs ao longo dos anos para permitir que os desenvolvedores acessem e interajam com dados que podem ser modelados como grafos. Por exemplo, serviços de redes sociais, como o LinkedIn, Twitter e Instagram, também têm suas próprias Graph APIs para acesso a dados de seus respectivos gráficos de conexões.
Em resumo, uma Graph API é uma interface que permite que os desenvolvedores acessem e manipulem dados em forma de grafo, onde os nós representam entidades e as arestas representam conexões entre essas entidades. Isso é útil para a construção de aplicativos que precisam consultar ou atualizar informações que têm relações complexas entre si.
No caso da Uniswap é a mesma coisa. Baseado em leituras de logs, um grafo é alimentado com os dados dos pools, tokens, transações e mais, gerando uma massa de dados que é exposta ao público em um endpoint do tipo Graph API, como iremos explorar neste tutorial.
Como usar a Graph API da Uniswap?
Antes de você pensar em se integrar à Graph API via código JS, é importante que você aprenda a interagir com ela manualmente, pelo explorador web disponível na plataforma que a equipe da Uniswap escolheu para hospedar seu grafo. Para isso, acesse o site da The Graph e você terá uma interface para usar a Graph API da Uniswap livremente no seu browser.
Basicamente o que temos aqui é um espaço na esquerda onde você informa uma espécie de objeto JSON com o filtro a ser utilizado na consulta, aperta o play, e na direita aparece o resultado, quase que instantaneamente. Por exemplo, se você quiser pegar dados globais da dex, pode usar o seguinte filtro:
1 2 3 4 5 6 7 8 9 |
{ factory(id: "0x1F98431c8aD98523631AE4a59f267346ea31F984" ) { poolCount txCount totalVolumeUSD } } |
Esse filtro indica que você quer consultar o contrato de factory, responsável pela criação dos pools. Mas não é qualquer contrato, mas sim aquele cujo ID seja o informado no filtro, que corresponde ao Uniswap V3 Factory na Ethereum Mainnet. Esse último ponto é importante frisar: essa Graph API é para Ethereum Mainnet, outras redes exigem usar outros endereços (falarei mais disso ao final do artigo).
Já a estrutura interna da factory diz respeito a quais campos você deseja que a consulta retorne, sendo que neste exemplo estou retornando a quantidade total de pools (poolCount), a quantidade total de transações (txCount) e o volume total transacionado em USD.
Um outro exemplo de consulta, para ajudar a fixar:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
{ pools(orderBy: volumeUSD, orderDirection: desc) { id, volumeUSD, feeTier, token0Price, token1Price, token0 { symbol, id, decimals } token1 { symbol, id, decimals } } } |
Nesta consulta eu quero retornar os pools de liquidez, ordenados pelo campo volumeUSD em direção/ordem decrescente. Já os campos retornados incluem o id (endereço) do pool, o volume em USD, a taxa/fee do pool, os preços do par de tokens e os dados dos mesmos. Isso vai me trazer os 100 pools com maior volume da Uniswap no momento.
Para obter os schemas completos, com as informações que podem ser trazidas de cada entidade, consulte esse arquivo.
Se você quiser trazer mais resultados em uma consulta, saiba que pode usar o parâmetro “first”, para definir quantos deseja, até o limite de 1000 resultados por requisição. E caso deseje paginar os resultados, pode usar o parâmetro “skip”, para definir quantos registros devem ser ignorados antes de começar a listagem. Abaixo, exemplo de uso de ambos:
1 2 3 |
pools(first: 1000, skip: 10, orderBy: volumeUSD, orderDirection: desc) |
Neste exemplo, mandei pular 10 registros e depois retornar os próximos 1000. Estes e outros exemplos podem ser encontrados na documentação oficial. E agora que já sabe como funcionam as consultas manualmente, vamos fazê-las via código.
Mas antes disso, você vai precisar ter uma API Key criada para usarmos a Graph API via código. Para isso, vá nessa página e siga o passo a passo, que consiste em:
- entrar com sua MetaMask;
- assinar uma mensagem para se autenticar na sessão;
- criar uma chave de API com o nome que quiser
Guarde esta chave consigo, vamos usá-la à seguir.
Integração com a Graph API via JS
Para este exemplo eu vou consumir a Graph API da Uniswap via JS client-side, ou seja, no frontend. No entanto, o mesmo princípio que vou usar aqui se aplica para aplicações de backend, ok? É até mais seguro fazer no backend, vou fazer no front pela didática.
Vamos criar uma aplicação de frontend bem simples usando NextJS. Caso nunca tenha usado Next, não tem problema, vai ver que é bem simples. Comece criando o projeto Next na sua máquina com o comando abaixo:
1 2 3 |
npx create-next-app uniswap-graph-api |
O assistente vai te fazer algumas perguntas, pode responder o default em praticamente todas, com exceção de Tailwind CSS que não será necessário. Nossa aplicação não vai ter qualquer estilo, pois não é o foco do tutorial.
Vamos precisar do pacote Axios, para fazer chamadas à Graph API. Para instalar ele, use o comando abaixo:
1 2 3 |
npm install axios |
Agora execute o seu projeto com o comando abaixo e abra-o no navegador, no endereço localhost:3000.
1 2 3 |
npm run dev |
Enquanto a página fica lá no navegador, abra o seu arquivo page.tsx e coloque dentro o seguinte código, que vai criar a interface pra gente. Apenas atente-se de trocar o {api-key} na URL pela sua API Key de verdade, criada na etapa anterior do tutorial:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
"use client" import { useState } from "react"; import axios from "axios"; export default function Home() { const [query, setQuery] = useState<string>(""); const [data, setData] = useState<string>(""); async function btnEnviarClick() { const { data } = await axios.post("https://gateway-arbitrum.network.thegraph.com/api/{api-key}/subgraphs/id/5zvR82QoaXYFyDEKLZ9t6v9adgnptxYpKpSbxtgVENFV", { query }); setData(data.data); } return ( <main> <div> <div style={{float: "left", width: 500 }}> <textarea id="txtFiltro" style={{height: 500, width: "100%"}} onChange={(evt) => setQuery(evt.target.value)} value={query}></textarea> <button onClick={btnEnviarClick}>Enviar</button> </div> <div style={{float: "right", width: 500 }}> <textarea style={{height: 500, width: "100%"}} readOnly={true} value={JSON.stringify(data)}></textarea> </div> </div> </main> ) } |
Muita atenção aqui à função btnEnviarClick, que é quem de fato usa o Axios para chamar a Graph API da Uniswap usando a query feita pelo usuário em um campo de texto que coloquei à esquerda na interface. Já à direita coloquei outro campo de texto, somente leitura, onde despejamos o retorno de cada consulta realizada.
O resultado não é algo bonito, mas perfeitamente funcional.
Essa mesma lógica de comunicação HTTP via Axios pode ser realizada em backends Node.js ou até mesmo com outras tecnologias HTTP.
Para completar, aqui vão endereços de Graph APIs da Uniswap em diversas blockchains:
- Ethereum: https://thegraph.com/explorer/subgraphs/5zvR82QoaXYFyDEKLZ9t6v9adgnptxYpKpSbxtgVENFV?view=Query&chain=arbitrum-one
- Polygon: https://thegraph.com/explorer/subgraphs/3hCPRGf4z88VC5rsBKU5AA9FBBq5nF3jbKJG7VZCbhjm?view=Query&chain=arbitrum-one
- BSC: https://thegraph.com/explorer/subgraphs/G5MUbSBM7Nsrm9tH2tGQUiAF4SZDGf2qeo1xPLYjKr7K?view=Query&chain=arbitrum-one
- BSC: https://thegraph.com/explorer/subgraphs/F85MNzUGYqgSHSHRGgeVMNsdnW1KtZSVgFULumXRZTw2?view=Query&chain=arbitrum-one
- Arbitrum: https://thegraph.com/explorer/subgraphs/3V7ZY6muhxaQL5qvntX1CFXJ32W7BxXZTGTwmpH5J4t3?view=Query&chain=arbitrum-one
- Optimism: https://thegraph.com/explorer/subgraphs/7SVwgBfXoWmiK6x1NF1VEo1szkeWLniqWN1oYsX3UMb5?view=Query&chain=arbitrum-one
- Avalanche: https://thegraph.com/explorer/subgraphs/4gTHdWa9PbqUugt9vsMmpzUowmjb6eRiFRnUSrYLeSJF?view=Query&chain=arbitrum-one
- Celo: https://thegraph.com/explorer/subgraphs/5GMxLtvwbfKxyCpSgHvS8FbeofS2ry9K76NL9RCzPNm2?view=Query&chain=arbitrum-one
E para mais links e suporte sobre os mesmos, recomendo o Discord da Uniswap.
Agora se quiser fazer um bot trader para Uniswap, confira este tutorial.
E com isso finalizamos mais este tutorial. Até a próxima!
Olá, tudo bem?
O que você achou deste conteúdo? Conte nos comentários.