market-settlement-engine
Solo build, in a fortnight.
Settlement Engine
Event ingestion and on-chain/off-chain reconciliation for a Solidity prediction market.
A parimutuel market contract on Sepolia, plus a Go service that ingests the contract’s event logs into an append-only PostgreSQL ledger and continuously reconciles on-chain state against the database, alerting on any divergence.
Why it's interesting
Built to explore the correctness problems real-money trading platforms face: idempotent event ingestion, auditable state, and detecting drift between two systems of record.
What I built
- Parimutuel yes/no market contract (createMarket, buy, resolve, claim) with Foundry lifecycle tests, deployed and verified on Sepolia. Checks-effects-interactions on claim, multiply-before-divide payout maths, call{value:} with the success flag checked.
- A Go indexer where backfill and live tail are the same loop: each pass closes the gap between the last checkpoint and the safe head (latest − 6 confirmations), whether that gap is fifteen thousand blocks or five.
- Idempotent ingestion keyed on (tx_hash, log_index) with ON CONFLICT DO NOTHING; the checkpoint advances only after every insert in a range succeeds, so a crash re-processes work instead of skipping it.
- Event sourcing
- Idempotency
- Checkpointing & recovery
- At-least-once delivery
- Reconciliation
- Confirmation depth
- Fault injection
- Re-entrancy safety
- SettlementMarket.solSepolia · source of truth
createMarket · buy · resolve · claim. Emits an event for every state change.
- Go indexerpolling loop
Reads chunked block ranges up to latest − 6. The checkpoint advances only after every insert in a range succeeds.
- chain_eventsPostgreSQL · append-only ledger
Idempotent insert: ON CONFLICT (tx_hash, log_index) DO NOTHING. Replaying any range is a no-op.
- foldderived, disposable
Truncates and replays the ledger in chain order, in one transaction, into markets and positions.
- reconcilerreconciliation_runs · audit trail
On-chain view calls vs off-chain SQL sums. Every comparison recorded; divergence raises an alert.
The contract’s pools and the database’s sums are two accounts of the same events, so they must always agree. The reconciler is the proof that they do.