Writing

What is deterministic accounting software?

Hard problem
Reconcile a year of on-chain activity by hand — thousands of swaps, a stake into a pool that's legally a disposal, an unstake that's a fresh acquisition at market value, a reorg that deletes transactions you already booked — and the ledger silently drifts from the truth, because it's a pile of rows you mutate and nothing checks them against the source.
Approach
Declare the inputs and the rules; derive the ledger from them. Same inputs + same rules → the same ledger, every time, with provenance on every row.

Most accounting software is imperative: someone posts each journal entry by hand, and the ledger is those stored rows. The source of truth is a pile of rows you mutate.

Deterministic accounting flips that. You declare the inputs and the rules — the way a spreadsheet recalculates every total from its formulas the moment a figure changes, instead of you typing the totals in — and the ledger is derived from them. You never hand-edit a ledger row; you change an input or a rule and regenerate the whole thing.

The piece that does the deriving is a generator: a pure function from immutable inputs to a full double-entry ledger.

function generateLedger(inputs: Input[]): LedgerRow[] {
	const rows: LedgerRow[] = []
	for (const input of inputs) {
		rows.push(...rulesFor(input).map((rule) => rule.apply(input)))
	}
	return rows
}

Because the ledger is derived, it is reproducible (same inputs + same rules → the same ledger, every time), every row keeps its provenance (which input and rule produced it), and the whole history is versionable.

Here is the shape in one domain — crypto, where the inputs are raw on-chain events:

On-chain eventDebitCredit
deposit 2 ETHETH (asset)Capital
buy 1 ETH @ $3,000ETH (asset)USD (asset)
sell 1 ETH @ $3,400USD (asset)ETH + Gain

I intend to keep developing this article — FIFO lots, multi-entity consolidation, what happens when an exchange collapses under you — explanations are to come.