Unit 1 · Lesson 01 · Web3 with Go & Polygon

Connect Go to Polygon

Your client's tokenized-property backend has exactly one thing it must do before anything else: talk to the blockchain. It can't mint a share, read a balance, or record a sale until a Go process is holding a live connection to a Polygon node. That connection is the foundation everything in this course stands on — so we build it first, today, and prove it works.

The win By the end of this lesson you'll run a Go program that connects to Polygon's test network and prints the latest block number straight off the live chain. That's your backend's heartbeat. You'll also start your gas piggy bank — a daily faucet habit that funds the whole course.

Three words you need

Node (RPC node)
A computer running Polygon that keeps a copy of the chain. You don't run one — you send requests to somebody else's over HTTP. That HTTP endpoint is an RPC URL.
ethclient
The Go package (from go-ethereum) that speaks the node's JSON-RPC dialect for you. You call normal Go methods; it does the network talking.
Amoy
Polygon's test network — a full copy of Polygon where the money is fake. Chain id 80002, gas paid in test POL. We live here for the whole course: real code, zero real money.

These and every later term live in the course glossary — bookmark it.

Set up the project

You need Go installed (go version should print 1.21+). Then, in a terminal:

terminal

mkdir polygon-backend && cd polygon-backend
go mod init polygon-backend
go get github.com/ethereum/go-ethereum

That last command downloads go-ethereum and records it in your go.mod. It's a big library — give it a moment.

Write the connection

main.go

package main

import (
	"context"
	"fmt"
	"log"

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

func main() {
	// Dial opens the connection to a Polygon (Amoy) RPC node.
	client, err := ethclient.Dial("https://rpc-amoy.polygon.technology/")
	if err != nil {
		log.Fatalf("could not connect: %v", err)
	}
	defer client.Close()

	ctx := context.Background()

	// Which chain did we actually reach? Should be 80002 (Amoy).
	chainID, err := client.ChainID(ctx)
	if err != nil {
		log.Fatalf("could not read chain id: %v", err)
	}

	// The latest block — proof we're reading live chain state.
	block, err := client.BlockNumber(ctx)
	if err != nil {
		log.Fatalf("could not read block number: %v", err)
	}

	fmt.Printf("connected to chain %s — latest block %d\n", chainID, block)
}

Run it:

terminal

go run main.go

You should see something like:

connected to chain 80002 — latest block 24518903
You did it That block number is real and it changes every ~2 seconds. Run the program twice with a short pause — the number climbs. Your Go code is reading a live blockchain.

Two Go details worth noticing

Every chain-reading method takes a context.Context as its first argument. context.Background() is the plain "no deadline, no cancellation" context — fine for now. Later you'll pass one with a timeout so a slow node can't hang your server. This ctx-first pattern is everywhere in ethclient.

Notice chainID isn't an int. Ethereum numbers can be astronomically large (a wallet balance is measured in units of 10-18 of a coin), so go-ethereum uses *big.Int for them. We printed it with %s because *big.Int knows how to render itself as text. Get comfortable seeing big.Int — it's the currency of this whole ecosystem, and Lesson 02 gives it the attention it deserves.

If it fails A timeout or connection error usually means the public RPC is rate-limiting you, not that your code is wrong — just re-run. If it persists, swap the URL for a backup Amoy endpoint (listed on the Amoy cheat sheet). A chainID that isn't 80002 means you dialed the wrong network.

Start the gas piggy bank — today

Reading the chain is free, forever. But from Unit 3 on you'll write to it — send transactions, deploy contracts — and every write costs a little test POL for gas. The faucet that hands out test POL is rationed (ETHGlobal's Amoy faucet gives ~0.05 POL per day), and the finale of this course — deploying a full ERC-3643 compliance suite — will burn around 1.5 POL including mistakes. So the field-craft is: claim a little every day, starting now, and never worry about gas again.

The faucet needs an address to send to. Here's a five-line recipe that creates your course wallet — treat it as a recipe for now; Unit 2 unpacks what this key actually is and why it must be protected:

wallet.go (run once: go run wallet.go in a separate folder)

package main

import (
	"fmt"
	"log"

	"github.com/ethereum/go-ethereum/crypto"
)

func main() {
	key, err := crypto.GenerateKey()
	if err != nil {
		log.Fatal(err)
	}
	// Saves the private key as hex — your course identity. Guard this file.
	if err := crypto.SaveECDSA("wallet.key", key); err != nil {
		log.Fatal(err)
	}
	fmt.Println("your course address:", crypto.PubkeyToAddress(key.PublicKey).Hex())
}

Copy the printed address into the faucet and claim your first 0.05 POL. Then make it a ritual: every study day, claim before you code.

Key hygiene, starting on day one wallet.key controls this wallet. Add it to .gitignore immediately, never paste it anywhere, and never send real funds to this address. Testnet key, testnet money, forever. Unit 2 covers the full discipline.

Check yourself

No peeking at the code — recall from memory. That effort is what makes it stick.

1. Which go-ethereum function opens the connection to a node?

2. What is the chain id of the Polygon Amoy testnet?

3. Chain methods like BlockNumber take which type as their first argument?

4. Why claim faucet POL daily starting now, when writes only begin in Unit 3?

Primary source · read this next
Ethereum Development with Go — Setting up the Client. The definitive free reference for ethclient; the next chapters (reading blocks & accounts) are exactly where we go in Lesson 02.

I'm your teacher — ask me anything that's unclear. Stuck on go get? Curious what a "block" actually contains, or why gas exists? Want to see the balance-reading version now? Just ask.