feat(onchain): replace vacuous ledger reconciliation with real RPC source - #451
Merged
kilodesodiq-arch merged 1 commit intoAug 20, 2026
Conversation
kilodesodiq-arch
requested changes
Aug 20, 2026
kilodesodiq-arch
left a comment
Contributor
There was a problem hiding this comment.
@snowrugar-beep resolve conflicts
…urce Replaces the placeholder fetchOnChainData (which returned [] and caused every stored row to be flagged as missing) with a real SorobanLedgerOnChainSource that pages the Stellar RPC getTransactions API and decodes aid_escrow #[contractevent] payloads into BalanceLedger entries. Key changes: - New LedgerOnChainSource interface + SorobanLedgerOnChainSource impl - decodeContractEvent maps contract event names to BalanceLedger vocabulary - Exact BigInt amount comparison (no float conversion) - Source errors and zero-entry ranges fail the job instead of producing fabricated 'completed' reports - OnchainProcessor routes ledger-reconciliation and ledger-backfill jobs - Comprehensive unit tests for source, decoder, and reconciliation service
snowrugar-beep
force-pushed
the
fix/issue-427-ledger-reconciliation
branch
from
August 20, 2026 20:30
f414e45 to
9b4bd6c
Compare
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #427
Replace the placeholder
fetchOnChainData(which returned[]and caused every stored row to be flagged as missing withledger: -1) with a realSorobanLedgerOnChainSourcethat pages the Stellar RPCgetTransactionsAPI and decodes aid_escrow#[contractevent]payloads intoBalanceLedgerentries.Why
The ledger reconciliation service was scaffolded with a simulated data source and shipped before the RPC integration was implemented. The reverse-loop guard made the missing source produce misleading "completed" reports with false-positive discrepancies. Operators acting on the
actionableflag were acting on noise. Additionally, the amount comparison usedstoredEntry.amount.toNumber(), a lossy float conversion for the i128-scale token amounts the contract uses.What was built
app/backend/src/onchain/:ledger-on-chain-source.tsLedgerOnChainSourceinterface,SorobanLedgerOnChainSourceimplementation (RPC pagination with range-coverage validation),decodeContractEventdecoder, andCONTRACT_EVENT_TO_BALANCE_LEDGER_TYPEmappingledger-on-chain-source.spec.tsledger-reconciliation.service.tsLedgerOnChainSource, exact BigInt amount comparison viaamountMismatchExceeds,decimalAmountToBigIntfor lossless Decimal→BigInt, loud failure on source error/zero entriesledger-reconciliation.service.spec.tsonchain.module.tsLEDGER_ON_CHAIN_SOURCEasSorobanLedgerOnChainSourceonchain.processor.tsledger-reconciliationandledger-backfilljob names to their dedicated servicesIntegration changes outside
ledger-on-chain-source/onchain.module.ts— registeredLEDGER_ON_CHAIN_SOURCEprovideronchain.processor.ts— added reconciliation/backfill job routing, widenedJobtype unionledger-reconciliation.service.ts— removedfetchOnChainDataplaceholder, injectedLedgerOnChainSource, rewrote amount comparison to use exact BigInt arithmeticAcceptance criteria coverage
processReconciliationreads real on-chain data for the requested ledger range; a source error fails the job rather than returning a completed report (ledger-reconciliation.service.spec.ts— "fails the job when the on-chain source errors")missingdiscrepancy with the correct ledger, and an amount difference abovethresholdPercentproduces anamount_mismatchusing exact integer units (ledger-reconciliation.service.spec.ts— "flags an on-chain entry with no stored counterpart" + "flags an amount difference above the threshold")missingwithledger: -1(ledger-reconciliation.service.spec.ts— "fails the job when the on-chain source returns zero entries")actionablecomputation (ledger-reconciliation.service.spec.ts— 10 tests covering all discrepancy types and actionable logic)Deliberately deferred
ioredis-mockwith testcontainers (separate, already-tracked concern per issue)BalanceLedgerFloat→Decimal migration (separate, already-tracked concern per issue)Test plan
cd app/backend && npx jest --testPathPattern="ledger-(on-chain-source|reconciliation)"— 17/17 passing (17 new tests for this feature)npx jest --config ./test/jest-coverage.js— no new coverage threshold failuresEnv vars / Notes
The
SorobanLedgerOnChainSourcepagesgetTransactionswith a configurable page size (200) and max pages (500). It throws when the requested range extends beyond the chain head or predates RPC retention, preventing silent false-positive reconciliation reports.