# Genex 后端开发指南 > DDD + Clean Architecture + 微服务 | NestJS + Go + Kong + PostgreSQL --- ## 1. 技术栈总览 | 层级 | 技术 | 用途 | |------|------|------| | **API网关** | Kong | 限流、认证、路由、负载均衡 | | **主要业务服务** | NestJS (TypeScript) | 业务逻辑微服务 | | **高性能服务** | Go | 撮合引擎、链上事件监听、高频任务 | | **翻译层** | Go + Redis | 地址映射、Gas代付、术语翻译 | | **数据库** | PostgreSQL 15+ | 核心业务数据 | | **时序数据库** | TimescaleDB | 行情数据、监控指标 | | **缓存** | Redis Cluster | 热点数据、会话、订单簿缓存 | | **消息队列** | Kafka | 事件驱动、链上事件监听 | | **搜索** | Elasticsearch | 全文检索、日志分析 | | **AI/ML** | FastAPI (Python) | 信用评分、价格预测、异常检测 | --- ## 2. 架构设计:三层五域 ### 2.1 五大业务域 | 域 | 服务名 | 语言 | 职责 | |----|--------|------|------| | D1 发行域 | `issuer-service` | NestJS | 发行方入驻、券管理、发行审批 | | D2 交易域 | `trading-service` | Go | 撮合引擎、订单簿、做市商 | | D3 清算域 | `clearing-service` | NestJS + Go | 链上结算、兑付清算、退款 | | D4 合规域 | `compliance-service` | NestJS | KYC/AML、OFAC、Travel Rule | | D5 AI域 | `ai-service` | FastAPI | 信用评分、定价、异常检测 | | 通用 | `user-service` | NestJS | 用户注册、认证、Profile | | 通用 | `translate-service` | Go | UX翻译层(地址映射、Gas代付) | | 通用 | `notification-service` | NestJS | 消息推送、邮件、短信 | | 通用 | `chain-indexer` | Go | 链上事件监听、数据索引 | ### 2.2 服务间通信 ``` ┌──────────────────────────────────────────────┐ │ Kong API Gateway │ │ 限流 | OAuth 2.1 + JWT | 路由 | 负载均衡 │ ├──────────────────────────────────────────────┤ │ │ │ ┌─────────┐ ┌──────────┐ ┌────────────┐ │ │ │ user │ │ issuer │ │ trading │ │ │ │ service │ │ service │ │ service(Go)│ │ │ └────┬────┘ └────┬─────┘ └─────┬──────┘ │ │ │ │ │ │ │ └────────────┼──────────────┘ │ │ │ │ │ ┌─────┴─────┐ │ │ │ Kafka │ │ │ └─────┬─────┘ │ │ ┌────────────┼───────────────┐ │ │ ┌────┴────┐ ┌─────┴──────┐ ┌─────┴─────┐ │ │ │clearing │ │compliance │ │ai-service │ │ │ │service │ │service │ │(FastAPI) │ │ │ └─────────┘ └────────────┘ └───────────┘ │ └──────────────────────────────────────────────┘ ``` - **同步通信**:gRPC(服务间直接调用,如撮合→结算) - **异步通信**:Kafka事件驱动(链上事件、通知、审计日志) --- ## 3. DDD + Clean Architecture(NestJS服务) ### 3.1 模块结构(以issuer-service为例) ``` issuer-service/ ├── src/ │ ├── main.ts │ ├── app.module.ts │ ├── domain/ # 领域层(纯业务逻辑,零外部依赖) │ │ ├── entities/ │ │ │ ├── issuer.entity.ts # 发行方聚合根 │ │ │ ├── coupon-template.entity.ts │ │ │ └── credit-rating.vo.ts # 值对象 │ │ ├── repositories/ │ │ │ └── issuer.repository.ts # Repository接口 │ │ ├── services/ │ │ │ ├── issuer-domain.service.ts │ │ │ └── credit-scoring.service.ts │ │ └── events/ │ │ ├── issuer-approved.event.ts │ │ └── coupon-issued.event.ts │ ├── application/ # 应用层(用例编排) │ │ ├── commands/ │ │ │ ├── register-issuer.command.ts │ │ │ ├── create-coupon.command.ts │ │ │ └── handlers/ │ │ ├── queries/ │ │ │ ├── get-issuer.query.ts │ │ │ └── handlers/ │ │ └── dto/ │ │ ├── create-issuer.dto.ts │ │ └── create-coupon.dto.ts │ ├── infrastructure/ # 基础设施层(外部实现) │ │ ├── persistence/ │ │ │ ├── issuer.repository.impl.ts │ │ │ ├── issuer.orm-entity.ts │ │ │ └── typeorm.config.ts │ │ ├── messaging/ │ │ │ └── kafka-publisher.ts │ │ └── external/ │ │ └── chain-client.ts # 链上交互 │ └── interfaces/ # 接口层(HTTP/gRPC) │ ├── http/ │ │ ├── issuer.controller.ts │ │ └── coupon.controller.ts │ └── grpc/ │ └── issuer.grpc-controller.ts ├── test/ └── package.json ``` ### 3.2 领域实体 ```typescript // src/domain/entities/issuer.entity.ts export class Issuer { readonly id: string; readonly companyName: string; private _creditRating: CreditRating; private _issuanceQuota: number; private _tier: IssuerTier; private _status: IssuerStatus; // 信用评分四因子 updateCreditScore(metrics: CreditMetrics): void { const score = 0.35 * metrics.redemptionRate + 0.25 * (1 - metrics.breakageRatio) + 0.20 * Math.log(metrics.marketTenure + 1) / Math.log(37) + 0.20 * metrics.userSatisfaction; this._creditRating = CreditRating.fromScore(score); this._issuanceQuota = this._creditRating.calculateQuota(); } // 发券校验 canIssueCoupon(params: CreateCouponParams): Result { if (this._status !== IssuerStatus.ACTIVE) return Result.fail('发行方状态异常'); if (params.totalValue > this.remainingQuota) return Result.fail('超出发行额度'); if (params.expiryDays > 365) return Result.fail('Utility Track有效期不得超过12个月'); return Result.ok(); } } ``` ### 3.3 应用层Command ```typescript // src/application/commands/handlers/create-coupon.handler.ts @CommandHandler(CreateCouponCommand) export class CreateCouponHandler { constructor( private issuerRepo: IssuerRepository, private eventBus: EventBus, ) {} async execute(command: CreateCouponCommand): Promise { const issuer = await this.issuerRepo.findById(command.issuerId); if (!issuer) throw new NotFoundException('发行方不存在'); // 领域校验 const validation = issuer.canIssueCoupon(command.params); if (validation.isFailure) throw new BadRequestException(validation.error); // 创建券草稿(待审核) const draft = CouponDraft.create(issuer, command.params); await this.issuerRepo.saveCouponDraft(draft); // 发布领域事件 this.eventBus.publish(new CouponDraftCreatedEvent(draft)); return draft; } } ``` --- ## 4. Go 高性能服务 ### 4.1 撮合引擎 ```go // trading-service/internal/matching/engine.go type MatchingEngine struct { orderBooks map[string]*OrderBook // couponId → OrderBook mu sync.RWMutex } type OrderBook struct { Bids *redblacktree.Tree // 买单:价格降序 Asks *redblacktree.Tree // 卖单:价格升序 } func (e *MatchingEngine) SubmitOrder(order *Order) []*Trade { e.mu.Lock() defer e.mu.Unlock() book := e.getOrCreateBook(order.CouponID) // Utility Track价格校验 if order.CouponType == CouponTypeUtility && order.Price > order.FaceValue { return nil // 拒绝溢价单 } // 撮合:价格优先 → 时间优先 trades := book.Match(order) // 成交后发布事件到Kafka for _, trade := range trades { e.publisher.Publish("trade.matched", trade) } return trades } ``` ### 4.2 链上事件监听 ```go // chain-indexer/internal/indexer/indexer.go type ChainIndexer struct { ethClient *ethclient.Client kafka sarama.SyncProducer contracts map[string]common.Address } func (i *ChainIndexer) Start(ctx context.Context) { // 监听Genex Chain事件 query := ethereum.FilterQuery{ Addresses: []common.Address{ i.contracts["CouponFactory"], i.contracts["Settlement"], i.contracts["Redemption"], }, } logs := make(chan types.Log) sub, _ := i.ethClient.SubscribeFilterLogs(ctx, query, logs) for { select { case log := <-logs: event := i.parseEvent(log) i.kafka.SendMessage(&sarama.ProducerMessage{ Topic: "chain.events", Value: sarama.ByteEncoder(event.Marshal()), }) case err := <-sub.Err(): log.Error("subscription error", "err", err) // 重连逻辑 case <-ctx.Done(): return } } } ``` --- ## 5. UX翻译层 > 核心创新:将所有Web3操作翻译为Web2用户可理解的操作。 ```go // translate-service/internal/service/translate.go type TranslateService struct { mappingDB *redis.Client // 手机号→链上地址映射 mpcClient MPCClient // MPC钱包服务 paymaster PaymasterClient // Gas代付服务 } // 手机号→链上地址 func (s *TranslateService) ResolveAddress(phone string) (common.Address, error) { addr, err := s.mappingDB.Get(ctx, "phone:"+phone).Result() if err == redis.Nil { return common.Address{}, ErrUserNotFound } return common.HexToAddress(addr), nil } // 购买券:法币→链上原子交换 func (s *TranslateService) ExecutePurchase(req PurchaseRequest) (*PurchaseResult, error) { // 1. 法币支付确认 // 2. 法币→稳定币转换 // 3. 调用Settlement合约原子交换(Gas由Paymaster代付) // 4. 返回"订单号"(映射TX Hash) } ``` --- ## 6. API设计 ### 6.1 RESTful规范 ```yaml API规范: 风格: RESTful 版本控制: URL路径 /api/v1/ 认证: OAuth 2.1 + JWT 限流: 普通用户: 100 req/min 发行方: 1,000 req/min 做市商: 10,000 req/min 响应格式: JSON 错误处理: RFC 7807 Problem Details ``` ### 6.2 核心API端点 | 域 | 路径前缀 | 主要接口 | |-----|---------|---------| | 用户 | `/api/v1/users` | 注册、登录、KYC、资产查询 | | 券 | `/api/v1/coupons` | 发行、查询、转让、核销 | | 交易 | `/api/v1/trades` | 挂单、撤单、成交、历史 | | 支付 | `/api/v1/payments` | 充值、提现、法币转换 | | 发行方 | `/api/v1/issuers` | 入驻、审核、数据统计 | | 合规 | `/api/v1/compliance` | KYC、AML、审计日志 | | 翻译层 | `/api/v1/translate` | 地址映射、Gas代付 | --- ## 7. 数据库设计 ### 7.1 PostgreSQL核心表 ```sql -- 用户表 CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), phone VARCHAR(20) UNIQUE, email VARCHAR(100) UNIQUE, kyc_level SMALLINT NOT NULL DEFAULT 0, wallet_mode VARCHAR(10) NOT NULL DEFAULT 'standard', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 发行方表 CREATE TABLE issuers ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), company_name VARCHAR(200) NOT NULL, business_license VARCHAR(100), credit_rating VARCHAR(5) NOT NULL DEFAULT 'BBB', credit_score NUMERIC(5,2) NOT NULL DEFAULT 60.00, issuance_quota NUMERIC(15,2) NOT NULL DEFAULT 100000, tier VARCHAR(10) NOT NULL DEFAULT 'silver', status VARCHAR(20) NOT NULL DEFAULT 'pending', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 券表(链下缓存,权威数据在链上) CREATE TABLE coupons ( id UUID PRIMARY KEY, chain_token_id BIGINT UNIQUE, -- 链上Token ID issuer_id UUID REFERENCES issuers(id), face_value NUMERIC(12,2) NOT NULL, current_price NUMERIC(12,2), expiry_date DATE NOT NULL, coupon_type VARCHAR(10) NOT NULL DEFAULT 'utility', status VARCHAR(20) NOT NULL DEFAULT 'available', resale_count SMALLINT NOT NULL DEFAULT 0, max_resale_count SMALLINT NOT NULL DEFAULT 3, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 地址映射表(翻译层核心) CREATE TABLE address_mappings ( user_id UUID REFERENCES users(id), chain_address VARCHAR(42) NOT NULL UNIQUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (user_id) ); ``` --- ## 8. 安全规范 | 领域 | 规范 | |------|------| | 传输 | TLS 1.3 + 服务间mTLS | | 认证 | OAuth 2.1 + JWT(短有效期 + Refresh Token) | | 授权 | RBAC | | 数据加密 | AES-256(敏感字段),HSM管理密钥 | | API安全 | Rate Limiting + CORS + CSRF防护 | | SQL注入 | ORM参数化查询(TypeORM / sqlx) | | 审计 | 全链路操作日志,不可篡改 | --- ## 9. 部署架构 ```yaml # Kubernetes部署 apiVersion: apps/v1 kind: Deployment metadata: name: issuer-service spec: replicas: 3 template: spec: containers: - name: issuer-service image: genex/issuer-service:latest resources: requests: { cpu: "250m", memory: "512Mi" } limits: { cpu: "1000m", memory: "1Gi" } env: - name: DB_HOST valueFrom: configMapKeyRef: { name: db-config, key: host } - name: DB_PASSWORD valueFrom: secretKeyRef: { name: db-secrets, key: password } ``` ### 多区域部署 | 区域 | 部署 | 角色 | |------|------|------| | AWS美国(主) | 全量服务 + 主数据库 + Genex Chain主验证节点 | | AWS新加坡 | 亚太服务 + 灾备数据库 + 区域验证节点 | | 香港 | 监管节点 + 审计接口 | --- ## 10. 监控与可观测性 | 组件 | 工具 | 用途 | |------|------|------| | 指标 | Prometheus + Grafana | 服务指标、业务指标 | | 日志 | ELK Stack | 日志收集分析 | | 链路追踪 | Jaeger | 分布式调用追踪 | | 告警 | AlertManager + PagerDuty | 异常告警 | --- ## 11. 手续费与收入计算 ### 11.1 交易手续费(核心收入) ```typescript // src/domain/services/fee-calculation.service.ts export class FeeCalculationService { // Maker-Taker模型 private readonly FEE_RATES = { taker: { buy: 0.005, sell: 0.005 }, // Taker 0.5% maker: { buy: 0.001, sell: 0.001 }, // Maker 0.1%(做市商激励) }; // 发行方分层手续费率 private readonly ISSUER_FEE_RATES: Record = { silver: 0.015, // 白银 1.5% gold: 0.012, // 黄金 1.2% platinum: 0.010, // 铂金 1.0% diamond: 0.008, // 钻石 0.8% }; calculateTradeFee(trade: Trade): TradeFees { const isMaker = (side: 'buyer' | 'seller') => trade[side].isMaker; return { buyerFee: trade.price * (isMaker('buyer') ? this.FEE_RATES.maker.buy : this.FEE_RATES.taker.buy), sellerFee: trade.price * (isMaker('seller') ? this.FEE_RATES.maker.sell : this.FEE_RATES.taker.sell), }; } calculateIssuanceFee(issuer: Issuer, totalValue: number): number { // 新入驻首月享黄金层级 const tier = issuer.isFirstMonth ? 'gold' : issuer.tier; return totalValue * this.ISSUER_FEE_RATES[tier]; } } ``` ### 11.2 Breakage收益计算与分配 ```typescript // src/domain/services/breakage.service.ts export class BreakageService { /** * 券过期后Breakage计算: * 未使用的券面值 → 发行方Breakage收入 * 平台按比例分润(发行服务协议约定) */ async processExpiredCoupons(): Promise { const expired = await this.couponRepo.findExpiredUnprocessed(); for (const coupon of expired) { const breakageAmount = coupon.faceValue; const platformShare = breakageAmount * 0.10; // 平台分润10%(可配置) const issuerShare = breakageAmount - platformShare; await this.financeService.recordBreakage({ couponId: coupon.id, issuerId: coupon.issuerId, totalAmount: breakageAmount, platformShare, issuerShare, expiredAt: coupon.expiryDate, }); // 更新券状态 await this.couponRepo.markBreakageProcessed(coupon.id); // 更新发行方信用评分(Breakage率因子) this.eventBus.publish(new CouponExpiredEvent(coupon)); } } } // 定时任务:每日批量处理过期券 @Cron('0 2 * * *') // 每天凌晨2点 async handleExpiredCoupons() { await this.breakageService.processExpiredCoupons(); } ``` ### 11.3 退款机制 ```typescript // src/domain/services/refund.service.ts interface RefundPolicy { primaryMarket: { windowDays: number; // 发行方可配退款窗口(默认7天) fullRefund: boolean; // 一级市场全额退(含手续费) }; secondaryMarket: { requireArbitration: true; // 二级市场需仲裁 feeRefund: false; // 手续费不退 }; } export class RefundService { async processRefund(request: RefundRequest): Promise { // 已核销/已过期券不可退 if (['redeemed', 'expired'].includes(request.coupon.status)) { throw new BadRequestException('已核销或已过期券不可退款'); } // 一级市场退款:发行方退款窗口内 if (request.type === 'primary') { const withinWindow = this.isWithinRefundWindow(request); if (!withinWindow) throw new BadRequestException('超出退款期限'); // 调用Settlement合约反向原子交换 return this.chainClient.executeRefund(request); } // 二级市场退款:需仲裁裁决 if (request.type === 'secondary') { return this.disputeService.createRefundCase(request); } } } ``` --- ## 12. 做市商系统 ### 12.1 做市商准入与管理 ```typescript // src/domain/entities/market-maker.entity.ts export class MarketMaker { id: string; userId: string; kycLevel: KycLevel; // 必须KYC L3 depositAmount: number; // 最低保证金 status: 'active' | 'suspended' | 'terminated'; obligations: MarketMakerObligations; } interface MarketMakerObligations { minSpreadBps: number; // 最大价差(基点) minDepthPerSide: number; // 单边最小挂单深度 uptimePercent: number; // 最低在线时间 (95%) maxResponseMs: number; // 报价响应时间上限 } ``` ### 12.2 做市商专用API ```typescript // 低延迟专用接口(10,000 req/min) @Controller('api/v1/mm') export class MarketMakerController { @Post('batch-orders') async batchOrders(@Body() dto: BatchOrderDto) { // 批量挂单/撤单(单次最多100单) } @Get('orderbook/:couponId') async getOrderBook(@Param('couponId') id: string) { // 实时订单簿快照 } @Ws('mm/stream') async streamMarketData() { // WebSocket低延迟行情推送 } } ``` ### 12.3 Spoofing/Layering检测 ```typescript // 做市商行为监控 export class MarketManipulationDetector { /** * Spoofing检测:大量挂单后短时间内撤单 * Layering检测:多层挂单制造虚假深度 */ detect(orders: OrderActivity[]): ManipulationAlert[] { const alerts: ManipulationAlert[] = []; // 挂单→撤单比率异常(>80%撤单率) const cancelRate = orders.filter(o => o.cancelled).length / orders.length; if (cancelRate > 0.8) { alerts.push({ type: 'spoofing', severity: 'high', cancelRate }); } // 短时间多层挂单检测 const layeringPattern = this.detectLayeringPattern(orders); if (layeringPattern) alerts.push(layeringPattern); return alerts; } } ``` --- ## 13. 三因子定价引擎 ```typescript // src/domain/services/pricing.service.ts export class PricingService { /** * P = F × (1 - dt - rc - lp) * dt = Time Discount = f(剩余有效期) * rc = Credit Risk = f(发行方信用评分) * lp = Liquidity Premium = f(市场供需) */ calculateSuggestedPrice(coupon: Coupon, issuer: Issuer, market: MarketData): PriceSuggestion { const F = coupon.faceValue; const totalDays = differenceInDays(coupon.expiryDate, coupon.issuedDate); const remainDays = differenceInDays(coupon.expiryDate, new Date()); // 时间折扣 (0% - 15%) const dt = ((totalDays - remainDays) / totalDays) * 0.15; // 信用风险溢价 (0% - 20%) const CREDIT_MAP: Record = { AAA: 0, AA: 0.03, A: 0.06, BBB: 0.10, BB: 0.15, }; const rc = CREDIT_MAP[issuer.creditRating] || 0.20; // 流动性溢价 (-5% - 10%) const supplyDemandRatio = (market.sellOrders - market.buyOrders) / (market.totalOrders || 1); const lp = Math.max(-0.05, Math.min(0.10, supplyDemandRatio * 0.1)); const price = F * (1 - dt - rc - lp); // Utility Track: 价格上限 = 面值 const cappedPrice = coupon.type === 'utility' ? Math.min(price, F) : price; return { suggestedPrice: cappedPrice, factors: { dt, rc, lp } }; } } ``` --- ## 14. AI/ML 模型服务 ### 14.1 信用评分引擎 ```python # ai-service/models/credit_scoring.py import lightgbm as lgb from sklearn.model_selection import cross_val_score class CreditScoringModel: """ 发行方信用评分:四因子基础 + ML增强 特征:核销率、Breakage率、市场存续月数、用户满意度、历史违约、行业 """ def __init__(self): self.model = lgb.LGBMRegressor( n_estimators=500, learning_rate=0.05, max_depth=6, num_leaves=31, ) def predict_credit_score(self, issuer_features: dict) -> float: # 四因子基础分 base = (0.35 * issuer_features['redemption_rate'] + 0.25 * (1 - issuer_features['breakage_ratio']) + 0.20 * math.log(issuer_features['tenure_months'] + 1) / math.log(37) + 0.20 * issuer_features['user_satisfaction']) # ML调整(基于更多特征) ml_adjustment = self.model.predict([self._extract_features(issuer_features)])[0] return min(100, max(0, base * 100 * 0.7 + ml_adjustment * 0.3)) ``` ### 14.2 价格预测模型 ```python # ai-service/models/price_prediction.py from prophet import Prophet import torch.nn as nn class LSTMPricePredictor(nn.Module): """LSTM序列预测:历史价格→未来价格走势""" def __init__(self, input_size=5, hidden_size=64, num_layers=2): super().__init__() self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True) self.fc = nn.Linear(hidden_size, 1) def forward(self, x): out, _ = self.lstm(x) return self.fc(out[:, -1, :]) class ProphetSeasonalPredictor: """Prophet周期性预测:节假日/季节性价格模式""" def predict(self, history: pd.DataFrame, periods: int = 30): model = Prophet(yearly_seasonality=True, weekly_seasonality=True) model.fit(history) future = model.make_future_dataframe(periods=periods) return model.predict(future) ``` ### 14.3 异常检测系统 ```python # ai-service/models/anomaly_detection.py from sklearn.ensemble import IsolationForest class TransactionAnomalyDetector: """ 异常交易检测:Isolation Forest + 规则引擎 实时消费Kafka trade.events,标记可疑交易 """ def __init__(self): self.isolation_forest = IsolationForest( contamination=0.01, n_estimators=200, random_state=42 ) def detect(self, transaction: dict) -> AnomalyResult: features = self._extract_features(transaction) # ML检测 score = self.isolation_forest.decision_function([features])[0] # 规则引擎检测 rule_alerts = self._apply_rules(transaction) return AnomalyResult( ml_score=score, is_anomaly=score < -0.5 or len(rule_alerts) > 0, alerts=rule_alerts, ) def _apply_rules(self, tx: dict) -> list: alerts = [] if tx['amount'] > 10000: alerts.append('large_amount') if tx['frequency_1h'] > 20: alerts.append('high_frequency') if tx['geolocation_change']: alerts.append('geo_anomaly') return alerts ``` ### 14.4 智能推荐引擎(P2优先级) ```python # 协同过滤 + 内容推荐 混合推荐 class CouponRecommender: def recommend(self, user_id: str, top_k: int = 10): # 协同过滤:相似用户购买历史 cf_scores = self.collaborative_filter(user_id) # 内容推荐:基于券属性(品牌、类别、折扣率) content_scores = self.content_based(user_id) # 混合加权 return self.blend(cf_scores, content_scores, top_k) ``` --- ## 15. AML反洗钱系统 ### 15.1 AML检测规则引擎 ```typescript // compliance-service/src/domain/services/aml-detection.service.ts export class AmlDetectionService { // 已识别洗钱路径检测 private readonly RULES: AmlRule[] = [ // 1. 买券洗钱:脏钱买券→P2P转给另一账户→卖出提现 { name: 'buy_transfer_withdraw', detect: this.detectBuyTransferWithdraw }, // 2. 分散洗钱:一个账户→P2P分散转给大量小账户 { name: 'fan_out', detect: this.detectFanOut }, // 3. 发行方自洗:关联账户自买自卖 { name: 'self_dealing', detect: this.detectSelfDealing }, // 4. 跨境洗钱:A国买→P2P转B国→B国提现 { name: 'cross_border', detect: this.detectCrossBorder }, // 5. Structuring:拆分交易规避阈值 { name: 'structuring', detect: this.detectStructuring }, ]; async detectFanOut(userId: string, window: TimeWindow): Promise { const transfers = await this.getP2PTransfers(userId, window); const uniqueRecipients = new Set(transfers.map(t => t.recipientId)); // 24h内向>10个不同账户P2P转移 if (uniqueRecipients.size > 10) { return { type: 'fan_out', severity: 'high', details: { recipients: uniqueRecipients.size } }; } return null; } async detectStructuring(userId: string, window: TimeWindow): Promise { const txs = await this.getTransactions(userId, window); // 检测是否有多笔接近$3,000阈值的交易($2,500-$2,999) const nearThreshold = txs.filter(t => t.amount >= 2500 && t.amount < 3000); if (nearThreshold.length >= 3) { return { type: 'structuring', severity: 'critical', details: { count: nearThreshold.length } }; } return null; } } ``` ### 15.2 交易图谱分析 ```typescript // 构建用户间交易关系图谱 export class TransactionGraphService { async buildGraph(timeWindow: TimeWindow): Promise { const edges = await this.tradeRepo.getTransferEdges(timeWindow); const graph = new Graph(); for (const edge of edges) { graph.addEdge(edge.sender, edge.receiver, { amount: edge.amount, timestamp: edge.timestamp, }); } // 检测环形转移 const cycles = graph.detectCycles(); // 检测扇入/扇出模式 const fanPatterns = graph.detectFanPatterns(threshold: 10); // 关联账户聚类 const clusters = graph.communityDetection(); return { graph, cycles, fanPatterns, clusters }; } } ``` ### 15.3 SAR自动生成 ```typescript // 可疑交易报告(Suspicious Activity Report) export class SarService { async generateSar(alert: AmlAlert): Promise { return { filingType: 'initial', subjectInfo: await this.getUserInfo(alert.userId), suspiciousActivity: { dateRange: alert.timeWindow, amount: alert.totalAmount, instruments: 'Digital Coupon Assets', description: this.generateNarrative(alert), }, // FinCEN BSA E-Filing格式 }; } } ``` --- ## 16. OFAC合规服务 ```typescript // compliance-service/src/infrastructure/external/ofac.service.ts export class OfacService { private sdnList: Map = new Map(); // 名单同步(24h内更新) @Cron('0 */6 * * *') // 每6小时同步 async syncSdnList(): Promise { // 主选:Chainalysis,备选:Elliptic/TRM Labs const entries = await this.chainalysis.getLatestSdnList(); this.sdnList = new Map(entries.map(e => [e.id, e])); this.logger.log(`OFAC SDN list synced: ${entries.length} entries`); } // 注册时筛查 async screenOnRegistration(user: UserRegistrationDto): Promise { return this.screenPerson({ name: user.fullName, nationality: user.nationality, address: user.address, dateOfBirth: user.dob, }); } // 每笔交易实时筛查 async screenTransaction(buyer: string, seller: string): Promise { const buyerResult = await this.screenAddress(buyer); const sellerResult = await this.screenAddress(seller); if (buyerResult.isMatch || sellerResult.isMatch) { // 命中:立即冻结 + 上报 await this.freezeAndReport(buyerResult, sellerResult); } return { buyerResult, sellerResult }; } // P2P转移链上地址筛查 async screenChainAddress(address: string): Promise { return this.chainalysis.checkAddress(address); } } ``` --- ## 17. Travel Rule合规(TRISA/TRP) ```typescript // compliance-service/src/domain/services/travel-rule.service.ts export class TravelRuleService { /** * FATF Travel Rule: ≥$3,000转移需传递身份信息 * 接入TRISA协议实现跨平台信息传递 */ async processP2PTransfer(transfer: P2PTransferRequest): Promise { if (transfer.amount >= 3000) { // 验证双方KYC≥L2 await this.verifyKycLevel(transfer.senderId, KycLevel.L2); await this.verifyKycLevel(transfer.receiverId, KycLevel.L2); // 身份信息哈希写入链上 const senderHash = this.hashIdentity(await this.getKycInfo(transfer.senderId)); const receiverHash = this.hashIdentity(await this.getKycInfo(transfer.receiverId)); await this.chainClient.recordTravelRule( transfer.senderAddress, transfer.receiverAddress, senderHash, receiverHash, ); // TRISA跨平台传递(如接收方在其他平台) if (transfer.isExternalReceiver) { await this.trisaClient.sendTravelRuleInfo({ originator: await this.getOriginatorInfo(transfer.senderId), beneficiary: await this.getBeneficiaryInfo(transfer.receiverId), }); } } } } ``` --- ## 18. 税务合规 ```typescript // compliance-service/src/domain/services/tax.service.ts export class TaxComplianceService { // IRS Form 1099-DA / 1099-B 生成 async generate1099(userId: string, taxYear: number): Promise { const trades = await this.tradeRepo.getUserTrades(userId, taxYear); const proceeds = trades.reduce((sum, t) => sum + t.sellPrice, 0); const costBasis = trades.reduce((sum, t) => sum + t.buyPrice, 0); return { form: proceeds > 600 ? '1099-DA' : null, // >$600 threshold recipientTIN: await this.getUserTIN(userId), grossProceeds: proceeds, costBasis, gainOrLoss: proceeds - costBasis, transactions: trades.map(t => this.formatTaxTransaction(t)), }; } // FATCA跨境税务(外国账户持有人) async checkFatcaObligation(userId: string): Promise { const user = await this.userRepo.findById(userId); return user.nationality !== 'US' && user.hasUsSourceIncome; } // 发行方Breakage收入税务处理 async generateIssuerTaxReport(issuerId: string, taxYear: number): Promise { const breakageIncome = await this.financeRepo.getBreakageIncome(issuerId, taxYear); const salesRevenue = await this.financeRepo.getSalesRevenue(issuerId, taxYear); return { breakageIncome, salesRevenue, totalTaxableIncome: breakageIncome + salesRevenue }; } } ``` --- ## 19. 数据隐私合规(CCPA/GDPR) ```typescript // user-service/src/domain/services/privacy.service.ts export class PrivacyService { /** * 用户数据删除流程: * 链上仅地址和哈希(不可删除,但不构成PII) * 链下PII全部可删除 * * 例外:AML/BSA法规要求交易记录保留≥5年 */ async processDeleteRequest(userId: string): Promise { // 检查数据保留义务 const retentionCheck = await this.checkRetentionObligation(userId); if (retentionCheck.hasActiveObligation) { return { status: 'deferred', reason: 'AML/BSA 5年保留期未满', deferUntil: retentionCheck.expiresAt }; } // 1. 删除链下所有PII await this.userRepo.deletePersonalData(userId); // 姓名、手机号、邮箱、身份证 await this.kycRepo.deleteKycMaterials(userId); // KYC资料(人脸、证件照) // 2. 删除映射表记录 await this.mappingRepo.deleteMapping(userId); // 手机号→地址映射 // 3. 链上地址变为匿名(不可逆删除映射后地址无法关联到人) // 4. Travel Rule链下明文删除,链上仅哈希(不可逆) return { status: 'completed', deletedAt: new Date() }; } } ``` --- ## 20. 数据留存与审计 ```typescript // 数据保留策略 const DATA_RETENTION_POLICIES = { transactionRecords: { minYears: 5, source: 'BSA/AML' }, kycDocuments: { minYears: 5, source: 'BSA/CDD' }, sarReports: { minYears: 5, source: 'FinCEN' }, auditLogs: { minYears: 7, source: 'SOX' }, chainData: { minYears: Infinity, source: 'blockchain' }, }; // 审计日志(append-only,不可篡改) export class AuditLogService { async log(entry: AuditEntry): Promise { await this.appendOnlyStore.write({ timestamp: new Date(), actor: entry.actorId, action: entry.action, resource: entry.resource, details: entry.details, ipAddress: entry.ip, hash: this.computeChainHash(entry), // 链式哈希防篡改 }); } } ``` --- ## 21. 券生命周期管理 ```typescript // 券状态流转 enum CouponStatus { MINTED = 'minted', // 已铸造(链上) LISTED = 'listed', // 已上架 SOLD = 'sold', // 已售出 IN_CIRCULATION = 'in_circulation', // 流通中(二级市场) REDEEMED = 'redeemed', // 已兑付 EXPIRED = 'expired', // 已过期 RECALLED = 'recalled', // 已召回 } // 过期自动处理 @Cron('0 0 * * *') // 每日凌晨 async processExpiredCoupons(): Promise { const expiring = await this.couponRepo.findExpiringToday(); for (const coupon of expiring) { await this.couponRepo.updateStatus(coupon.id, CouponStatus.EXPIRED); // Breakage收益计算 await this.breakageService.calculateAndDistribute(coupon); // 通知持有人 await this.notificationService.send(coupon.holderId, { type: 'coupon_expired', couponName: coupon.name, }); } } ``` --- ## 22. 争议与纠纷处理 ```typescript // 争议处理流程 interface DisputeCase { id: string; type: 'buyer_complaint' | 'seller_complaint' | 'refund_request'; status: 'submitted' | 'evidence_collection' | 'arbitration' | 'resolved' | 'escalated'; buyerId: string; sellerId: string; orderId: string; chainEvidence: ChainEvidence[]; // 链上不可篡改证据 slaDeadline: Date; // 24h响应,72h处理 } export class DisputeService { async createDispute(dto: CreateDisputeDto): Promise { const chainEvidence = await this.chainClient.getTransactionProof(dto.orderId); const dispute = DisputeCase.create({ ...dto, chainEvidence }); // SLA:24h内响应 await this.slaService.scheduleReminder(dispute.id, '24h'); return dispute; } async arbitrate(disputeId: string, decision: ArbitrationDecision): Promise { if (decision.refundApproved) { await this.refundService.processRefund(decision.refundDetails); } } } ``` --- ## 23. 客服系统 ```typescript // 工单系统 interface Ticket { id: string; userId: string; category: 'transaction' | 'account' | 'coupon' | 'compliance' | 'other'; priority: 'low' | 'medium' | 'high' | 'urgent'; status: 'open' | 'in_progress' | 'waiting_user' | 'resolved' | 'closed'; sla: { responseTime: '24h', resolutionTime: '72h' }; } // 发行方专属客服通道(铂金/钻石层级) export class IssuerSupportService { getDedicatedChannel(issuer: Issuer): SupportChannel { if (['platinum', 'diamond'].includes(issuer.tier)) { return { type: 'dedicated', responseTime: '1h', manager: this.getAccountManager(issuer.id) }; } return { type: 'standard', responseTime: '24h' }; } } ``` --- ## 24. 安全事件响应计划 ### 24.1 事件分级 | 级别 | 定义 | 响应时限 | 示例 | |------|------|---------|------| | **P0** | 资产被盗/合约漏洞被利用 | 15分钟内启动 | MPC密钥泄露、合约攻击 | | **P1** | 数据泄露/系统被入侵 | 1小时内响应 | 用户数据泄露、映射表篡改 | | **P2** | 局部服务异常/可疑活动 | 4小时内响应 | API攻击、异常登录 | | **P3** | 潜在风险/安全隐患 | 24小时内评估 | 依赖库漏洞 | ### 24.2 P0应急流程 ```typescript // 自动化应急响应 export class IncidentResponseService { async handleP0Incident(incident: SecurityIncident): Promise { // 1. 自动触发紧急冻结(Governance合约) await this.chainClient.triggerEmergencyFreeze(incident.affectedAddresses); // 2. 通知安全团队(PagerDuty) await this.pagerDuty.trigger({ severity: 'critical', description: incident.description, }); // 3. 保全证据 await this.forensics.preserveEvidence({ logs: await this.collectLogs(incident.timeRange), chainState: await this.chainClient.getStateSnapshot(), systemSnapshot: await this.infrastructure.getSnapshot(), }); // 4. 用户通知(≤24h,CCPA要求72h内通知受影响用户) await this.notificationService.scheduleBreachNotification(incident); } } ``` ### 24.3 Bug Bounty | 严重程度 | 奖励范围 | 示例 | |---------|---------|------| | Critical | $50K-$100K | 合约资金盗取、MPC密钥泄露 | | High | $10K-$50K | 权限绕过、数据泄露 | | Medium | $2K-$10K | 信息泄露、DoS | | Low | $500-$2K | 低影响漏洞 | --- ## 25. 灾难恢复与业务连续性 ### 25.1 DR指标 | 指标 | 目标 | |------|------| | RPO(恢复点目标) | < 1分钟 | | RTO(恢复时间目标) | < 15分钟 | ### 25.2 备份与故障转移 ```yaml # 数据库备份策略 postgresql: replication: streaming_replication # 实时同步至备用区域 backup: full: weekly # 每周全量备份 incremental: every_15_minutes # 每15分钟增量备份 retention: 90_days # 备份保留90天 failover: automatic: true # 自动故障转移 health_check_interval: 5s # 链下数据快照 orderbook: snapshot: every_5_minutes # 订单簿快照 wal: continuous # 预写日志持续记录 # 链上数据:区块链本身分布式存储,天然灾备 genex_chain: validators: 3 # ≥3自有验证节点,不同地理位置 third_party_rpc: [alchemy, quicknode] # 备用RPC节点 ``` ### 25.3 业务连续性 | 故障场景 | 应对策略 | |---------|---------| | 交易系统故障 | 自动切换备用撮合引擎,未完成订单状态保护 | | 链节点故障 | 多节点冗余(≥3个自有 + 第三方RPC备用) | | 法币通道故障 | ≥2家支付服务商,自动热备切换 | | MPC密钥服务故障 | 密钥分片跨地理位置存储,Fireblocks/Fordefi热备 | | 年度DR演练 | 每年≥1次全量灾难恢复演练并记录 | --- ## 26. 映射表安全方案 > 手机号→地址映射表是最高价值安全资产,被篡改将导致资产错误转移。 ```typescript // translate-service/src/security/mapping-security.service.ts export class MappingSecurityService { /** * 映射记录创建/修改需多方签名: * 平台服务器 + HSM + 第三方审计节点 */ async createMapping(userId: string, chainAddress: string): Promise { // 1. MPC多方签名 const signature = await this.mpcSigner.multiSign({ parties: ['platform_server', 'hsm_module', 'audit_node'], threshold: 2, // 至少2方签名 data: { userId, chainAddress }, }); // 2. 写入加密数据库(AES-256,HSM管理密钥) await this.encryptedStore.write(userId, chainAddress, signature); // 3. 记录到append-only审计日志 await this.auditLog.append({ action: 'mapping_created', userId, chainAddress, signature, }); } // 定期链上锚定(Merkle Root) @Cron('0 * * * *') // 每小时 async anchorToChain(): Promise { const merkleRoot = await this.computeMappingMerkleRoot(); await this.chainClient.anchorMerkleRoot(merkleRoot); } // 完整性校验 async verifyIntegrity(): Promise { const currentRoot = await this.computeMappingMerkleRoot(); const chainRoot = await this.chainClient.getLatestMerkleRoot(); return currentRoot === chainRoot; } } ``` --- ## 27. 发行方违约处理 ```typescript // issuer-service/src/domain/services/default-handling.service.ts export class IssuerDefaultService { async handleDefault(issuerId: string, severity: 'minor' | 'major' | 'critical'): Promise { switch (severity) { case 'minor': // 降级 + 额度缩减 await this.issuerRepo.downgradeCreditRating(issuerId, 1); break; case 'major': // 冻结发行 + 启用保障资金 await this.issuerRepo.freezeIssuance(issuerId); if (await this.hasGuaranteeFund(issuerId)) { await this.activateGuaranteeFund(issuerId); } break; case 'critical': // 跑路:冻结账户 + 链上标记风险券 + 通知持有人 await this.issuerRepo.freezeAccount(issuerId); await this.chainClient.markRiskCoupons(issuerId); await this.notifyAllHolders(issuerId, '发行方异常,请关注券状态'); break; } } } ``` --- ## 28. 多币种与法币通道 ```typescript // 多稳定币支持 interface StablecoinConfig { primary: 'USDC'; secondary: 'USDT'; oracle: 'chainlink'; // 汇率预言机 } // 法币通道热备 export class FiatGatewayService { private providers: FiatProvider[] = [ { name: 'primary_bank', priority: 1, status: 'active' }, { name: 'backup_processor', priority: 2, status: 'standby' }, ]; async processPayment(request: PaymentRequest): Promise { for (const provider of this.providers.sort((a, b) => a.priority - b.priority)) { try { if (provider.status === 'active' || provider.status === 'standby') { return await provider.process(request); } } catch (error) { this.logger.error(`Fiat provider ${provider.name} failed, trying next`); provider.status = 'failed'; continue; // 自动切换 } } throw new ServiceUnavailableException('All fiat providers unavailable'); } } // 汇率管理 export class ExchangeRateService { async getRate(from: string, to: string): Promise { // Oracle获取实时汇率 const rate = await this.oracleClient.getRate(from, to); return { rate: rate.value, lockedUntil: addMinutes(new Date(), 15) }; // 锁定15分钟 } } ``` --- ## 29. 链上对账 ```typescript // 链上数据 vs 链下账本对账 export class ReconciliationService { // 实时对账(链上数据即账本) async reconcile(): Promise { const chainBalances = await this.chainClient.getAllBalances(); const dbBalances = await this.financeRepo.getAllBalances(); const discrepancies: Discrepancy[] = []; for (const [userId, chainBal] of chainBalances) { const dbBal = dbBalances.get(userId); if (Math.abs(chainBal - dbBal) > 0.01) { discrepancies.push({ userId, chainBalance: chainBal, dbBalance: dbBal }); } } if (discrepancies.length > 0) { await this.alertService.sendAlert('reconciliation_mismatch', discrepancies); } return { totalChecked: chainBalances.size, discrepancies }; } } ``` --- ## 30. 容量规划 | 阶段 | 用户规模 | 日交易量 | 基础设施 | |------|---------|---------|---------| | Phase 1 (基础平台) | 10万 | 50万笔 | 单区域K8s(3节点) | | Phase 2 (商业化) | 100万 | 500万笔 | 双区域K8s + 热备(5+节点) | | Phase 3 (金融化) | 1,000万 | 5,000万笔 | 多区域集群 + GCFN节点 | ### 关键性能指标 | 指标 | 目标 | |------|------| | API响应时间(P99) | < 200ms | | 撮合引擎延迟 | < 10ms | | 翻译层额外耗时 | < 50ms | | 系统可用性 | > 99.9% SLA | --- ## 31. SDK开发计划 | SDK | 语言/平台 | 功能范围 | 优先级 | |-----|----------|---------|--------| | genex-js | JavaScript/Node.js | 全功能(发行、交易、核销、数据查询) | P0 | | genex-java | Java/Android | 全功能 + Android原生集成 | P0 | | genex-python | Python | 数据分析、信用查询、批量操作 | P1 | | genex-swift | Swift/iOS | 移动端核销、用户端功能 | P1 | | genex-go | Go | 高性能服务端集成、做市商接入 | P2 | ### 开发者门户 - 沙箱环境(Testnet API + 测试券 + 测试USDC) - API文档(OpenAPI 3.0 + Swagger UI) - SDK快速入门指南 - Webhook事件订阅 --- ## 32. 会计处理(ASC 606 / GAAP) ### 32.1 收入确认框架(ASC 606五步法) ```typescript // clearing-service/src/domain/services/accounting.service.ts /** * ASC 606 五步法收入确认: * 1. 识别合同 → 券发行/交易成交 * 2. 识别履约义务 → 券兑付义务(发行方)/ 平台服务义务 * 3. 确定交易价格 → 发行价/成交价 * 4. 分配交易价格 → 各履约义务 * 5. 确认收入 → 履约义务满足时 */ export class AccountingService { /** * 券发行时:发行方收到资金 → 记入递延负债(Deferred Revenue) * 券核销时:履约义务满足 → 递延负债转为已确认收入 * 券过期时:Breakage收入确认(ASC 606-10-55-48~51) */ async recordIssuance(event: CouponIssuedEvent): Promise { const entries: JournalEntry[] = []; // 发行方视角:收到现金,形成递延负债 entries.push({ date: event.issuedAt, debit: { account: 'cash', amount: event.totalSalesAmount }, credit: { account: 'deferred_revenue', amount: event.totalSalesAmount }, memo: `券发行 Batch#${event.batchId},发行方${event.issuerId}`, reference: event.txHash, }); // 平台视角:发行服务费收入(立即确认,平台履约义务已完成) const issuanceFee = event.totalSalesAmount * event.feeRate; entries.push({ date: event.issuedAt, debit: { account: 'accounts_receivable_issuer', amount: issuanceFee }, credit: { account: 'revenue_issuance_fee', amount: issuanceFee }, memo: `发行服务费 ${event.feeRate * 100}%`, reference: event.txHash, }); await this.journalRepo.batchSave(entries); return entries; } async recordRedemption(event: CouponRedeemedEvent): Promise { const entries: JournalEntry[] = []; // 发行方视角:券核销 → 递延负债转为已确认收入 entries.push({ date: event.redeemedAt, debit: { account: 'deferred_revenue', amount: event.faceValue }, credit: { account: 'revenue_earned', amount: event.faceValue }, memo: `券核销 Token#${event.tokenId}`, reference: event.txHash, }); await this.journalRepo.batchSave(entries); return entries; } async recordTrade(event: TradeSettledEvent): Promise { const entries: JournalEntry[] = []; // 平台视角:交易手续费收入(成交即确认) entries.push({ date: event.settledAt, debit: { account: 'cash_stablecoin', amount: event.buyerFee + event.sellerFee }, credit: { account: 'revenue_trading_fee', amount: event.buyerFee + event.sellerFee }, memo: `交易手续费 Order#${event.orderId}`, reference: event.txHash, }); await this.journalRepo.batchSave(entries); return entries; } } ``` ### 32.2 Breakage收入确认(ASC 606-10-55-48~51) ```typescript // clearing-service/src/domain/services/breakage-accounting.service.ts export class BreakageAccountingService { /** * ASC 606 Breakage收入确认规则: * - 如果发行方预期部分券不会被兑付(Breakage),且Breakage金额可合理估计 * → 在券生命周期内按比例确认Breakage收入(proportional method) * - 如果Breakage不可合理估计 * → 在券到期/权利失效时一次性确认(remote method) * * 平台策略:初期采用remote method(到期时确认),积累足够历史数据后切换proportional method */ private readonly RECOGNITION_METHOD: 'proportional' | 'remote' = 'remote'; async processBreakageAccounting(coupon: ExpiredCoupon): Promise { const entries: JournalEntry[] = []; if (this.RECOGNITION_METHOD === 'remote') { // Remote method: 到期时一次性确认 // 发行方侧:递延负债 → Breakage收入 entries.push({ date: coupon.expiryDate, debit: { account: 'deferred_revenue', amount: coupon.faceValue }, credit: { account: 'revenue_breakage', amount: coupon.faceValue }, memo: `Breakage收入确认(remote method)Token#${coupon.tokenId}`, }); // 平台侧:Breakage分润(按协议比例) const platformShare = coupon.faceValue * this.PLATFORM_BREAKAGE_SHARE; entries.push({ date: coupon.expiryDate, debit: { account: 'accounts_receivable_breakage', amount: platformShare }, credit: { account: 'revenue_breakage_share', amount: platformShare }, memo: `平台Breakage分润 ${this.PLATFORM_BREAKAGE_SHARE * 100}%`, }); } await this.journalRepo.batchSave(entries); return entries; } /** * 递延负债余额报表(监管/审计用) * 展示平台上所有未兑付券的递延负债总额 */ async getDeferredRevenueReport(asOfDate: Date): Promise { const outstandingCoupons = await this.couponRepo.findOutstanding(asOfDate); const totalDeferred = outstandingCoupons.reduce((sum, c) => sum + c.faceValue, 0); const byIssuer = this.groupByIssuer(outstandingCoupons); return { asOfDate, totalDeferredRevenue: totalDeferred, byIssuer, byMaturity: this.groupByMaturityBucket(outstandingCoupons), recognitionMethod: this.RECOGNITION_METHOD, }; } } // 会计科目表(Chart of Accounts) const CHART_OF_ACCOUNTS = { // 资产类 cash: '1001 现金及等价物', cash_stablecoin: '1002 稳定币资产(USDC/USDT)', accounts_receivable_issuer: '1101 应收账款-发行方', accounts_receivable_breakage: '1102 应收账款-Breakage分润', // 负债类 deferred_revenue: '2001 递延收入(券未兑付负债)', user_deposits: '2002 用户托管资金', guarantee_funds_held: '2003 发行方保障资金(代管)', // 收入类 revenue_trading_fee: '4001 交易手续费收入', revenue_issuance_fee: '4002 发行服务费收入', revenue_breakage_share: '4003 Breakage分润收入', revenue_vas: '4004 增值服务收入', revenue_earned: '4005 已确认收入(发行方侧)', revenue_breakage: '4006 Breakage收入(发行方侧)', }; ``` ### 32.3 链上数据与GAAP对账 ```typescript // 链上资产余额 vs GAAP账面价值对账 export class ChainGaapReconciliationService { async reconcile(period: AccountingPeriod): Promise { // 1. 链上数据汇总 const chainData = { totalCouponsOutstanding: await this.chainClient.getTotalOutstandingCoupons(), totalStablecoinHeld: await this.chainClient.getTotalStablecoinBalance(), totalGuaranteeFunds: await this.chainClient.getTotalGuaranteeFunds(), }; // 2. GAAP账面数据 const gaapData = { deferredRevenue: await this.accountingRepo.getDeferredRevenue(period.endDate), userDeposits: await this.accountingRepo.getUserDeposits(period.endDate), guaranteeFunds: await this.accountingRepo.getGuaranteeFunds(period.endDate), }; // 3. 差异分析 const discrepancies = this.computeDiscrepancies(chainData, gaapData); return { period, chainData, gaapData, discrepancies, isClean: discrepancies.length === 0, auditorNotes: discrepancies.map(d => this.generateAuditNote(d)), }; } } ``` --- ## 33. 消费者保护法合规(FTC / UDAAP / CARD Act) ### 33.1 FTC Act Section 5 / Dodd-Frank UDAAP 规则引擎 ```typescript // compliance-service/src/domain/services/consumer-protection.service.ts export class ConsumerProtectionService { /** * FTC Act Section 5: 禁止不公平或欺骗性商业行为 * Dodd-Frank UDAAP: 禁止Unfair, Deceptive, or Abusive Acts or Practices * * 平台作为券交易市场,对发行方的券描述负审核责任 */ private readonly RULES: ConsumerProtectionRule[] = [ // 券信息披露完整性检查 { name: 'disclosure_completeness', check: (coupon: CouponListing) => { const required = ['faceValue', 'expiryDate', 'useConditions', 'issuerCreditRating']; const missing = required.filter(f => !coupon[f]); return missing.length === 0 ? { pass: true } : { pass: false, violation: `缺少必要披露: ${missing.join(',')}` }; }, }, // 定价不得误导(折扣率标注准确性) { name: 'pricing_accuracy', check: (coupon: CouponListing) => { const actualDiscount = 1 - coupon.currentPrice / coupon.faceValue; const labeledDiscount = coupon.displayedDiscount; return Math.abs(actualDiscount - labeledDiscount) <= 0.01 ? { pass: true } : { pass: false, violation: `标注折扣${labeledDiscount}与实际折扣${actualDiscount}不符` }; }, }, // 发行方信用等级标注准确性 { name: 'credit_rating_accuracy', check: (coupon: CouponListing) => { const currentRating = coupon.issuer.creditRating; const displayedRating = coupon.displayedCreditRating; return currentRating === displayedRating ? { pass: true } : { pass: false, violation: `展示信用等级${displayedRating}与实际${currentRating}不符` }; }, }, // 退款政策透明化 { name: 'refund_policy_disclosure', check: (coupon: CouponListing) => { return coupon.refundPolicy && coupon.refundPolicy.isVisible ? { pass: true } : { pass: false, violation: '退款政策未明确展示' }; }, }, ]; async auditListing(coupon: CouponListing): Promise { const violations = this.RULES .map(rule => ({ rule: rule.name, result: rule.check(coupon) })) .filter(r => !r.result.pass); if (violations.length > 0) { await this.alertService.sendViolationAlert(coupon.id, violations); } return { couponId: coupon.id, pass: violations.length === 0, violations }; } // AI辅助虚假宣传检测(批量扫描) @Cron('0 6 * * *') // 每日凌晨6点 async batchScanListings(): Promise { const activeListings = await this.couponRepo.findActiveListings(); for (const listing of activeListings) { const result = await this.auditListing(listing); if (!result.pass) { await this.createEnforcementCase(listing, result.violations); } } } } ``` ### 33.2 CARD Act 有效期冲突检测 ```typescript // compliance-service/src/domain/services/card-act.service.ts export class CardActComplianceService { /** * CARD Act (Credit CARD Act of 2009) 礼品卡条款: * - 有效期不得少于5年 * - 不得收取休眠费(dormancy/inactivity fees) * * 冲突:Utility Track强制有效期≤12个月(SEC合规) * 解决:论证"消费型券≠Gift Card"(券是发行方预付债务工具,非零售商礼品卡) * * 本服务实现分类检测:如果券可能被认定为Gift Card,则触发合规审查 */ async checkCardActApplicability(coupon: CouponTemplate): Promise { // Gift Card特征匹配 const giftCardIndicators = { hasFixedFaceValue: coupon.faceValue > 0 && !coupon.isPercentageDiscount, isOpenLoop: !coupon.allowedStores || coupon.allowedStores.length === 0, isStoreBranded: coupon.allowedStores && coupon.allowedStores.length > 0, labeledAsGiftCard: /gift\s*card|礼品卡|礼券/i.test(coupon.name + coupon.description), isPreloaded: coupon.couponCategory === 'stored_value', }; const isLikelyGiftCard = giftCardIndicators.labeledAsGiftCard || (giftCardIndicators.hasFixedFaceValue && giftCardIndicators.isPreloaded); if (isLikelyGiftCard && coupon.couponType === 'utility') { // 冲突检测:Utility Track ≤12个月 vs CARD Act ≥5年 const expiryDays = differenceInDays(coupon.expiryDate, coupon.issuedDate); if (expiryDays < 365 * 5) { return { isConflict: true, couponId: coupon.id, conflictType: 'CARD_ACT_VS_UTILITY_TRACK', detail: `券"${coupon.name}"可能被认定为Gift Card(CARD Act要求≥5年有效期),但Utility Track限制≤12个月`, recommendation: [ '1. 修改券名称/描述,避免使用"礼品卡/Gift Card"字样', '2. 或在法律意见书中论证该券为"预付债务工具"而非"零售礼品卡"', '3. 或将该券移出Utility Track,按CARD Act规则设置≥5年有效期', ], requiresLegalReview: true, }; } } // 休眠费检查(平台不收取,但检查发行方设置) if (coupon.inactivityFee && coupon.inactivityFee > 0) { return { isConflict: true, couponId: coupon.id, conflictType: 'CARD_ACT_DORMANCY_FEE', detail: 'CARD Act禁止对礼品卡/预付卡收取休眠费', recommendation: ['移除休眠费设置'], requiresLegalReview: false, }; } return { isConflict: false, couponId: coupon.id }; } // 发行审核时自动触发 async preIssuanceCardActCheck(template: CouponTemplate): Promise { const result = await this.checkCardActApplicability(template); if (result.isConflict) { // 标记为需要法律审查,暂停发行审批 await this.issuerRepo.flagForLegalReview(template.id, result); throw new ComplianceException(`CARD Act合规冲突: ${result.detail}`); } } } ``` ### 33.3 GENIUS Act 稳定币合规 ```typescript // compliance-service/src/domain/services/genius-act.service.ts export class GeniusActComplianceService { /** * GENIUS Act (2025年签署) — 稳定币监管法: * 平台策略:使用第三方合规稳定币(USDC/USDT),不自行发行 * 合规责任:确保出入金通道对接的稳定币发行方持有合规牌照 */ private readonly APPROVED_STABLECOINS: StablecoinInfo[] = [ { symbol: 'USDC', issuer: 'Circle', license: 'NY BitLicense + State MTLs', reserveAudit: 'Deloitte (monthly attestation)', compliant: true, }, { symbol: 'USDT', issuer: 'Tether', license: 'Various', reserveAudit: 'BDO Italia', compliant: true, }, { symbol: 'PYUSD', issuer: 'PayPal/Paxos', license: 'NYDFS regulated', reserveAudit: 'Withum', compliant: true, }, ]; async validateStablecoinCompliance(stablecoinAddress: string): Promise { const info = this.APPROVED_STABLECOINS.find(s => s.contractAddress === stablecoinAddress ); if (!info || !info.compliant) { throw new ComplianceException('不支持的或不合规的稳定币'); } return true; } // 季度审查:更新稳定币合规状态 @Cron('0 0 1 */3 *') // 每季度1号 async quarterlyStablecoinReview(): Promise { for (const coin of this.APPROVED_STABLECOINS) { const latestAttestation = await this.fetchLatestReserveAttestation(coin.issuer); coin.compliant = latestAttestation.isClean; if (!coin.compliant) { await this.alertService.sendCriticalAlert( `稳定币${coin.symbol}储备审计异常,考虑暂停出入金通道` ); } } } } ``` --- ## 34. 州级合规路由(MTL / BitLicense / DFAL) ```typescript // compliance-service/src/domain/services/state-compliance.service.ts export class StateComplianceService { /** * 美国49州+DC各自有独立的Money Transmitter License (MTL)要求 * 不同州的交易限额、KYC要求、报告义务不同 * 本服务根据用户所在州动态应用对应合规规则 */ private readonly STATE_RULES: Record = { NY: { state: 'New York', license: 'BitLicense (NYDFS)', status: 'required', additionalKyc: true, // NY要求增强KYC maxSingleTx: 10000, // 单笔上限(USD) reportingThreshold: 3000, // 报告阈值 custodyRequirements: 'NYDFS托管规则:客户资产必须隔离托管', restrictions: ['不允许匿名交易', '需额外的NY居民声明'], }, CA: { state: 'California', license: 'DFAL (2026年7月生效)', status: 'pending_regulation', additionalKyc: false, maxSingleTx: null, // 无额外限制 reportingThreshold: 3000, custodyRequirements: 'DFAL框架下的托管要求(待细则)', restrictions: ['CCPA增强隐私要求'], }, TX: { state: 'Texas', license: 'MTL (Texas Dept of Banking)', status: 'required', additionalKyc: false, maxSingleTx: null, reportingThreshold: 3000, custodyRequirements: '标准MTL托管要求', restrictions: [], }, FL: { state: 'Florida', license: 'MTL (OFR)', status: 'required', additionalKyc: false, maxSingleTx: null, reportingThreshold: 3000, custodyRequirements: '标准MTL托管要求', restrictions: [], }, // ... 其他州配置(配置化管理,通过Admin后台维护) }; // 默认规则(适用于未单独配置的州) private readonly DEFAULT_RULE: StateComplianceRule = { state: 'Default', license: 'MTL (standard)', status: 'required', additionalKyc: false, maxSingleTx: null, reportingThreshold: 3000, custodyRequirements: '标准MTL托管要求', restrictions: [], }; // 受限州(暂不服务,直到获得相应牌照) private readonly RESTRICTED_STATES = ['NY', 'HI']; // NY需BitLicense,HI暂不服务 async checkStateCompliance(userId: string, transaction: TransactionRequest): Promise { const user = await this.userRepo.findById(userId); const state = user.residenceState; // 1. 检查是否为受限州 if (this.RESTRICTED_STATES.includes(state)) { const hasLicense = await this.licenseRepo.hasActiveLicense(state); if (!hasLicense) { return { allowed: false, reason: `暂不支持${state}州用户交易,待取得${this.STATE_RULES[state]?.license || 'MTL'}牌照`, }; } } // 2. 获取州规则 const rule = this.STATE_RULES[state] || this.DEFAULT_RULE; // 3. 单笔限额检查 if (rule.maxSingleTx && transaction.amount > rule.maxSingleTx) { return { allowed: false, reason: `${state}州单笔交易上限$${rule.maxSingleTx}`, }; } // 4. 增强KYC检查(如NY) if (rule.additionalKyc && user.kycLevel < KycLevel.L2) { return { allowed: false, reason: `${state}州要求KYC L2+`, action: 'upgrade_kyc', }; } // 5. 州级报告义务 if (transaction.amount >= rule.reportingThreshold) { await this.stateReportingService.queueReport(state, transaction); } return { allowed: true, appliedRule: rule }; } // 牌照状态管理 async getLicenseStatus(): Promise { const allStates = Object.keys(this.STATE_RULES); const statuses = await Promise.all( allStates.map(async (state) => ({ state, required: this.STATE_RULES[state].license, obtained: await this.licenseRepo.hasActiveLicense(state), expiryDate: await this.licenseRepo.getLicenseExpiry(state), renewalDue: await this.licenseRepo.isRenewalDue(state), })) ); return { statuses, restrictedStates: this.RESTRICTED_STATES }; } } ``` --- ## 35. SEC证券合规(Phase 4预留) ```typescript // compliance-service/src/domain/services/securities-compliance.service.ts /** * Securities Track合规服务(Phase 4启用) * * 前提条件: * 1. 券的法律属性意见书已出具 * 2. 如需Broker-Dealer注册,已完成SEC注册 * 3. 如需ATS注册,已提交Form ATS * * 豁免路径(SRS 1.5-1.6): * - Reg D (Rule 506(b/c)): 面向合格投资者,无公开募集,无发行上限 * - Reg A+ (Tier 2): 面向所有投资者,年发行上限$75M,需SEC审查 * - Reg CF: 众筹豁免,年上限$5M,需通过注册融资门户 */ export class SecuritiesComplianceService { private readonly PHASE4_ENABLED = false; // Phase 4前保持关闭 // Reg D 506(c) 合格投资者验证 async verifyAccreditedInvestor(userId: string): Promise { if (!this.PHASE4_ENABLED) throw new Error('Securities Track not enabled'); const user = await this.userRepo.findById(userId); // SEC Rule 501(a) 合格投资者标准 const criteria = { // 个人:年收入>$200K(或与配偶合计>$300K)连续2年 incomeTest: user.annualIncome >= 200000 || user.jointIncome >= 300000, // 个人:净资产>$1M(不含主要住所) netWorthTest: user.netWorthExcludingPrimaryResidence >= 1000000, // 专业认证:Series 7/65/82等 professionalTest: user.hasFinancialLicense, // 实体:资产>$5M entityTest: user.isEntity && user.entityAssets >= 5000000, }; const isAccredited = criteria.incomeTest || criteria.netWorthTest || criteria.professionalTest || criteria.entityTest; return { userId, isAccredited, verificationMethod: 'self_certification', // 初期自认证,后期第三方验证 verifiedAt: new Date(), validUntil: addMonths(new Date(), 12), // 12个月有效 criteria, }; } // Reg A+ 投资限额检查 async checkRegAInvestmentLimit(userId: string, amount: number): Promise { if (!this.PHASE4_ENABLED) throw new Error('Securities Track not enabled'); const user = await this.userRepo.findById(userId); // Reg A+ Tier 2: 非合格投资者年投资上限 = max(年收入, 净资产) × 10% if (!user.isAccredited) { const limit = Math.max(user.annualIncome, user.netWorth) * 0.10; const ytdInvestment = await this.investmentRepo.getYtdTotal(userId); return (ytdInvestment + amount) <= limit; } return true; // 合格投资者无限额 } // Form ATS报告义务 async generateAtsReport(quarter: string): Promise { if (!this.PHASE4_ENABLED) throw new Error('Securities Track not enabled'); return { quarter, totalSecuritiesTraded: await this.tradeRepo.getSecuritiesVolume(quarter), uniqueParticipants: await this.tradeRepo.getUniqueSecuritiesTraders(quarter), topSecurities: await this.tradeRepo.getTopSecuritiesByVolume(quarter, 10), // SEC Form ATS-N 披露要求 atsOperations: { orderTypes: ['limit', 'market'], matchingLogic: 'price-time priority', feeSchedule: this.getSecuritiesFeeSchedule(), }, }; } } ``` --- ## 36. 商业保险需求跟踪 ```typescript // compliance-service/src/domain/services/insurance-tracking.service.ts /** * 商业保险管理(Nasdaq上市审计要求) * IPO前12个月完成所有保险采购 */ export class InsuranceTrackingService { private readonly REQUIRED_POLICIES: InsurancePolicyRequirement[] = [ { type: 'D&O', name: '董事及高管责任险 (Directors & Officers)', description: '董事/高管因管理决策被诉的法律费用与赔偿', minCoverage: 'match_market_cap', // 覆盖额度匹配公司市值 requiredBy: 'IPO前12个月', status: 'not_purchased', carriers: ['AIG', 'Chubb', 'Berkshire Hathaway'], }, { type: 'E&O', name: '专业责任险 (Errors & Omissions)', description: '平台服务失误导致用户损失(信用评级错误、交易撮合问题)', minCoverage: 10_000_000, // $10M requiredBy: 'IPO前12个月', status: 'not_purchased', carriers: ['Lloyd\'s', 'AIG', 'Travelers'], }, { type: 'CYBER', name: '网络安全险 (Cyber Liability)', description: '数据泄露、黑客攻击、勒索软件损失与响应成本', minCoverage: 50_000_000, // $50M(覆盖MPC托管的全部用户资产) requiredBy: 'IPO前12个月', status: 'not_purchased', carriers: ['Coalition', 'Beazley', 'AIG'], notes: '需覆盖数字资产托管风险,保费较高', }, { type: 'FIDELITY', name: '忠诚保证金 (Fidelity Bond)', description: '内部员工欺诈、盗窃数字资产', minCoverage: 5_000_000, // $5M requiredBy: 'IPO前12个月', status: 'not_purchased', carriers: ['Travelers', 'Hartford', 'CNA'], }, { type: 'GL', name: '商业综合险 (General Liability)', description: '一般商业责任', minCoverage: 2_000_000, // $2M requiredBy: 'IPO前12个月', status: 'not_purchased', carriers: ['Progressive', 'Hartford'], }, ]; async getInsuranceStatus(): Promise { const policies = await this.policyRepo.findAll(); return { requiredPolicies: this.REQUIRED_POLICIES.map(req => { const purchased = policies.find(p => p.type === req.type); return { ...req, status: purchased ? 'active' : 'not_purchased', policyNumber: purchased?.policyNumber, effectiveDate: purchased?.effectiveDate, expiryDate: purchased?.expiryDate, coverageAmount: purchased?.coverageAmount, annualPremium: purchased?.annualPremium, isAdequate: purchased ? this.isCoverageAdequate(req, purchased) : false, }; }), allRequirementsMet: this.REQUIRED_POLICIES.every( req => policies.some(p => p.type === req.type && p.status === 'active') ), }; } // 保险到期提醒 @Cron('0 9 * * 1') // 每周一上午9点 async checkExpiringPolicies(): Promise { const policies = await this.policyRepo.findExpiringWithin(90); // 90天内到期 for (const policy of policies) { await this.alertService.sendAlert({ type: 'insurance_expiring', severity: 'high', message: `${policy.name}将于${policy.expiryDate}到期,请及时续期`, }); } } } ``` --- *文档版本: v2.1* *基于: Genex 券交易平台 - 软件需求规格说明书 v4.1* *技术栈: NestJS + Go + Kong + PostgreSQL + Kafka + Redis* *更新: v2.1补充会计处理(ASC 606/递延负债/GAAP对账)/消费者保护法(FTC/UDAAP/CARD Act冲突检测/GENIUS Act)/州级合规路由(MTL/BitLicense/DFAL)/SEC证券合规(Reg D/A+/CF预留)/商业保险跟踪*