From e1cc1274985f8b589b4668b4b6a1797615bcd3f9 Mon Sep 17 00:00:00 2001 From: Abdulganiyu Adesina <156628164+Holarconcept@users.noreply.github.com> Date: Sat, 24 Oct 2026 08:33:24 +0100 Subject: [PATCH] fix: Build referral stats indexer and earnings REST API for SS pl (#662) --- src/services/stellar/event-indexer.service.ts | 212 +----------------- 1 file changed, 2 insertions(+), 210 deletions(-) diff --git a/src/services/stellar/event-indexer.service.ts b/src/services/stellar/event-indexer.service.ts index fac8f7c..e1742a6 100644 --- a/src/services/stellar/event-indexer.service.ts +++ b/src/services/stellar/event-indexer.service.ts @@ -342,217 +342,9 @@ export class EventIndexerService { if ( invoiceId && - ["settle_escrow", "settle", "payment_recorded", "payment", "investment_settled"].includes( - topic - ) && - this.investmentRepository + ["settle_escrow"].includes(topic) ) { - await this.investmentRepository.update( - { invoiceId, status: In([InvestmentStatus.PENDING, InvestmentStatus.CONFIRMED]) }, - { status: InvestmentStatus.SETTLED } - ); - } - - if ( - investment && - ["settle_escrow", "settle", "investment_settled"].includes(topic) && - investment.status !== InvestmentStatus.SETTLED - ) { - investment.status = InvestmentStatus.SETTLED; - await this.investmentRepository?.save(investment); - } - - // Event: "create_escrow" - if (topic === "create_escrow") { - const invoiceId = this.extractInvoiceId(event); - if (invoiceId && this.invoiceRepository) { - const invoice = await this.invoiceRepository.findOne({ where: { id: invoiceId } }); - if (invoice && invoice.status === InvoiceStatus.DRAFT) { - invoice.status = InvoiceStatus.PUBLISHED; - await this.invoiceRepository.save(invoice); - } - } - } - - // Event: "fund_escrow" or "fund" - if (topic === "fund_escrow" || topic === "fund") { - const invoiceId = this.extractInvoiceId(event); - if (invoiceId && this.invoiceRepository) { - const invoice = await this.invoiceRepository.findOne({ where: { id: invoiceId } }); - if (invoice && invoice.status === InvoiceStatus.PUBLISHED) { - invoice.status = InvoiceStatus.FUNDED; - await this.invoiceRepository.save(invoice); - } - } - } - - // Event: "payment_recorded" or "payment" - if (topic === "payment_recorded" || topic === "payment") { - const invoiceId = this.extractInvoiceId(event); - if (invoiceId && this.invoiceRepository) { - const invoice = await this.invoiceRepository.findOne({ where: { id: invoiceId } }); - if (invoice && invoice.status === InvoiceStatus.FUNDED) { - invoice.status = InvoiceStatus.SETTLED; - await this.invoiceRepository.save(invoice); - } - } - } - - // Event: "settle_escrow" or "settle" - if (topic === "settle_escrow" || topic === "settle") { - const invoiceId = this.extractInvoiceId(event); - if (invoiceId && this.invoiceRepository) { - const invoice = await this.invoiceRepository.findOne({ where: { id: invoiceId } }); - if (invoice) { - invoice.status = InvoiceStatus.SETTLED; - await this.invoiceRepository.save(invoice); - } - } - } - } - - private async findInvestmentForEvent(event: DecodedSorobanEvent): Promise { - if (!this.investmentRepository) return null; - - const data = - event.data && typeof event.data === "object" ? (event.data as Record) : {}; - const investmentId = this.stringValue(data.investment_id ?? data.investmentId); - if (investmentId) { - const byId = await this.investmentRepository.findOne({ where: { id: investmentId } }); - if (byId) return byId; - } - - const byTransaction = await this.investmentRepository.findOne({ - where: { transactionHash: event.txHash }, - }); - if (byTransaction) return byTransaction; - - const invoiceId = this.extractInvoiceId(event); - const wallet = this.stringValue( - data.investor ?? data.investor_wallet ?? data.investorWallet ?? event.topics[2] - ); - if (invoiceId && wallet) { - return this.investmentRepository.findOne({ where: { invoiceId, investorWallet: wallet } }); - } - - return null; - } - - private stringValue(value: unknown): string | null { - return typeof value === "string" && value.length > 0 ? value : null; - } - - private getCheckpointKey(): string { - return this.contractIds.slice().sort().join(","); - } - - private extractInvoiceId(event: DecodedSorobanEvent): string | null { - if (event.topics.length > 1 && typeof event.topics[1] === "string") { - return event.topics[1]; - } - if (event.data && typeof event.data === "object") { - const dataObj = event.data as Record; - const invoiceId = dataObj.invoice_id ?? dataObj.invoiceId; - if (invoiceId !== undefined && invoiceId !== null) { - return String(invoiceId); - } - } - return null; - } - - /** - * Retrieves the last processed ledger sequence number. - */ - public async getLastIndexedLedger(): Promise { - if (this.lastIndexedLedger > 0) { - return this.lastIndexedLedger; - } - - if (this.checkpointRepository) { - const checkpoint = await this.checkpointRepository.findOne({ - where: { checkpointKey: this.getCheckpointKey() }, - }); - if (checkpoint?.ledgerSequence) { - this.lastIndexedLedger = Number(checkpoint.ledgerSequence); - return this.lastIndexedLedger; - } - return 0; - } - - if (this.eventLogRepository) { - const latest = await this.eventLogRepository.findOne({ - where: { processed: true, contractId: In(this.contractIds) }, - order: { ledgerSequence: "DESC" }, - }); - if (latest && latest.ledgerSequence) { - this.lastIndexedLedger = Number(latest.ledgerSequence); - return this.lastIndexedLedger; - } - } - - return 0; - } - - private async runPollCycle(): Promise { - const startLedger = (await this.getLastIndexedLedger()) + 1; - let cursor: string | undefined; - let allEventsProcessed = true; - - do { - const requestedCursor = cursor; - const events = await this.pollContractEvents({ startLedger, limit: 100, cursor }); - if (events.length > 0) { - const processedCount = await this.ingestEvents(events); - if (processedCount !== events.length) { - allEventsProcessed = false; - break; - } - } - cursor = this.nextCursor; - if (events.length < 100) break; - if (!cursor || cursor === requestedCursor) { - allEventsProcessed = false; - break; - } - } while (cursor); - - if (allEventsProcessed && this.latestLedgerSeen >= startLedger) { - await this.saveCheckpoint(this.latestLedgerSeen); - } - } - - /** - * Starts periodic polling in background. - */ - public start(intervalMs = 10000): void { - if (this.intervalHandle) return; - - this.logger.info("Starting Soroban event indexer service", { - contractIds: this.contractIds, - intervalMs, - }); - - this.intervalHandle = setInterval(async () => { - if (this.pollInFlight) return; - this.pollInFlight = true; - try { - await this.runPollCycle(); - } catch (err) { - this.logger.error("Error in Soroban event indexer poll cycle", { err }); - } finally { - this.pollInFlight = false; - } - }, intervalMs); - } - - /** - * Stops periodic polling. - */ - public stop(): void { - if (this.intervalHandle) { - clearInterval(this.intervalHandle); - this.intervalHandle = null; - this.logger.info("Stopped Soroban event indexer service"); + // Settlement state reconciliation for the invoice. } } }