From 550061c4dacb0c03d4015f1dfac079ca72e5679c Mon Sep 17 00:00:00 2001 From: Noloquideus Date: Thu, 14 May 2026 01:36:30 +0300 Subject: [PATCH] feat: update --- src/queue/messageSchema.ts | 17 ++++++++++------- src/services/TransferOrchestrator.ts | 20 +++++++++++++++----- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/queue/messageSchema.ts b/src/queue/messageSchema.ts index 8e14b90..7194ebf 100644 --- a/src/queue/messageSchema.ts +++ b/src/queue/messageSchema.ts @@ -10,27 +10,30 @@ export interface CryptoTransferCompleted { order_id: string; trace_id: string; message_id: string; + web3_transaction_hash: string; } const ULID_REGEX = /^[0-9A-HJKMNP-TV-Z]{26}$/; export function parseCryptoTransferRequest(raw: unknown): CryptoTransferRequest { - if (!raw || typeof raw !== "object" || Array.isArray(raw)) { - throw new Error("message body must be a JSON object"); + if (!raw || typeof raw !== 'object' || Array.isArray(raw)) { + throw new Error('message body must be a JSON object'); } const candidate = raw as Record; return { - order_id: requireUlid(candidate, "order_id"), - user_id: requireUlid(candidate, "user_id"), - trace_id: requireUlid(candidate, "trace_id"), - message_id: requireUlid(candidate, "message_id") + order_id: requireUlid(candidate, 'order_id'), + user_id: requireUlid(candidate, 'user_id'), + trace_id: requireUlid(candidate, 'trace_id'), + message_id: requireUlid(candidate, 'message_id') }; } + + function requireUlid(source: Record, key: string): string { const value = source[key]; - if (typeof value !== "string" || !ULID_REGEX.test(value)) { + if (typeof value !== 'string' || !ULID_REGEX.test(value)) { throw new Error(`field '${key}' must be a ULID string`); } return value; diff --git a/src/services/TransferOrchestrator.ts b/src/services/TransferOrchestrator.ts index 28b0094..6b77a78 100644 --- a/src/services/TransferOrchestrator.ts +++ b/src/services/TransferOrchestrator.ts @@ -149,7 +149,7 @@ export class TransferOrchestrator { await this.db.markPaymentDelivered(message.order_id, txHash); log.info({ event: 'transfer.delivered', tx_hash: txHash }, 'marked usdt_delivered'); - await this.publishCompleted(message, log); + await this.publishCompleted(message, log, txHash); }); } @@ -208,16 +208,21 @@ export class TransferOrchestrator { return false; } - private async publishCompleted(message: CryptoTransferRequest, log: Logger): Promise { + private async publishCompleted( + message: CryptoTransferRequest, + log: Logger, + web3TransactionHash: string + ): Promise { const completedMessageId = ulid(); await this.amqp.publishCompleted({ user_id: message.user_id, order_id: message.order_id, trace_id: message.trace_id, - message_id: completedMessageId + message_id: completedMessageId, + web3_transaction_hash: web3TransactionHash }); log.info( - { event: 'transfer.completed.published', message_id: completedMessageId }, + { event: 'transfer.completed.published', message_id: completedMessageId, tx_hash: web3TransactionHash }, 'published crypto.transfer.completed' ); } @@ -228,8 +233,13 @@ export class TransferOrchestrator { log: Logger ): Promise { if (existing.status === 'usdt_delivered') { + const txHash = existing.web3_transaction_hash; + if (!txHash) { + log.error({ event: 'payment.delivered_missing_hash' }, 'usdt_delivered but web3_transaction_hash is null'); + return; + } log.info({ event: 'payment.already_delivered' }, 'already delivered, publishing completion'); - await this.publishCompleted(message, log); + await this.publishCompleted(message, log, txHash); return; }