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 <noreply@anthropic.com>
This commit is contained in:
parent
a0d2271cd5
commit
03e5f5b3e3
|
|
@ -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隔离设计*
|
||||
|
|
|
|||
|
|
@ -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<Either<Failure, void>> call() async {
|
||||
final mnemonic = await _walletService.generateMnemonic();
|
||||
// 显示12词助记词,用户手动抄写
|
||||
// 验证确认(随机抽3个词验证)
|
||||
return _walletService.confirmBackup(mnemonic);
|
||||
}
|
||||
}
|
||||
|
||||
// 社交恢复(Guardian机制)
|
||||
class SocialRecoveryUseCase {
|
||||
/// 预设3-5个可信联系人,多数确认即可恢复
|
||||
Future<Either<Failure, void>> setupGuardians(List<String> guardianPhones) async {
|
||||
if (guardianPhones.length < 3 || guardianPhones.length > 5) {
|
||||
return Left(Failure.validation(errors: {'guardians': '需要3-5个守护人'}));
|
||||
}
|
||||
return _repo.setupSocialRecovery(guardianPhones);
|
||||
}
|
||||
|
||||
/// 发起恢复(需>50%守护人确认)
|
||||
Future<Either<Failure, void>> initiateRecovery() async {
|
||||
return _repo.initiateRecovery();
|
||||
}
|
||||
}
|
||||
|
||||
// AA钱包(ERC-4337)集成
|
||||
class AAWalletService {
|
||||
/// 邮箱/手机号作为恢复入口
|
||||
Future<void> 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<Either<Failure, DepositResult>> call(DepositParams params) {
|
||||
// 银行卡/信用卡/Apple Pay → 法币入金 → 后台转换USDC
|
||||
return _repo.deposit(params);
|
||||
}
|
||||
}
|
||||
|
||||
class WithdrawUseCase {
|
||||
Future<Either<Failure, WithdrawResult>> 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<Either<Failure, void>> 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<void> 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<String>? 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钱包/外部钱包提取/转赠记录/余额/订单/换手机号/离线核销增强/争议投诉/消息通知*
|
||||
|
|
|
|||
|
|
@ -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<TransactionEntry> entries;
|
||||
final double totalIncome;
|
||||
final double totalExpense;
|
||||
final double netBalance;
|
||||
|
||||
// 导出为CSV/PDF
|
||||
Future<File> exportAsCsv() async { /* ... */ }
|
||||
Future<File> 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<PricePoint> 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<CashFlowPoint> 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<Either<Failure, List<CouponDraft>>> batchCreate(
|
||||
List<CreateCouponParams> paramsList
|
||||
) async {
|
||||
return _repo.batchSubmitDrafts(paramsList);
|
||||
}
|
||||
|
||||
// 批量核销
|
||||
Future<Either<Failure, BatchRedeemResult>> batchRedeem(
|
||||
List<String> couponCodes
|
||||
) async {
|
||||
return _repo.batchRedeem(couponCodes);
|
||||
}
|
||||
|
||||
// 批量数据导出
|
||||
Future<File> 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<Either<Failure, RecallResult>> recallUnsold(String couponBatchId) async {
|
||||
return _repo.recallUnsoldCoupons(couponBatchId);
|
||||
}
|
||||
|
||||
/// 问题券紧急下架
|
||||
Future<Either<Failure, void>> emergencyDelist(String couponId, String reason) async {
|
||||
return _repo.delistCoupon(couponId, reason);
|
||||
}
|
||||
|
||||
/// 已售出券的退款处理
|
||||
Future<Either<Failure, void>> 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<StoreHierarchy> 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<String> 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*
|
||||
*更新: 补充保证金/冻结销售款/对账报表/二级市场分析/融资效果/退款窗口/批量操作/券召回/多门店增强/专属客服*
|
||||
|
|
|
|||
|
|
@ -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<Tax1099Report[]>;
|
||||
reviewReport: (reportId: string) => Promise<Tax1099Report>;
|
||||
submitToIRS: (reportIds: string[]) => Promise<SubmissionResult>;
|
||||
userPortalExport: (userId: string, taxYear: number) => Promise<TaxDocument>;
|
||||
}
|
||||
|
||||
// 1099报表页面
|
||||
export function Tax1099Page() {
|
||||
const [taxYear, setTaxYear] = useState(2025);
|
||||
const reports = useQuery(['tax1099', taxYear], () => taxApi.getReports(taxYear));
|
||||
|
||||
return (
|
||||
<div>
|
||||
<YearSelector value={taxYear} onChange={setTaxYear} />
|
||||
<StatsCards>
|
||||
<Card title="需生成1099" value={reports.pendingCount} />
|
||||
<Card title="已生成" value={reports.generatedCount} />
|
||||
<Card title="已提交IRS" value={reports.submittedCount} />
|
||||
</StatsCards>
|
||||
<Button onClick={() => taxApi.generateBatch(taxYear)}>批量生成1099</Button>
|
||||
<TanStackTable data={reports.data} columns={tax1099Columns} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 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 (
|
||||
<div>
|
||||
<h3>虚假宣传监控</h3>
|
||||
{/* AI自动扫描所有上架券的描述 vs 实际兑付记录 */}
|
||||
<AlertList alerts={consumerProtectionAlerts} />
|
||||
{/* 手动审查队列 */}
|
||||
<CaseQueue cases={pendingCases} onResolve={handleResolve} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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 (
|
||||
<Tabs>
|
||||
<Tab label="内部控制">
|
||||
<InternalControlMatrix />
|
||||
</Tab>
|
||||
<Tab label="合约升级日志">
|
||||
<ContractUpgradeAuditTrail />
|
||||
</Tab>
|
||||
<Tab label="链上对账">
|
||||
<ChainGaapReconciliation />
|
||||
</Tab>
|
||||
<Tab label="操作审计日志">
|
||||
<AuditLogViewer /> {/* 全链路操作日志,append-only */}
|
||||
</Tab>
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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<IssuerTier, number>;
|
||||
breakageSharePercent: number; // 平台Breakage分润比例
|
||||
}
|
||||
|
||||
// 手续费收入仪表盘
|
||||
export function FeeRevenueDashboard() {
|
||||
return (
|
||||
<div>
|
||||
<RevenueCards>
|
||||
<Card title="交易手续费" value={tradingFeeRevenue} />
|
||||
<Card title="发行服务费" value={issuanceFeeRevenue} />
|
||||
<Card title="Breakage分润" value={breakageRevenue} />
|
||||
<Card title="增值服务" value={vasRevenue} />
|
||||
</RevenueCards>
|
||||
<RevenueChart data={revenueTimeSeries} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 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 (
|
||||
<div>
|
||||
<SlaOverview />
|
||||
<DisputeList
|
||||
columns={[
|
||||
{ key: 'id', title: '工单号' },
|
||||
{ key: 'type', title: '类型' },
|
||||
{ key: 'status', title: '状态' },
|
||||
{ key: 'sla', title: 'SLA倒计时', render: (sla) => <SlaCountdown deadline={sla.resolutionDeadline} /> },
|
||||
{ key: 'actions', title: '操作', render: (_, row) => <ArbitrationActions dispute={row} /> },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 16. Web商户核销后台
|
||||
|
||||
```typescript
|
||||
// src/app/(dashboard)/merchant-redemption/page.tsx
|
||||
// 门店管理员通过浏览器核销+查看核销记录
|
||||
export default function MerchantRedemptionPage() {
|
||||
return (
|
||||
<div>
|
||||
<h2>Web端核销后台</h2>
|
||||
|
||||
{/* 输码核销 */}
|
||||
<Card title="核销券">
|
||||
<Input placeholder="输入券码" />
|
||||
<Button type="primary">查询并核销</Button>
|
||||
</Card>
|
||||
|
||||
{/* 核销记录 */}
|
||||
<Card title="核销记录">
|
||||
<DateRangePicker />
|
||||
<TanStackTable
|
||||
data={redemptionRecords}
|
||||
columns={[
|
||||
{ key: 'couponCode', title: '券码' },
|
||||
{ key: 'couponName', title: '券名' },
|
||||
{ key: 'faceValue', title: '面值' },
|
||||
{ key: 'operator', title: '核销员' },
|
||||
{ key: 'store', title: '门店' },
|
||||
{ key: 'time', title: '核销时间' },
|
||||
{ key: 'status', title: '状态' },
|
||||
]}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
{/* 门店数据汇总 */}
|
||||
<StoreRedemptionStats />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 17. 做市商管理
|
||||
|
||||
```typescript
|
||||
// src/features/trading/market-maker-management.ts
|
||||
interface MarketMakerManagement {
|
||||
marketMakers: MarketMaker[];
|
||||
obligations: MarketMakerObligation[];
|
||||
performanceMetrics: MmPerformanceMetric[];
|
||||
violationAlerts: MmViolation[];
|
||||
}
|
||||
|
||||
// 做市商活动监控页面
|
||||
export function MarketMakerMonitorPage() {
|
||||
return (
|
||||
<div>
|
||||
<h3>做市商监控</h3>
|
||||
<MmPerformanceTable data={marketMakers} />
|
||||
{/* Spoofing/Layering检测告警 */}
|
||||
<ManipulationAlerts alerts={spoofingAlerts} />
|
||||
{/* 做市义务合规检查 */}
|
||||
<ObligationComplianceCheck />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*文档版本: v2.0*
|
||||
*基于: Genex 券交易平台 - 软件需求规格说明书 v4.1*
|
||||
*技术栈: React 18 + TypeScript 5 + Next.js 14 + Zustand + Redux Toolkit*
|
||||
*更新: 补充数据报表/用户行为分析/券类别分析/1099税务/FATCA/虚假宣传监控/SOX审计/财务管理/争议仲裁/Web核销后台/做市商管理*
|
||||
|
|
|
|||
|
|
@ -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<Locale, Record<string, string>> = {
|
||||
'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<string, Intl.NumberFormat> = {
|
||||
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)、多币种展示*
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -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/资产证券化预留*
|
||||
|
|
|
|||
Loading…
Reference in New Issue