A small double-entry accounting kernel for fintech teams who want correctness without buying a platform.
LedgerKit is a lightweight, embeddable double-entry ledger engine written in Rust.
It is designed for developers building wallets, payment systems, marketplaces, banking products, gaming economies, escrow services, and other financial applications that require auditable money movement.
Instead of storing balances directly, LedgerKit records every movement of value as immutable journal entries and derives balances from transaction history.
Many applications start with a simple approach:
user.balance += 10000;This works until you need:
- Audit trails
- Chargebacks and reversals
- Reconciliation
- Multi-wallet systems
- Regulatory compliance
- Financial correctness guarantees
LedgerKit solves these problems using double-entry bookkeeping.
Every transaction must balance.
Example:
| Account | Debit | Credit |
|---|---|---|
| Cash | 10,000 | |
| User Wallet Liability | 10,000 |
The following rule always holds:
Total Debits = Total Credits
Unbalanced transactions are rejected.
Transactions are never modified or deleted.
Corrections are performed through reversal transactions.
This guarantees a complete audit trail.
Balances are calculated from ledger entries.
Instead of:
account.balance = 10000;LedgerKit derives balances from transaction history.
This prevents inconsistencies and provides complete traceability.
Create and manage ledger accounts.
Examples:
- Cash
- User Wallet
- Merchant Wallet
- Escrow
- Revenue
- Settlement
Represent debits and credits.
Entry {
account_id,
amount,
entry_type,
}Group multiple entries into a single financial event.
Transaction {
id,
entries,
}Validate and record transactions.
ledger.post(transaction)?;Calculate balances from transaction history.
ledger.balance(account_id)?;Reverse transactions without modifying history.
ledger.reverse(transaction_id)?;Retrieve account history.
ledger.history(account_id)?;LedgerKit aims to become:
- The SQLite of financial ledgers
- Easy to embed into existing systems
- Correct by default
- Storage agnostic
- Extensible
- Production ready
ledger-kit/
├── ledger-core
├── ledger-storage
├── ledger-sqlite
├── ledger-postgres
├── ledger-events
├── examples
├── benches
├── tests
└── docs
Contains:
- Accounts
- Entries
- Transactions
- Validation logic
- Balance calculations
Storage abstractions and repository interfaces.
SQLite implementation.
PostgreSQL implementation.
Event publishing and subscriptions.
let cash = ledger.create_account("Cash");
let wallet = ledger.create_account("User Wallet");ledger.post(Transaction::new(vec![
debit(cash, 10_000),
credit(wallet, 10_000),
]))?;let balance = ledger.balance(cash)?;- Account type (Asset, Liability, Equity, Revenue, Expense)
- Money type (i64 cents, Display, Add, Sub)
- Entry type (Debit / Credit with account_id + amount)
- Transaction (batched entries with UUID id)
- Validation (balanced, non-empty enforcement)
- Create accounts
- Post transactions (reject unbalanced / missing account)
- Balance computation (sum of entries for an account)
- Reversal (create offsetting transaction by tx id)
- Transaction count
- Account history (filter transactions involving an account)
- In-memory storage backend
- JSON serialization (serde)
- Storage trait (
LedgerStore) - InMemoryStore (HashMap-backed, full impl)
- SQLiteStore schema (accounts + transactions tables)
- SQLiteStore
load_transactionsandload_accounts(stubbed withtodo!()) - SQLiteStore
save_account(stubbed) - SQLite-backed
Ledgerintegration tests
- Idempotency keys (duplicate transaction detection)
- Multi-currency support (currency code on Money)
- Event publishing (on_post, on_reverse hooks)
- Transaction metadata (description, timestamp, reference)
- Entry-level metadata
- PostgreSQL backend
- Snapshots / checkpoints for fast balance queries
- Streaming history (cursor / pagination)
- High-performance batch balance computation
- Python bindings (PyO3)
- Node.js bindings (napi-rs)
- REST API (axum or actix-web)
- WASM support
- CLI tool for inspection
LedgerKit is not:
- An accounting application
- A bookkeeping UI
- A banking platform
- A payment processor
LedgerKit is a financial infrastructure component.
It provides the ledger layer upon which those systems can be built.
Financial correctness is more important than convenience.
Money movement should always be represented by transactions.
History should never be rewritten.
Keep the kernel simple and composable.
This project is also designed as a learning challenge for Rust engineers.
By building LedgerKit you will learn:
- Rust ownership and borrowing
- Traits and abstractions
- Error handling
- Domain-driven design
- Repository pattern
- Event-driven architecture
- Database persistence
- Financial systems design
- Testing strategies
- Crate organization
LedgerKit draws inspiration from:
- Traditional accounting systems
- Banking core ledgers
- Event sourcing architectures
- SQLite's embeddable philosophy
- Modern fintech infrastructure platforms
MIT
Financial systems should not start with:
user.balance += amount;They should start with:
ledger.post(transaction)?;LedgerKit exists to make financial correctness the default.