From 03e5f5b3e3179da30d3f3951cd0d60f41362739a Mon Sep 17 00:00:00 2001 From: hailin Date: Tue, 10 Feb 2026 17:39:05 -0800 Subject: [PATCH] v2.0: Supplement all guides to achieve 100% SRS coverage Comprehensive additions across all 7 guide files (+2,439 lines): - 05-Backend: fee calculation (Maker-Taker), Breakage processing, refund mechanism, market maker system, three-factor pricing engine, AI/ML models (LightGBM/LSTM/IsolationForest), AML detection rules, OFAC sync service, Travel Rule (TRISA), tax compliance (1099/FATCA), CCPA/GDPR data deletion, security incident response (P0-P3), disaster recovery (RPO/RTO), mapping table security (MPC+audit+anchor), multi-currency, fiat hot-standby, chain reconciliation, capacity planning, SDK development plan, dispute handling, customer service - 06-Blockchain: GNX token economics, non-transferable coupon revert, differentiated KYC checks, validator-level OFAC/structuring/TravelRule interception, batch transfer, Treasury guarantee fund locking, contract upgrade rollback, multi-stablecoin (USDC+USDT), Oracle integration, asset securitization contract reserve - 01-Flutter Mobile: Pro mode (seed phrase, social recovery, AA wallet), MetaMask integration, external wallet extraction, transfer history, balance/deposit/withdraw, order history, phone number change, offline redemption limits/conflicts, dispute/complaint, notifications - 02-Flutter Admin: guarantee fund/frozen sales, reconciliation reports, secondary market analysis, financing effect analysis, refund window config, batch operations, coupon recall, multi-store hierarchy, dedicated customer service channel - 03-Web Admin: user behavior analytics, coupon category analysis, 1099 tax reports, FATCA, false advertising monitoring, SOX audit module, fee/revenue dashboard, settlement management, dispute arbitration, web merchant redemption console, market maker monitoring - 00-UI Design: Utility/Securities Track UI isolation design - 04-Mini Program: multi-language i18n (zh-CN/en-US/ja-JP), multi-currency display Co-Authored-By: Claude Opus 4.6 --- docs/guides/00-UI设计需求.md | 43 +- .../guides/01-Flutter移动端开发指南.md | 315 ++++- .../02-Flutter管理后台App开发指南.md | 257 ++++- docs/guides/03-Web管理前端开发指南.md | 350 +++++- docs/guides/04-小程序H5开发指南.md | 83 +- docs/guides/05-后端开发指南.md | 1012 ++++++++++++++++- docs/guides/06-区块链开发指南.md | 387 ++++++- 7 files changed, 2439 insertions(+), 8 deletions(-) diff --git a/docs/guides/00-UI设计需求.md b/docs/guides/00-UI设计需求.md index eb519a9..17cf1dd 100644 --- a/docs/guides/00-UI设计需求.md +++ b/docs/guides/00-UI设计需求.md @@ -456,6 +456,45 @@ AI Agent可代用户执行的操作(均需用户确认): --- -*文档版本: v1.1* +--- + +## I. Utility Track / Securities Track UI隔离设计 + +> SRS 1.6要求:Utility Track和Securities Track使用不同的交易市场界面(前端隔离)。MVP阶段仅开放Utility Track。 + +### I1. 双轨UI隔离原则 + +| 维度 | Utility Track(消费型券) | Securities Track(投资型券) | +|------|--------------------------|---------------------------| +| **市场入口** | 默认市场(首页即Utility市场) | 独立入口(需KYC L2+才可见) | +| **价格展示** | 显示"折扣价"标签,面值上限提示 | 显示价格走势、K线图、涨跌幅 | +| **挂单界面** | 价格输入上限=面值,自动校验 | 无价格上限,自由定价 | +| **交易提示** | "您正在购买消费券用于消费" | "您正在进行投资交易,有亏损风险" | +| **转售计数** | 显示"剩余可转售X次" | 不显示限制 | +| **合规标识** | "消费券"标签(绿色) | "投资券"标签(橙色)+ 风险警示 | +| **KYC要求** | 交易前提示升级KYC L1 | 交易前提示升级KYC L2+ | + +### I2. MVP阶段处理 + +``` +MVP阶段: +- 只展示Utility Track市场 +- Securities Track入口隐藏(代码预留,配置开关控制) +- 所有挂单价格自动校验 ≤ 面值 +- 券详情页不显示"投资收益"相关信息 +``` + +### I3. 关键UI差异点 + +| 页面 | Utility Track | Securities Track(预留) | +|------|--------------|------------------------| +| **券详情页** | 面值、折扣价、使用条件、发行方信用、到期日 | 同左 + 价格历史K线 + 涨跌幅 + 收益率 | +| **出售页面** | 价格滑块上限=面值,溢价时红色提示 | 无价格限制,显示市场参考价 | +| **持有目的声明** | 购买时弹窗确认"购买用于消费" | 购买时弹窗确认"我了解投资风险" | +| **我的券列表** | 标签:消费券(绿) | 标签:投资券(橙) | + +--- + +*文档版本: v1.2* *基于: Genex 券交易平台 - 软件需求规格说明书 v4.1* -*更新: 增加AI Agent深度融合设计规范* +*更新: 增加AI Agent深度融合设计规范、Utility/Securities Track UI隔离设计* diff --git a/docs/guides/01-Flutter移动端开发指南.md b/docs/guides/01-Flutter移动端开发指南.md index d13b875..5d2a7cc 100644 --- a/docs/guides/01-Flutter移动端开发指南.md +++ b/docs/guides/01-Flutter移动端开发指南.md @@ -554,6 +554,319 @@ void main() { --- -*文档版本: v1.0* +## 13. Pro模式(加密原生用户) + +### 13.1 Pro模式切换 + +```dart +// lib/features/profile/presentation/pages/pro_mode_settings.dart +class ProModeSettings extends ConsumerWidget { + @override + Widget build(BuildContext context, WidgetRef ref) { + final user = ref.watch(userProfileProvider); + + return Column(children: [ + // 风险提示确认 + RiskDisclosureCard( + text: '切换至Pro模式后,您将自行管理钱包私钥。' + '平台无法帮您恢复丢失的私钥或资产。', + ), + + // 开启Pro模式 + SwitchListTile( + title: Text('开启Pro模式'), + value: user.walletMode == WalletMode.pro, + onChanged: (enabled) async { + if (enabled) { + // 必须确认风险提示 + final confirmed = await showRiskConfirmDialog(context); + if (confirmed) { + await ref.read(walletProvider.notifier).switchToProMode(); + } + } else { + // Pro→标准:需将资产转回平台托管 + await ref.read(walletProvider.notifier).switchToStandard(); + } + }, + ), + + if (user.walletMode == WalletMode.pro) ...[ + // 链上地址显示 + CopyableAddressField(address: user.chainAddress), + // WalletConnect连接 + WalletConnectButton(), + // MetaMask连接 + MetaMaskConnectButton(), + // 交易哈希查看入口 + ListTile( + title: Text('查看链上交易'), + onTap: () => launchUrl(explorerUrl), + ), + ], + ]); + } +} +``` + +### 13.2 助记词备份与社交恢复 + +```dart +// lib/features/wallet/domain/usecases/backup_usecase.dart +class BackupSeedPhraseUseCase { + /// Pro模式开启时强制提示备份助记词 + Future> call() async { + final mnemonic = await _walletService.generateMnemonic(); + // 显示12词助记词,用户手动抄写 + // 验证确认(随机抽3个词验证) + return _walletService.confirmBackup(mnemonic); + } +} + +// 社交恢复(Guardian机制) +class SocialRecoveryUseCase { + /// 预设3-5个可信联系人,多数确认即可恢复 + Future> setupGuardians(List guardianPhones) async { + if (guardianPhones.length < 3 || guardianPhones.length > 5) { + return Left(Failure.validation(errors: {'guardians': '需要3-5个守护人'})); + } + return _repo.setupSocialRecovery(guardianPhones); + } + + /// 发起恢复(需>50%守护人确认) + Future> initiateRecovery() async { + return _repo.initiateRecovery(); + } +} + +// AA钱包(ERC-4337)集成 +class AAWalletService { + /// 邮箱/手机号作为恢复入口 + Future recoverViaEmail(String email) async { + // ERC-4337 Account Abstraction恢复流程 + } +} +``` + +--- + +## 14. 提取到外部钱包 + +```dart +// lib/features/wallet/presentation/pages/extract_to_external.dart +class ExtractToExternalPage extends ConsumerWidget { + @override + Widget build(BuildContext context, WidgetRef ref) { + return Column(children: [ + // KYC L2+才可提取 + KycGuard(requiredLevel: KycLevel.L2, child: Column(children: [ + // 输入外部钱包地址(EVM兼容) + TextField( + decoration: InputDecoration(labelText: '外部钱包地址(0x...)'), + controller: _addressController, + ), + // 风险提示 + WarningCard( + text: '提取后平台将不再托管该券。' + '您需自行保管钱包私钥,平台无法冻结、恢复或干预该券。', + ), + // 选择要提取的券 + CouponSelector(onSelected: (coupons) => setState(() => _selected = coupons)), + // 确认提取 + ElevatedButton( + onPressed: () => _confirmExtract(ref), + child: Text('确认提取'), + ), + ])), + ]); + } +} +``` + +--- + +## 15. 个人中心完整模块 + +### 15.1 转赠记录 + +```dart +// lib/features/transfer/presentation/pages/transfer_history.dart +class TransferHistoryPage extends ConsumerWidget { + @override + Widget build(BuildContext context, WidgetRef ref) { + final transfers = ref.watch(transferHistoryProvider); + + return transfers.when( + data: (list) => ListView.builder( + itemCount: list.length, + itemBuilder: (_, i) => TransferHistoryCard( + direction: list[i].direction, // sent / received + recipientDisplay: list[i].recipientPhone ?? '外部钱包', + couponName: list[i].couponName, + timestamp: list[i].createdAt, + status: list[i].status, // completed / pending + ), + ), + loading: () => SkeletonList(), + error: (e, _) => ErrorWidget(e), + ); + } +} +``` + +### 15.2 我的余额/充值/提现 + +```dart +// lib/features/wallet/domain/entities/balance.dart +@freezed +class WalletBalance with _$WalletBalance { + const factory WalletBalance({ + required double totalBalance, // 总余额(链上+链下聚合,美元显示) + required double availableBalance, // 可用余额 + required double frozenBalance, // 冻结金额(挂单中/待结算) + required double withdrawable, // 可提现 + }) = _WalletBalance; +} + +// 充值/提现流程 +class DepositUseCase { + Future> call(DepositParams params) { + // 银行卡/信用卡/Apple Pay → 法币入金 → 后台转换USDC + return _repo.deposit(params); + } +} + +class WithdrawUseCase { + Future> call(WithdrawParams params) { + // USDC → 法币 → 银行卡(T+1到账) + return _repo.withdraw(params); + } +} +``` + +### 15.3 我的订单 + +```dart +// lib/features/trading/presentation/pages/order_history.dart +class OrderHistoryPage extends ConsumerWidget { + @override + Widget build(BuildContext context, WidgetRef ref) { + final orders = ref.watch(orderHistoryProvider); + return DefaultTabController( + length: 3, + child: Column(children: [ + TabBar(tabs: [ + Tab(text: '全部'), + Tab(text: '买入'), + Tab(text: '卖出'), + ]), + Expanded(child: TabBarView(children: [ + OrderList(orders: orders), + OrderList(orders: orders.where((o) => o.side == OrderSide.buy)), + OrderList(orders: orders.where((o) => o.side == OrderSide.sell)), + ])), + ]), + ); + } +} +``` + +### 15.4 换手机号 + +```dart +// lib/features/profile/domain/usecases/change_phone.dart +class ChangePhoneUseCase { + /// 换手机号:KYC身份验证(人脸+证件)后迁移账户 + Future> call(ChangePhoneParams params) async { + // 1. 验证新手机号未注册 + // 2. KYC身份验证(人脸识别 + 证件对比) + // 3. 旧手机号验证码确认 + // 4. 更新映射表(旧手机→新手机,链上地址不变) + return _repo.changePhone(params); + } +} +``` + +--- + +## 16. 离线核销增强 + +```dart +// lib/features/merchant/data/services/offline_redeem_service.dart +// 补充:离线核销限额与冲突处理 + +class OfflineRedeemConfig { + static const maxSingleAmount = 500.0; // 单笔离线核销限额$500 + static const maxDailyAmount = 5000.0; // 单日离线核销限额$5,000 + static const maxDailyCount = 50; // 单日离线核销笔数限制 +} + +class OfflineConflictResolver { + /// 冲突处理:同一张券被两个门店离线核销 + /// 以先上链者为准,后者自动退回并通知 + Future resolveConflict(PendingRedemption local, ChainRedemption chain) async { + if (chain.redeemedBy != local.storeId) { + // 该券已被其他门店核销,本地核销无效 + await _notifyStore(local.storeId, '券${local.couponCode}已被其他门店核销'); + await _queue.delete(local.key); + } + } +} +``` + +--- + +## 17. 争议与投诉 + +```dart +// lib/features/support/domain/entities/ticket.dart +@freezed +class SupportTicket with _$SupportTicket { + const factory SupportTicket({ + required String id, + required TicketCategory category, // transaction/account/coupon + required String description, + required TicketStatus status, + String? orderId, // 关联订单号 + List? attachments, + }) = _SupportTicket; +} + +enum TicketCategory { transaction, account, coupon, compliance, other } +enum TicketStatus { open, inProgress, waitingUser, resolved, closed } +``` + +--- + +## 18. 消息通知 + +```dart +// lib/features/notification/domain/entities/notification.dart +@freezed +class AppNotification with _$AppNotification { + const factory AppNotification({ + required String id, + required NotificationType type, + required String title, + required String body, + required DateTime createdAt, + required bool isRead, + String? deepLink, // 点击跳转(如券详情、订单详情) + }) = _AppNotification; +} + +enum NotificationType { + tradeComplete, // 交易完成 + couponExpiringSoon, // 券即将过期 + priceAlert, // 价格变动 + transferReceived, // 收到转赠 + systemAnnouncement, // 系统公告 + issuerNotice, // 发行方公告 +} +``` + +--- + +*文档版本: v2.0* *基于: Genex 券交易平台 - 软件需求规格说明书 v4.1* *技术栈: Flutter 3.x + Riverpod + Clean Architecture* +*更新: 补充Pro模式/助记词/社交恢复/AA钱包/外部钱包提取/转赠记录/余额/订单/换手机号/离线核销增强/争议投诉/消息通知* diff --git a/docs/guides/02-Flutter管理后台App开发指南.md b/docs/guides/02-Flutter管理后台App开发指南.md index c9f8675..8ae1764 100644 --- a/docs/guides/02-Flutter管理后台App开发指南.md +++ b/docs/guides/02-Flutter管理后台App开发指南.md @@ -282,6 +282,261 @@ class AiSuggestionCard extends StatelessWidget { --- -*文档版本: v1.0* +## 9. 财务管理增强 + +### 9.1 保证金与冻结销售款 + +```dart +// 发行方可选:缴纳保证金以快速提升额度 +@freezed +class GuaranteeFund with _$GuaranteeFund { + const factory GuaranteeFund({ + required double deposited, // 已缴纳保证金 + required double frozenSales, // 冻结的销售款(自愿开启) + required bool autoFreezeEnabled, // 是否开启销售款自动冻结 + required double freezePercent, // 冻结比例(如20%销售额) + }) = _GuaranteeFund; +} + +// 财务管理增强视图 +@freezed +class FinanceDetailView with _$FinanceDetailView { + const factory FinanceDetailView({ + required double salesRevenue, // 销售收入 + required double breakageIncome, // Breakage收入(过期券) + required double platformFees, // 平台手续费支出 + required double pendingSettlement, // 待结算 + required double withdrawable, // 可提现 + required double totalWithdrawn, // 已提现 + required double guaranteeDeposit, // 保证金 + required double frozenSales, // 冻结销售款 + }) = _FinanceDetailView; +} +``` + +### 9.2 对账报表 + +```dart +// 日/月对账单 +class ReconciliationReport { + final DateTime periodStart; + final DateTime periodEnd; + final List entries; + final double totalIncome; + final double totalExpense; + final double netBalance; + + // 导出为CSV/PDF + Future exportAsCsv() async { /* ... */ } + Future exportAsPdf() async { /* ... */ } +} +``` + +--- + +## 10. 发行方数据分析增强 + +### 10.1 二级市场分析 + +```dart +@freezed +class SecondaryMarketAnalysis with _$SecondaryMarketAnalysis { + const factory SecondaryMarketAnalysis({ + required int listedCount, // 二级市场挂单数 + required double avgResalePrice, // 平均转售价 + required double avgDiscount, // 平均折扣率 + required int resaleVolume, // 转售成交量 + required double resaleRevenue, // 转售成交额 + required List priceHistory, // 价格历史(K线数据) + }) = _SecondaryMarketAnalysis; +} +``` + +### 10.2 融资效果分析 + +```dart +@freezed +class FinancingEffectReport with _$FinancingEffectReport { + const factory FinancingEffectReport({ + required double cashAdvanced, // 现金提前回笼总额 + required double avgAdvanceDays, // 平均提前回笼天数 + required double financingCost, // 融资成本(平台手续费+折扣损失) + required double effectiveRate, // 等效年利率 + required List cashFlowTimeline, // 现金流时序图 + }) = _FinancingEffectReport; +} +``` + +--- + +## 11. 退款窗口配置 + +```dart +// 发行方可配置退款期限 +@freezed +class RefundPolicy with _$RefundPolicy { + const factory RefundPolicy({ + required int refundWindowDays, // 退款窗口(天,默认7天) + required bool autoRefundEnabled, // 是否自动退款 + required String refundConditions, // 退款条件说明 + }) = _RefundPolicy; +} + +// 创建券时配置退款策略 +class CreateCouponWithRefundPolicy { + Widget buildRefundSection() { + return Column(children: [ + Text('退款策略'), + NumberPicker( + label: '退款窗口(天)', + min: 0, max: 30, initial: 7, + onChanged: (days) => _refundDays = days, + ), + SwitchListTile( + title: Text('允许自动退款'), + subtitle: Text('窗口期内用户可直接退款无需审核'), + value: _autoRefund, + onChanged: (v) => setState(() => _autoRefund = v), + ), + ]); + } +} +``` + +--- + +## 12. 批量操作 + +```dart +// 批量发行、批量核销、批量导出 +class BatchOperationsService { + // 批量发行(一次创建多种券模板) + Future>> batchCreate( + List paramsList + ) async { + return _repo.batchSubmitDrafts(paramsList); + } + + // 批量核销 + Future> batchRedeem( + List couponCodes + ) async { + return _repo.batchRedeem(couponCodes); + } + + // 批量数据导出 + Future exportData({ + required ExportType type, // coupons / transactions / reconciliation + required DateRange range, + required ExportFormat format, // csv / xlsx / pdf + }) async { + return _repo.exportBatchData(type, range, format); + } +} +``` + +--- + +## 13. 券召回与下架 + +```dart +// 券召回流程 +class CouponRecallService { + /// 召回未售出的券(链上销毁) + Future> recallUnsold(String couponBatchId) async { + return _repo.recallUnsoldCoupons(couponBatchId); + } + + /// 问题券紧急下架 + Future> emergencyDelist(String couponId, String reason) async { + return _repo.delistCoupon(couponId, reason); + } + + /// 已售出券的退款处理 + Future> initiateRefundForSold( + String couponBatchId, String refundReason + ) async { + return _repo.initiateRefundForSoldCoupons(couponBatchId, refundReason); + } +} +``` + +--- + +## 14. 多门店管理增强 + +```dart +// 门店层级管理 +@freezed +class StoreHierarchy with _$StoreHierarchy { + const factory StoreHierarchy({ + required String id, + required String name, + required StoreLevel level, // headquarters / regional / store + String? parentId, // 上级ID + required List children, + required StorePermissions permissions, + }) = _StoreHierarchy; +} + +enum StoreLevel { headquarters, regional, store } + +// 门店员工管理 +@freezed +class StoreEmployee with _$StoreEmployee { + const factory StoreEmployee({ + required String id, + required String name, + required String phone, + required StoreRole role, // cashier / manager / admin + required List storeIds, // 可操作的门店 + }) = _StoreEmployee; +} + +enum StoreRole { + cashier, // 收银员:仅核销权限 + manager, // 店长:核销 + 数据查看 + admin, // 管理员:全部权限 +} +``` + +--- + +## 15. 专属客服通道 + +```dart +// 铂金/钻石层级发行方专属客服 +class DedicatedSupportWidget extends ConsumerWidget { + @override + Widget build(BuildContext context, WidgetRef ref) { + final issuer = ref.watch(issuerProfileProvider); + + if (['platinum', 'diamond'].contains(issuer.tier.name)) { + return Card( + child: ListTile( + leading: Icon(Icons.headset_mic, color: Colors.amber), + title: Text('专属客服'), + subtitle: Text('1小时内响应 | 您的客户经理:${issuer.accountManager}'), + onTap: () => _openDedicatedChat(context), + ), + ); + } + + return Card( + child: ListTile( + leading: Icon(Icons.support_agent), + title: Text('在线客服'), + subtitle: Text('24小时内响应'), + onTap: () => _openSupportTicket(context), + ), + ); + } +} +``` + +--- + +*文档版本: v2.0* *基于: Genex 券交易平台 - 软件需求规格说明书 v4.1* *技术栈: Flutter 3.x + Riverpod + Clean Architecture* +*更新: 补充保证金/冻结销售款/对账报表/二级市场分析/融资效果/退款窗口/批量操作/券召回/多门店增强/专属客服* diff --git a/docs/guides/03-Web管理前端开发指南.md b/docs/guides/03-Web管理前端开发指南.md index 83ef4be..23b5c3d 100644 --- a/docs/guides/03-Web管理前端开发指南.md +++ b/docs/guides/03-Web管理前端开发指南.md @@ -347,6 +347,354 @@ CMD ["npm", "start"] --- -*文档版本: v1.0* +## 10. 数据报表与分析 + +### 10.1 平台数据报表 + +```typescript +// src/features/reports/types.ts +interface PlatformReport { + type: 'daily' | 'monthly' | 'quarterly'; + metrics: { + totalTransactionVolume: number; + totalTransactionAmount: number; + activeUsers: number; + newIssuers: number; + avgDiscountRate: number; + platformRevenue: number; // 手续费收入 + breakageRevenue: number; + }; +} +``` + +### 10.2 用户行为分析 + +```typescript +// src/features/analytics/user-analytics.ts +interface UserBehaviorAnalytics { + registrationFunnel: FunnelData; // 注册→KYC→首次交易转化率 + retentionRate: RetentionData; // 留存率(日/周/月) + activeUserTrend: TimeSeriesData; // DAU/WAU/MAU + tradingPatterns: TradingPatternData; // 交易行为模式 + kycLevelDistribution: PieData; // KYC等级分布 + walletModeDistribution: PieData; // 标准/Pro模式占比 +} +``` + +### 10.3 券类别分析 + +```typescript +// src/features/analytics/coupon-analytics.ts +interface CouponCategoryAnalytics { + byIndustry: CategoryBreakdown[]; // 按行业(餐饮/购物/娱乐) + byTemplate: CategoryBreakdown[]; // 按模板(满减/折扣/礼品卡/储值) + byIssuerTier: CategoryBreakdown[]; // 按发行方层级 + redemptionByCategory: BarData; // 各品类兑付率 + breakageByCategory: BarData; // 各品类Breakage率 + priceDistribution: HistogramData; // 价格分布 +} +``` + +--- + +## 11. 税务合规报表 + +### 11.1 IRS 1099报表管理 + +```typescript +// src/features/compliance/tax-reports.ts +interface Tax1099Management { + // IRS Form 1099-DA/1099-B 生成与管理 + generateBatch: (taxYear: number) => Promise; + reviewReport: (reportId: string) => Promise; + submitToIRS: (reportIds: string[]) => Promise; + userPortalExport: (userId: string, taxYear: number) => Promise; +} + +// 1099报表页面 +export function Tax1099Page() { + const [taxYear, setTaxYear] = useState(2025); + const reports = useQuery(['tax1099', taxYear], () => taxApi.getReports(taxYear)); + + return ( +
+ + + + + + + + +
+ ); +} +``` + +### 11.2 FATCA跨境税务 + +```typescript +interface FatcaReport { + foreignAccountHolders: ForeignUser[]; + totalUsSourceIncome: number; + reportingStatus: 'pending' | 'submitted'; +} +``` + +--- + +## 12. 消费者保护与虚假宣传监控 + +```typescript +// src/features/compliance/consumer-protection.ts +interface ConsumerProtectionCase { + id: string; + type: 'misleading_description' | 'false_advertising' | 'undisclosed_conditions'; + couponId: string; + issuerId: string; + reportedBy: 'user' | 'ai_scan' | 'admin'; + evidence: { + couponDescription: string; // 券描述 + actualRedemptionInfo: string; // 实际兑付情况 + discrepancy: string; // 差异说明 + }; + status: 'reported' | 'investigating' | 'confirmed' | 'dismissed'; + action: 'warning' | 'delist' | 'suspend_issuer' | 'none'; +} + +// AI扫描券描述一致性 +export function FalseAdvertisingMonitor() { + return ( +
+

虚假宣传监控

+ {/* AI自动扫描所有上架券的描述 vs 实际兑付记录 */} + + {/* 手动审查队列 */} + +
+ ); +} +``` + +--- + +## 13. SOX审计模块 + +```typescript +// src/features/compliance/sox-audit.ts +interface SoxAuditDashboard { + // Section 302: CEO/CFO认证追踪 + certifications: CertificationRecord[]; + // Section 404: 内部控制评估 + internalControls: InternalControlAssessment[]; + // 智能合约升级审计追踪 + contractUpgradeAudit: ContractUpgradeLog[]; + // 链上记录与GAAP对账 + chainToGaapReconciliation: ReconciliationReport; +} + +interface ContractUpgradeLog { + proposalId: string; + contractName: string; + oldImplementation: string; + newImplementation: string; + proposedBy: string; + approvedBy: string[]; // 多签审批人 + timelockExpiry: Date; + executedAt: Date; + auditReport: string; // 第三方审计报告链接 +} + +// SOX审计页面 +export function SoxAuditPage() { + return ( + + + + + + + + + + + + {/* 全链路操作日志,append-only */} + + + ); +} +``` + +--- + +## 14. 财务管理 + +### 14.1 手续费管理 + +```typescript +// src/features/finance/fee-management.ts +interface FeeConfiguration { + tradingFees: { + takerBuy: number; // 0.5% + takerSell: number; + makerBuy: number; // 0.1% + makerSell: number; + }; + issuanceFees: Record; + breakageSharePercent: number; // 平台Breakage分润比例 +} + +// 手续费收入仪表盘 +export function FeeRevenueDashboard() { + return ( +
+ + + + + + + +
+ ); +} +``` + +### 14.2 结算管理 + +```typescript +// 发行方结算管理 +interface SettlementManagement { + pendingSettlements: SettlementBatch[]; + completedSettlements: SettlementBatch[]; + issuerBalances: IssuerBalance[]; + withdrawalRequests: WithdrawalRequest[]; +} +``` + +--- + +## 15. 争议与仲裁处理 + +```typescript +// src/features/disputes/types.ts +interface DisputeCase { + id: string; + type: 'buyer_complaint' | 'seller_complaint' | 'refund_request'; + status: 'submitted' | 'evidence_collection' | 'arbitration' | 'resolved' | 'escalated'; + orderId: string; + buyerId: string; + sellerId: string; + chainEvidence: { + txHash: string; + blockNumber: number; + timestamp: Date; + transferRecord: string; + }; + sla: { + responseDeadline: Date; // 24h响应 + resolutionDeadline: Date; // 72h处理 + }; + arbitrationDecision?: { + decidedBy: string; + decision: 'refund' | 'reject' | 'partial_refund'; + reason: string; + }; +} + +// 争议处理页面 +export function DisputeManagementPage() { + return ( +
+ + }, + { key: 'actions', title: '操作', render: (_, row) => }, + ]} + /> +
+ ); +} +``` + +--- + +## 16. Web商户核销后台 + +```typescript +// src/app/(dashboard)/merchant-redemption/page.tsx +// 门店管理员通过浏览器核销+查看核销记录 +export default function MerchantRedemptionPage() { + return ( +
+

Web端核销后台

+ + {/* 输码核销 */} + + + + + + {/* 核销记录 */} + + + + + + {/* 门店数据汇总 */} + +
+ ); +} +``` + +--- + +## 17. 做市商管理 + +```typescript +// src/features/trading/market-maker-management.ts +interface MarketMakerManagement { + marketMakers: MarketMaker[]; + obligations: MarketMakerObligation[]; + performanceMetrics: MmPerformanceMetric[]; + violationAlerts: MmViolation[]; +} + +// 做市商活动监控页面 +export function MarketMakerMonitorPage() { + return ( +
+

做市商监控

+ + {/* Spoofing/Layering检测告警 */} + + {/* 做市义务合规检查 */} + +
+ ); +} +``` + +--- + +*文档版本: v2.0* *基于: Genex 券交易平台 - 软件需求规格说明书 v4.1* *技术栈: React 18 + TypeScript 5 + Next.js 14 + Zustand + Redux Toolkit* +*更新: 补充数据报表/用户行为分析/券类别分析/1099税务/FATCA/虚假宣传监控/SOX审计/财务管理/争议仲裁/Web核销后台/做市商管理* diff --git a/docs/guides/04-小程序H5开发指南.md b/docs/guides/04-小程序H5开发指南.md index 3d4169c..2c48d56 100644 --- a/docs/guides/04-小程序H5开发指南.md +++ b/docs/guides/04-小程序H5开发指南.md @@ -317,6 +317,87 @@ export default defineAppConfig({ --- -*文档版本: v1.0* +## 10. 多语言与国际化 + +### 10.1 i18n配置 + +```typescript +// src/utils/i18n.ts +import Taro from '@tarojs/taro'; + +// 支持语言:中文(默认)、英文、日文 +type Locale = 'zh-CN' | 'en-US' | 'ja-JP'; + +const messages: Record> = { + 'zh-CN': { + 'home.title': '发现好券', + 'coupon.buy': '立即购买', + 'coupon.faceValue': '面值', + 'coupon.discount': '折扣', + 'coupon.expiry': '有效期至', + 'my.coupons': '我的券', + 'my.orders': '我的订单', + 'redeem.show': '出示给商户扫码', + // ... + }, + 'en-US': { + 'home.title': 'Discover Deals', + 'coupon.buy': 'Buy Now', + 'coupon.faceValue': 'Face Value', + 'coupon.discount': 'Discount', + 'coupon.expiry': 'Valid Until', + 'my.coupons': 'My Coupons', + 'my.orders': 'My Orders', + 'redeem.show': 'Show to Merchant', + // ... + }, + 'ja-JP': { + 'home.title': 'クーポンを探す', + 'coupon.buy': '今すぐ購入', + 'coupon.faceValue': '額面', + 'coupon.discount': '割引', + 'coupon.expiry': '有効期限', + 'my.coupons': 'マイクーポン', + 'my.orders': '注文履歴', + 'redeem.show': '店舗に提示', + // ... + }, +}; + +export function useI18n() { + const locale = useLocaleStore((s) => s.locale); + const t = (key: string) => messages[locale]?.[key] || messages['zh-CN'][key] || key; + return { t, locale }; +} + +// 自动检测系统语言 +export function detectLocale(): Locale { + const systemInfo = Taro.getSystemInfoSync(); + const lang = systemInfo.language || 'zh-CN'; + if (lang.startsWith('en')) return 'en-US'; + if (lang.startsWith('ja')) return 'ja-JP'; + return 'zh-CN'; +} +``` + +### 10.2 多币种展示 + +```typescript +// src/utils/currency.ts +export function formatPrice(amount: number, currency: string = 'USD'): string { + const formatters: Record = { + USD: new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }), + CNY: new Intl.NumberFormat('zh-CN', { style: 'currency', currency: 'CNY' }), + JPY: new Intl.NumberFormat('ja-JP', { style: 'currency', currency: 'JPY' }), + SGD: new Intl.NumberFormat('en-SG', { style: 'currency', currency: 'SGD' }), + }; + return formatters[currency]?.format(amount) || `$${amount.toFixed(2)}`; +} +``` + +--- + +*文档版本: v2.0* *基于: Genex 券交易平台 - 软件需求规格说明书 v4.1* *技术栈: Taro 3.x + React 18 + TypeScript* +*更新: 补充多语言国际化(i18n)、多币种展示* diff --git a/docs/guides/05-后端开发指南.md b/docs/guides/05-后端开发指南.md index 4d91d3b..0ecb8bb 100644 --- a/docs/guides/05-后端开发指南.md +++ b/docs/guides/05-后端开发指南.md @@ -451,6 +451,1016 @@ spec: --- -*文档版本: v1.0* +## 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 (MVP) | 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事件订阅 + +--- + +*文档版本: v2.0* *基于: Genex 券交易平台 - 软件需求规格说明书 v4.1* *技术栈: NestJS + Go + Kong + PostgreSQL + Kafka + Redis* +*更新: 补充手续费/Breakage/退款/做市商/定价引擎/AI-ML/AML/OFAC/Travel Rule/税务/隐私/安全IR/DR/映射表安全/多币种/对账/容量规划/SDK* diff --git a/docs/guides/06-区块链开发指南.md b/docs/guides/06-区块链开发指南.md index b9ca05a..010a199 100644 --- a/docs/guides/06-区块链开发指南.md +++ b/docs/guides/06-区块链开发指南.md @@ -556,6 +556,391 @@ forge verify-contract \ --- -*文档版本: v1.0* +## 12. GNX原生代币经济模型 + +### 12.1 代币用途(MVP阶段) + +| 用途 | 说明 | MVP状态 | +|------|------|---------| +| **Gas消耗** | 支付交易费用(平台全额补贴) | 用户不接触 | +| **治理投票** | 参与链参数决策 | 仅平台内部 | +| **质押收益** | 验证节点质押获奖励 | 暂不开放 | +| **二级市场交易** | 交易所买卖GNX | 暂不开放 | + +> MVP阶段GNX仅用于Gas(平台补贴),不上交易所,回避SEC证券风险。质押开放需取得法律意见书。 + +### 12.2 代币分配(预留设计) + +``` +总供应量: 1,000,000,000 GNX +├── 平台运营/Gas补贴: 40%(4亿)— 前期Gas支出从此池扣除 +├── 团队与顾问: 20%(2亿)— 4年线性释放,1年锁定期 +├── 生态基金: 15%(1.5亿)— 开发者激励、做市商激励 +├── 未来融资预留: 15%(1.5亿)— Reg D/Reg S豁免发行 +└── 社区治理: 10%(1亿)— DAO治理基金 +``` + +### 12.3 Gas经济模型 + +```go +// genex-chain/x/evm/keeper/gas.go +// MVP阶段:Gas Price = 0,平台全额补贴 +// 后期可通过Governance合约调整Gas参数 + +func (k Keeper) GetBaseFee(ctx sdk.Context) *big.Int { + params := k.GetParams(ctx) + if params.MinGasPrice.IsZero() { + return big.NewInt(0) // 免费Gas + } + return params.MinGasPrice.BigInt() +} +``` + +--- + +## 13. Coupon合约补充 — 不可转让券 + +```solidity +// src/Coupon.sol — 补充transfer限制逻辑 +contract Coupon is ERC721Upgradeable, AccessControlUpgradeable { + mapping(uint256 => CouponConfig) private _configs; + + /// @notice 重写transfer,不可转让券直接revert + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId, + uint256 /* batchSize */ + ) internal virtual override { + // 铸造(from=0)和销毁(to=0)不受限 + if (from == address(0) || to == address(0)) return; + + CouponConfig memory config = _configs[tokenId]; + + // 不可转让券:revert + require(config.transferable, "Coupon: non-transferable"); + + // 转售次数检查 + require( + _resaleCount[tokenId] < config.maxResaleCount, + "Coupon: max resale count exceeded" + ); + } + + /// @notice 批量转移(批量P2P/批量交易) + function batchTransfer( + address from, + address to, + uint256[] calldata tokenIds + ) external { + for (uint256 i = 0; i < tokenIds.length; i++) { + safeTransferFrom(from, to, tokenIds[i]); + } + } +} +``` + +--- + +## 14. Compliance合约补充 — 差异化KYC检查 + +```solidity +// src/Compliance.sol — 补充KYC等级差异化检查 +contract Compliance is Initializable, AccessControlUpgradeable { + // KYC等级映射 + mapping(address => uint8) private _kycLevels; // 0=L0, 1=L1, 2=L2, 3=L3 + + // 不同操作要求不同KYC等级 + function requireKycLevel(address account, uint8 requiredLevel) public view { + require(_kycLevels[account] >= requiredLevel, "Compliance: insufficient KYC level"); + } + + /// @notice 交易前合规检查(Settlement调用) + function preTradeCheck( + address buyer, + address seller, + uint256 amount, + CouponType couponType + ) external view { + // OFAC黑名单检查 + require(!_blacklist[buyer], "Buyer blacklisted"); + require(!_blacklist[seller], "Seller blacklisted"); + + // Utility Track: 双方至少KYC L1 + if (couponType == CouponType.Utility) { + requireKycLevel(buyer, 1); + requireKycLevel(seller, 1); + } + // Securities Track: 双方至少KYC L2 + else { + requireKycLevel(buyer, 2); + requireKycLevel(seller, 2); + } + + // 大额交易: KYC L2+ + if (amount >= 10000e6) { // $10,000 + requireKycLevel(buyer, 2); + requireKycLevel(seller, 2); + } + + // 做市商: KYC L3 + // (做市商身份由链下服务标记,链上通过MARKET_MAKER_ROLE验证) + } + + /// @notice P2P转移合规路由 + function p2pComplianceCheck( + address sender, + address receiver, + uint256 amount + ) external { + require(!_blacklist[sender], "Sender blacklisted"); + require(!_blacklist[receiver], "Receiver blacklisted"); + + // ≥$3,000 强制Travel Rule + if (amount >= 3000e6) { + requireKycLevel(sender, 2); + requireKycLevel(receiver, 2); + // Travel Rule数据必须已记录 + require(_travelRuleRecorded[sender][receiver], "Travel Rule data required"); + } + } +} +``` + +--- + +## 15. 验证节点级交易拦截 + +```go +// genex-chain/x/evm/ante/compliance_ante.go +// 验证节点在打包交易前执行合规检查 + +type ComplianceAnteHandler struct { + ofacList map[string]bool + travelRule TravelRuleChecker +} + +func (h ComplianceAnteHandler) AnteHandle( + ctx sdk.Context, tx sdk.Tx, simulate bool, +) (sdk.Context, error) { + for _, msg := range tx.GetMsgs() { + evmMsg, ok := msg.(*evmtypes.MsgEthereumTx) + if !ok { continue } + + from := evmMsg.GetFrom() + to := evmMsg.GetTo() + + // 1. OFAC地址拦截(链级强制) + if h.ofacList[from.Hex()] || h.ofacList[to.Hex()] { + return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, + "OFAC sanctioned address, transaction rejected at validator level") + } + + // 2. Structuring检测(拆分交易规避$3,000阈值) + if h.isStructuringPattern(ctx, from, evmMsg.GetValue()) { + // 不拒绝,但标记为可疑(升级为Travel Rule流程) + ctx = ctx.WithValue("suspicious_structuring", true) + } + + // 3. Travel Rule预打包检查 + if evmMsg.GetValue().Cmp(big.NewInt(3000e6)) >= 0 { + if !h.travelRule.HasRecord(from, *to) { + return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, + "Travel Rule: identity data required for transfers >= $3,000") + } + } + } + return ctx, nil +} +``` + +--- + +## 16. Treasury合约 — 保障资金锁定 + +```solidity +// src/Treasury.sol — 补充保障资金逻辑 +contract Treasury is Initializable, AccessControlUpgradeable { + IERC20 public stablecoin; + + // 发行方保障资金(自愿缴纳,提升信用评级) + mapping(address => uint256) public guaranteeFunds; + + // 发行方冻结的销售款(自愿,作为兑付保障) + mapping(address => uint256) public frozenSalesRevenue; + + /// @notice 发行方缴纳保障资金 + function depositGuaranteeFund(uint256 amount) external { + stablecoin.transferFrom(msg.sender, address(this), amount); + guaranteeFunds[msg.sender] += amount; + emit GuaranteeFundDeposited(msg.sender, amount); + } + + /// @notice 发行方违约时启用保障资金赔付 + function activateGuaranteeFund( + address issuer, + address[] calldata claimants, + uint256[] calldata amounts + ) external onlyRole(GOVERNANCE_ROLE) { + uint256 totalClaim = 0; + for (uint256 i = 0; i < claimants.length; i++) { + totalClaim += amounts[i]; + } + require(guaranteeFunds[issuer] >= totalClaim, "Insufficient guarantee fund"); + + guaranteeFunds[issuer] -= totalClaim; + for (uint256 i = 0; i < claimants.length; i++) { + stablecoin.transfer(claimants[i], amounts[i]); + } + emit GuaranteeFundActivated(issuer, totalClaim); + } + + /// @notice 交易资金托管(原子交换中间态) + function escrow( + uint256 orderId, + address buyer, + uint256 amount + ) external onlyRole(SETTLER_ROLE) { + stablecoin.transferFrom(buyer, address(this), amount); + emit FundsEscrowed(orderId, buyer, amount); + } + + /// @notice 释放托管资金给卖方 + function release( + uint256 orderId, + address seller, + uint256 amount, + uint256 platformFee + ) external onlyRole(SETTLER_ROLE) { + stablecoin.transfer(seller, amount - platformFee); + // 平台手续费归集 + stablecoin.transfer(platformFeeCollector, platformFee); + emit FundsReleased(orderId, seller, amount); + } +} +``` + +--- + +## 17. 合约升级回滚能力 + +```solidity +// src/Governance.sol — 补充回滚能力 +contract Governance is Initializable { + // 保留前一版Implementation地址 + mapping(address => address) public previousImplementations; + + /// @notice 紧急回滚至上一版本(需4/5多签) + function rollback(address proxy) external { + require( + _getApprovalCount(currentProposalId) >= 4, + "Rollback requires 4/5 multisig" + ); + address prevImpl = previousImplementations[proxy]; + require(prevImpl != address(0), "No previous version"); + + // 执行回滚 + ITransparentUpgradeableProxy(proxy).upgradeTo(prevImpl); + emit ContractRolledBack(proxy, prevImpl); + } + + /// @notice 升级时自动记录前一版本 + function _recordPreviousImpl(address proxy, address newImpl) internal { + address currentImpl = ITransparentUpgradeableProxy(proxy).implementation(); + previousImplementations[proxy] = currentImpl; + } +} +``` + +--- + +## 18. 多稳定币支持 + +```solidity +// src/Settlement.sol — 补充多稳定币支持 +contract Settlement is Initializable, AccessControlUpgradeable { + // 支持多种稳定币 + mapping(address => bool) public supportedStablecoins; + // 默认稳定币 + address public defaultStablecoin; // USDC + + function addStablecoin(address token) external onlyRole(GOVERNANCE_ROLE) { + supportedStablecoins[token] = true; + emit StablecoinAdded(token); + } + + /// @notice 原子交换(支持指定稳定币) + function executeSwap( + uint256 tokenId, + address buyer, + address seller, + uint256 price, + address stablecoin // 买方选择的稳定币 + ) external onlyRole(SETTLER_ROLE) { + require(supportedStablecoins[stablecoin], "Unsupported stablecoin"); + + // 合规检查 + 原子交换 + // ...(同原有逻辑,使用传入的stablecoin地址) + IERC20(stablecoin).transferFrom(buyer, seller, price); + couponContract.safeTransferFrom(seller, buyer, tokenId); + } +} +``` + +--- + +## 19. Oracle集成(汇率) + +```solidity +// src/Oracle.sol — 汇率预言机集成 +interface IChainlinkPriceFeed { + function latestRoundData() external view returns ( + uint80 roundId, int256 answer, uint256 startedAt, + uint256 updatedAt, uint80 answeredInRound + ); +} + +contract ExchangeRateOracle is Initializable { + // 各币种对USD汇率Feed + mapping(string => address) public priceFeeds; + + function getRate(string calldata currency) external view returns (uint256) { + address feed = priceFeeds[currency]; + require(feed != address(0), "Unsupported currency"); + + (, int256 answer,, uint256 updatedAt,) = IChainlinkPriceFeed(feed).latestRoundData(); + // 汇率不能太旧(最多15分钟) + require(block.timestamp - updatedAt <= 900, "Stale price data"); + return uint256(answer); + } +} +``` + +--- + +## 20. 资产证券化合约预留(Phase 4) + +```solidity +// src/future/CouponBackedSecurity.sol — 预留设计 +// Phase 4: 券收益流打包为CBS(Coupon-Backed Securities) +// 仅在Securities Track + Broker-Dealer牌照后启用 + +/** + * @notice 预留接口定义,不在MVP实现 + * - 券收益流打包 + * - 信用评级接口 + * - 收益曲线计算 + */ +interface ICouponBackedSecurity { + function createPool(uint256[] calldata couponIds) external returns (uint256 poolId); + function getCreditRating(uint256 poolId) external view returns (string memory); + function getYieldCurve(uint256 poolId) external view returns (uint256[] memory); +} +``` + +--- + +*文档版本: v2.0* *基于: Genex 券交易平台 - 软件需求规格说明书 v4.1 + 技术架构开发需求 v3.0* *技术栈: Cosmos SDK + cosmos/evm + CometBFT + Solidity + Foundry* +*更新: 补充GNX代币经济/不可转让revert/差异化KYC/验证节点拦截/批量转移/Treasury保障资金/回滚能力/多稳定币/Oracle/资产证券化预留*