Skip to content

[API] Implement Soroban event XDR decoder in StellarIndexerService #2

Description

@Mona-i

Problem

src/common/stellar-indexer.service.ts polls Horizon for contract events but the fetchAndStoreEvents method has a critical // TODO and does nothing with the events it receives:

// stellar-indexer.service.ts line ~60
this.logger.debug(Found ${records.length} ${eventType} events for contract ${contractId});
// TODO: Parse and upsert into contributions / loans tables
// This is where you'd decode the XDR event payloads from Soroban

Without this, the database is never populated from on-chain data — the whole sync loop is a no-op.

Task

Implement event decoding and database upsert for contribution and loan events:

  1. Decode Soroban event XDR payloads

import { xdr, scValToNative } from "@stellar/stellar-sdk";

// Each event record has a value field with base64 XDR
const decoded = scValToNative(xdr.ScVal.fromXDR(record.value.xdr, "base64"));

  1. Handle contribution events

Event payload from contract: (member_address, amount, period)
Upsert into Contribution table:

await this.prisma.contribution.upsert({
where: { txHash: record.transaction_hash },
create: { groupId, memberAddress: member, amount, period, txHash, ledger },
update: {},
});

  1. Handle loan_requested events
    Event payload: (loan_id, borrower, amount)
    Upsert into Loan table with status "Pending".

  2. Handle loan_approved events
    Update matching loan to status: "Approved", set approvedAt.

  3. Track last-synced ledger per contract

Store a lastSyncedLedger per contractId in a simple in-memory Map (or new Prisma model) to avoid re-processing old events on every poll.

Acceptance Criteria

  • XDR payloads decoded using @stellar/stellar-sdk
  • contribution events upserted into Contribution table
  • loan_requested and loan_approved events upserted into Loan table
  • Duplicate events handled gracefully (upsert, not insert)
  • Last-synced ledger tracked to avoid duplicate processing
  • Unit test with mocked Horizon response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions