Skip to main content
Both rails are live in sandbox today. Base Sepolia (eip155:84532) and Stellar testnet (stellar:testnet) settle real USDC through the same Sly governance loop. Mainnet for both rails (Base + Stellar pubnet) ships with production access — contact us once you’ve worked through the production access checklist.

What “rail-neutral” actually means

The four Sly primitives — Identity, Governance, Policy, Receipts — work the same on every rail. A receipt minted on Base and a receipt minted on Stellar carry the same identity fields, the same canonical encoding, the same HMAC algorithm, and the same offline verifier. The rail is a setting, not an integration.
The same /v1/agents/:id/... endpoints, the same dashboard surfaces, the same receipt shape. Only chain and the address format differ.

The two production rails

Base (EVM L2)

Coinbase’s L2 on Optimism Stack. Mid-large settlements. EVM ecosystem. ~2s finality. EIP-191 key-control proofs.

Stellar (Soroban)

Stellar Development Foundation’s smart-contract chain. Agent micro-payments. Fee-sponsored settlement. ~5s finality. SEP-10 key-control proofs.

Side by side

Picking a rail by hand? The short rule: Base for mid/large settles in EVM-heavy stacks; Stellar for sub-cent agent micropayments and emerging-markets edges. Better: let selectRail() pick for you.

selectRail() — the decision function

Rail-neutrality at the platform level becomes a single pure function at the code level. selectRail() takes an intent, the tenant’s allow-list, the agent’s allow-list, and current network conditions, intersects them, scores the survivors, and returns the chosen rail plus the human-readable reasons it won.
The reasons land in the receipt’s rail_selection field. The receipt explains itself.

The decision tree

Full source: apps/api/src/services/x402/select-rail.ts. Pure function, fully unit-tested, 0 side effects — replayable forever.

Allow-lists — two levers

Every agent’s effective rail allow-list is tenant.allowed_rails ∩ agent.allowed_rails. Two operators can independently dial down (never up) the rails their agents can settle on.
Empty array ([]) means “no restriction” — defaults to platform-wide allow. Both fields render as Allowed Rails chip panels in the dashboard for the relevant scope.

Receipt shape, across rails

Every Sly governed payment — Base or Stellar — produces the same receipt envelope. Only chain, address format, and a couple of optional rail-specific fields vary.
Every field above is in the canonical encoding. Every field is in the HMAC. Tampering with the rail, the address, the agent, the custody provider, or the decision invalidates the signature on either rail.

Offline verification works the same

The verify-offline.mjs script in examples/stellar-demo/ is rail-agnostic — it re-derives the canonical encoding and HMAC, then byte-compares. Works for both Base and Stellar receipts because the canonical encoding is json-sort-keys-v1 regardless of chain.
This is the layer that lets you audit a Sly settlement without trusting Sly’s API at the moment of audit. Cryptography over wire.

What’s NOT yet at parity

Three places where Base is ahead of Stellar today, by design: All three are coded against an abstraction; flipping one over is a config change, not a rebuild.

Where to go from here

Settling on Base

Full guide — endpoints, EIP-191 binding, witness receipts, dashboard surface, EAS anchoring.

Settling on Stellar

Full guide — endpoints, SEP-10 binding, custody providers, AttestProtocol anchoring, the three identity layers.

x402 protocol

The HTTP 402 micropayment protocol that both rails serve under the same Sly governance loop.

Production access

How to graduate from sandbox (both rails) to live mainnet settlement.