chore(wallet-service): 移除已执行的OTP修复脚本
This commit is contained in:
parent
c2ff11bd6d
commit
dbeef0a80b
|
|
@ -20,8 +20,6 @@ import {
|
|||
import { RedisModule } from './redis';
|
||||
import { KafkaModule } from './kafka';
|
||||
import { IdentityModule } from './external/identity';
|
||||
// OTP: One-Time fix for D25122600004 -> D25122600006 transfer (remove after fix)
|
||||
import { TransferFixService } from './otp/transfer-fix.service';
|
||||
|
||||
const repositories = [
|
||||
{
|
||||
|
|
@ -54,7 +52,7 @@ const repositories = [
|
|||
@Global()
|
||||
@Module({
|
||||
imports: [RedisModule, KafkaModule, IdentityModule],
|
||||
providers: [PrismaService, ...repositories, TransferFixService], // OTP: remove TransferFixService after fix
|
||||
providers: [PrismaService, ...repositories],
|
||||
exports: [PrismaService, RedisModule, KafkaModule, IdentityModule, FeeConfigRepositoryImpl, ...repositories],
|
||||
})
|
||||
export class InfrastructureModule {}
|
||||
|
|
|
|||
|
|
@ -1,185 +0,0 @@
|
|||
/**
|
||||
* One-Time-Fix: 修复 D25122600004 -> D25122600006 的转账
|
||||
*
|
||||
* 问题:由于并发修改导致冻结余额少了 2 USDT (手续费)
|
||||
* 解决:修复冻结余额,完成转账,更新订单状态
|
||||
*
|
||||
* 幂等性:检查订单状态,已 CONFIRMED 则跳过
|
||||
* 部署后删除此文件和 infrastructure.module.ts 中的引用
|
||||
*/
|
||||
|
||||
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
||||
import { PrismaService } from '@/infrastructure/persistence/prisma/prisma.service';
|
||||
import { LedgerEntryType, WithdrawalStatus } from '@/domain/value-objects';
|
||||
import Decimal from 'decimal.js';
|
||||
|
||||
@Injectable()
|
||||
export class TransferFixService implements OnModuleInit {
|
||||
private readonly logger = new Logger(TransferFixService.name);
|
||||
|
||||
// 需要修复的订单号
|
||||
private readonly ORDER_NO = 'WD1766719397843H90GUW';
|
||||
private readonly SENDER_ACCOUNT = 'D25122600004';
|
||||
private readonly RECEIVER_ACCOUNT = 'D25122600006';
|
||||
private readonly MISSING_FEE = new Decimal('2'); // 缺失的手续费
|
||||
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
async onModuleInit() {
|
||||
// 延迟 5 秒执行,确保所有服务都已启动
|
||||
setTimeout(() => this.executeFixOnce(), 5000);
|
||||
}
|
||||
|
||||
private async executeFixOnce(): Promise<void> {
|
||||
this.logger.log('========================================');
|
||||
this.logger.log('[OTP-FIX] Starting one-time transfer fix');
|
||||
this.logger.log(`[OTP-FIX] Order: ${this.ORDER_NO}`);
|
||||
this.logger.log(`[OTP-FIX] From: ${this.SENDER_ACCOUNT} -> To: ${this.RECEIVER_ACCOUNT}`);
|
||||
this.logger.log('========================================');
|
||||
|
||||
try {
|
||||
// 检查订单状态
|
||||
const order = await this.prisma.withdrawalOrder.findUnique({
|
||||
where: { orderNo: this.ORDER_NO },
|
||||
});
|
||||
|
||||
if (!order) {
|
||||
this.logger.log('[OTP-FIX] Order not found, skipping (may be wrong environment)');
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果已经确认,说明已修复过(幂等性)
|
||||
if (order.status === WithdrawalStatus.CONFIRMED) {
|
||||
this.logger.log('[OTP-FIX] Order already CONFIRMED, skipping');
|
||||
return;
|
||||
}
|
||||
|
||||
if (order.status !== WithdrawalStatus.FROZEN) {
|
||||
this.logger.warn(`[OTP-FIX] Unexpected order status: ${order.status}, skipping`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 执行修复
|
||||
await this.prisma.$transaction(async (tx) => {
|
||||
// 1. 获取发送方钱包
|
||||
const senderWallet = await tx.walletAccount.findUnique({
|
||||
where: { accountSequence: this.SENDER_ACCOUNT },
|
||||
});
|
||||
|
||||
if (!senderWallet) {
|
||||
throw new Error(`Sender wallet not found: ${this.SENDER_ACCOUNT}`);
|
||||
}
|
||||
|
||||
// 2. 获取接收方钱包
|
||||
const receiverWallet = await tx.walletAccount.findUnique({
|
||||
where: { accountSequence: this.RECEIVER_ACCOUNT },
|
||||
});
|
||||
|
||||
if (!receiverWallet) {
|
||||
throw new Error(`Receiver wallet not found: ${this.RECEIVER_ACCOUNT}`);
|
||||
}
|
||||
|
||||
const amount = new Decimal(order.amount.toString());
|
||||
const fee = new Decimal(order.fee.toString());
|
||||
const totalAmount = amount.add(fee);
|
||||
|
||||
this.logger.log(`[OTP-FIX] Amount: ${amount}, Fee: ${fee}, Total: ${totalAmount}`);
|
||||
|
||||
// 3. 修复发送方冻结余额 (加上缺失的手续费) 并同时扣除
|
||||
const senderCurrentFrozen = new Decimal(senderWallet.usdtFrozen.toString());
|
||||
// 加上缺失的手续费后再扣除全部
|
||||
const senderNewFrozen = senderCurrentFrozen.add(this.MISSING_FEE).minus(totalAmount);
|
||||
|
||||
this.logger.log(`[OTP-FIX] Sender frozen: ${senderCurrentFrozen} + ${this.MISSING_FEE} - ${totalAmount} = ${senderNewFrozen}`);
|
||||
|
||||
await tx.walletAccount.update({
|
||||
where: { id: senderWallet.id },
|
||||
data: {
|
||||
usdtFrozen: senderNewFrozen,
|
||||
version: senderWallet.version + 1,
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
// 4. 增加接收方余额
|
||||
const receiverCurrentAvailable = new Decimal(receiverWallet.usdtAvailable.toString());
|
||||
const receiverNewAvailable = receiverCurrentAvailable.add(amount);
|
||||
|
||||
this.logger.log(`[OTP-FIX] Receiver available: ${receiverCurrentAvailable} + ${amount} = ${receiverNewAvailable}`);
|
||||
|
||||
await tx.walletAccount.update({
|
||||
where: { id: receiverWallet.id },
|
||||
data: {
|
||||
usdtAvailable: receiverNewAvailable,
|
||||
version: receiverWallet.version + 1,
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
// 5. 创建发送方流水 (TRANSFER_OUT)
|
||||
await tx.ledgerEntry.create({
|
||||
data: {
|
||||
accountSequence: order.accountSequence,
|
||||
userId: order.userId,
|
||||
entryType: LedgerEntryType.TRANSFER_OUT,
|
||||
amount: amount.negated(),
|
||||
assetType: 'USDT',
|
||||
balanceAfter: senderWallet.usdtAvailable,
|
||||
refOrderId: order.orderNo,
|
||||
refTxHash: 'OTP-FIX-INTERNAL',
|
||||
memo: `转账至 ${order.toAccountSequence} (OTP修复)`,
|
||||
payloadJson: {
|
||||
toAccountSequence: order.toAccountSequence,
|
||||
toUserId: order.toUserId?.toString(),
|
||||
fee: order.fee.toString(),
|
||||
fixNote: 'One-time fix for concurrent modification issue',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// 6. 创建接收方流水 (TRANSFER_IN)
|
||||
await tx.ledgerEntry.create({
|
||||
data: {
|
||||
accountSequence: order.toAccountSequence!,
|
||||
userId: order.toUserId!,
|
||||
entryType: LedgerEntryType.TRANSFER_IN,
|
||||
amount: amount,
|
||||
assetType: 'USDT',
|
||||
balanceAfter: receiverNewAvailable,
|
||||
refOrderId: order.orderNo,
|
||||
refTxHash: 'OTP-FIX-INTERNAL',
|
||||
memo: `来自 ${order.accountSequence} 的转账 (OTP修复)`,
|
||||
payloadJson: {
|
||||
fromAccountSequence: order.accountSequence,
|
||||
fromUserId: order.userId.toString(),
|
||||
fixNote: 'One-time fix for concurrent modification issue',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// 7. 更新订单状态为 CONFIRMED
|
||||
await tx.withdrawalOrder.update({
|
||||
where: { id: order.id },
|
||||
data: {
|
||||
status: WithdrawalStatus.CONFIRMED,
|
||||
txHash: 'OTP-FIX-INTERNAL',
|
||||
broadcastedAt: new Date(),
|
||||
confirmedAt: new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.log('[OTP-FIX] Transaction completed successfully');
|
||||
});
|
||||
|
||||
this.logger.log('========================================');
|
||||
this.logger.log('[OTP-FIX] Transfer fix completed!');
|
||||
this.logger.log(`[OTP-FIX] ${this.SENDER_ACCOUNT} -> ${this.RECEIVER_ACCOUNT}: ${this.prisma}`);
|
||||
this.logger.log('[OTP-FIX] Order status: CONFIRMED');
|
||||
this.logger.log('[OTP-FIX] Please remove this file after deployment');
|
||||
this.logger.log('========================================');
|
||||
|
||||
} catch (error) {
|
||||
this.logger.error('[OTP-FIX] Failed to execute fix', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue