This content originally appeared on DEV Community and was authored by Adriano P. Araujo
Desenvolvedores que atuam no ecossistema blockchain frequentemente enfrentam um desafio comum: como obter dados do mundo real, como preços de ativos, de forma segura e confiável dentro de uma aplicação descentralizada.
A dependência de serviços centralizados pode criar um ponto de falha, e as limitações de planos gratuitos podem ser um obstáculo.
A Chainlink Data Feeds surge como uma solução robusta para esse problema, oferecendo dados descentralizados e auditáveis diretamente on-chain.
Neste guia, construiremos uma aplicação em Golang para consultar os preços de múltiplos tokens de forma concorrente e eficiente, utilizando a infraestrutura da Chainlink.
Entendendo a Chainlink e o "Problema do Oráculo"
Por padrão, blockchains são sistemas isolados; elas não conseguem acessar dados de sistemas externos (off-chain). Essa limitação é conhecida como o "problema do oráculo". Como um contrato inteligente pode saber o preço do Ethereum em dólar se ele não pode "olhar" para fora da blockchain?
A Chainlink resolve exatamente isso. Ela é uma rede de oráculos descentralizada que atua como uma ponte segura entre as blockchains (on-chain) e fontes de dados do mundo real (off-chain). Ela permite que contratos inteligentes reajam a dados, eventos e pagamentos externos de forma confiável e à prova de adulteração.
Os Data Feeds são um dos serviços mais populares da Chainlink. Eles são redes de oráculos descentralizadas que fornecem informações de preços de ativos para contratos inteligentes, agregando dados de múltiplas fontes para garantir precisão e resiliência.
Agora vamos deixar de papinho e vamos ao código!
⚙️ Pré-requisitos
Antes de iniciarmos, certifique-se de que seu ambiente de desenvolvimento atende aos seguintes requisitos:
- Go instalado (versão 1.21 ou superior).
- Um provedor de RPC Ethereum. Utilizaremos um endpoint público para este guia, mas para aplicações em produção, recomenda-se serviços dedicados como Infura ou Alchemy.
- Os endereços dos contratos dos Data Feeds. Consulte a página oficial de endereços para obter os contratos corretos para a rede desejada (ex: Ethereum Mainnet, Sepolia).
- Conhecimento básico de Golang e da interação com contratos inteligentes.
1. Configuração do Projeto
Inicie criando um diretório para o projeto e inicializando um módulo Go.
mkdir chainlink-price-feed
cd chainlink-price-feed
go mod init chainlink-price-feed
2. Instalação das Dependências
Precisamos das bibliotecas go-ethereum
para interagir com a blockchain e do pacote da Chainlink que contém as interfaces dos contratos.
go get github.com/ethereum/go-ethereum
go get github.com/ethereum/go-ethereum/ethclient
go get github.com/smartcontractkit/chainlink/core/gethwrappers/generated/aggregator_v3_interface
3. Estruturando o Código
Vamos construir nosso arquivo main.go
aos poucos. Assim, você entende o propósito de cada trecho antes de ver o monstro completo.
Primeiro, vamos definir as estruturas que organizarão nossos dados. Uma (TokenConfig
) para guardar o nome e o endereço de cada token e outra (PreçoFormatado
) para armazenar o resultado bonitinho que receberemos.
package main
import (
"context"
"fmt"
"log"
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/aggregator_v3_interface"
)
// TokenConfig armazena a configuração de cada token que desejamos monitorar.
type TokenConfig struct {
Symbol string
Address common.Address
}
// FormattedPrice guarda o preço final e outras informações úteis.
type FormattedPrice struct {
Symbol string
Price *big.Float
Timestamp uint64
Decimals uint8
}
Agora, vamos começar a função main
. Aqui, nós nos conectamos à rede Ethereum e definimos quais tokens queremos monitorar. Sinta-se à vontade para adicionar ou remover tokens desta lista!
func main() {
// Conectando a um nó da Ethereum. Este endpoint público é ótimo para começar.
client, err := ethclient.Dial("https://ethereum-rpc.publicnode.com")
if err != nil {
log.Fatalf("Ops! Deu ruim ao conectar no Ethereum: %v", err)
}
defer client.Close()
// Nossa lista de alvos! Adicione quantos tokens quiser aqui.
// Esses endereços são endereços da MAINNET.
tokens := []TokenConfig{
{Symbol: "ETH", Address: common.HexToAddress("0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419")},
{Symbol: "BTC", Address: common.HexToAddress("0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c")},
{Symbol: "LINK", Address: common.HexToAddress("0x2c1d072e956AFFC0D435Cb7AC38EF18d24d9127c")},
}
Para buscar os preços de forma eficiente, vamos usar a mágica da concorrência em Go. Lançaremos uma busca para cada token ao mesmo tempo (goroutine
). Para receber os resultados de volta de forma organizada e segura, usaremos um canal (channel
).
Também adicionamos um context
com timeout, uma espécie de cronômetro de segurança para garantir que nosso programa não fique esperando para sempre se a rede estiver lenta.
// ... continuando dentro da função main()
// Este canal vai receber os preços assim que eles foremencontrados.
pricesChan := make(chan FormattedPrice, len(tokens))
// Um contexto com timeout para não ficarmos presos esperando para sempre. :p
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// Lança uma "missão" para buscar o preço de cada token, tudo ao mesmo tempo.
for _, token := range tokens {
go fetchTokenPrice(ctx, client, token, pricesChan)
}
// Agora, a gente espera e coleta os resultados que chegam pelo canal.
fmt.Println("Buscando preços...")
for i := 0; i < len(tokens); i++ {
select {
case price := <-pricesChan:
fmt.Printf("✅ Preço do %s: %.2f USD (Atualizado em: %d)\n",
price.Symbol, price.Price, price.Timestamp)
case <-ctx.Done():
log.Fatalf("Demorou demais! O timeout foi atingido: ", ctx.Err())
}
}
}
A função fetchTokenPrice
contém a lógica de interação com o contrato. Ela instancia o contrato, chama a função latestRoundData
e formata o valor retornado.
// fetchTokenPrice é o nosso "operário": ele busca o preço de um token específico.
func fetchTokenPrice(ctx context.Context, client *ethclient.Client, token TokenConfig, pricesChan chan<- FormattedPrice) {
// Cria uma instância do contrato para a gente poder interagir com ele.
aggregator, err := aggregator_v3_interface.NewAggregatorV3Interface(token.Address, client)
if err != nil {
log.Printf("Erro ao instanciar o contrato para %s: %v", token.Symbol, err)
return
}
// Pega os dados mais recentes do oráculo.
roundData, err := aggregator.LatestRoundData(nil)
if err != nil {
log.Printf("Erro ao buscar os dados para %s: %v", token.Symbol, err)
return
}
// Descobre quantas casas decimais o preço tem.
decimals, err := aggregator.Decimals(nil)
if err != nil {
log.Printf("Erro ao buscar as casas decimais para %s: %v", token.Symbol, err)
return
}
// O preço vem como um número inteiro gigante. A gente precisa formatá-lo.
priceFloat := new(big.Float).SetInt(roundData.Answer)
divisor := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimals)), nil))
formattedPrice := new(big.Float).Quo(priceFloat, divisor)
// Envia o resultado bonitão de volta para a função main através do canal.
pricesChan <- FormattedPrice{
Symbol: token.Symbol,
Price: formattedPrice,
Timestamp: roundData.UpdatedAt.Uint64(),
Decimals: decimals,
}
}
4. Código Completo (main.go
)
Ufa! Agora que você entendeu cada parte 🤔, aqui está o arquivo main.go
completo para você copiar e colar:
package main
import (
"context"
"fmt"
"log"
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/smartcontractkit/chainlink/core/gethwrappers/generated/aggregator_v3_interface"
)
// TokenConfig armazena a configuração de cada token que desejamos monitorar.
type TokenConfig struct {
Symbol string
Address common.Address
}
// FormattedPrice guarda o preço final e outras informações úteis.
type FormattedPrice struct {
Symbol string
Price *big.Float
Timestamp uint64
Decimals uint8
}
func main() {
// Conectando a um nó da Ethereum. Este endpoint público é ótimo para começar.
client, err := ethclient.Dial("https://ethereum-rpc.publicnode.com")
if err != nil {
log.Fatalf("Ops! Deu ruim ao conectar no Ethereum: %v", err)
}
defer client.Close()
// Nossa lista de alvos! Adicione quantos tokens quiser aqui.
// Esses endereços são endereços da MAINNET.
tokens := []TokenConfig{
{Symbol: "ETH", Address: common.HexToAddress("0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419")},
{Symbol: "BTC", Address: common.HexToAddress("0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c")},
{Symbol: "LINK", Address: common.HexToAddress("0x2c1d072e956AFFC0D435Cb7AC38EF18d24d9127c")},
}
// Este canal vai receber os preços assim que eles foremencontrados.
pricesChan := make(chan FormattedPrice, len(tokens))
// Um contexto com timeout para não ficarmos presos esperando para sempre. :p
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// Lança uma "missão" para buscar o preço de cada token, tudo ao mesmo tempo.
for _, token := range tokens {
go fetchTokenPrice(ctx, client, token, pricesChan)
}
// Agora, a gente espera e coleta os resultados que chegam pelo canal.
fmt.Println("Buscando preços...")
for i := 0; i < len(tokens); i++ {
select {
case price := <-pricesChan:
fmt.Printf("✅ Preço do %s: %.2f USD (Atualizado em: %d)\n",
price.Symbol, price.Price, price.Timestamp)
case <-ctx.Done():
log.Fatalf("Demorou demais! O timeout foi atingido: ", ctx.Err())
}
}
}
func fetchTokenPrice(ctx context.Context, client *ethclient.Client, token TokenConfig, pricesChan chan<- FormattedPrice) {
// Cria uma instância do contrato para a gente poder interagir com ele.
aggregator, err := aggregator_v3_interface.NewAggregatorV3Interface(token.Address, client)
if err != nil {
log.Printf("Erro ao instanciar o contrato para %s: %v", token.Symbol, err)
return
}
// Pega os dados mais recentes do oráculo.
roundData, err := aggregator.LatestRoundData(nil)
if err != nil {
log.Printf("Erro ao buscar os dados para %s: %v", token.Symbol, err)
return
}
// Descobre quantas casas decimais o preço tem.
decimals, err := aggregator.Decimals(nil)
if err != nil {
log.Printf("Erro ao buscar as casas decimais para %s: %v", token.Symbol, err)
return
}
// O preço vem como um número inteiro gigante. A gente precisa formatá-lo.
priceFloat := new(big.Float).SetInt(roundData.Answer)
divisor := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimals)), nil))
formattedPrice := new(big.Float).Quo(priceFloat, divisor)
// Envia o resultado bonitão de volta para a função main através do canal.
pricesChan <- FormattedPrice{
Symbol: token.Symbol,
Price: formattedPrice,
Timestamp: roundData.UpdatedAt.Uint64(),
Decimals: decimals,
}
}
5. Execução do Código
Para compilar e executar a aplicação, utilize o comando:
go run main.go
Se tudo deu certo (tomara), a saída esperada será similar a:
Fetching asset prices...
Price of BTC: 65100.50 USD (Timestamp: 1731599876)
Price of ETH: 3520.18 USD (Timestamp: 1731599870)
Price of LINK: 18.45 USD (Timestamp: 1731599882)
⚠️ Pontos de Atenção
Rede Certa, Endereço Certo: Os endereços dos contratos mudam de uma rede para outra (Mainnet é diferente de Sepolia). Use sempre o endereço correto para a rede à qual você está conectado.
Sem Custos de Gás: Este código apenas lê dados da blockchain, o que é de graça! Operações de escrita, por outro lado, exigiriam uma carteira com fundos para pagar as taxas (gás).
Latência: Os preços não são atualizados em tempo real, mas sim quando há uma variação mínima ou quando um período de tempo (o tal do heartbeat) passa. Leve isso em conta!
Conclusão
Pronto! Agora você tem uma aplicação em Go eficiente para buscar preços de criptomoedas usando o poder da Chainlink. Esse é um exemplo simples mas com essa base, podemos criar projetos muito mais legais e complexos.
Usamos concorrência para acelerar as coisas e garantimos que o programa não trave com timeouts.
Para mais informações, a documentação oficial da Chainlink é sempre o melhor lugar para procurar.
Agora, é com você. Just Code It!
This content originally appeared on DEV Community and was authored by Adriano P. Araujo

Adriano P. Araujo | Sciencx (2025-09-23T18:09:02+00:00) Como Integrar Chainlink Data Feeds em Go para Múltiplos Tokens. Retrieved from https://www.scien.cx/2025/09/23/como-integrar-chainlink-data-feeds-em-go-para-multiplos-tokens/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.