Lesson 02 · Web3 with Go & Polygon

Reading an Account Balance

Before an investor can buy a share of your client's property, your backend needs to answer a very ordinary question: how much does this address hold? Does the buyer have enough POL to pay the gas? Later — once shares are a token — the exact same call tells you how many shares an address owns. Reading a balance is the first read your product actually cares about.

The win A Go program that takes any Amoy address and prints its balance — first in raw wei, then converted to human POL. This is the pattern behind every "your balance is…" line your app will ever show.

What is an "account", really?

On Polygon (and every EVM chain) an account is just an entry in the chain's giant ledger, named by a 20-byte address written as 40 hex characters: 0x71C7…976F. There are two kinds — and the difference matters for your product:

EOA — externally owned account
A wallet controlled by a private key. Your investors are EOAs. A human (or your Go signing code) authorizes its transactions. It has a balance and nothing else.
Contract account
An account controlled by code deployed on-chain, not a key. Your property-share token will live at a contract account. It has a balance and stored data (who owns which shares). We deploy one in a later lesson.

BalanceAt works the same on both. Today we read an EOA's native POL balance — the gas money.

wei: the only unit the chain uses

The chain never stores decimals. A balance is always a whole number of wei, the smallest unit, where 1 POL = 1,000,000,000,000,000,000 wei (that's 1018). Think of wei as "cents", except there are a quintillion of them per coin. That's exactly why balances come back as *big.Int — the number is far too big for a normal int64. You met big.Int in Lesson 01; here's why it's unavoidable.

Read the balance

Pick any address that has funds on Amoy — your own faucet wallet, or a random active one copied from Amoy Polygonscan.

main.go

package main

import (
	"context"
	"fmt"
	"log"
	"math"
	"math/big"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethclient"
)

func main() {
	client, err := ethclient.Dial("https://rpc-amoy.polygon.technology/")
	if err != nil {
		log.Fatalf("could not connect: %v", err)
	}
	defer client.Close()

	// Turn the human hex string into a typed 20-byte address.
	account := common.HexToAddress("0x0000000000000000000000000000000000001010")

	// nil block number = "the latest block". Returns wei as *big.Int.
	wei, err := client.BalanceAt(context.Background(), account, nil)
	if err != nil {
		log.Fatalf("could not read balance: %v", err)
	}
	fmt.Printf("balance (wei): %s\n", wei)

	// Convert wei -> POL for humans. big.Float, because we're dividing by 1e18.
	fbalance := new(big.Float).SetInt(wei)
	pol := new(big.Float).Quo(fbalance, big.NewFloat(math.Pow10(18)))
	fmt.Printf("balance (POL): %s\n", pol.Text('f', 6))
}

Run it:

terminal

go run main.go
balance (wei): 1943500000000000000
balance (POL): 1.943500
You did it You just read live on-chain state for an arbitrary account — the same call, unchanged, will later tell you how many property shares an investor holds. Swap in your own faucet address and watch the number match Polygonscan exactly.

Two things worth noticing

common.HexToAddress is not just a cast. It parses the hex into a fixed 20-byte value and is the type every go-ethereum method expects. Passing a raw string won't compile — addresses are a real type here, which stops a whole class of typo bugs.

The nil block number means "latest". Because balances live in state, and state exists at every block, you can ask "what was this balance 10,000 blocks ago?" by passing a block number instead. That's how you'll later audit ownership at the moment a sale closed. Powerful, and free to read.

Zero is normal A brand-new address you've never funded reads 0 — that's correct, not an error. If you want a non-zero result, grab test POL from the Amoy faucet for your own wallet first (we generate that wallet in Lesson 05).

Check yourself

No peeking — recall from memory. The effort is the point.

1. How many wei are in one POL?

2. An account controlled by a private key is called a…

3. What does passing nil as the block number mean?

Primary source · read this next
Ethereum Development with Go — Account Balances. The canonical reference for BalanceAt and wei conversion, straight from our backbone book.

I'm your teacher — ask me anything. Want to see the balance at a past block? Curious why the chain refuses to store decimals at all? Wondering how a token balance differs from this native balance? Ask away.