Skip to main content
The ledger (@corridor/ledger) is the system of record. Chains and partners are evidence; the ledger is what Corridor says happened, and reconciliation proves the two agree.

Accounts

An account is identified by its type and owner, scoped by corridor, asset and venue:
Named helpers (Accounts.customer, .customerHold, .vault, .clearing, .revenue, .expense, .equity) open accounts on first use, so legs never build account ids by hand.

Invariants

Every entry balances per asset

The sum of debits equals the sum of credits for each asset in an entry. Checked before any write; an unbalanced entry never reaches the database.

No overdraft where it matters

Vaults and customer balances are flagged no_overdraft. After applying postings, the natural balance of each such account is checked inside the same transaction, which rolls back on violation.

Exactly once per external movement

unique (external_venue, external_ref) on journal entries. A Tempo log, a Solana signature or a partner order id can be booked once; a second attempt returns the original entry as a duplicate.

Append-only

Database triggers reject UPDATE and DELETE on the journal and postings. Mistakes are corrected with reversing entries, so the history is never rewritten.
checkInvariants() re-verifies globally (every entry balances per asset; the balance projection equals a full recompute from postings) and runs in tests and on demand.

Schema

Amounts are numeric(78,0) integer minor units, wide enough for any 256-bit on-chain amount. Balance rows are locked in a stable order before posting, so concurrent writers cannot deadlock.

Posting

Two assets, each balanced: the customer’s hold is released against the pathUSD side of the peg, and the Solana egress vault is credited against the USDC side. The usd-peg clearing pair nets to zero across a flow, and the console shows it doing so.

Storage

Locally and in tests the ledger runs on PGlite, Postgres compiled to WebAssembly, so a developer needs no database server. Production uses managed Postgres with the same schema and triggers. Both satisfy the same small Db interface (query, exec, transaction).