Como monitorar preços de criptomoedas na PancakeSwap V3

Cripto

Como monitorar preços de criptomoedas na PancakeSwap V3

Luiz Duarte
Escrito por Luiz Duarte em 09/05/2024
Junte-se a mais de 34 mil devs

Entre para minha lista e receba conteúdos exclusivos e com prioridade

Uma das primeiras barreiras que encontramos quando queremos iniciar um trabalho de monitorar uma dex qualquer, como a PancakeSwap, é que como ela roda inteiramente na blockchain (web3 baby!), não há APIs REST para usarmos do modo que faríamos com corretoras centralizadas como Binance, por exemplo. Ao invés disso, precisamos interagir com smart contracts na blockchain usando bibliotecas com Web3.js ou EthersJS, que já mostrei como algumas vezes aqui no blog (clique nos links para conhecer os tutoriais).

No entanto, as dex não costumam fornecer em seus smart contracts funções que exibam os preços dos ativos e aí mora nosso primeiro e maior problema. Isso não é possível de maneira tão simples quanto em exchanges centralizadas porque não existe um book de ofertas para se consultar o preço atual em 99% das dex, pois elas operam de maneira diferente, baseadas na Constant Product Formula e outras “matemáticas” derivadas dela. Assim, com base na oferta de um par de moedas em um pool de liquidez vs o tamanho do lote a ser negociado, um “preço” é estipulado para aquela operação, na própria transação do swap em si.

Ou seja, não é algo impossível de ser calculado, apenas um pouco mais complexo do que gostaríamos e é justamente isso que vou te mostrar como fazer neste tutorial. É importante entender que para conseguir acompanhar este tutorial você deve ter conhecimentos básicos de Node.js e de funcionamento da PancakeSwap, como usuário. Ajuda um pouco se você conhecer o básico de smart contracts em Solidity também, mas não é algo obrigatório.

Vamos lá!

Estruturando o Projeto

Para fazer chamadas aos smart contracts da PancakeSwap você vai precisar ter acesso a um nó da blockchain que desejará monitorar. Felizmente a BNB Chain, rede onde a PancakeSwap opera, fornece um nó público para usarmos, mas se tiver problemas com ele pode usar um nó profissional fornecido pela QuickNode gratuitamente (basta se cadastrar e criar o endpoint).

Agora vamos criar nosso projeto Node.js, começando pela criação de uma pasta pancakeswap-monitor e inicialização de um projeto Node.js nela.

Depois, vamos instalar as dependências que vamos precisar.

A saber:

  • DotEnv: pacote para carregamento das variáveis de ambiente;
  • Ethers: pacote para comunicação com a blockchain;
  • @pancakeswap: pacotes utilitários para comunicação com os smart contracts da PancakeSwap;

Agora crie um arquivo .env na raiz do seu projeto e coloque nele as seguintes variáveis:

  • INTERVAL: informe o intervalo em que o bot vai coletar o preço atualizado. Ex: 300000 (5min);
  • PROVIDER_URL: o endereço do nó RPC que vai usar para acessar a rede. Ex: https://bsc-dataseed.binance.org/ (nó BSC Mainnet)
  • FACTORY_ADDRESS: o endereço do contrato de pool factory da PancakeSwap V3, chamado PancakeV3PoolDeployer. Lista completa de endereços neste link.
  • QUOTER_ADDRESS: o endereço do contrato de quoting (cotação) da PancakeSwap V3, chamado QuoterV2. Lista completa de endereços neste link.
  • TOKEN_IN_ADDRESS: o endereço do contrato ERC20 do token in na rede que vai monitorar. Ex: 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c (WBNB na BSC Mainnet)
  • TOKEN_OUT_ADDRESS: o endereço do contrato ERC20 do token out na rede que vai monitorar. Ex: 0x55d398326f99059fF775485246999027B3197955 (USDT na BSC Mainnet)

Muita atenção aqui à variável INTERVAL, pois os nós possuem uma limitação de chamadas por dia. É bastante, mas não custa nada tomar cuidado né. Outro ponto de atenção são os endereços dos tokens in e out, sendo que aqui vamos ter como resultado a cotação em dólares do BNB, através do par WBNB/USDT (Wrapped BNB, pareado com BNB e Tether, pareado com dólar).

Agora crie um arquivo Pool.abi.json na raiz do projeto onde você deverá colocar o código abaixo, que especifica um ABI (Application Binary Interface) do contrato de liquidity pool da dex. Ele serve para fazermos a comunicação com pools de liquidez na blockchain.

Da mesma forma, precisaremos de mais um ABI, o Quoter.abi.json, com o código abaixo. Ele serve para nos comunicarmos com o contrato de cotação da dex na blockchain.

Por fim, crie um arquivo index.js na raiz do seu projeto e configure no package.json para que ele seja executado no comando de start, já que é nele que irá toda a lógica do nosso bot.

E com isso temos toda a “infraestrutura” necessária para desenvolver o nosso robô de monitoramento de preços na PancakeSwap, vamos em frente.

Curso Node.js e MongoDB

Preparando o Monitoramento

O primeiro passo agora que estamos com a estrutura inicial do projeto pronta é obter as informações da exchange relativas ao pool de liquidez que vamos monitorar. Para isso precisaremos configurar uma série de variáveis e codificar uma função. Mas vamos por partes.

Primeiro, carregamos os pacotes e as variáveis de ambiente em constantes locais no index.js.

Em seguida, vamos criar objetos com as configurações das duas moedas que formam o par de monitoramento. Para isso usarei o enumerador ChainId e a classe Token, provenientes do SDK da PancakeSwap. Repare que você terá de mudar estas configurações de tokens conforme o par que decidir monitorar, sendo que aqui estou conduzindo tudo para monitorar WBNB em USDT.

A última etapa de configuração da preparação do monitoramento é configurarmos o provedor de acesso à blockchain, usando a classe JsonRpcProvider disponível na biblioteca Ethers v6 em conjunto com o carregamento dos arquivos JSON de ABIs que criamos anteriormente e que usaremos logo mais.

Agora que temos todas variáveis monitoradas, vamos escrever a função que carrega todas as informações do pool que precisamos para obter as cotações. O primeiro passo desta função é descobrir o endereço do pool a ser monitorado. Se você já possui esse endereço, pode ignorar esta etapa e colocar ele em uma constante chamada currentPoolAddress.

O endereço do pool é resultado de um cálculo em cima de algumas informações que passamos para a função computePoolAddress, presente no PancakeSwap SDK. Repare que WBNB_TOKEN e USDT_TOKEN são objetos que pré-configuramos antes (não confundir com os endereços deles). Além disso, repare também que estarei considerando para nossas cotações a taxa mais baixa (fee) do pool e que os preços podem variar para mais ou para menos conforme a liquidez do pool com taxas menores e maiores. Resumindo: teremos uma ideia de preço, mas não absoluto/universal.

O próximo passo é carregar o ABI do contrato de pool e carregar um objeto com o referido endereço de contrato (usando o provider criado anteriormente). Com esse objeto poolContract podemos fazer uma chamada ao contrato de pool para saber a última informação que ainda não temos: o valor nominal da taxa de swap ou simplesmente: a fee. Novamente: se você já sabe o fee exato do pool que vai monitorar, você pode apenas colocar ele no código, embora essa chamada é interessante para garantir que o pool em questão existe.

Com estas três informações do pool a ser monitorado (tokenIn, tokenOut e fee), estamos com tudo pronto para finalizar nosso bot.

Curso Beholder
Curso Beholder

Programando o Monitoramento

Repare que até esta etapa já tivemos de fazer uma chamada à blockchain e, além disto gastar acessos no nó RPC, é algo que toma tempo e que você não vai querer fazer toda hora. Por isso que essa etapa de preparação está em uma função exclusiva. Função essa que será chamada logo mais.

Mas agora é hora de começarmos a implementar a função de monitoramento de fato.

Nesta função nós vamos receber as informações que obtivemos anteriormente na etapa de preparação, usando-as ao longo da função. A primeira etapa é usar o endereço do contrato de QuoterV2 e seu ABI em conjunto do mesmo provider que configuramos lá atrás. Assim teremos um objeto e comunicação com o contrato de cotação.

Na sequência, chamamos a função quoteExactInputSingle do contrato de Quoter que espera os dados dos tokens, da fee, a quantidade de token que vamos gastar e o mínimo que esperamos receber (“0” quer dizer qualquer quantia no sqrtPriceLimitX96).

Repare que após a chamada da função eu usei o recurso staticCall. Esse recurso é crucial para nosso robô pois a função quoteExactInputSingle é uma transaction, ou seja: escreve na blockchain e consequentemente gera custos na sua execução. No entanto, ao usarmos uma static call nós dizemos ao nó da blockchain que ele deve executar a transação mas não deve persisti-la no disco, nos livrando dos custos envolvidos. Como é apenas uma informação que queremos, esse comportamento de transação “efêmera” é perfeitamente aceitável.

Agora que finalizamos nossa função de execução do ciclo de monitoramento, vamos implementar o monitoramento em si.

Aqui estou usando um IIFE para conseguir fazer chamadas com Async/Await na raiz do index.js. Começo fazendo a única chamada que teremos à função preparationCycle, pego estas informações para serem passadas adiante e configuro o timer que rodará a cada x tempo refazendo o monitoramento. Como não quero ter de esperar pela execução do primeiro ciclo, já chamo a executionCycle logo na sequência.

Internamente, a executionCycle já vai imprimir pra gente o preço obtido na cotação, então com isso programado e rodando o projeto com npm start, você terá o preço impresso no seu console a cada 5 minutos.

A própria PancakeSwap criou uma Graph API que faz exatamente o que mostrei neste tutorial, mas expõe de maneira mais simples, saiba mais aqui.

Também possuo tutoriais que podem lhe ajudar a transformar esse conhecimento em um bot de sinais, como esse de Telegram, de email, de SMS e até de Whatsapp ou esse aqui onde ensino a fazer um bot trader para PancakeSwap.

Está tendo erros? Consulte no meu guia de erros comuns de integração com PancakeSwap, neste link.

E com isso finalizamos mais este tutorial. Até o próximo!

Olá, tudo bem?

O que você achou deste conteúdo? Conte nos comentários.

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *