E chegamos finalmente na terceira e última etapa de construção do nosso bot trader de criptomoedas na exchange decentralizada (dex) PancakeSwap usando a tecnologia Node.js. Na etapa anterior, que é imprescindível que você tenha finalizado com sucesso, nós implementamos o swap de tokens que não sejam BNB e nesta última parte faremos o mesmo, mas para swaps justamente envolvendo BNB, seja como moeda que será enviada ou recebida na transação.
Essa diferença se dá pelo fato de que o BNB é a moeda nativa da rede BSC, assim como o Bitcoin é na rede BTC e o Ether é na rede ETH. As moedas nativas das redes possuem funções específicas para serem transacionadas e por isso exigirá códigos diferentes em nosso bot, caso você queira negociá-las. A parte boa é que não muda muito em relação ao que já fizemos anteriormente e muitas funções serão reaproveitadas inclusive.
Então vamos lá!
#1 – Swap para BNB
A primeira função que vamos fazer no api.js é a swapToBNB, ou seja, trocar algum token da sua carteira pelo equivalente em BNB. Para fazer isso é muito parecido com o que fizemos na função swapTokens: temos de conectar no full node/provider usando a carteira, conectar no contrato de roteamento da dex, passar a interface da função, configurar parâmetros e aprovar o valor a ser transferido, tudo isso antes da transação em si, como abaixo.
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 |
const WBNB_CONTRACT = "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd"; async function swapToBNB(walletAddress, tokenContract, amountIn) { const account = getWallet(); const contract = new ethers.Contract( ROUTER_CONTRACT, ["function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts)"], account); const value = ethers.parseEther(amountIn).toString(); await approve(tokenContract, value); const gasPrice = ethers.parseUnits('10', 'gwei'); return contract.swapExactTokensForETH(value, 0, [ tokenContract, WBNB_CONTRACT ], walletAddress, Date.now() + 10000,//prazo para ordem ser concluída { gasPrice, gasLimit: 300000 }); } |
Esta função vai esperar o endereço da carteira que fará o swap, o endereço do contrato do token que vai ser enviado e a quantidade de tokens. A constante ROUTER_CONTRACT é a que usamos anteriormente, indicando o endereço do contrato de roteamento na PancakeSwap, sendo que os dois valores possíveis para esta constante são:
- Testnet: 0xD99D1c33F9fC3444f8101754aBC46c52416550D1
- Mainnet: 0x10ED43C718714eb63d5aA57B78B54704E256024E
Já o ABI que usamos é o swapExactTokensForETH, ou seja, trocar uma quantia específica de um token à nossa escolha por tantos BNB quanto for possível. Não se confunda com o ETH no nome da função, pois por questões de compatibilidade a BSC mantém todos os nomes de funções do mesmo jeito que na rede ETH. Assim, sempre que ver ETH ou Ether escrito, considere que estamos falando de BNB ou a moeda nativa da rede que estiver usando.
As configurações de gás permanecem as mesmas e o fluxo de pré-aprovação da quantia também. Já o envio da transação muda um pouco já que temos de informar no path do roteamento o endereço do contrato de WBNB, que aqui eu deixei fixo em uma constante. Os dois valores possíveis para esta constante são:
- Testnet: 0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd
- Mainnet: 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c
Mas por que devemos usar o contrato de WBNB ao invés de BNB “normal”?
O contrato BNB normal é de autoria e propriedade da Binance, logo acabaríamos caindo na boa e velha centralização novamente. WBNB ou Wrapped BNB é um token associado ao BNB, ou seja, possui exatamente o mesmo valor do mesmo, mas é representado por outro token e possui outro contrato, sendo usado no roteamento dos swaps dentro da PancakeSwap.
Na prática, isso não muda nada na sua carteira, é apenas para fins de transacionar os swaps corretamente mesmo.
Agora você pode alterar o seu index.js caso queira trocar seus tokens para BNB.
#2 – Swap de BNB
A função que ensinei a criar anteriormente serve para fazer o caminho de um token qualquer para BNB. Mas se você quiser fazer o caminho contrário deve utilizar outra função, que vamos chamar de swapFromBNB e que vai esperar a carteira, o contrato do token que deseja receber e quantos BNB deseja gastar. No mais esta função do api.js é bem parecida com a anterior, salvo alguns detalhes que falarei a seguir.
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 |
async function swapFromBNB(walletAddress, tokenContract, bnbToSpend) { const account = getWallet(); const contract = new ethers.Contract( ROUTER_CONTRACT, ["function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts)"], account); const value = ethers.parseEther(bnbToSpend).toString(); const gasPrice = ethers.parseUnits('10', 'gwei'); return contract.swapExactETHForTokens(0, [ WBNB_CONTRACT, tokenContract ], walletAddress, Date.now() + 10000,//prazo para ordem ser concluída { gasPrice, gasLimit: 300000, value }); } |
A primeira diferença é o uso da função swapExactETHForTokens, que serve para trocar uma quantia exata de BNB por algum outro token qualquer, na quantidade que for possível. Como esta função é no sentido contrário da anterior, você verá no envio da transação que passamos primeiro o contrato de WBNB e depois o contrato do token desejado.
Outra diferença significativa nesta função é o fato de não haver necessidade de pré-aprovação da quantia a ser gasta. Sim, isso mesmo: quando você quer trocar BNB por outro token não há necessidade de aprovação prévia já que é o token nativo da rede e desta forma possui mecanismos internos diferentes.
E a última diferença é que a quantia a ser gasta deve ser informada no campo value das configurações da transação, logo após as configs de gás. Novamente, essa diferença se deve ao fato de estarmos enviando a moeda nativa da rede.
Com isso, agora você tem todas as funções necessárias para que seu bot possa fazer o swap de qualquer token negociado na PancakeSwap e pode alterar o seu index.js com a sua lógica de swap que for mais vantajosa para você, usando as funções que ensinei.
#3 – Bônus: getBalance
Como bônus quero ensinar você a codificar mais uma função no api.js, desta vez para pegar o saldo de um token na sua carteira. Isso porque pode ser interessante o seu bot dar uma olhada na sua carteira para ver o quanto ele pode comprar ou vender de um token, antes de tentar fazê-lo, certo?
Assim, vamos criar uma nova função no api.js chamada getBalance que vai esperar o endereço da carteira, o endereço do contrato do token e o número de casas decimais do dito-cujo, que definiremos por padrão como sendo 18 casas.
1 2 3 4 5 6 7 8 |
async function getBalance(walletAddress, contractAddress, decimals = 18) { const provider = getProvider(); const contract = new ethers.Contract(contractAddress, ["function balanceOf(address) view returns (uint)"], provider); const balance = await contract.balanceOf(walletAddress) return ethers.utils.formatUnits(balance, decimals); } |
O primeiro passo é obter o objeto provider, que informa onde está nosso full node. Na sequência configuramos nosso objeto Contract com o endereço do token, o ABI da função balanceOf, presente em todos tokens ERC20 e BEP20, e o provider usado. Repare aqui que não precisamos nos conectar na carteira, isso porque as informações de saldo das carteiras são públicas na blockchain e como é uma operação somente de leitura, não haverá execução de transação e nem incidência de taxas.
Com o contract devidamente configurado, basta passar o endereço da carteira que queremos dar uma olhadinha e teremos o balance daquele token naquela carteira.
A cereja do bolo é a formatação do número que vai vir com a quantidade certa de casas decimais do seu token. Agora sim, todas as vezes que chamar a função getBalance do api.js você terá o saldo de um token à sua escolha na carteira informada.
E com isso espero ter contribuído para seu aprendizado de integração e automação com a dex PancakeSwap usando Node.js.
Teve algum problema? Confira este artigo com os erros mais comuns!
Até a próxima!
Olá, tudo bem?
O que você achou deste conteúdo? Conte nos comentários.
Como faz para colocar o saldo total de tokens na venda? Por exemplo, comprei 1wbnb de cake usando o bot, agora na hora da venda eu quero colocar todo o meu saldo de cake para receber em wbnb.
Pode pegar nos logs da transação o valor recebido ou então pode consultar o saldo do token recebido na sua carteira (função balanceOf do contrato do token ERC20).