This guide focuses on writing code to retrieve blockchain data from Ethereum nodes. Since synchronizing a full Ethereum node can be time-consuming, we'll use Infura's public Ethereum nodes for our demonstrations. Let’s dive in!
Prerequisites
To get started, install the go-ethereum library:
$ go get -u -v github.com/ethereum/go-ethereum/ethclientQuerying Transaction Records
Ethereum transactions don’t explicitly include the sender’s address. To recover it:
- Extract the sender’s public key from the transaction signature.
- Derive the sender’s address from the public key.
Code Example
package main
import (
"context"
"log"
"math/big"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/godump/doa"
)
func main() {
ethClient := doa.Try(ethclient.Dial("https://mainnet.infura.io/v3/YOUR_API_KEY"))
blockNumber := doa.Try(ethClient.BlockNumber(context.Background()))
block := doa.Try(ethClient.BlockByNumber(context.Background(), big.NewInt(int64(blockNumber))))
for _, tx := range block.Transactions() {
sender := doa.Try(types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx))
amount, _ := tx.Value().Float64()
log.Printf("%s -> %s %14.6f ETH", sender, tx.To(), amount/1e18)
}
}This script fetches the latest block and logs sender/receiver addresses with transaction amounts.
Querying USDT-ERC20 Transfers
Tether (USDT) is an ERC20 token. To query transfers:
Code Example
package main
import (
"context"
"log"
"math/big"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/godump/doa"
)
func main() {
ethClient := doa.Try(ethclient.Dial("https://mainnet.infura.io/v3/YOUR_API_KEY"))
query := ethereum.FilterQuery{
Addresses: []common.Address{common.HexToAddress("0xdac17f958d2ee523a2206206994597c13d831ec7")}, // USDT Contract
Topics: [][]common.Hash{{common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")}}, // Transfer event
}
logs := doa.Try(ethClient.FilterLogs(context.Background(), query))
for _, l := range logs {
amount := new(big.Int).SetBytes(l.Data)
log.Printf("TX: %s, From: %s, To: %s, Amount: %f USDT", l.TxHash.Hex(), common.HexToAddress(l.Topics[1].Hex()), common.HexToAddress(l.Topics[2].Hex()), float64(amount.Int64())/1e6)
}
}Checking USDT Balance
Call the balanceOf(address) function:
Code Example
package main
import (
"context"
"log"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/godump/doa"
)
func main() {
ethClient := doa.Try(ethclient.Dial("https://mainnet.infura.io/v3/YOUR_API_KEY"))
response := doa.Try(ethClient.CallContract(context.Background(), ethereum.CallMsg{
To: common.HexToAddress("0xdac17f958d2ee523a2206206994597c13d831ec7"),
Data: common.Hex2Bytes("70a08231000000000000000000000000F977814e90dA44bFA03b6295A0616a897441aceC"),
}, nil))
balance := new(big.Int).SetBytes(response)
log.Printf("Balance: %f USDT", float64(balance.Int64())/1e6)
}Deploying and Interacting with Contracts
Deploying a Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SimpleStorage {
uint256 public value;
function set(uint256 _value) public { value = _value; }
function get() public view returns (uint256) { return value; }
}Deployment Code
package main
import (
"context"
"log"
"math/big"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/godump/doa"
)
func main() {
client := doa.Try(ethclient.Dial("https://mainnet.infura.io/v3/YOUR_API_KEY"))
tx := types.NewContractCreation(nonce, value, gasLimit, gasPrice, bytecode)
signedTx := doa.Try(types.SignTx(tx, signer, privateKey))
err := client.SendTransaction(context.Background(), signedTx)
if err != nil { log.Fatal(err) }
log.Printf("Contract deployed at: %s", signedTx.Hash().Hex())
}FAQs
Q1: How do I recover a sender’s address from a transaction?
A1: Use types.Sender() with the transaction’s signature and chain ID.
Q2: What’s the gas limit for a simple ETH transfer?
A2: 21,000 units is standard for basic transfers.
Q3: How can I interact with an existing smart contract?
A3: Use CallContract for read-only functions or send a transaction for state-changing methods.
👉 Explore more Ethereum development tools
Conclusion
This guide covered essential Ethereum RPC operations—from querying transactions to deploying contracts. For more advanced use cases, refer to the official Geth documentation.
👉 Learn about optimizing gas fees
By mastering these techniques, you’ll efficiently interact with Ethereum’s blockchain for data retrieval and smart contract management.