Education only. Not financial advice.
Education only. Not financial advice.
Watch the video
Show transcript
Welcome to bonus Lesson C4. Before we start, this lesson is education only. It is not financial advice. Today you'll build a small tool that reads a balance from a test network. It only reads. No keys, no wallet, nothing to install.
Your Colab notebook is off-chain. The balance lives on-chain. To connect them, Ethereum dot org says, quote, "every Ethereum client implements a JSON-RPC specification." End quote. One of those methods, eth get balance, quote, "Returns the balance of the account at a given address." End quote. Reading a balance needs no private key. Our tip: an agent that only reads can't move money.
We'll read from Sepolia. Ethereum dot org says, quote, "Sepolia is a network for contract and application developers to test their applications." End quote.
Let's ask Grok to write it. Paste the prompt from the lesson page. We ask for a read-only tool with no installs and no keys. It should only allow read methods and refuse anything else. Convert the answer to ETH. And print a log line for every call.
Here's Grok's code, with comments. Yours may look a little different. That's fine. When we tested Grok's version, the test network refused it until we added a User-Agent header, so our ready-made block includes one. Always run and test AI code.
So we all see the same thing, the lesson page has a ready-made block. Let's paste it into Colab. See the allowed list near the top? Only two read methods. Anything else gets blocked. And each call prints a log line, so you can see exactly what the tool did.
Press Run. First, a log line with the time and the method. Then the balance, in test ETH. The address in the block is the zero address, all zeros. It's a placeholder address that people and programs sometimes send coins to by mistake or on purpose, so it holds a lot of test ETH. Its balance changes, so yours will differ. And last, the line that matters most. We tried to send a transaction, and the tool said blocked. It only reads.
Now paste the output into Grok and ask what the balance means, and why the second call was blocked. Look for this: it's test ETH with no real value, and the tool only allows read methods. In our run, Grok said much the same. It's play money on a test chain, and sending a transaction is refused.
Our tip: the endpoint in the block is one free public example, listed on PublicNode and Chainlist. Public endpoints can be slow or change. If it fails, pick another Sepolia endpoint from Chainlist.
Safety check. Ethereum dot org says, quote, "ETH on testnets is supposed to have no real value." End quote. Our tip: read-only only. No signing keys, ever.
Quick check. Does reading a balance need a private key? No. Why keep a list of allowed methods? So it can only read, never send. Is Sepolia ETH real money? No. Education only. Not financial advice. If you haven't yet, head to the Capstone.
What you'll learn
- How an off-chain program can read on-chain data
- How to build a read-only tool that refuses anything else
- Why logs help you see what your agent did
Step 1: Reading is not spending
Ethereum.org says "every Ethereum client implements a JSON-RPC specification" so "there is a uniform set of methods that applications can rely on." One read method, eth_getBalance, "Returns the balance of the account at a given address." (Ethereum.org JSON-RPC) Reading a balance needs no private key. Our tip: an agent that only reads can't move money.
We'll read from Sepolia. Ethereum.org says: "Sepolia is a network for contract and application developers to test their applications." (Ethereum.org networks)
Step 2: Ask Grok to write the tool
Paste this into Grok:
Write beginner Python for Google Colab. No installs and no API keys.
Make a READ-ONLY tool that asks a public Sepolia test network JSON-RPC
endpoint for the balance of one address using eth_getBalance.
1. Only allow read methods (eth_getBalance, eth_blockNumber). Refuse anything else.
2. Convert the answer from hex wei to ETH.
3. Print a log line with the time and method for every call.
4. Comment each part and explain it in plain words.
Never use private keys or send transactions.
Grok's real answer (our test run)
We ran this exact prompt through Grok (model grok-4.7) on Oct 30, 2026. Grok's answers change from run to run, so yours will differ. Quoted as Grok returned it, except where we mark [trimmed] and where we swapped dashes for commas to match our style.
This is a small read-only Colab script. It only calls two public read methods, never uses a private key, and never sends a transaction. Paste it into one cell and run it. No installs and no API key.
[trimmed: Grok's full code block is not shown. Use our tested ready-made block below.]
When we tested Grok's code on our computer, the public test network refused it with a 403 error. It worked after we added a User-Agent header, so our ready-made block includes one. This is a good reminder: always run and test AI code. Education only. Not financial advice.
Step 3: Or use our ready-made block
Paste this into one Colab cell and press Run:
# Read-only tool: looks up a balance on the Sepolia TEST network.
# No keys. No wallet. It can only read, never send.
import json, urllib.request, datetime
RPC_URL = "https://ethereum-sepolia-rpc.publicnode.com" # a public test network endpoint
ALLOWED = {"eth_getBalance", "eth_blockNumber"} # read-only methods only
def call(method, params):
if method not in ALLOWED: # safety: refuse anything else
raise ValueError("Blocked: " + method + " is not a read-only method")
body = json.dumps({"jsonrpc": "2.0", "method": method, "params": params, "id": 1}).encode()
req = urllib.request.Request(RPC_URL, data=body,
headers={"Content-Type": "application/json", "User-Agent": "lesson-c4"})
print("LOG", datetime.datetime.now().isoformat(timespec="seconds"), method, params) # keep a log, before the request
with urllib.request.urlopen(req, timeout=15) as r:
result = json.load(r)["result"]
return result
def get_test_balance(address):
wei = int(call("eth_getBalance", [address, "latest"]), 16) # answer comes back in hex
return wei / 10**18 # 1 ETH = 10^18 wei
address = "0x0000000000000000000000000000000000000000" # the "zero address" (all zeros)
print(f"Sepolia test balance: {get_test_balance(address):,.4f} test ETH (play money)")
try:
call("eth_sendRawTransaction", ["0x00"]) # this should be blocked
except ValueError as e:
print(e)
What you should see: a LOG line, a balance in test ETH, then "Blocked: eth_sendRawTransaction is not a read-only method". We ran this block on our own computer and saw all three lines.
The address in the block is the "zero address" (all zeros). It's a placeholder address that people and programs sometimes send coins to by mistake or on purpose, so it holds a lot of test ETH. Its balance changes, so yours will differ.
Step 4: Ask Grok to explain the result
Paste the output into Grok and ask: "In plain words, what does this balance mean, and why was the second call blocked?" Look for: it's test ETH with no real value, and the tool only allows read methods.
Our tip: the endpoint in the block is one free public example, listed on PublicNode and Chainlist. Public endpoints can be slow or change. If it fails, pick another Sepolia endpoint from Chainlist.
Grok's real answer (our test run)
We ran the output from our ready-made block and the question through Grok (model grok-4.7) on Oct 30, 2026. Grok's answers change from run to run, so yours will differ. Quoted as Grok returned it, except where we mark [trimmed] and where we swapped dashes for commas to match our style.
The first line is a read-only balance check. It asked how much ETH the all-zero address holds on Ethereum’s Sepolia test network and got about 133,761.67 test ETH. That is play money on a test chain, not real ETH, and the zero address is a special null/burn address, not someone’s wallet you can spend from.
The second call was blocked because
eth_sendRawTransactionis not a query. It would broadcast a signed transaction and change chain state. A read-only endpoint only allows lookups like balances, so sending a transaction is refused.
One correction: in our block, it's our own allow-list (ALLOWED) that refused the call, before anything was sent. The endpoint never saw it. Grok's answer says the endpoint refused it, which isn't what happened here.
Education only. Not financial advice.
Check yourself
- Does reading a balance need a private key? (Answer: No)
- Why does the tool keep a list of allowed methods? (Answer: so it can only read, never send)
- Is Sepolia ETH real money? (Answer: No. It's for testing.)
Caution box Ethereum.org says: "ETH on testnets is supposed to have no real value." (Ethereum.org networks) Our tip: read-only only. No signing keys, ever. Education only. Not financial advice.
Builds on
- Lesson C1: Blockchain basics: wallets and seed phrases
- Lesson B1: Prompt injection, explained simply
- Lesson A4: Give your agent tools (function calling and MCP)
Sources
- Ethereum.org JSON-RPC: https://ethereum.org/en/developers/docs/apis/json-rpc/
- Ethereum.org networks: https://ethereum.org/en/developers/docs/networks/
- PublicNode: https://publicnode.com/
- Chainlist, Sepolia: https://chainlist.org/chain/11155111
Creator credits
- xAI (Grok): X https://x.com/grok , https://x.com/spacexsi
- Ethereum.org: X https://x.com/ethdotorg
Education only. Not financial advice.