Accounting Ledger System
Double-Entry • Dual-Run Verified • Append-Only
Banking-grade precision for digital assets. This double-entry ledger system delivers ACID guarantees, idempotent posting, and high-volume reconciliation that regulators trust. Track confirmations, handle reversals, generate audit-ready snapshots—all while maintaining strict invariants and append-only journals. Real-time balances, aging reports, deterministic closing ensure accuracy across every transaction.
Crypto Movements Break Traditional Books
Digital-asset accounting lives between two worlds: blockchains that finalize slowly and compliance teams that hold funds. Most ledgers handle neither — and floating-point math quietly corrupts the rest.
Floating-Point Money
IEEE floats round. Over millions of postings, sub-cent errors compound into balances nobody can reconcile — and no regulator will sign off on.
Retries That Double-Post
Networks fail and clients retry. Without deep idempotency, every retry risks a duplicate entry and a phantom balance.
Funds in Limbo
A deposit that's on-chain isn't final, and a confirmed deposit isn't necessarily compliant. Single-status ledgers can't say where the money actually stands.
Unbalanced, Editable Records
Ledgers that allow one-sided or mutated entries can't prove their own history. Audit becomes archaeology.
A Ledger That Proves Itself — Twice
A double-entry ledger for digital-asset movements, run as a dual-run system: a Kotlin/Spring Boot platform ledger shadowed by a byte-compatible Rust reimplementation that verifies every posting.
Balanced by Construction
Every movement becomes a debit + credit pair. assert_balanced() rejects any non-zero sum per transaction, ledger, asset, and account with a typed UnbalancedTransaction error.
Dual-Track Lifecycle
A single Detected event opens two parallel tracks at once — blockchain confirmation depth and compliance clearance — moving funds pool-to-pool across 10 accounts until both agree.
Three-Layer Idempotency
Unique row keys with ON CONFLICT DO NOTHING, business keys where replays return the same entry IDs, and dedicated reversal keys. Retry all you want.
Dual-Run Verification
A Rust reimplementation of the ledger engine shadows the production platform, posting the same movements byte-for-byte — divergence is a bug, caught before it's a balance.
Four Layers, One Invariant: Books That Balance
From the API down to storage, every layer enforces the same rule — no entry lands unless its debits and credits sum to zero, exactly once.
API & Client Surface
Eight REST routes for direct posting, reversals, status transitions, and balance queries — with scope-based bearer auth and RFC-7807 problem+json errors. A typed Rust client crate ships builder helpers and assertion decoders.
Lifecycle Engine
A six-state status machine — Reserved, Detected, Quarantine, Compliance, Confirmed, Finalized — drives pool-to-pool transfers across 10 pools on two parallel tracks, with transition guards that forbid leaving Finalized or regressing to Detected.
Posting Core
The double-entry heart: balanced debit + credit pairs, hand-rolled arbitrary-precision integer arithmetic on decimal strings (round-trip tested past 2^127), insufficient-balance checks, and reversals as linked offsetting rows that net to zero.
Dual-Run Foundation
One append-only PostgreSQL entry table with five indexes; balances are never stored — they're computed on read by summing pools. The Kotlin/Spring Boot platform and the Rust service (axum, tokio, sqlx) run against the same byte-compatible schema.
The Life of a Movement
From first detection to settled balance — or clean reversal — every asset movement follows the same auditable path across ledgers like stellar-testnet and bitcoin-testnet, in XLM, USDC, and BTC.
Post
API → LedgerWhat Happens
- Entry posted with a business idempotency key (ledger:batch:tx:index:asset:debitor:creditor:status)
- Movement expanded into a balanced debit + credit pair
- assert_balanced() verifies zero-sum before anything lands
- Replays return the same entry IDs — test-proven
Track
Dual-Track InitWhat Happens
- Detected opens both tracks simultaneously — dual track initialization
- Block track mirrors chain depth: BlockDetected → BlockConfirmed → BlockFinalized
- Compliance track runs in parallel: Detected → Quarantined → Cleared → Settled
- Funds move pool-to-pool across 10 pools as each track advances
Settle
Guarded TransitionsWhat Happens
- Transition guards enforce legal moves only — no leaving Finalized, no regressing to Detected
- Settled pool feeds total balance; BroadcastReserved feeds reserved; Quarantined feeds quarantined
- Balances computed on read via SUM by pool — nothing cached, nothing stale
- Insufficient pool balance rejected with a typed error
Reverse & Audit
When Things Go WrongWhat Happens
- Reversals post offsetting rows with negated amounts — originals untouched
- Status set to REVERSED_reason, linked via reversal_of_entry_id
- Dedicated reversal idempotency keys prevent double-reversal
- Net-zero after reversal — test-proven
Four Guarantees, All Test-Proven
Each pillar turns an accounting promise into an enforced invariant — with the test evidence to back it.
Balance Invariant
Zero-Sum or RejectedControls
- assert_balanced() on every (transaction, ledger, asset, account)
- Typed UnbalancedTransaction errors
- InsufficientPoolBalance checks before transfer
- Append-only journal — corrections are new rows
Idempotency ×3
Retry-Safe by DesignControls
- Unique row_idempotency_key + ON CONFLICT DO NOTHING
- Business key replay returns identical entry IDs
- Reversal keys prevent double-reversal
- Safe under client retries and redelivery
Exact Arithmetic
No Floats, EverControls
- Arbitrary-precision unsigned integers as decimal strings
- Hand-rolled digit-by-digit add, subtract, compare
- 2^127 round-trip test
- NUMERIC columns in PostgreSQL
Test Evidence
47 TestsControls
- 30 domain tests on the posting core
- 11 embedded service tests
- 6 integration tests via the test-it harness
- Replay and reversal net-zero proven in tests
From Verified Core to Full Back Office
The posting engine and lifecycle machine are live in beta under dual-run verification. Each phase adds reporting depth without touching the invariants.
Beta
Live TodayDelivered
- Dual-run ledger: Kotlin platform + Rust verifier
- Six-state, dual-track lifecycle across 10 pools
- 8-route API with scoped auth and RFC-7807 errors
- Prometheus /metrics and on-read pool balances
Rules Engine
In the Domain LayerPlanned Deliverables
- YAML-configurable posting rules wired to HTTP
- TransitionRule and LedgerEntryRule definitions
- ValidationConfig-driven guards per ledger
- Operator-editable lifecycle policy
Reporting & Close
PlannedPlanned Deliverables
- Audit-ready balance snapshots
- Aging reports across pools
- Deterministic period close
- Reconciliation exports
Hardening
PlannedPlanned Deliverables
- Append-only enforced at the database layer
- Expanded analytics beyond Prometheus gauges
- Production ledger rollout beyond testnets
- Extended asset coverage
Books You Can Hand to an Auditor
Finance, engineering, and operations each get invariants instead of assurances.
For Finance & Compliance
For Engineering Teams
For Platform Operators
Need a Ledger Regulators Can Trust?
Let's talk about double-entry accounting for digital assets — from posting-engine design and dual-run verification to compliance-aware settlement.