Skip to content

Implement real-time invoice payment aggregator with streaming updates, conflict resolution, and rollup snapshots #187

@Kingsman-99

Description

@Kingsman-99

Description

Build a PaymentAggregator that maintains a live, incrementally-updated payment summary for an invoice. It must handle out-of-order payment events (from blockchain reorgs or delayed delivery), resolve conflicts via ledger sequence number, produce periodic rollup snapshots to avoid recomputing from scratch, and expose a reactive subscription API.

Acceptance Criteria

  • Create src/paymentAggregator.ts exporting PaymentAggregator class
  • PaymentAggregator accepts an initial Invoice and maintains internal state: totalFunded: bigint, percentFunded: number, payerBreakdown: Map<string, bigint>, paymentCount: number, lastLedger: number
  • applyPayment(payment: Payment & { ledger: number }): void — applies a payment; ignores duplicates (same payer + same ledger); if a payment with lower ledger arrives after a higher one, re-sorts and recomputes (conflict resolution)
  • subscribe(cb: (summary: PaymentSummary) => void): () => void — fires callback synchronously on every applyPayment call; returns unsubscribe
  • snapshot(): PaymentSnapshot — returns current state serializable to JSON; restore(snapshot: PaymentSnapshot): void — restores state without reprocessing all payments
  • getTopPayers(n: number): { address: string, amount: bigint }[] — returns top N payers sorted descending by amount
  • percentFunded must never exceed 100 even if totalFunded > invoiceTotal
  • All exported from src/index.ts with full types
  • Tests: out-of-order payment conflict resolution, duplicate payment ignored, snapshot/restore round-trip, subscriber fires on each apply, unsubscribe works, top payers sorted correctly with tie-breaking by address alphabetically

Context

  • Invoice and Payment types are in src/types.tsPayment may need a ledger: number field added
  • src/snapshot.ts already exists — align snapshot format conventions
  • bigint arithmetic only — no Number() conversion for amounts

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestgrantfoxIssue for GrantFox program

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions