Architecture overview
Corridor is a modular TypeScript monorepo. Its central design rule is that every corridor runs through the same engines: a KES payout through an anchor and a naira payout through an off-Stellar partner differ only in the path the planner chooses, not in which subsystem handles them.
Two things about Stellar decide the shape of the system:
MEMO_HASHis exactly 32 bytes, which is exactly a Corridor Reference. The reference travels whole, as part of the signed transaction, so reconciliation is a join rather than an inference.- Anchors settle on Stellar itself. The fiat spoke touches the hub directly, so the common payout path has no bridge in it at all.
Everything in that diagram runs in the customer’s own environment.
The layers
Section titled “The layers”Route planner (packages/routing)
Turns a request (corridor, purpose, privacy, source, destination, environment) into an ordered list of legs by searching a graph of venue/asset positions. It rejects any payout not funded from the Stellar hub and any collection that does not land on it, and it is the only place privacy is decided — today by refusing privacy: "shielded", because no shielded venue is configured. Routing →
Saga engine (packages/saga)
Runs a plan as durable steps in Postgres. Each leg has forward and an optional compensate. Steps retry with backoff, a lease keeps one worker per saga, and a failure compensates completed steps in reverse order. Failures after money has left Corridor’s control stop at manual_review instead. Saga →
Legs (packages/legs and chain packages)
Each implemented leg kind (stellar.transfer, partner.payout, partner.collect, ledger.reserve, ledger.credit, bridge.simulated) moves value on one venue and returns the ledger entries that describe what it did. Two more, stellar.pathPayment and cctp.transfer, are declared in the route graph and not yet written. Legs are idempotent: before sending, they ask the network whether the movement already landed. Stellar →
Ledger (packages/ledger)
Double-entry, append-only journal on Postgres, at Stellar’s own 7 decimal places. Postings balance per asset, accounts can be flagged no-overdraft, and each external movement is booked exactly once through a unique (venue, external_ref). Ledger →
Anchors (packages/partners)
Every fiat spoke sits behind one partner interface. SepAnchor implements it over SEP-1, 10, 12, 38 and 31; PajPartner and MockPartner implement the same interface for currencies no Stellar anchor serves yet. Anchors →
Observers and reconciliation (packages/recon)
Observers turn Horizon payments, anchor status and partner webhooks into one Observation shape. The matcher joins them with ledger entries on the external reference, and a vault check compares each vault’s on-chain balance with the books. Reconciliation →
Design principles
Section titled “Design principles”Every dollar is settled, held and reconciled on Stellar. The planner refuses anything else, and that is what makes anchors additive.
One reference, carried whole32 bytes in MEMO_HASH, part of the signed transaction. Reconciliation is a join on a watched account’s own payment stream — no indexer.
Fees, sponsored reserves and funding are booked against the transaction that proves them, never against what the code intended.
The ledger keeps 7 decimal placesStellar’s own precision, so a booked balance can equal an on-chain balance exactly and reconciliation needs no tolerance.
Customers hold the keysEvery vault signs through the customer’s own KMS or MPC. Corridor sends digests and receives signatures.
Say what is not builtThe confidential lane is deferred and the planner refuses it with that reason. SEP-6 collections raise rather than guess.
Code map
Section titled “Code map”| Package | Responsibility |
|---|---|
@corridor/core |
Venues, 32 fiat currencies with stable one-byte indices, digital assets at 7 dp, Money in integer minor units, Corridor Reference codec, Observation |
@corridor/chain-stellar |
Horizon client, asset registry by issuer, transferWithReference, StellarObserver, trustlines |
@corridor/routing |
Route graph (DEFAULT_EDGES), planRoute, hub enforcement |
@corridor/saga |
SagaEngine, Leg, NonRetryableError, ManualReviewError, reserve leg |
@corridor/ledger |
Schema, Ledger.post, invariants, named Accounts |
@corridor/legs |
Stellar transfer, simulated bridge, anchor payout and collect, ledger credit |
@corridor/partners |
RampPartner, SepAnchor, PartnerRegistry, Paj adapter, mock partner, webhook signing |
@corridor/recon |
reconcile, reconcileReadOnly, bookVaultMovements, checkVaults |
@corridor/signer |
Signer interface for Ed25519 and secp256k1; local, AWS KMS and Turnkey adapters |
@corridor/webhooks |
Partner webhook server, event store, exactly-once order links |
@corridor/chain-solana, @corridor/chain-evm |
The cross-chain spokes, for currencies no Stellar anchor serves yet |
The authoritative version of all of this is docs/ARCHITECTURE.md in the repository.