Networks and endpoints
Horizon, Soroban RPC, passphrase and friendbot per network, how RPC failover works, and how the app picks a network.
The app supports two networks, mainnet and testnet. Their endpoints are pinned in
src/lib/config/networks.ts and are not environment variables: editing that file is how you
point a deployment at different providers.
The table
| mainnet | testnet | |
|---|---|---|
| Horizon | https://horizon.stellar.org | https://horizon-testnet.stellar.org |
| Soroban RPC | https://soroban-rpc.mainnet.stellar.gateway.fm | https://soroban-testnet.stellar.org |
| RPC failovers | https://mainnet.sorobanrpc.com, https://stellar.api.onfinality.io/public | https://soroban-rpc.testnet.stellar.gateway.fm |
| Passphrase | Networks.PUBLIC | Networks.TESTNET |
| Friendbot | none | https://friendbot.stellar.org |
| Allow-list entries | 64 (54 entry points) | 50 (41 entry points) |
The mainnet Soroban RPC default is a third-party gateway, not an SDF-run endpoint. Review it, or replace it with an RPC you operate or trust, before mainnet use.
Looking a network up
parseNetworkId(id) returns the config for mainnet or testnet and null for anything else.
requireNetwork(id) throws on anything else. Nothing guesses: a stored recovery record, a relay
request or a metrics event that names another network is refused, never resolved to a default.
RPC failover
getRpc(network) returns one memoized client per primary URL that fails over across the primary
and its fallbacks, with plain HTTP disabled and a 20-second timeout on every request.
Only a rate limit (429), a 5xx, the RPC's processing-limit answer (JSON-RPC code -32001), or a
named transport failure moves a call to the next host. A deterministic error is returned as-is,
because every host would answer it the same way. Once a host answers, the client stays on it.
A failed-over sendTransaction that comes back txBadSeq can be the same transaction already
applied through the first host, so the client looks the hash up on every host and reports a
transaction any host knows as DUPLICATE, for the caller to poll.
Each fallback returns a CORS header, so a browser can use it, and tracks the same ledger as the primary, so a failover does not read stale state.
Which network the app is on
The starting network is NEXT_PUBLIC_STELLAR_NETWORK, testnet by default. The header selector
offers TESTNET and MAINNET, and the choice persists in the browser under
demolisher.network; only those two values are read back.
- Switching networks tears down the wallet session, because a connected account belongs to one network.
- Switching is disabled while a close runs or signatures are being collected.
- Being on mainnet, from the build default, a restored choice or a switch, needs the browser to have acknowledged that the code has not had an independent audit. Switching back to testnet applies at once.
A co-signer on /sign signs on the network the signing request names, whatever the header shows.
Friendbot
The testnet demo account is funded through friendbot, so it is offered on testnet only.
Explorer links
Transaction, account and contract links point at stellar.expert, with the slug public for mainnet
and testnet for testnet.
Adding an endpoint
The browser contacts only hosts in the Content Security Policy. connect-src is derived from
NETWORKS (each network's Horizon, RPC, failovers and friendbot), so an endpoint you add in
src/lib/config/networks.ts joins the policy with it. Any other host the browser needs goes into
src/lib/config/csp.ts, which already lists the Aquarius API, the Lumeus hosts
(src/lib/lumeus/hosts.ts) and WalletConnect.
See Security model.