One Weird Trick to Save $25,000 On Your RPC Bill

Node providers hate it!


We were re-negotiating our node provider contracts a few weeks ago and found about $25,000 of low-hanging fruit that we managed to cut with a one-line pull request.

Hello eth_chainId, my old friend

The eth_chainId RPC call is used to retrieve the unique identifier of the Ethereum blockchain network the node is connected to. This identifier ensures that transactions are signed and broadcasted on the correct network, preventing cross-network replay attacks. In decentralized applications and other web3 integrations, knowing the chain ID is crucial for ensuring compatibility and security across different blockchain environments.

This matters when you are building something where the chain ID might change. Like if you're building a browser extension or mobile app, it makes a lot of sense to check the chain ID very often.

But in our workloads, we isolate and segregate processes by blockchain network (therefore by chain ID). So the chain ID will never change within a single process.

Getting the Chain ID

Most web3 provider libraries will constantly ping to get the node's chain ID. When this happens, the provider makes the eth_chainId call.

When you do this once or twice, it doesn't really matter.

When you do it a hundred times, it still doesn't matter.

But when you index everything on every chain, it starts to add up.

Calls to eth_chainId start to add up

How to fix:

Here's one of our configuration files where we get our default web3 provider class:

/**
 * Handles things related to our web3 configuration pertaining to this app.
 */
import { NetworkID } from 'common'
import { Network, Networkish } from 'ethers'
import {
  isNullOrUndefined,
  RetriableJsonRpcProvider,
} from '@center-inc/common-node/src'
import { getNetworkConfig } from './networks.config'

export const getWeb3Provider = (networkId: NetworkID) => {
  const netw = getNetworkConfig(networkId)

  if (isNullOrUndefined(netw.chainId)) {
    throw new Error(`Web3 Provider requires a chain ID`)
  }

  const ethersNetwork: Networkish = Network.from(netw.chainId)

  return new RetriableJsonRpcProvider(netw.httpProviderURI[0], ethersNetwork, {
    staticNetwork: ethersNetwork,
  })
}

Most notably, see how we pass in staticNetwork into the ethers provider subclass.

It's rare to make such a small code change that saves so much money. After all, as the proverb says: the best time to save $25,000 on your node provider bill was last year; the second best time is today in 9df0c717.

Happy building.