From 999d0389b38dc2c87076db56dc97a4b38528cdd8 Mon Sep 17 00:00:00 2001 From: hailin Date: Mon, 2 Feb 2026 23:13:59 -0800 Subject: [PATCH] =?UTF-8?q?refactor(trading):=20=E4=BB=B7=E6=A0=BC?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=BA=90=E4=BB=8E=20SharePool=20=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E5=88=B0=E5=81=9A=E5=B8=82=E5=95=86=20cashBalance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 积分股价格公式中的"绿积分"(分子)本质上就是做市商的积分值余额, SharePool 是多余的抽象层。此次改动将价格计算的数据源从独立的 SharePool 表切换到做市商的 TradingAccount.cashBalance。 主要变更: - price.service.ts: 通过 PrismaService 直接读取做市商 cashBalance 作为价格公式的分子(绿积分),移除 SharePoolRepository 依赖 - asset.service.ts: getMarketOverview() 同步切换数据源 - order.service.ts: 10%交易手续费从 sharePoolRepository.feeIn() 改为 increment 回做市商的 TradingAccount,手续费自然留存在池中 - burn.service.ts: 移除 SharePool 初始化逻辑和依赖 - infrastructure.module.ts: 移除 SharePoolRepository 注册和导出 - seed.ts: 移除 SharePool 57.6亿初始化 价格公式、10%手续费扣除、销毁机制均保持不变,仅切换数据源。 SharePool 表和 repository 文件保留在磁盘上供历史数据参考。 Co-Authored-By: Claude Opus 4.5 --- .../services/trading-service/prisma/seed.ts | 17 +-------- .../src/application/services/asset.service.ts | 31 ++++++++++++--- .../src/application/services/burn.service.ts | 13 +------ .../src/application/services/order.service.ts | 29 +++++++------- .../src/application/services/price.service.ts | 38 ++++++++++++++----- .../infrastructure/infrastructure.module.ts | 3 -- 6 files changed, 70 insertions(+), 61 deletions(-) diff --git a/backend/services/trading-service/prisma/seed.ts b/backend/services/trading-service/prisma/seed.ts index 5a2d1127..89238992 100644 --- a/backend/services/trading-service/prisma/seed.ts +++ b/backend/services/trading-service/prisma/seed.ts @@ -93,22 +93,7 @@ async function main() { console.log('Black hole account already exists'); } - // 4. 初始化积分股池(绿积分池) - // 初始绿积分为 57.6亿,使初始价格约为 0.576 (57.6亿 / 100.02亿 ≈ 0.576) - const INITIAL_GREEN_POINTS = '5760000000'; // 57.6亿 - const existingSharePool = await prisma.sharePool.findFirst(); - if (!existingSharePool) { - await prisma.sharePool.create({ - data: { - greenPoints: new Decimal(INITIAL_GREEN_POINTS), - totalInflow: new Decimal(INITIAL_GREEN_POINTS), - totalOutflow: new Decimal(0), - }, - }); - console.log(`Created share pool with initial green points: ${INITIAL_GREEN_POINTS} (57.6亿)`); - } else { - console.log('Share pool already exists'); - } + // 4. 绿积分(价格分子)现在由做市商的 cashBalance 提供,不再需要独立的 SharePool // 5. 初始化流通池 const existingCirculationPool = await prisma.circulationPool.findFirst(); diff --git a/backend/services/trading-service/src/application/services/asset.service.ts b/backend/services/trading-service/src/application/services/asset.service.ts index f2a7ac6d..5e2248ae 100644 --- a/backend/services/trading-service/src/application/services/asset.service.ts +++ b/backend/services/trading-service/src/application/services/asset.service.ts @@ -4,7 +4,7 @@ import { TradingCalculatorService } from '../../domain/services/trading-calculat import { TradingAccountRepository } from '../../infrastructure/persistence/repositories/trading-account.repository'; import { BlackHoleRepository } from '../../infrastructure/persistence/repositories/black-hole.repository'; import { CirculationPoolRepository } from '../../infrastructure/persistence/repositories/circulation-pool.repository'; -import { SharePoolRepository } from '../../infrastructure/persistence/repositories/share-pool.repository'; +import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service'; import { PriceService } from './price.service'; import { Money } from '../../domain/value-objects/money.vo'; import Decimal from 'decimal.js'; @@ -59,11 +59,14 @@ export class AssetService { private readonly calculator = new TradingCalculatorService(); private readonly miningServiceUrl: string; + // 缓存做市商 accountSequence + private mmAccountSequence: string | null = null; + constructor( private readonly tradingAccountRepository: TradingAccountRepository, private readonly blackHoleRepository: BlackHoleRepository, private readonly circulationPoolRepository: CirculationPoolRepository, - private readonly sharePoolRepository: SharePoolRepository, + private readonly prisma: PrismaService, private readonly priceService: PriceService, private readonly configService: ConfigService, ) { @@ -218,6 +221,24 @@ export class AssetService { }; } + /** + * 获取做市商积分值余额(即价格公式中的"绿积分") + */ + private async getGreenPoints(): Promise { + if (!this.mmAccountSequence) { + const config = await this.prisma.marketMakerConfig.findUnique({ + where: { name: 'MAIN_MARKET_MAKER' }, + }); + this.mmAccountSequence = config?.accountSequence || null; + } + if (!this.mmAccountSequence) return Money.zero(); + + const account = await this.prisma.tradingAccount.findUnique({ + where: { accountSequence: this.mmAccountSequence }, + }); + return account ? new Money(account.cashBalance) : Money.zero(); + } + /** * 获取市场概览 */ @@ -232,13 +253,11 @@ export class AssetService { burnTarget: string; burnProgress: string; }> { - const [sharePool, blackHole, circulationPool] = await Promise.all([ - this.sharePoolRepository.getPool(), + const [greenPoints, blackHole, circulationPool] = await Promise.all([ + this.getGreenPoints(), this.blackHoleRepository.getBlackHole(), this.circulationPoolRepository.getPool(), ]); - - const greenPoints = sharePool?.greenPoints || Money.zero(); const blackHoleAmount = blackHole?.totalBurned || Money.zero(); const circulationPoolAmount = circulationPool?.totalShares || Money.zero(); diff --git a/backend/services/trading-service/src/application/services/burn.service.ts b/backend/services/trading-service/src/application/services/burn.service.ts index 1eacd63d..8d228e9c 100644 --- a/backend/services/trading-service/src/application/services/burn.service.ts +++ b/backend/services/trading-service/src/application/services/burn.service.ts @@ -2,7 +2,6 @@ import { Injectable, Logger } from '@nestjs/common'; import { TradingCalculatorService } from '../../domain/services/trading-calculator.service'; import { BlackHoleRepository } from '../../infrastructure/persistence/repositories/black-hole.repository'; import { CirculationPoolRepository } from '../../infrastructure/persistence/repositories/circulation-pool.repository'; -import { SharePoolRepository } from '../../infrastructure/persistence/repositories/share-pool.repository'; import { TradingConfigRepository } from '../../infrastructure/persistence/repositories/trading-config.repository'; import { OutboxRepository } from '../../infrastructure/persistence/repositories/outbox.repository'; import { RedisService } from '../../infrastructure/redis/redis.service'; @@ -39,7 +38,6 @@ export class BurnService { constructor( private readonly blackHoleRepository: BlackHoleRepository, private readonly circulationPoolRepository: CirculationPoolRepository, - private readonly sharePoolRepository: SharePoolRepository, private readonly tradingConfigRepository: TradingConfigRepository, private readonly outboxRepository: OutboxRepository, private readonly redis: RedisService, @@ -243,11 +241,10 @@ export class BurnService { * 初始化交易系统(黑洞、配置、积分股池、流通池) */ async initialize(): Promise { - const [existingConfig, existingBlackHole, existingSharePool, existingCirculationPool] = + const [existingConfig, existingBlackHole, existingCirculationPool] = await Promise.all([ this.tradingConfigRepository.getConfig(), this.blackHoleRepository.getBlackHole(), - this.sharePoolRepository.getPool(), this.circulationPoolRepository.getPool(), ]); @@ -263,13 +260,7 @@ export class BurnService { this.logger.log('Black hole initialized'); } - // 初始化积分股池(绿积分池),初始值 57.6亿 - // 使初始价格约为 0.576 (57.6亿 / 100.02亿 ≈ 0.576) - if (!existingSharePool) { - const initialGreenPoints = new Money('5760000000'); // 57.6亿 - await this.sharePoolRepository.initializePool(initialGreenPoints); - this.logger.log(`Share pool initialized with ${initialGreenPoints.toFixed(8)} green points (57.6亿)`); - } + // 绿积分(价格分子)现在由做市商的 cashBalance 提供,不再需要独立的 SharePool // 初始化流通池 if (!existingCirculationPool) { diff --git a/backend/services/trading-service/src/application/services/order.service.ts b/backend/services/trading-service/src/application/services/order.service.ts index 2967f7d9..a3ee1a16 100644 --- a/backend/services/trading-service/src/application/services/order.service.ts +++ b/backend/services/trading-service/src/application/services/order.service.ts @@ -2,7 +2,6 @@ import { Injectable, Logger } from '@nestjs/common'; import { OrderRepository } from '../../infrastructure/persistence/repositories/order.repository'; import { TradingAccountRepository } from '../../infrastructure/persistence/repositories/trading-account.repository'; import { CirculationPoolRepository } from '../../infrastructure/persistence/repositories/circulation-pool.repository'; -import { SharePoolRepository } from '../../infrastructure/persistence/repositories/share-pool.repository'; import { OutboxRepository } from '../../infrastructure/persistence/repositories/outbox.repository'; import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service'; import { RedisService } from '../../infrastructure/redis/redis.service'; @@ -32,7 +31,6 @@ export class OrderService { private readonly orderRepository: OrderRepository, private readonly accountRepository: TradingAccountRepository, private readonly circulationPoolRepository: CirculationPoolRepository, - private readonly sharePoolRepository: SharePoolRepository, private readonly outboxRepository: OutboxRepository, private readonly prisma: PrismaService, private readonly redis: RedisService, @@ -338,21 +336,22 @@ export class OrderService { this.logger.warn(`Failed to add shares to circulation pool: ${error}`); } - // 10%手续费进入积分股池(非关键操作,可以在事务外执行) + // 10%手续费存入做市商账户(做市商的 cashBalance 即积分股池的绿积分) try { - await this.sharePoolRepository.feeIn( - tradeFee, - match.trade.tradeNo, - match.buyOrder.accountSequence, - match.sellOrder.accountSequence, - match.buyOrder.source, - match.sellOrder.source, - ); - this.logger.debug( - `Trade fee added to share pool: ${tradeFee.toFixed(8)}, tradeNo=${match.trade.tradeNo}`, - ); + const mmConfig = await this.prisma.marketMakerConfig.findUnique({ + where: { name: 'MAIN_MARKET_MAKER' }, + }); + if (mmConfig) { + await this.prisma.tradingAccount.update({ + where: { accountSequence: mmConfig.accountSequence }, + data: { cashBalance: { increment: tradeFee.value } }, + }); + this.logger.debug( + `Trade fee deposited to market maker: ${tradeFee.toFixed(8)}, tradeNo=${match.trade.tradeNo}`, + ); + } } catch (error) { - this.logger.error(`Failed to add trade fee to share pool: ${error}`); + this.logger.error(`Failed to deposit trade fee to market maker: ${error}`); } this.logger.log( diff --git a/backend/services/trading-service/src/application/services/price.service.ts b/backend/services/trading-service/src/application/services/price.service.ts index 2f8ab934..0c89c8c0 100644 --- a/backend/services/trading-service/src/application/services/price.service.ts +++ b/backend/services/trading-service/src/application/services/price.service.ts @@ -1,10 +1,10 @@ import { Injectable, Logger } from '@nestjs/common'; import { TradingCalculatorService } from '../../domain/services/trading-calculator.service'; import { BlackHoleRepository } from '../../infrastructure/persistence/repositories/black-hole.repository'; -import { SharePoolRepository } from '../../infrastructure/persistence/repositories/share-pool.repository'; import { CirculationPoolRepository } from '../../infrastructure/persistence/repositories/circulation-pool.repository'; import { PriceSnapshotRepository } from '../../infrastructure/persistence/repositories/price-snapshot.repository'; import { TradingConfigRepository } from '../../infrastructure/persistence/repositories/trading-config.repository'; +import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service'; import { Money } from '../../domain/value-objects/money.vo'; import Decimal from 'decimal.js'; @@ -26,27 +26,47 @@ export class PriceService { private readonly logger = new Logger(PriceService.name); private readonly calculator = new TradingCalculatorService(); + // 缓存做市商 accountSequence,避免每次查 MarketMakerConfig + private mmAccountSequence: string | null = null; + constructor( private readonly blackHoleRepository: BlackHoleRepository, - private readonly sharePoolRepository: SharePoolRepository, private readonly circulationPoolRepository: CirculationPoolRepository, private readonly priceSnapshotRepository: PriceSnapshotRepository, private readonly tradingConfigRepository: TradingConfigRepository, + private readonly prisma: PrismaService, ) {} + /** + * 获取做市商积分值余额(即价格公式中的"绿积分") + * 做市商的 cashBalance 就是积分股池的绿积分 + */ + private async getGreenPoints(): Promise { + if (!this.mmAccountSequence) { + const config = await this.prisma.marketMakerConfig.findUnique({ + where: { name: 'MAIN_MARKET_MAKER' }, + }); + this.mmAccountSequence = config?.accountSequence || null; + } + if (!this.mmAccountSequence) return Money.zero(); + + const account = await this.prisma.tradingAccount.findUnique({ + where: { accountSequence: this.mmAccountSequence }, + }); + return account ? new Money(account.cashBalance) : Money.zero(); + } + /** * 获取当前价格信息 */ async getCurrentPrice(): Promise { - const [sharePool, blackHole, circulationPool, config, firstSnapshot] = await Promise.all([ - this.sharePoolRepository.getPool(), + const [greenPoints, blackHole, circulationPool, config, firstSnapshot] = await Promise.all([ + this.getGreenPoints(), this.blackHoleRepository.getBlackHole(), this.circulationPoolRepository.getPool(), this.tradingConfigRepository.getConfig(), this.priceSnapshotRepository.getFirstSnapshot(), ]); - - const greenPoints = sharePool?.greenPoints || Money.zero(); const blackHoleAmount = blackHole?.totalBurned || Money.zero(); const circulationPoolAmount = circulationPool?.totalShares || Money.zero(); @@ -152,14 +172,12 @@ export class PriceService { */ async createSnapshot(): Promise { try { - const [sharePool, blackHole, circulationPool, config] = await Promise.all([ - this.sharePoolRepository.getPool(), + const [greenPoints, blackHole, circulationPool, config] = await Promise.all([ + this.getGreenPoints(), this.blackHoleRepository.getBlackHole(), this.circulationPoolRepository.getPool(), this.tradingConfigRepository.getConfig(), ]); - - const greenPoints = sharePool?.greenPoints || Money.zero(); const blackHoleAmount = blackHole?.totalBurned || Money.zero(); const circulationPoolAmount = circulationPool?.totalShares || Money.zero(); diff --git a/backend/services/trading-service/src/infrastructure/infrastructure.module.ts b/backend/services/trading-service/src/infrastructure/infrastructure.module.ts index 7cdc2aa2..a9e86f1f 100644 --- a/backend/services/trading-service/src/infrastructure/infrastructure.module.ts +++ b/backend/services/trading-service/src/infrastructure/infrastructure.module.ts @@ -8,7 +8,6 @@ import { OrderRepository } from './persistence/repositories/order.repository'; import { OutboxRepository } from './persistence/repositories/outbox.repository'; import { TradingConfigRepository } from './persistence/repositories/trading-config.repository'; import { BlackHoleRepository } from './persistence/repositories/black-hole.repository'; -import { SharePoolRepository } from './persistence/repositories/share-pool.repository'; import { CirculationPoolRepository } from './persistence/repositories/circulation-pool.repository'; import { PriceSnapshotRepository } from './persistence/repositories/price-snapshot.repository'; import { ProcessedEventRepository } from './persistence/repositories/processed-event.repository'; @@ -53,7 +52,6 @@ import { IdentityClient } from './identity/identity.client'; OutboxRepository, TradingConfigRepository, BlackHoleRepository, - SharePoolRepository, CirculationPoolRepository, PriceSnapshotRepository, ProcessedEventRepository, @@ -81,7 +79,6 @@ import { IdentityClient } from './identity/identity.client'; OutboxRepository, TradingConfigRepository, BlackHoleRepository, - SharePoolRepository, CirculationPoolRepository, PriceSnapshotRepository, ProcessedEventRepository,