جميع المقالات
6 دقيقة للقراءة
Multi-chain in one afternoon
A practical walk-through. Start with an Ethereum-only dApp, end with the same code reading from Ethereum, Base, Arbitrum, Polygon, and Avalanche — without changing your data layer.
A practical walk-through. Start with an Ethereum-only dApp, end with the same code reading from Ethereum, Base, Arbitrum, Polygon, and Avalanche — without changing your data layer.
You have a dApp that reads from Ethereum. Your users keep asking when you'll support Base / Arbitrum / Polygon. You've been putting it off because the last time you tried, you ended up with five if (chain === ...) branches and a half-finished provider abstraction.
This post is a practical recipe for going from "one chain" to "five chains" in an afternoon. The trick is that you don't need to change your data layer — only how you target the RPC endpoint.
A typical Ethereum-only setup with viem:
Three lines of glue: chain, endpoint, key. Same pattern with ethers, web3.js, or whatever your stack uses.
Every Suward EVM endpoint has the same shape: https://<chain>.suward.com/<YOUR_KEY>. The only thing that changes between Ethereum and Base is the <chain> subdomain. So if your code can pick a chain at call time, you can multiplex.
Replace the single-client pattern with a per-chain factory:
Done. Now clients.ethereum, clients.base, clients.arbitrum, etc. all read from the right chain. Same auth, same key, same rate-limit pool.
ERC-20 balance lookups, ENS resolution (where supported), event log filtering — the JSON-RPC API is identical across EVM chains. The only chain-specific differences are:
finalized tag (epoch finalization, ~12 min). Most L2s don't yet — use a confirmation-count heuristic instead.For most cross-chain UIs, you want "total balance across all chains" or "logs from any of these chains where event X happened." Parallelise:
Five concurrent calls hit five chain endpoints through Suward. All bill against the same key. The rate-limit pool is shared across chains, so you don't need a separate quota for each.
The factory-of-clients pattern works for read workloads. For write workloads (signing + submitting transactions) there are chain-specific quirks:
eth_maxPriorityFeePerGas works on Ethereum but isn't supported on Arbitrum (where the priority fee is non-meaningful).For writes, you still use one client per chain, but your wallet code has to know which chain it's signing for. The pattern of "transparent fan-out" doesn't apply to writes.
By the end of the afternoon you have:
clients map covering 5+ EVM chains.SUWARD_KEY) instead of one per provider per chain.The work that used to take a week of provider integration is now a one-file refactor.
https://solana.suward.com/<YOUR_KEY> and https://bitcoin.suward.com/<YOUR_KEY> respectively. Their JSON-RPC APIs differ (Solana is getSlot, getBalance, getAccountInfo; Bitcoin is getblockcount, getrawtransaction, etc.) — but the auth + endpoint shape is identical.@tanstack/react-query's placeholderData for this.finalized. On L2s without it, use latest minus N (where N is the chain's safe confirmation count). Wrap the difference in a helper so your business logic doesn't care.Questions, hit us at @suward on X.