From c802519ec2861c721ccd2ee820ae968f544b7415 Mon Sep 17 00:00:00 2001 From: hailin Date: Sun, 1 Feb 2026 05:02:19 -0800 Subject: [PATCH] =?UTF-8?q?fix(c2c-bot):=20=E8=B0=83=E6=95=B4purchaseOrder?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E9=A1=BA=E5=BA=8F=EF=BC=8C=E5=85=88=E6=89=A3?= =?UTF-8?q?=E4=BD=99=E9=A2=9D=E5=86=8D=E9=93=BE=E4=B8=8A=E8=BD=AC=E8=B4=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题:原流程先执行不可逆的链上dUSDT转账,再扣减卖家DB余额。 若转账成功但扣减失败(余额不足、DB异常),会导致: - dUSDT已转出(链上不可回退) - 订单仍为PENDING(可能被重复处理) - 卖家余额未扣减 修复: 1. 将deductSellerBalance移至transferDusdt之前(可逆操作先行) 2. 链上转账失败时调用restoreSellerBalance回补余额 3. 新增restoreSellerBalance方法,失败时记录CRITICAL级别日志 修改后流程:扣余额(可逆) → 链上转账(不可逆) → 更新订单状态(DB) 任何步骤失败都不会导致资金损失。 Co-Authored-By: Claude Opus 4.5 --- .../application/services/c2c-bot.service.ts | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/backend/services/trading-service/src/application/services/c2c-bot.service.ts b/backend/services/trading-service/src/application/services/c2c-bot.service.ts index 6d9dc06a..3c77bd8d 100644 --- a/backend/services/trading-service/src/application/services/c2c-bot.service.ts +++ b/backend/services/trading-service/src/application/services/c2c-bot.service.ts @@ -47,15 +47,24 @@ export class C2cBotService { } this.logger.log(`[BOT] Seller Kava address: ${kavaAddress}`); - // 2. 计算 dUSDT 支付金额(积分值 = dUSDT,1:1 兑换) + // 2. 先扣减卖家积分值余额(可逆的DB操作,放在不可逆的链上转账之前) const paymentAmount = order.totalAmount; - this.logger.log(`[BOT] Payment amount: ${paymentAmount} dUSDT`); + await this.deductSellerBalance(order.makerAccountSequence, paymentAmount); + this.logger.log(`[BOT] Deducted seller balance, proceeding with on-chain transfer`); - // 3. 调用 mining-blockchain-service 转账 dUSDT - const transferResult = await this.blockchainClient.transferDusdt(kavaAddress, paymentAmount); + // 3. 调用 mining-blockchain-service 转账 dUSDT(不可逆) + let transferResult; + try { + transferResult = await this.blockchainClient.transferDusdt(kavaAddress, paymentAmount); + } catch (error: any) { + this.logger.error(`[BOT] Transfer exception: ${error.message}, restoring seller balance`); + await this.restoreSellerBalance(order.makerAccountSequence, paymentAmount); + return false; + } if (!transferResult.success) { - this.logger.error(`[BOT] Transfer failed: ${transferResult.error}`); + this.logger.error(`[BOT] Transfer failed: ${transferResult.error}, restoring seller balance`); + await this.restoreSellerBalance(order.makerAccountSequence, paymentAmount); return false; } @@ -67,9 +76,6 @@ export class C2cBotService { paymentTxHash: transferResult.txHash!, }); - // 5. 扣减卖家的积分值余额 - await this.deductSellerBalance(order.makerAccountSequence, order.totalAmount); - this.logger.log(`[BOT] Order ${order.orderNo} completed successfully`); return true; } catch (error: any) { @@ -96,7 +102,6 @@ export class C2cBotService { throw new Error(`Insufficient cash balance for ${accountSequence}`); } - // 扣减余额 await this.tradingAccountRepository.updateCashBalance( accountSequence, amountDecimal.negated().toString(), @@ -105,6 +110,22 @@ export class C2cBotService { this.logger.log(`[BOT] Deducted ${amount} from ${accountSequence}'s cash balance`); } + /** + * 回补卖家的积分值余额(链上转账失败时的补偿操作) + */ + private async restoreSellerBalance(accountSequence: string, amount: string): Promise { + try { + await this.tradingAccountRepository.updateCashBalance( + accountSequence, + amount, // 正数,加回余额 + ); + this.logger.log(`[BOT] Restored ${amount} to ${accountSequence}'s cash balance`); + } catch (error: any) { + // 回补失败是严重问题,必须告警 + this.logger.error(`[BOT] CRITICAL: Failed to restore ${amount} to ${accountSequence}: ${error.message}`); + } + } + /** * 检查 Bot 服务是否可用 */