Network and RPC

How SOL_NETWORK picks a cluster, why the runtime cannot be pointed at a paid RPC, which parts of the platform hit Solana hardest, and the knobs you actually have when the public cluster starts rate-limiting.

5 min readUpdated 3 August 2026rpc, cluster, rate-limits, sol-network, websocket

Every other chain family in Ecosystem takes an RPC URL. Solana does not. The connection is constructed from SOL_NETWORK alone, resolved to the public cluster endpoint for that cluster, and cached on a singleton for the life of the process. This page is about what follows from that.

Cluster selection

SOL_NETWORK Cluster Endpoint the service uses
mainnet mainnet-beta https://api.mainnet-beta.solana.com
testnet testnet https://api.testnet.solana.com
anything else devnet https://api.devnet.solana.com

The third row is not a fallback you were told about. Unset, misspelled, lowercased differently, or set to mainnet-beta — which is the cluster's real name and the value most people reach for — all resolve to devnet. There is no exception thrown and no log line in the request path.

The consequence is total but invisible: addresses are generated for devnet keys, the deposit monitor subscribes to devnet, and a customer's mainnet SOL sits at an address the platform is not watching on a network it is not connected to. The funds are not lost — the keypair is the same on every cluster — but nothing will credit them until the cluster is corrected.

Run Admin → Ecosystem → Blockchains → Requirements and read the Cluster resolution line. It prints the resolved endpoint, which is the only statement in the product that cannot be misread.

The two network variables

Selects the cluster for every runtime operation — deposits, withdrawals, balances, mint deployment. Only "mainnet" and "testnet" are recognised; everything else resolves to devnet.
A separate variable that selects nothing. It is stamped into the wallet address record when an address is generated, and read by nothing afterwards. Keep it equal to SOL_NETWORK.

The requirements report raises a warning when the two disagree, because the stored metadata then records a cluster the address is not on. That is a diagnosis problem rather than a money problem, but it is the kind of disagreement that makes an incident take twice as long.

Why there is no custom RPC

Read only by the admin token-deployment cost estimate. The runtime Solana service never reads it and always uses the public cluster endpoint.

SOL_<NETWORK>_RPC — for example SOL_MAINNET_RPC — is checked by the Ecosystem overview badge to decide whether to draw a chain as configured. The Solana service does not read it. Setting it makes a badge look right while changing nothing, which is the worst possible combination, and the requirements report labels it display-only for exactly that reason.

So: buying a Helius, QuickNode or Triton endpoint and putting it in .env does not move your traffic. There is no supported way to redirect the runtime short of editing backend/src/blockchains/sol.ts, which puts you outside the upgrade path.

The public cluster applies per-IP limits and returns 429 under load. Everything below exists because that is the expected condition, not an exceptional one.

What hits Solana hardest

Four parts of the platform generate Solana RPC traffic, in roughly descending order of cost.

Transaction history. Opening a Solana transaction list fetches the last 50 signatures for the address and then fetches each transaction individually — 51 calls for one page view. Results are cached in Redis for 30 minutes per address, so the second view is free and the twenty-ninth is too. It also only parses System Program transfers, so an SPL-only address renders rows with an empty counterparty and a zero amount; that is a display limitation of this view, not a sign that the deposit was missed.

Live deposit monitoring. While a user has a deposit page open, the platform holds a WebSocket subscription for their address. Native SOL uses a logs subscription on the account; SPL uses a token-program account subscription filtered to the mint and owner. Both self-cancel after one hour of no activity, and both are torn down once a deposit is credited — the next page visit re-arms a fresh one.

The background deposit scanner. Addresses seen on a deposit page stay in a working set for 72 hours and are re-scanned on a schedule. Each Solana pass fetches the last 25 signatures for the address, or for the token account on the SPL side, and inspects the ones it has not already credited.

Withdrawals. Each one costs a fee probe, a balance read, a broadcast, a confirmation wait and then up to ten verification polls with a growing backoff. The withdrawal queue enforces a 5-second cooldown per chain between transactions, so Solana withdrawals are serialised whatever the queue depth.

The mitigations already in the code

You do not need to configure these; you need to recognise their symptoms.

  • Transaction fetches are de-duplicated and cached. Concurrent lookups of the same signature share one request, and a successful result is held for 60 seconds. Several monitors observing the same deposit therefore cost one call, not several.
  • Native deposit tracking retries up to 30 times, roughly every 5 seconds with jitter, waiting for a just-seen signature to become fetchable at finalized commitment. A deposit that takes a couple of minutes to credit under load is this working, not failing.
  • Withdrawal verification retries ten times with a 2-, 4-, 6-second … backoff capped at 10 seconds, and treats "broadcast but unverifiable" as TIMEOUT rather than FAILED. See Withdrawals and fees for why that distinction protects your float.
  • The scanner is paced by a token bucket at 0.5 Solana address scans per second by default. When more addresses are active the sweep takes longer; the request rate does not rise. Detection latency degrades gracefully instead of the whole chain 429ing.

What you can actually tune

These are Ecosystem-wide scanner settings, not Solana-specific ones, but Solana is the chain most likely to make you reach for them.

Solana-specific override for the background scanner's rate, in address scans per second. Raise it only if you have evidence the cluster tolerates it.
How often each address in the working set is re-scanned, in milliseconds.
How long an address stays in the background working set after its last deposit-page visit, in milliseconds. The default is 72 hours.
Set to "false" to disable the background deposit scanner entirely. Deposits then rely on a live session being open.

Raising ECOSYSTEM_SCAN_RATE_SOL is the one that will bite. The default is conservative because the anonymous cluster quota is shared with every other anonymous client; pushing it produces 429s, which the scanner logs and skips past, which looks exactly like deposits going missing.

Lowering ECOSYSTEM_SCAN_ACTIVE_TTL_MS reduces load in direct proportion to how many stale addresses you stop watching, and is usually the safer lever.

Degradation, in the order you will see it

  1. Transaction history goes stale or empty first. It is the most expensive read and the most tolerant of failure, and it is cached for half an hour, so a bad minute shows up as an odd-looking list rather than an error.
  2. Live detection stops before background detection does. The subscription side is a WebSocket; the scanner side is plain HTTP. If the cluster's WebSocket endpoint is refusing you, deposits still credit — just on the scanner's cadence rather than instantly, and only for addresses that have been on a deposit page.
  3. Withdrawal confirmation gets slower, then uncertain. The retries absorb a lot. Past that, a broadcast transaction that cannot be verified is parked as TIMEOUT for a human to resolve, which is a queue that needs watching.
  4. Withdrawal broadcasts start failing. At this point the cluster is rejecting you outright and the queue backs up behind the 5-second cooldown.

If you are consistently at stage 3, you are past what this integration is sized for on the public cluster. Reduce the working set, lengthen the scan interval, and be honest with yourself about Solana volume before it becomes a support queue.