Networks and compatibility
For architects.
In short
CryptoRail works with EVM networks through standard Ethereum JSON-RPC over plain HTTP: public networks with a fee market, and permissioned consortium networks where gas is free. Several networks run side by side in one deployment, each declared in configuration with a profile that sets coherent defaults for fees, finality and stuck transactions. Compatibility is declared against the JSON-RPC specification, not against one node implementation, and proven on every change against Anvil and a Hyperledger Besu QBFT network, with sponsored execution against a self-hosted bundler. Public test networks were exercised by recorded manual runs. Chains outside the EVM family are not supported.
Networks, side by side
Every network is declared in the configuration with its chain id, a name, a profile and one or more node endpoints. There is no default network: every identity, contract, transaction, paymaster and subscription names the one it belongs to, so a record can never be sent to the wrong chain by omission.
flowchart LR
CORE[CryptoRail] --> R[Provider router per network<br/>first healthy endpoint, lag-aware]
R --> OWN[Your own nodes<br/>Besu, Geth, Nethermind, Erigon]
R --> RMT[Nodes in your infrastructure]
R --> PRV[Node providers]
OWN --> N1[(A public network)]
PRV --> N1
RMT --> N2[(Your consortium network)]
The node behind an endpoint can be yours, a remote one in your infrastructure, or a provider’s; CryptoRail does not distinguish between them beyond configuration. HTTP is enough for full correctness; a WebSocket endpoint is optional and only speeds up the notice of new blocks. Each endpoint is asked which network it serves when the process starts, and one serving another chain is refused before anything is sent to it. Provider quirks, such as a maximum block range for log queries, are configured per endpoint and respected on CryptoRail’s side.
Several networks at once, each declared in configuration, with every record carrying the network it belongs to.
Works with your own nodes or a provider's, through standard Ethereum JSON-RPC over plain HTTP.
Every endpoint is asked which network it serves when the process starts; one that answers with another chain id is refused before anything is sent to it.
An endpoint counts as healthy only when it answers in time and its head is within a set number of blocks of the most advanced endpoint; rate and concurrency limits per endpoint, and provider limits such as the eth_getLogs block range, are respected on CryptoRail's side.
Several node endpoints per network: calls go to the first healthy one, an operation stays on the endpoint it started on, and a dead or lagging node is left aside without losing anything.
Network profiles
An operator configuring a consortium network should not have to know which of a dozen settings differ from a public chain. The profile fills them; any one can still be overridden on its own.
| Setting | public | permissioned |
|---|---|---|
| Gas policy | EIP-1559 market (or, when set, a legacy market or a fixed price) | Free: zero fee, no fee-market query |
| Finality | A number of blocks on top, or the node’s finalized block | Instant: deterministic finality |
| Stuck transaction | Replaced at the same nonce with a higher fee, within the cap | Rebroadcast, or a fresh zero-fee attempt at the same nonce |
| Priority tiers | Fee multipliers, caps and bump percentages | Only the stuck thresholds matter |
| Gas balance needed | Yes, for every paying identity | No |
flowchart LR
C["chains[]: chainId, name, profile, endpoints"] --> P{profile}
P -->|public| PU[EIP-1559 fees, finality after N blocks, fee bumps]
P -->|permissioned| PE[free gas, instant finality, rebroadcast]
PU --> O[overrides from the file, one setting at a time]
PE --> O
O --> V[validated at startup, every problem listed]
Two network profiles, public and permissioned, fill coherent defaults for fees, finality, stuck thresholds and priority tiers; every default can be overridden on its own.
Fees follow the network's gas policy (EIP-1559 market, legacy market, fixed price or free) and the sending identity's tier, never the caller's guess; an override is allowed only under the cap.
Each network declares its finality rule: a number of blocks on top, the node's finalized block, or instant on networks with deterministic finality, with coherent defaults for public and permissioned networks.
The life of a transaction explains how fees, stuck transactions and finality are handled inside the state machine.
Free-gas consortium networks
Permissioned networks on Hyperledger Besu with QBFT consensus are first-class, including those where gas costs nothing. On such a network a transaction is sent with a zero fee, no fee-market query is made, no identity needs a balance, and a caller’s fee override above zero is refused. Gas is still metered: estimation and the block gas limit apply as usual.
A stuck transaction is never “bumped” on a free network, because there is no fee to raise. If the node no longer knows it, it is rebroadcast unchanged; if the node still knows it, a fresh attempt at the same nonce replaces it, because an identical rebroadcast would be ignored. Nobody needs sponsorship where nobody pays, so a paymaster on a free-gas network is refused as a configuration error.
Permissioned consortium networks with free gas (Hyperledger Besu with QBFT): no fee market, no gas balance to keep topped up.
The requirement covers IBFT 2.0 as well as QBFT; only QBFT is tested.
What is tested, and against what
Every change to the code runs the integration suites against real nodes in CI. No test in CI spends funds or sends anything to a public network; the fork journeys only read a public network’s state at a pinned block. Anything that needs real funds is a manual procedure, recorded with its date when it is run.
flowchart TB
PR[A change to the code] --> A[Anvil, Prague hardfork<br/>reorgs, drops, outages, process kills]
PR --> B[Besu QBFT, four validators, zero gas price]
PR --> AL[Alto bundler on Anvil<br/>canonical ERC-4337 contracts]
PR --> N[Node.js 22 and 24]
PR --> J[Journeys on the full stack in Docker]
M[Manual, dated runs] --> PUB[Public test networks:<br/>Base Sepolia, Sepolia]
| Target | Version | What runs there |
|---|---|---|
| Anvil (Foundry) | Foundry’s stable release, installed fresh by CI (anvil 1.8.3 when last recorded), Prague hardfork | The pipeline, forced reorganisations, dropped transactions, a fault-injecting provider, process kills, the indexer, approvals, EIP-7702 onboarding |
| Hyperledger Besu | 26.8.1, four QBFT validators, zero minimum gas price | Deploy and call from an identity holding no ether, stuck handling without fees, the indexer, the tokenisation pack |
| Pimlico Alto bundler | Pinned by image digest | Sponsored execution end to end: account deployment, both nonce spaces, the paymaster |
| ERC-4337 contracts on Anvil | EntryPoint v0.7, Kernel v3.3, with the runtime bytes copied from mainnet | The same code hashes the production pins verify |
| Node.js | 22 and 24 | Every package’s tests |
| PostgreSQL | 17 | Storage, database roles, the deployment journeys |
| Forks of public networks | Ethereum mainnet and Base Sepolia at pinned blocks | The stablecoin, attestation and Aave packs against the real contracts |
Foundry is not pinned to one version: CI takes the stable release, and a local run older than CI’s can disagree on genesis contracts of the Prague hardfork, which the contributor guide calls out. Besu does not host the ERC-4337 harness, so sponsored execution is tested on Anvil with Alto only.
On every change to the code, the integration suites run against Anvil on the Prague hardfork, against a four-validator Hyperledger Besu QBFT network with zero gas price, and, for sponsored execution, against the Alto bundler pinned by digest; no test in CI spends funds or sends anything to a public network.
Runs on Node.js 22 and 24, both tested on every change; the service ships as an OCI container image over PostgreSQL, tested on PostgreSQL 17.
Tested with a real wallet on a public test network, beyond the automated tests against a bundler.
The pinned contracts
Sponsored execution relies on contracts CryptoRail does not write: the canonical ERC-4337 EntryPoint, an audited account implementation and a verifying paymaster. Each is pinned per network by address and by the hash of its deployed code, and checked against the node when the process starts.
| Contract | Version | Address |
|---|---|---|
| EntryPoint | eth-infinitism v0.7.0 | 0x0000000071727De22E5E9d8BAf0edAc6f37da032 |
| Account | ZeroDev Kernel v3.3 | 0xd6CEDDe84be40893d153Be9d467CD6aD37875b28 |
| Account factory | Kernel v3.3 | 0x2577507b78c2008Ff367261CB6285d44ba5eF2E9 |
| Signing validator | Kernel ECDSAValidator | 0x845ADb2C711129d4f3966735eD98a9F09fC4cE57 |
| Approval validator, for on-chain approvals | Kernel v3.3 WeightedECDSAValidator 0.0.3 | 0xeD89244160CfE273800B58b1B534031699dFeEEE |
| Paymaster | eth-infinitism v0.7.0 VerifyingPaymaster | Deployed per deployment; its code hash is pinned |
The code hashes were read from mainnet and cross-checked on Base and Arbitrum. Kernel’s hash differs from chain to chain, so on any other network it is read from that network’s node when the network is configured. Kernel v3.3 and the validators stand on the audits of their lineage, not on an audit of these exact bytes; that is recorded in the decision and is one of the items the external audit must cover.
The EntryPoint, account and validator contracts are pinned per network by address and code hash; a process whose node shows other code, or none, at a pinned address refuses to start, naming the network, the contract and both hashes.
Only the canonical EntryPoint and public account and paymaster contracts from audited lineages, pinned per network; no custom contract.
Where the pilot packs ran
Each pilot pack is tested on every change against a local network or a fork; the three that use contracts already on public networks were also run there, by hand, with the outcome recorded.
| Pack | Tested on every change | Run on a public test network |
|---|---|---|
| Stablecoin payouts | Fork of Ethereum mainnet, real USDC and USDT | Base Sepolia, Circle’s test USDC |
| Tokenisation | Besu QBFT, free gas | None: our own contract, by the owner’s decision |
| Customer programmes | Anvil with Alto, a paymaster paying | None: our own contract, by the owner’s decision |
| Attestations | Fork of Base Sepolia, the real Ethereum Attestation Service | Base Sepolia |
| Treasury on Aave V3 | Fork of Ethereum mainnet, Aave V3 and Chainlink | Sepolia, in test EURS while Aave’s test USDC is over its supply cap |
Run on Base Sepolia, a public test network, with Circle's official test USDC: a payout confirmed, a payout to an unlisted address refused, a payout above the threshold held until the approver signed, the daily limit enforced, and an incoming payment delivered as a signed webhook.
Run on Base Sepolia, a public test network, against the network's own Ethereum Attestation Service: the schema registered once, an accreditation attested and delivered as a signed webhook, an attestation under another schema refused, a revocation held until the reviewer approved, each visible on EAS's explorer.
Run on Sepolia, a public test network, against Aave's own test market and Chainlink's live feeds, in test EURS while Aave's test USDC is over its supply cap: two supplies as ordered batches, the larger one held until the treasurer approved, an approval to another spender and a supply past the daily cap refused, and withdrawals of part and of everything, each visible on the explorer.
Proven on every change on a Hyperledger Besu QBFT network without fees: the asset deployed through CryptoRail by an identity holding no ether, every function called by name, an issuance above a threshold held until the issuer's board approved, the contract's refusals reported with their reason, and every event delivered to the back office as a signed webhook.
Run on public test networks by manual procedures recorded with their dates: a real wallet asking for sponsorship on Base Sepolia, the stablecoin and attestation packs on Base Sepolia, the Aave treasury pack on Sepolia.
The public runs earn their keep: the Aave run on Sepolia found a defect the fork journeys had not shown (a step of an ordered batch simulated before the step it depended on was mined), and it was fixed.
What it does not do
- Blockchains outside the EVM family. Not supported
- Private transactions on Besu (privacy groups). Not supported
- It does not certify node clients. Any node that follows the Ethereum JSON-RPC specification is expected to work; Anvil and Besu are the ones tested.
- It does not declare a public network “supported” by name. Public test networks were exercised by the manual runs listed above; a production network is configured, and its contract pins read from its node, when you add it.
- It does not run sponsored execution on Besu or on any network without the canonical EntryPoint; on a free-gas network there is nothing to sponsor.
- It does not use a newer EntryPoint yet. v0.8 and v0.9 exist; v0.7 is the version pinned, chosen because every audited account and bundler examined at the time of the decision supported it.
- Load spread across healthy node endpoints: by design one endpoint is used at a time, in the configured order. Not supported
Evidence
Every claim above links to its evidence on the evidence page. The main ones:
| Subject | Requirements and decisions | Journeys |
|---|---|---|
| Several networks, JSON-RPC, endpoints | FR-CHN-01 to FR-CHN-07, FR-CHN-09, FR-CHN-14, FR-CHN-15 | J06, J39 |
| Profiles, gas and finality policies | FR-CHN-12, FR-CHN-13, FR-CHN-16, FR-FIN-01 | J05, J06, J08 |
| Free-gas Besu networks | FR-CHN-08, FR-CHN-11 | J05, J17, J54 |
| Tested targets, no funds in CI | NFR-INT-03, NFR-INT-05, NFR-INT-06, NFR-QA-02, NFR-QA-05 | J05, J31, J32 |
| Pinned contracts | NFR-SEC-09, FR-SPN-06, ADR-0003 | J32 |
| Public test networks | NFR-INT-06, FR-PLT-05, FR-PLT-24, FR-PLT-29 | J52, J58, J60 |