Using CKB/Ethereum RPC Interfaces: A Comprehensive Guide

·

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/ethclient

Querying Transaction Records

Ethereum transactions don’t explicitly include the sender’s address. To recover it:

  1. Extract the sender’s public key from the transaction signature.
  2. 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.