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

    Fields

    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