diff --git a/backend/services/wallet-service/src/application/services/wallet-application.service.ts b/backend/services/wallet-service/src/application/services/wallet-application.service.ts index 7c66644f..5fb8f881 100644 --- a/backend/services/wallet-service/src/application/services/wallet-application.service.ts +++ b/backend/services/wallet-service/src/application/services/wallet-application.service.ts @@ -685,31 +685,63 @@ export class WalletApplicationService { ); } - /** - * 分配资金到系统账户 - * 通过记录流水,实际资金转移由 authorization-service 处理 - */ - private async allocateToSystemAccount( - allocation: FundAllocationItem, - orderId: string, - ): Promise { - // 记录系统账户分配流水(用于审计和对账) - // 系统账户不通过 wallet-service 管理余额,而是发送事件通知 authorization-service - this.logger.debug( - `System account allocation: ${allocation.amount} USDT to ${allocation.targetId} for ${allocation.allocationType}`, - ); - - // TODO: 发布 Kafka 事件通知 authorization-service 更新系统账户余额 - // await this.eventPublisher.publish('system-account.funds-allocated', { - // targetAccountType: allocation.targetId, - // amount: allocation.amount, - // allocationType: allocation.allocationType, - // sourceOrderId: orderId, - // hashpowerPercent: allocation.hashpowerPercent, - // metadata: allocation.metadata, - // }); - } - + + /** + * 分配资金到系统账户 + * 系统账户(S开头)已由 migration seed 创建,直接更新余额 + * + * 系统账户说明: + * - S0000000001: 总部社区 (user_id = -1) + * - S0000000002: 成本费账户 (user_id = -2) + * - S0000000003: 运营费账户 (user_id = -3) + * - S0000000004: RWA底池 (user_id = -4) + */ + private async allocateToSystemAccount( + allocation: FundAllocationItem, + orderId: string, + ): Promise { + this.logger.debug( + `System account allocation: ${allocation.amount} USDT to ${allocation.targetId} for ${allocation.allocationType}`, + ); + + const targetId = allocation.targetId; + if (!targetId.startsWith('S')) { + this.logger.warn(`Invalid system account format: ${targetId}`); + return; + } + + // 获取系统账户(已由 migration seed 创建) + const wallet = await this.walletRepo.findByAccountSequence(targetId); + if (!wallet) { + this.logger.error(`System account not found: ${targetId}`); + return; + } + + const amount = Money.USDT(allocation.amount); + + // 系统账户直接增加可用余额(不需要待领取/过期机制) + wallet.addAvailableBalance(amount); + await this.walletRepo.save(wallet); + + // 记录流水 + const ledgerEntry = LedgerEntry.create({ + accountSequence: wallet.accountSequence, + userId: wallet.userId, + entryType: LedgerEntryType.SYSTEM_ALLOCATION, + amount, + refOrderId: orderId, + memo: `${allocation.allocationType} - system account allocation`, + payloadJson: { + allocationType: allocation.allocationType, + metadata: allocation.metadata, + }, + }); + await this.ledgerRepo.save(ledgerEntry); + + this.logger.debug( + `Allocated ${allocation.amount} USDT to system account ${targetId} for ${allocation.allocationType}`, + ); + } // =============== Region Accounts =============== /** diff --git a/backend/services/wallet-service/src/domain/aggregates/wallet-account.aggregate.ts b/backend/services/wallet-service/src/domain/aggregates/wallet-account.aggregate.ts index 69d47170..cc43222d 100644 --- a/backend/services/wallet-service/src/domain/aggregates/wallet-account.aggregate.ts +++ b/backend/services/wallet-service/src/domain/aggregates/wallet-account.aggregate.ts @@ -186,6 +186,16 @@ export class WalletAccount { })); } + // 直接增加可用余额(用于系统账户分配) + addAvailableBalance(amount: Money): void { + this.ensureActive(); + + const balance = this.getBalance(amount.currency as AssetType); + const newBalance = balance.add(amount); + this.setBalance(amount.currency as AssetType, newBalance); + this._updatedAt = new Date(); + } + // 扣款 (如认种支付) deduct(amount: Money, reason: string, refOrderId?: string): void { this.ensureActive(); diff --git a/backend/services/wallet-service/src/domain/value-objects/ledger-entry-type.enum.ts b/backend/services/wallet-service/src/domain/value-objects/ledger-entry-type.enum.ts index 77aa0484..70443210 100644 --- a/backend/services/wallet-service/src/domain/value-objects/ledger-entry-type.enum.ts +++ b/backend/services/wallet-service/src/domain/value-objects/ledger-entry-type.enum.ts @@ -1,18 +1,19 @@ -export enum LedgerEntryType { - DEPOSIT_KAVA = 'DEPOSIT_KAVA', - DEPOSIT_BSC = 'DEPOSIT_BSC', - PLANT_PAYMENT = 'PLANT_PAYMENT', - PLANT_FREEZE = 'PLANT_FREEZE', // 认种冻结 - PLANT_UNFREEZE = 'PLANT_UNFREEZE', // 认种解冻(失败回滚) - REWARD_PENDING = 'REWARD_PENDING', - REWARD_TO_SETTLEABLE = 'REWARD_TO_SETTLEABLE', - REWARD_EXPIRED = 'REWARD_EXPIRED', - REWARD_SETTLED = 'REWARD_SETTLED', - TRANSFER_TO_POOL = 'TRANSFER_TO_POOL', - SWAP_EXECUTED = 'SWAP_EXECUTED', - WITHDRAWAL = 'WITHDRAWAL', - TRANSFER_IN = 'TRANSFER_IN', - TRANSFER_OUT = 'TRANSFER_OUT', - FREEZE = 'FREEZE', - UNFREEZE = 'UNFREEZE', -} +export enum LedgerEntryType { + DEPOSIT_KAVA = 'DEPOSIT_KAVA', + DEPOSIT_BSC = 'DEPOSIT_BSC', + PLANT_PAYMENT = 'PLANT_PAYMENT', + PLANT_FREEZE = 'PLANT_FREEZE', // 认种冻结 + PLANT_UNFREEZE = 'PLANT_UNFREEZE', // 认种解冻(失败回滚) + REWARD_PENDING = 'REWARD_PENDING', + REWARD_TO_SETTLEABLE = 'REWARD_TO_SETTLEABLE', + REWARD_EXPIRED = 'REWARD_EXPIRED', + REWARD_SETTLED = 'REWARD_SETTLED', + TRANSFER_TO_POOL = 'TRANSFER_TO_POOL', + SWAP_EXECUTED = 'SWAP_EXECUTED', + WITHDRAWAL = 'WITHDRAWAL', + TRANSFER_IN = 'TRANSFER_IN', + TRANSFER_OUT = 'TRANSFER_OUT', + FREEZE = 'FREEZE', + UNFREEZE = 'UNFREEZE', + SYSTEM_ALLOCATION = 'SYSTEM_ALLOCATION', // 系统账户分配 +} diff --git a/backend/services/wallet-service/src/domain/value-objects/user-id.vo.ts b/backend/services/wallet-service/src/domain/value-objects/user-id.vo.ts index 1d9477e4..943287f2 100644 --- a/backend/services/wallet-service/src/domain/value-objects/user-id.vo.ts +++ b/backend/services/wallet-service/src/domain/value-objects/user-id.vo.ts @@ -1,29 +1,31 @@ -import { DomainError } from '@/shared/exceptions/domain.exception'; - -export class UserId { - private readonly _value: bigint; - - private constructor(value: bigint) { - this._value = value; - } - - static create(value: bigint | number | string): UserId { - const bigintValue = typeof value === 'bigint' ? value : BigInt(value); - if (bigintValue < 0) { - throw new DomainError('UserId cannot be negative'); - } - return new UserId(bigintValue); - } - - get value(): bigint { - return this._value; - } - - equals(other: UserId): boolean { - return this._value === other._value; - } - - toString(): string { - return this._value.toString(); - } -} +import { DomainError } from '@/shared/exceptions/domain.exception'; + +export class UserId { + private readonly _value: bigint; + + private constructor(value: bigint) { + this._value = value; + } + + static create(value: bigint | number | string): UserId { + const bigintValue = typeof value === 'bigint' ? value : BigInt(value); + // 允许负数 userId,用于系统账户: + // -1: 总部社区 (S0000000001) + // -2: 成本费账户 (S0000000002) + // -3: 运营费账户 (S0000000003) + // -4: RWA底池 (S0000000004) + return new UserId(bigintValue); + } + + get value(): bigint { + return this._value; + } + + equals(other: UserId): boolean { + return this._value === other._value; + } + + toString(): string { + return this._value.toString(); + } +}