Skip to content

feat(onchain): replace vacuous ledger reconciliation with real RPC source - #451

Merged
kilodesodiq-arch merged 1 commit into
ChainForgee:mainfrom
snowrugar-beep:fix/issue-427-ledger-reconciliation
Aug 20, 2026
Merged

feat(onchain): replace vacuous ledger reconciliation with real RPC source#451
kilodesodiq-arch merged 1 commit into
ChainForgee:mainfrom
snowrugar-beep:fix/issue-427-ledger-reconciliation

Conversation

@snowrugar-beep

Copy link
Copy Markdown
Contributor

Summary

Closes #427

Replace the placeholder fetchOnChainData (which returned [] and caused every stored row to be flagged as missing with ledger: -1) with a real SorobanLedgerOnChainSource that pages the Stellar RPC getTransactions API and decodes aid_escrow #[contractevent] payloads into BalanceLedger entries.

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 actionable flag were acting on noise. Additionally, the amount comparison used storedEntry.amount.toNumber(), a lossy float conversion for the i128-scale token amounts the contract uses.

What was built

app/backend/src/onchain/:

File What it contains
ledger-on-chain-source.ts LedgerOnChainSource interface, SorobanLedgerOnChainSource implementation (RPC pagination with range-coverage validation), decodeContractEvent decoder, and CONTRACT_EVENT_TO_BALANCE_LEDGER_TYPE mapping
ledger-on-chain-source.spec.ts 7 tests: event decoding, event-type mapping, diagnostic/other-contract filtering, RPC pagination, range-coverage failures
ledger-reconciliation.service.ts Injected LedgerOnChainSource, exact BigInt amount comparison via amountMismatchExceeds, decimalAmountToBigInt for lossless Decimal→BigInt, loud failure on source error/zero entries
ledger-reconciliation.service.spec.ts 10 tests: source error fails job, zero entries fail job, missing with correct ledger, amount mismatch (exact integer), within threshold, fractional Decimal, event type mismatch, stored-only missing, actionable computation
onchain.module.ts Provides LEDGER_ON_CHAIN_SOURCE as SorobanLedgerOnChainSource
onchain.processor.ts Routes ledger-reconciliation and ledger-backfill job names to their dedicated services

Integration changes outside ledger-on-chain-source/

  • onchain.module.ts — registered LEDGER_ON_CHAIN_SOURCE provider
  • onchain.processor.ts — added reconciliation/backfill job routing, widened Job type union
  • ledger-reconciliation.service.ts — removed fetchOnChainData placeholder, injected LedgerOnChainSource, rewrote amount comparison to use exact BigInt arithmetic

Acceptance criteria coverage

  • processReconciliation reads 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")
  • With on-chain data present, a stored row with no on-chain counterpart produces a real missing discrepancy with the correct ledger, and an amount difference above thresholdPercent produces an amount_mismatch using exact integer units (ledger-reconciliation.service.spec.ts — "flags an on-chain entry with no stored counterpart" + "flags an amount difference above the threshold")
  • With zero on-chain entries available, the job does not flag every stored row as missing with ledger: -1 (ledger-reconciliation.service.spec.ts — "fails the job when the on-chain source returns zero entries")
  • Unit tests inject a fake on-chain source and assert each discrepancy type and the actionable computation (ledger-reconciliation.service.spec.ts — 10 tests covering all discrepancy types and actionable logic)

Deliberately deferred

  • Replacing ioredis-mock with testcontainers (separate, already-tracked concern per issue)
  • BalanceLedger Float→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 failures
  • No existing files broken by this change (purely additive module + refactored service)

Env vars / Notes

AID_ESCROW_CONTRACT_ID=<contract-id>   # Required for SorobanLedgerOnChainSource to identify contract events
STELLAR_RPC_URL=<rpc-url>              # Stellar RPC endpoint (defaults to testnet)

The SorobanLedgerOnChainSource pages getTransactions with 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.

@kilodesodiq-arch kilodesodiq-arch left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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
snowrugar-beep force-pushed the fix/issue-427-ledger-reconciliation branch from f414e45 to 9b4bd6c Compare August 20, 2026 20:30

@kilodesodiq-arch kilodesodiq-arch left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kilodesodiq-arch
kilodesodiq-arch merged commit 8a0e1da into ChainForgee:main Aug 20, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LedgerReconciliationService never fetches on-chain data: reconciliation flags every stored entry missing

2 participants