
Reads, writes and events want different paths. Reads go through Wagmi and Viem with caching; history comes from subgraphs; live state arrives over websockets with reorg handling. Mixing them — polling RPC in the render loop — is how dApps get slow and wrong at the same time.
The transaction-state machine
Every write moves through idle, simulating, signing, broadcasting, confirming, confirmed or failed. Each state gets explicit UI: gas and receive previews before signing, progress with cancel guidance while confirming, and human revert copy on failure. Optimistic updates are allowed only with a named revert path.
On L2s, keep gas estimates honest by simulating against the sequencer feed and labelling the confirmation window per chain.
Related: Wallet UX · Indexing realtime data · dApp services