- Category
- Guides
- Reading time
- 8 minutes
- Published
Free Base RPC for an ETH and USDC balance monitor
To read ETH and native USDC balances on Base without signup, use https://rpc.solidrpc.io/public/evm/8453 for a bounded test. Base mainnet has chain ID 8453, and a balance read does not need a wallet signature. A continuous monitor needs an additional decision: can its polling pattern stay inside the endpoint's published limits?
This guide designs a monitor for 20 addresses, two assets, and a 30-second poll interval. It separates the first successful read from a sustainable service, explains why JSON-RPC batching does not erase call usage, and gives a durable SQLite model for restarts. The public limits and plan allowance below were checked on October 29, 2026.
Which free Base RPC access should you use?
SolidRPC's public RPC policy documents keyless HTTPS access to Base for development and light traffic. It accepts one JSON-RPC call per HTTP request. Multi-call JSON-RPC batches and public WebSocket access are not supported. The published per-IP limit is 20 requests per 10 seconds, shared with demo traffic, with a 10-second mitigation period. Shared service capacity can also cause throttling.
For an authenticated worker, the Free plan currently includes 10,000 responses per UTC day and 10 method calls per second. These are different limits from the anonymous public route. A free API key permits batching within account limits, but each method call still counts.
Base's official connection guide lists https://mainnet.base.org, and PublicNode lists another public option. Check current provider policies rather than assuming that a keyless URL grants unlimited daily capacity. Choose one qualified service for the worker's requirements.
Check the network and token before reading balances
First verify eth_chainId returns 0x2105:
curl --silent --show-error \
https://rpc.solidrpc.io/public/evm/8453 \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}'Native USDC on Base uses 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, as listed by Circle. Do not substitute a bridged token that happens to use a similar ticker. Store the chain ID and token address together.
Read token metadata with the verified contract ABI, including decimals(), and retain integer base units. ETH balances are denominated in wei. Display formatting belongs at the boundary, not in the stored balance or change calculation. Floating-point conversion can lose precision.
Read ETH and USDC at the same block
Resolve a block header once per poll, save its number and hash, and use that block reference for the reads. eth_getBalance(address, block) returns native ETH. USDC requires eth_call to the verified USDC contract with ABI-encoded balanceOf(address). The ERC-20 reference defines that read interface. Use a tested ABI encoder rather than hand-padding addresses.
A minimal read sequence is:
- Request
eth_getBlockByNumberfor the chosen freshness or finality tag. - For each watched address, read ETH and call USDC
balanceOfat that resolved block. - Check every JSON-RPC ID and error, then decode successful results as integers.
- Verify the block hash still matches before accepting a numbered-block snapshot, or use supported block-hash reads with canonicality checks.
- Commit the completed snapshot and change records together.
Several independent latest calls can describe different blocks. A safe or finalized policy may intentionally repeat the same block across polls. Deduplicate it rather than treating every timer tick as new chain state. The block-reference guide explains the choices.
Can 20 addresses be polled every 30 seconds for free?
Twenty addresses times two independent balance methods gives 40 reads per poll. At 2,880 polls per day, that is 115,200 balance reads per day, before block headers, token metadata, verification, or retries. It exceeds SolidRPC's 10,000-response Free daily allowance. A large per-second limit does not remove a daily cap.
Sending 40 calls at once also exceeds the public route's published 20-per-10-second threshold. A bounded public test should pace individual requests with headroom and honor throttling. A continuous job needs capacity you have explicitly qualified. The arithmetic is not a guarantee of anonymous service capacity.
Possible changes include a longer polling interval, fewer addresses, or a verified contract multicall that combines compatible reads into one eth_call. Contract multicall is different from a JSON-RPC array. It requires a verified deployment, correct ABI, checks on each subcall result, and testing against execution and response limits. Do not assume an address copied from another chain is valid. If using a read-aggregation contract, verify its documented code and deployment before relying on it.
For the naïve 40-read design, spreading 10,000 calls across 24 hours gives a theoretical minimum interval of 345.6 seconds before overhead. In practice, leave more headroom or choose an authenticated paid allowance. The batching guide explains why one HTTP envelope is not one billable method.
A concrete read-only option is Multicall3. Its deployment list identifies the Base deployment at 0xcA11bde05977b3631167028862bE2a173976CA11. The contract reference documents aggregate3 and getEthBalance. Encode 20 getEthBalance(address) calls targeting Multicall3 and 20 USDC balanceOf(address) calls targeting the token, then execute the aggregate through one eth_call at the chosen block. Decode every subcall and reject an incomplete snapshot. Verify the listed deployment and code before use. No token approval or onchain transaction is required for these offchain reads.
If the aggregate fits in one RPC call, one header lookup plus one aggregate plus one header recheck gives 8,640 calls per day at a 30-second interval. That leaves 1,360 of a 10,000-call allowance for startup, verification, and retries. This is a conditional budget calculation, not a capacity test. If aggregation splits, retries consume the reserve, or other jobs share the account, recalculate before running continuously.
Persist snapshots and changes in SQLite
Keep raw balances as decimal strings or another exact integer representation. A useful snapshot record contains chain ID, block number, block hash, wallet address, asset identifier, raw balance, and observed time. Give each chain, block hash, address, and asset tuple a unique identity. Store the watched-address set and its version with the job.
Within one transaction, insert a complete poll's snapshots, derive changes from the previous accepted state, and mark that poll committed. After a crash, resume from the last committed state. Replaying the same poll should not emit another change event. Do not publish a partial snapshot as if all 40 reads succeeded.
Use a persistent database file or volume. Test a restart after reads but before commit, then after commit but before a notification is acknowledged. If notifications leave the process, a durable outbox and delivery identity prevent duplicate alerts. Follow the SQLite transaction documentation for atomic updates.
Handle throttling, stale data, and missed polls explicitly
A failed request is not a zero balance. Keep the last accepted value and mark freshness unknown until a complete valid poll succeeds. Honor Retry-After, use bounded backoff, and stop overlapping poll loops from building an ever-growing queue. If the next scheduled tick arrives while the previous poll is still running, apply a deliberate skip or reschedule policy.
For unfinalized reads, retain block hashes and reconcile changed canonical history before issuing irreversible downstream actions. A balance snapshot only tells you the value at that block. It does not capture every intermediate transfer or prove that no movement occurred between polls. If every USDC transfer matters, use a durable log indexer instead.
A launch test should prove chain identity, token identity, complete snapshots, exact units, restart deduplication, throttle handling, and the request budget over a representative interval. A one-minute successful run proves connectivity during that minute. It does not establish sustained production capacity.
Give a coding agent a bounded implementation brief
Ask Cursor, Codex, or Claude to build against explicit requirements: Base chain ID 8453, verified native USDC, an owner-provided list of public addresses, a selected block policy, exact integer balances, a private RPC configuration, durable SQLite state, and bounded retries. Require a dry run before scheduling the continuous worker. No wallet private key or transaction signing belongs in this task.
For light tests, start with the public endpoint above. For sustained usage, select an allowance from the current plans. If the owner wants the agent to provision paid access programmatically, use the separate agent onboarding guide. The monitoring process itself should keep only the access it needs to read balances.