Read-Only Multi-Chain RPC Relay

Unified RPC access + ABI-decoded contract reads + a built-in address book of common contracts. Never broadcasts transactions, never touches private keys — signing and broadcasting always happen in the client-side wallet.

21 whitelisted chains10 contract ABIsMulti-node auto failoverCORS wide openRuns on free tier
🧭 New to blockchain terms? Open for a 30-second beginner explainer
Chain ID / name
≈ a LAN (local network) — Ethereum, BSC, Polygon are independent LANs; address formats look alike but the networks don't interconnect. Pick which network to enter before calling.
Contract address / name
≈ an IP address — every contract on every chain has a unique 0x address. Address-book names (like usdc) are memorable "domain names" this service resolves to the right address per chain.
Method
≈ an API endpoint — contracts expose functions, split into reads (balance, config) and writes (transfer, approve). This project is a focused specialization: reads only, making "web2 frontend reads blockchain directly" fast, easy and cheap.
Why read-only?
Writes require a private-key signature, and that must happen in your own browser wallet (e.g. MetaMask). This service is a read-only gateway: fast, free, and structurally incapable of touching your assets.

Quick CallChain (ID or name) → contract (name or 0x address) → method → read, producing a shareable GET link

Common examples:
Inputs are generated from the method's arguments

Contract ReadsCore endpoints: two forms of the same thing, GET preferred

GET/api/call

GET version of the contract read call, same read-only pipeline as POST /api/contract/call. chain accepts a chainId or chain name; contract accepts an address-book name (0x addresses need the POST version with an explicit ABI); arguments are passed as repeated p params in order. The Quick Call form above uses this endpoint.

# Query vitalik's USDC balance
curl 'https://<your-worker>/api/call?chain=1&contract=usdc&fn=balanceOf&p=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'

# Chain can also be a name; param types are inferred
curl 'https://<your-worker>/api/call?chain=bsc&contract=weth&fn=symbol'

POST/api/contract/call

Encodes params and decodes results by ABI; only view/pure functions are allowed; multi-node failover. contractAddress can be an address-book name (contractName is then inferred); with a 0x address you must pass contractName explicitly (the GET version rejects 0x addresses precisely because ABI can't be reliably inferred from a URL). Preferred for programmatic calls and complex inputs (arrays/structs).

# Query USDC balance of an address (name usage, chainName omitted)
curl -X POST https://<your-worker>/api/contract/call \
  -H 'Content-Type: application/json' \
  -d '{"chainId":1,"contractAddress":"usdc","functionName":"balanceOf","params":["0x…"]}'

# Browser fetch
fetch('/api/contract/call', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ chainId: 1, contractAddress: 'usdc',
                         functionName: 'balanceOf', params: ['0x…'] })
}).then(r => r.json())

Generic RPCRaw methods not covered by the contract endpoints

POST/api/rpc

Generic read-only RPC: whitelisted read methods are forwarded directly (eth_blockNumber / eth_getBalance / eth_getLogs / eth_call…); broadcast and signing methods always get 403. Use it for balance / block / log queries that don't need ABI decoding.

curl -X POST https://<your-worker>/api/rpc \
  -H 'Content-Type: application/json' \
  -d '{"chainId":56,"request":{"method":"eth_getBalance","params":["0x…","latest"]}}'

Auxiliary MetadataAll GET — open directly in a browser

GET/api/contracts/:name/functions

Function list of one ABI (inputs/outputs/mutability) — enough for a frontend to build call forms dynamically, which is exactly how the Quick Call form above works. Integrators use it most: fetch the list, then let users pick a method.

curl https://<your-worker>/api/contracts/token/functions

GET/api/addresses?chainId=1

Address book: "name → per-chain address" for common contracts. Without chainId it returns the full mapping. Frontends remember the name; switching chains doesn't change it.

curl 'https://<your-worker>/api/addresses?chainId=56'

GET/api/chains

Supported chain whitelist: chainId, name, currency, RPC node list. Fetch once at app startup to build a chain selector.

curl https://<your-worker>/api/chains

GET/api/contracts

Built-in contract ABI list (token, erc721, erc1155, erc4626, multicall3, the uniswapV2 family, etc.).

curl https://<your-worker>/api/contracts

GET/api/health

Health check returning status and version. For uptime monitoring; rarely needed otherwise.

curl https://<your-worker>/api/health

Status Codes

CodeMeaning
200Success (BigInt values serialized as strings)
400Missing/invalid parameters, JSON-RPC param error
403Write operation, signing/broadcast method, or method not in the read-only whitelist
404Chain / ABI / function / address-book name not found
502All nodes for the chain failed (failover exhausted)