Commit Graph

1374 Commits

Author SHA1 Message Date
hailin 86461a052d feat(contracts): 合同管理功能 - 查询/下载/批量打包
新增功能:
- 合同列表查询(支持省市、状态、时间筛选)
- 单个合同 PDF 下载(支持断点续传)
- 批量下载 ZIP 打包(异步任务处理)
- 增量下载(基于上次下载时间)
- 用户详情页合同 Tab

后端:
- planting-service: 内部合同查询 API
- admin-service: 合同管理控制器、服务、批量下载 Job
- 新增 contract_batch_download_tasks 表

前端:
- 新增独立合同管理页面 /contracts
- 用户详情页新增合同信息 Tab
- 侧边栏新增合同管理入口

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 22:50:17 -08:00
hailin a1aba14ccf feat(trade-password): 实现卖出交易的支付密码验证功能
## 后端改动

### auth-service
- user.aggregate.ts: 添加支付密码相关方法 (setTradePassword, verifyTradePassword, hasTradePassword)
- trade-password.service.ts: 新建支付密码业务逻辑服务
- trade-password.controller.ts: 新建支付密码 REST API (status/set/change/verify)
- user.repository.ts: 添加 tradePasswordHash 字段的持久化
- schema.prisma: 添加 trade_password_hash 字段
- migration 0003: 添加支付密码字段迁移

### trading-service
- audit-ledger.service.ts: 新建审计分类账服务 (Append-Only设计,仅INSERT)
- schema.prisma: 添加 AuditLedger 模型和 AuditActionType 枚举
- migration 0008: 添加审计分类账表迁移

## 前端改动 (mining-app)

### 新增页面/组件
- trade_password_page.dart: 支付密码设置/修改页面 (6位数字)
- trade_password_dialog.dart: 交易时的支付密码验证弹窗

### 功能集成
- trading_page.dart: 卖出时检查支付密码
  - 未设置: 提示用户跳转设置页面
  - 已设置: 弹出验证弹窗,验证通过后才能卖出
- profile_page.dart: 账户设置增加"支付密码"入口
- user_providers.dart: 添加支付密码相关 Provider
- auth_remote_datasource.dart: 添加支付密码 API 调用
- api_endpoints.dart: 添加支付密码 API 端点
- routes.dart/app_router.dart: 添加支付密码页面路由

## 安全设计
- 支付密码独立于登录密码 (6位纯数字)
- 审计分类账采用链式哈希保证完整性
- 所有敏感操作记录不可变审计日志

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 18:12:39 -08:00
hailin d29454fc74 feat(admin-web): 省团队收益汇总明细增加来源用户列并修复账户名称显示
问题描述:
1. 省团队收益汇总的详细明细中缺少收益来源用户信息
2. 账户类型显示为数字(如7440000)而不是省名称

修改内容:

1. 后端 reward-service (reward-application.service.ts)
   - getRewardEntriesByType 方法返回值新增 sourceAccountSequence 字段
   - 该字段表示触发此收益的用户账户序列号(来自认种用户)

2. 后端 reporting-service (reward-service.client.ts)
   - RewardEntryDTO 接口新增 sourceAccountSequence 字段

3. 前端 admin-web
   - system-account.types.ts: RewardEntryDTO 新增 sourceAccountSequence 字段
   - system-account.types.ts: getAccountDisplayName 函数支持7开头的省团队账户
     示例:7440000 → "广东省团队 (7440000)"
   - SystemAccountsTab.tsx: 详细明细表格新增"来源用户"列

效果:
- 省团队收益明细现在显示:时间、账户(省名称)、来源用户、订单号、金额、状态
- 账户列显示格式:"{省名}省团队 ({账户序列号})"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:35:22 -08:00
hailin 207b522754 feat(customer-service): 客服联系方式从硬编码改为后台可配置
将 mobile-app "联系客服" 弹窗的微信/QQ联系方式从硬编码改为
admin-web 后台动态配置,支持任意数量的联系方式管理。

## Backend (admin-service)

- 新增 Prisma 模型: ContactType 枚举(WECHAT/QQ) + CustomerServiceContact
- 新增迁移 SQL: 建表 + 2条索引 + 4条种子数据(保留现有硬编码联系方式)
- 新增双 Controller (参考 app-asset.controller.ts 模式):
  - AdminCustomerServiceContactController (admin/customer-service-contacts)
    GET 列表 / POST 新增 / PUT 更新 / DELETE 删除
  - PublicCustomerServiceContactController (customer-service-contacts)
    GET 仅返回 isEnabled=true,按 sortOrder 排序
- 注意: 公开 Controller 用 @Controller('customer-service-contacts')
  避免与全局前缀 api/v1 双重叠加

## Kong 网关

- 新增路由 admin-customer-service-contacts-public
  路径 /api/v1/customer-service-contacts → admin-service:3010
- Admin 端点由已有 admin-api 路由 (/api/v1/admin) 覆盖

## Admin-web

- endpoints.ts: 新增 CUSTOMER_SERVICE_CONTACTS 端点组
- customerServiceContactService.ts: CRUD 服务 (list/create/update/delete)
- settings/page.tsx: 新增"客服联系方式管理"区块
  表格展示(排序/类型/标签/联系方式/启停/操作) + 内联新增/编辑表单
- settings.module.scss: contactTable / contactForm / contactFormFields 样式

## Flutter Mobile-app

- storage_keys.dart: 新增 cachedCustomerServiceContacts 缓存 key
- customer_service_contact_service.dart: API + 缓存服务
  (内存5分钟TTL + SharedPreferences持久化 + 后台静默刷新)
- injection_container.dart: 注册 customerServiceContactServiceProvider
- profile_page.dart: _showCustomerServiceDialog() 从硬编码改为
  动态 API 加载,contacts 为空时显示"暂无客服联系方式"占位符

## 文件清单 (4 新建 + 9 修改)

新建:
- backend/.../migrations/20260205100000_add_customer_service_contacts/migration.sql
- backend/.../controllers/customer-service-contact.controller.ts
- frontend/admin-web/src/services/customerServiceContactService.ts
- frontend/mobile-app/lib/core/services/customer_service_contact_service.dart

修改:
- backend/.../prisma/schema.prisma
- backend/.../src/app.module.ts
- backend/api-gateway/kong.yml
- frontend/admin-web/src/infrastructure/api/endpoints.ts
- frontend/admin-web/src/app/(dashboard)/settings/page.tsx
- frontend/admin-web/src/app/(dashboard)/settings/settings.module.scss
- frontend/mobile-app/lib/core/storage/storage_keys.dart
- frontend/mobile-app/lib/core/di/injection_container.dart
- frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 05:00:25 -08:00
hailin 34ba209e44 fix(app-assets): 修复公开API路径双重前缀 + Kong网关路由缺失
问题:移动端配置的开屏图/引导图无效
根因:
1. PublicAppAssetController 和 PublicSystemConfigController 的
   @Controller('api/v1/xxx') 与 NestJS 全局前缀 api/v1 叠加,
   导致实际端点为 api/v1/api/v1/xxx(双重前缀)
2. Kong 网关缺少 /api/v1/app-assets 和 /api/v1/system-config 路由
3. Flutter 端使用 /admin-service/api/v1/xxx 路径,不匹配任何 Kong 路由

修复:
- 后端:Controller 路径去掉 api/v1 前缀,由全局前缀统一添加
- Kong:新增 admin-app-assets-public 和 admin-system-config-public 路由
- Flutter:API 路径改为 /app-assets 和 /system-config/display/settings

受影响文件:
- backend/api-gateway/kong.yml (新增2条路由)
- backend/.../app-asset.controller.ts (Controller路径修正)
- backend/.../system-config.controller.ts (Controller路径修正)
- frontend/.../app_asset_service.dart (API路径修正)
- frontend/.../system_config_service.dart (API路径修正)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 04:36:53 -08:00
hailin b639b5d499 fix(mining-app): 价格显示优化 + 涨跌幅精度再提升
- 兑换页顶部价格改用 formatPriceFull 显示完整零(不再用 0.0{n} 缩写)
- K线纵坐标有效数字从7位精简为4位,节省空间更简洁
- 涨跌幅精度再提升:后端 toFixed(8)→toFixed(12),前端 6位→10位小数

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 20:43:48 -08:00
hailin 2e91686a88 fix(mining-app): 优化页面文案与涨跌幅精度
- 兑换页顶部隐藏价格后方"积分值"文字,界面更简洁
- 兑换页"较上线首日"涨跌幅精度从2位小数提升至6位,每分钟销毁引起的涨幅尾数可见
- 兑换页"黑洞销毁量"文案改为"已销毁量",更直观易懂
- 贡献值页"积分股池实时余量"文案改为"100亿销毁剩余量"
- 后端 priceChangePercent 精度从 toFixed(2) 提升至 toFixed(8),支持前端高精度显示

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 20:23:59 -08:00
hailin 59acea33fe feat(trading): K线图增加周/月/年周期
- 前端周期选项增加「周」「月」「年」
- 后端 parsePeriodToMinutes 增加 1w/1M/1y 映射
- getPeriodStart 对日历周期按自然边界对齐:
  - 1w → 周一 00:00 UTC(ISO 周标准)
  - 1M → 月初1日 00:00 UTC
  - 1y → 年初1月1日 00:00 UTC
- 固定周期(1m~1d)仍使用 epoch 模运算,不受影响

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 18:42:38 -08:00
hailin c24f383501 fix(trading): K线Y轴动态缩放 + 价格显示格式统一 + 首日涨幅修复
- K线图Y轴改为只基于可见K线计算范围,实现动态缩放(类似TradingView)
- 价格显示统一使用 0.0{n}xxx 格式替代科学计数法,覆盖全局 formatPrice、
  K线图、交易记录页、挖矿记录页
- 修复"较上线首日"百分比始终显示 +0.00% 的问题:getFirstSnapshot 过滤
  price=0 的早期快照

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 18:36:26 -08:00
hailin d075853a7f feat(app-assets): 应用图片管理 — 开屏图/引导图可从 admin-web 配置
新增从 admin-web 后台管理开屏图(2张)和引导图(5张+标题/副标题)的完整功能链路。
移动端优先使用后台配置的远程图片,无配置或加载失败时自动回退到本地 asset。

### Backend (admin-service)
- Prisma schema 新增 AppAssetType 枚举 + AppAsset 模型 (type/sortOrder 唯一约束)
- 新增 AdminAppAssetController: 图片上传(multipart)、列表查询、元数据更新、删除
- 新增 PublicAppAssetController: 公开查询接口供移动端消费 (仅返回 isEnabled=true)
- 新增数据库 migration: 20260204100000_add_app_assets

### Admin-web
- endpoints.ts 新增 APP_ASSETS 端点组
- 新增 appAssetService.ts: list/upload/update/delete 方法
- Settings 页新增"应用图片管理"区块: 开屏图 2 卡槽 + 引导图 5 卡槽
- 每个卡槽支持: 图片上传预览、启用/禁用开关、删除、引导图额外支持标题和副标题编辑

### Mobile-app (Flutter)
- 新增 AppAssetService: 3 级缓存策略 (内存 5min TTL → SharedPreferences → 后台静默刷新)
- splash_page.dart: 支持远程开屏图 (CachedNetworkImage),fallback 到本地 asset
- guide_page.dart: 支持远程引导图+标题/副标题覆盖,fallback 到本地 asset
- 替换 2 张开屏图为新版 (1280x1826/1834, ~245KB)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 11:20:26 -08:00
hailin c7978f6fb5 fix(mining-wallet-service): pool-account GET :type 改为 @Public() 允许内网服务间调用
mining-admin-service 通过 fetch 查询余额时无 token,@AdminOnly() 导致 401,UI 始终显示 0.00

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 09:21:39 -08:00
hailin 17ecc9954f fix(admin-service): 认种筛选改用 PlantingOrderQueryView 实时查询
UserQueryView.personalAdoptionCount 预计算字段未被事件同步更新(始终为 0),
导致前端选"已认种"后查不到数据。

修复:认种数过滤(minAdoptions/maxAdoptions)不再查 UserQueryView 的
stale 字段,改为实时 groupBy 查询 PlantingOrderQueryView
(status='MINING_ENABLED'),与 getBatchUserStats 展示数据源保持一致。

- 已认种(minAdoptions>=1):accountSequence IN 有订单的集合
- 未认种(maxAdoptions=0):accountSequence NOT IN 有订单的集合

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 08:09:12 -08:00
hailin 126169c631 fix(injection): findUnique 改为 findFirst 避免命名唯一索引类型错误
Prisma @@unique 单字段命名索引 uk_adoption_id 的 TypeScript 类型
与 findUnique where 输入不兼容(TS2322)。改用 findFirst + where
字段查询,走同一个唯一索引,性能相同。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 06:14:13 -08:00
hailin 1baed76d8e fix(injection): docker-compose 添加注入钱包环境变量 + 未配置时不启用消费者
问题:
  .env 配置了 FUSDT_INJECTION_WALLET_USERNAME 和 FUSDT_INJECTION_WALLET_ADDRESS,
  但 docker-compose.2.0.yml 没有将这两个变量传入容器,导致容器内 process.env
  拿不到值,Adoption Injection Consumer 启动后报错。

修复:
  1. docker-compose.2.0.yml: 添加 FUSDT_INJECTION_WALLET_USERNAME/ADDRESS
     和 CDC_TOPIC_CONTRIBUTION_OUTBOX 环境变量传递
  2. AdoptionInjectionConsumerService: onModuleInit 检查钱包是否配置,
     未配置时跳过 Kafka 连接(不浪费消费者组资源)
  3. AdoptionInjectionHandler: 检查 Consumer 是否启用,未启用时不注册

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 06:08:48 -08:00
hailin c93eeba79a fix(injection): findUnique 使用命名唯一索引 uk_adoption_id
Prisma 的 @@unique 使用自定义名 "uk_adoption_id" 后,
findUnique 的 where 必须用 { uk_adoption_id: { adoptionId } }
而非 { adoptionId },否则报 PrismaClientValidationError。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 06:05:26 -08:00
hailin 8980a169ed fix(trading): 修复做市商吃单扣款金额错误(使用交易总额而非原始数量×价格)
问题:
  做市商吃单时,buyerPayAmount = tradeQuantity × price(原始数量×价格),
  未计入销毁倍数。例如:卖出 697.81 积分股,销毁倍数 5000.88,
  交易总额 = 17,615.96 积分值,但做市商只被扣了 697.81 × 0.005 = 3.49。
  10% 手续费(1,761.60)反而大于做市商支出,导致做市商不减反增。

修复:
  - 做市商吃单时:actualBuyerCost = sellerGrossAmount(含销毁倍数的交易总额)
  - 普通用户买入时:actualBuyerCost = buyerPayAmount(原始数量×价格,不变)
  - frozenCash 仍释放下单时冻结的原始金额(buyerPayAmount)
  - 做市商交易流水记录 assetType=CASH + 实际支付金额

做市商吃单扣款计算(修复后):
  MM 支出 = sellerGrossAmount(交易总额)
  MM 手续费收入 = tradeFee(10%)
  MM 净支出 = sellerReceiveAmount = 交易总额 × 90%

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 05:56:12 -08:00
hailin 000e8f7ef1 fix(trading): 修复积分股重复记账,做市商吃单积分股只进流通池
问题:
  之前所有卖出成交时,积分股同时记入了买方账户和流通池,
  导致同一笔积分股被重复计入两处(双重记账)。

修复:
  - 做市商吃单时:积分股只进入流通池,不增加做市商 shareBalance
    (目前不允许做市商挂卖单,做市商不需要持有积分股)
  - 普通用户买入时:积分股直接进入买方账户,不再重复计入流通池
  - 将 mmConfig 查询提到循环外复用,去掉循环内冗余查询

积分股流向(修复后):
  做市商吃单: 卖方 -X → 流通池 +X(做市商 shareBalance 不变)
  用户间交易: 卖方 -X → 买方 +X(流通池不变)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 05:47:16 -08:00
hailin 4817d92507 feat(adoption-injection): 认种自动 fUSDT 注入做市商钱包 + CDC outbox 修复
## contribution-service 改动

### 1. CDC Outbox 实时发布修复
- adoption-synced.handler: handleCreate/handleUpdate 在同步数据后立即写入
  AdoptionSynced outbox 事件,确保 mining-admin-service 实时接收认种同步
- referral-synced.handler: 同理,写入 ReferralSynced outbox 事件
- 之前只有手动调用 /admin/adoptions/publish-all 才会创建 outbox 事件

### 2. 认种 fUSDT 注入事件
- 新增 AdoptionFusdtInjectionRequestedEvent 事件类
  - 当认种状态变为 MINING_ENABLED 时触发
  - 写入 outbox,topic: contribution.adoptionfusdtinjectionrequested
  - payload 含: adoptionId, accountSequence, treeCount, adoptionDate, amount
  - 转账金额 = treeCount × 5760 fUSDT

## mining-blockchain-service 改动

### 3. fUSDT 注入钱包 MPC 签名支持
- mpc-signing.client: 新增 FUSDT_INJECTION_WALLET_USERNAME/ADDRESS 配置
  isFusdtInjectionConfigured(), signMessageAsFusdtInjection() 等方法
- erc20-transfer.service: IMpcSigningClient 接口增加注入钱包方法
  新增 transferFusdtAsInjectionWallet() 转账方法(含余额检查、MPC签名、广播)

### 4. 认种注入 Kafka 消费者
- adoption-injection-consumer.service: 订阅 cdc.contribution.outbox
  过滤 AdoptionFusdtInjectionRequested 事件,解析 Debezium 扁平化消息格式
- adoption-injection.handler: 处理注入事件
  - 幂等性检查(已确认的跳过)
  - 写入 adoption_injection_records 分类账(PROCESSING 状态)
  - 从注入钱包转 fUSDT 到做市商钱包
  - 成功: markConfirmed (txHash, blockNumber, gasUsed)
  - 失败: markFailed (errorMessage),支持重试
  - 发布 confirmed/failed Kafka 事件

### 5. 分类账持久化
- Prisma schema: 新增 AdoptionInjectionRecord 模型 (adoption_injection_records 表)
  字段: adoption_id, account_sequence, tree_count, adoption_date, from/to_address,
  amount, chain_type, tx_hash, block_number, gas_used, memo, status, error_message
  索引: uk_adoption_id (唯一), idx_injection_account, idx_injection_status 等
- migration: 20250203000000_add_adoption_injection_records
- Repository 接口 + 实现: save, findByAdoptionId, markConfirmed, markFailed

### 6. 启动余额检查
- main.ts: 启动时异步查询注入钱包 fUSDT 余额,余额为 0 时输出警告日志
  新增注入钱包配置验证

## 部署前需添加环境变量 (.env)
FUSDT_INJECTION_WALLET_USERNAME=wallet-bff20b69
FUSDT_INJECTION_WALLET_ADDRESS=0x7BDB89dA47F16869c90446C41e70A00dDc432DBB

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 05:25:56 -08:00
hailin 4a69fdd070 fix(trading): getConfig 自动从环境变量填充空的钱包地址
之前只有 initializeConfig 会读取 env 填充钱包地址,
getConfig 只读数据库。导致新增 eusdtWalletAddress 字段后
即使 .env 配置了地址,前端仍显示"未配置"。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 04:09:00 -08:00
hailin 2192f5e917 fix(trading): 修复迁移表名 MarketMakerConfig → market_maker_configs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 03:50:52 -08:00
hailin ebe7123583 feat(market-maker): 积分股(eUSDT)和积分值(fUSDT)使用独立 MPC 钱包
- Prisma: MarketMakerConfig 新增 eusdt_wallet_address 字段
- 后端: 初始化/更新配置时读取 EUSDT_MARKET_MAKER_ADDRESS 环境变量
- 后端: getConfig API 返回 eusdtWalletAddress
- 前端: 积分股充值弹窗使用 eusdtWalletAddress (不再共用 kavaWalletAddress)
- 前端: 积分值充值弹窗继续使用 kavaWalletAddress (fUSDT 钱包)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 03:39:54 -08:00
hailin 38ee808239 fix(wallet): 池余额不足时跳过 Kafka 消息,避免无限重试
BurnConsumer 和 MiningDistributionConsumer 在池余额为 0 时抛出
Insufficient pool balance 错误导致 offset 不提交,造成无限重试。
现改为记录 warn 日志并标记事件为已处理(带 :skipped:insufficient_balance 标记)。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 03:28:34 -08:00
hailin 8cfd107a92 refactor(pool-accounts): 移除硬编码钱包名,改为从后端 API 动态获取
- 后端: 新增 GET /admin/pool-accounts 接口,返回从 .env 配置的池账户列表
- 前端: 新增 usePoolAccounts hook,动态渲染池账户卡片
- 前端: 提取 PoolAccountCard 子组件,消除重复代码
- 移除前端硬编码的 BURN_POOL_WALLET_NAME / MINING_POOL_WALLET_NAME 常量

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 02:57:40 -08:00
hailin 7972163af6 fix(docker): 移除池账户钱包硬编码默认值,改为从 .env 读取
所有池账户钱包配置(USERNAME/ADDRESS)不再有硬编码默认值,
必须在 .env 中配置才会生效。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 02:54:00 -08:00
hailin c89c8769d9 fix(docker): 设置池账户钱包地址默认值
从 .env.example 获取池账户 MPC 钱包地址作为 docker-compose 默认值:
- BURN_POOL_WALLET_ADDRESS: 0xdE2932D2A25e1698c1354A41e2e46B414C46F5a1
- MINING_POOL_WALLET_ADDRESS: 0x8BC9091375ae8ef43ae011F0f9bAf10e51bC9D59

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 02:48:58 -08:00
hailin a8098d801b fix(docker): 添加池账户 MPC 钱包环境变量到 mining-blockchain-service
为100亿销毁池和200万挖矿池添加 BURN_POOL_WALLET_USERNAME/ADDRESS
和 MINING_POOL_WALLET_USERNAME/ADDRESS 环境变量配置。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 02:42:55 -08:00
hailin a5f6b23a95 feat(pool-account): 池账户充值弹窗新增中心化充值 tab
与做市商管理一致,充值弹窗包含"中心化充值"和"区块链充值"两个 tab。
中心化充值直接调整池账户余额(ADJUSTMENT 类型分类账),无需区块链交易。

变更:
- wallet-service: pool-account.service 新增 centralizedDeposit 方法
- wallet-service: pool-account.controller 新增 POST /centralized-deposit
- admin-service: pool-account.controller 新增 POST /:walletName/centralized-deposit 代理
- frontend: configs.api + use-configs hook + configs page 充值弹窗 Tabs UI

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 02:26:31 -08:00
hailin c51539e494 fix(docker): 补充 mining-admin-service 池账户相关环境变量
添加 MINING_WALLET_SERVICE_URL、MINING_BLOCKCHAIN_SERVICE_URL、
BURN_POOL_WALLET_USERNAME、MINING_POOL_WALLET_USERNAME 到
docker-compose.2.0.yml 的 mining-admin-service 配置中。

缺少这些变量导致池账户 API 的 walletName→poolType 映射为空,
返回 400 Bad Request。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 02:18:35 -08:00
hailin 46f85b13b0 fix(pool-account): 修复 seed.ts 覆盖池余额 + 激活挖矿前校验池余额
1. seed.ts upsert 的 update 子句移除 balance/targetBurn/remainingBurn,
   避免重新部署时将已有池余额清零(导致 BurnConsumer 和
   MiningDistributionConsumer 因余额不足崩溃)
2. activateMining 激活前检查 SHARE_POOL_A/B 余额,任一为0则阻止激活
   并返回 400 错误提示先通过区块链充值

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 02:00:59 -08:00
hailin 4f5b18be48 feat(pool-account): 实现池账户区块链充值检测和提现功能
为100亿销毁池和200万挖矿池实现完整的区块链充值/提现流程:
- 充值:独立扫描器检测 fUSDT 转入 → Kafka 事件 → wallet-service 入账
- 提现:前端 → admin-service 代理 → blockchain-service MPC签名转账 → wallet-service 记账

mining-blockchain-service:
- 新增 PoolAccountDeposit/PoolAccountBlockCheckpoint Prisma 模型
- 新增 PoolAccountDepositDetectionService(每5秒扫描 fUSDT 充值,每30秒更新确认数)
- 扩展 MPC 签名客户端支持 burnPool/miningPool 2-of-3 门限钱包
- 扩展 ERC20TransferService 支持池账户 fUSDT 转账
- 新增 API: POST /transfer/pool-account, GET /pool-accounts/:poolType/wallet-info
- 新增 Kafka topic 映射: pool_account.deposit.confirmed → pool_account.deposits

mining-wallet-service:
- TransactionType 枚举新增 BLOCKCHAIN_DEPOSIT/BLOCKCHAIN_WITHDRAW
- Seed: SHARE_POOL_A/B 初始余额改为0(完全靠链上充值)
- PoolAccountService 新增 blockchainDeposit()/blockchainWithdraw() 方法
- 新增 PoolAccountDepositConsumer 监听 Kafka 充值确认事件(Redis+DB 双重幂等)
- 新增 POST /pool-accounts/blockchain-withdraw 内部 API

mining-admin-service:
- 新增 PoolAccountController 代理到 wallet-service + blockchain-service
- GET /admin/pool-accounts/:walletName/balance(并行查询链下余额+链上钱包信息)
- POST /admin/pool-accounts/:walletName/blockchain-withdraw(先链上转账再记账)
- 新增配置: MINING_WALLET_SERVICE_URL, MINING_BLOCKCHAIN_SERVICE_URL, 池钱包用户名

frontend (mining-admin-web):
- 池账户 API 从 tradingClient (→trading-service) 改为 apiClient (→admin-service)
- 移除未使用的 tradingClient 和 axios 依赖

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 01:34:06 -08:00
hailin 4d2bcc7568 fix(mining-admin): 池账户钱包配置移到后端 .env,前端从 API 读取
做市商的 kavaWalletAddress 是后端 API 返回的,池账户应该一样。

- 后端 mining-blockchain-service/.env.example: 新增
  BURN_POOL_WALLET_USERNAME/ADDRESS 和
  MINING_POOL_WALLET_USERNAME/ADDRESS(同做市商钱包配置模式)
- 前端 .env.production: 移除 NEXT_PUBLIC_BURN/MINING_POOL 变量
- 前端 configs/page.tsx: 钱包地址改从 API 响应
  (poolAccountBalance.walletAddress) 读取,未配置时显示提示

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 00:14:38 -08:00
hailin 999d0389b3 refactor(trading): 价格数据源从 SharePool 切换到做市商 cashBalance
积分股价格公式中的"绿积分"(分子)本质上就是做市商的积分值余额,
SharePool 是多余的抽象层。此次改动将价格计算的数据源从独立的
SharePool 表切换到做市商的 TradingAccount.cashBalance。

主要变更:
- price.service.ts: 通过 PrismaService 直接读取做市商 cashBalance
  作为价格公式的分子(绿积分),移除 SharePoolRepository 依赖
- asset.service.ts: getMarketOverview() 同步切换数据源
- order.service.ts: 10%交易手续费从 sharePoolRepository.feeIn()
  改为 increment 回做市商的 TradingAccount,手续费自然留存在池中
- burn.service.ts: 移除 SharePool 初始化逻辑和依赖
- infrastructure.module.ts: 移除 SharePoolRepository 注册和导出
- seed.ts: 移除 SharePool 57.6亿初始化

价格公式、10%手续费扣除、销毁机制均保持不变,仅切换数据源。
SharePool 表和 repository 文件保留在磁盘上供历史数据参考。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 23:13:59 -08:00
hailin 14e70b56bb fix(c2c-bot): 水单完成时间转换为北京时间 (UTC+8)
问题:水单上的完成时间显示 UTC 时间(如 03:38:40),实际北京时间为 11:38:40。
原因:toISOString() 始终返回 UTC 时间。
修复:手动加 8 小时偏移量,将 UTC 转换为北京时间后再格式化。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 19:42:13 -08:00
hailin bf11a269a4 fix(c2c-bot): 水单移除交易哈希,仅保留在分类账中
水单图片不再显示交易哈希(txHash),减少对终端用户暴露的链上细节。
txHash 仍保留在 ProofData 接口和数据库中,供分类账和审计使用。
同时缩小 SVG 高度(480→420)并重新排列剩余字段。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 19:35:48 -08:00
hailin 0fe0f3b72a fix(c2c-bot): 水单显示优化:dUSDT→绿积分,收款地址→对方ID
水单图片调整:
- "支付金额 (dUSDT)" → "支付金额 (绿积分)"
- "收款地址"(显示 Kava 地址)→ "对方ID"(显示卖家账户 ID)
- ProofData 接口新增 sellerId 字段(来自 order.makerAccountSequence)
- sellerAddress 仍保留在数据结构中,供明细分类账使用

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 19:24:02 -08:00
hailin 7ee6d633c6 fix(kafka): 修复 MPC Kafka consumer 启动订阅失败后不重试的问题
问题现象:
- blockchain-service 启动时 Kafka consumer subscribe() 抛出
  "This server does not host this topic-partition" 错误
- 原实现只 try-catch 一次就放弃,consumer 永久失效
- 后续所有 MPC 签名结果都收不到,表现为 signing timeout 300s
- 需要手动 docker restart 才能恢复

根因分析:
- 服务启动时 Kafka broker 可能尚未完成 topic-partition 分配
  (特别是容器编排环境中服务启动顺序不确定)
- onModuleInit() 中的 connect/subscribe/run 是一次性调用
- KafkaJS 的 retry 配置只作用于内部操作,不覆盖初始连接流程

修复方案:
- 新增 connectWithRetry() 方法:指数退避重试(2s→4s→8s→...→60s)
  最多 10 次,总等待约 5 分钟
- 每次重试前断开连接清理状态,避免 KafkaJS 内部状态残留
- 监听 consumer CRASH 事件:当 KafkaJS 不自动重启时(restart=false)
  手动触发 connectWithRetry() 重连
- 新增 isShuttingDown 标志:防止 onModuleDestroy 时触发无意义的重连
- 同时修复 blockchain-service 和 identity-service 两个 consumer

影响范围:
- blockchain-service: 影响 MPC 签名结果接收(热钱包转账)
- identity-service: 影响 MPC 密钥生成结果接收(用户钱包创建)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 19:18:10 -08:00
hailin 2de4baf0af fix(c2c-bot): 安装中文字体解决水单图片乱码问题
Alpine Linux 容器没有中文字体,sharp 渲染 SVG 时中文显示为方块。
- Dockerfile: 安装 fontconfig + font-noto-cjk 并刷新字体缓存
- SVG 模板: font-family 改为 Noto Sans CJK SC

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 18:56:55 -08:00
hailin 21f51c5d84 fix(c2c-bot): 修复 sharp 导入方式,解决水单生成 is not a function 错误
NestJS 使用 CommonJS 模块系统,`import sharp from 'sharp'` 编译后
生成 `sharp_1.default` 调用,但 sharp 没有 default export。
改为 `import * as sharp from 'sharp'` 修复。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 18:47:38 -08:00
hailin eab61abace feat(c2c-bot): 顺序处理订单 + 自动生成付款水单图片
1. 顺序处理订单:
   - Scheduler 每个10s周期只处理1个卖单(原先最多10个)
   - 移除 for 循环,确保完成一个订单后再处理下一个
   - 分布式锁 TTL 从 8s 增加到 30s,留足链上转账时间

2. 付款水单自动生成:
   - 新增 PaymentProofService,使用 SVG 模板 + sharp 转 PNG
   - 水单包含:订单号、支付金额、交易哈希、收款地址、完成时间
   - Bot 完成转账后自动生成水单并调用 updatePaymentProof 更新订单
   - 水单生成失败不影响订单本身(try-catch 保护)

文件变更:
- package.json: 添加 sharp ^0.33.2 依赖
- c2c-bot.scheduler.ts: 限制每周期1单,增加锁时间
- payment-proof.service.ts: 新文件,SVG→PNG 水单生成服务
- application.module.ts: 注册 PaymentProofService
- c2c-bot.service.ts: 注入 PaymentProofService,步骤5生成水单

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 18:32:52 -08:00
hailin 7a1d438f84 fix(mpc): 去除 message_hash 的 0x 前缀,修复 MPC 签名 400 错误
MPC account-service 期望纯 hex 格式的 message_hash,不接受 0x 前缀。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 18:15:40 -08:00
hailin cb8c69788b fix(deploy): curl -s 改为 curl -sf,修复 HTTP 404 不被检测的问题
curl -s 只是静默输出,HTTP 404 仍然返回 exit code 0,导致就绪
检查在 Kafka Connect REST API 未初始化完时就通过了。
-f 标志让 curl 在 HTTP 4xx/5xx 时返回非零 exit code。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 10:30:37 -08:00
hailin d8ef156b5e fix(debezium): 修复 authorization connector 凭据和注册重试逻辑
- authorization-connector.json: 将硬编码的 debezium/debezium_password
  改为 ${POSTGRES_USER}/${POSTGRES_PASSWORD} 占位符,与其他 connector 一致
- register-connectors.sh: 添加 3 次重试逻辑,应对 Kafka Connect REST API
  初始化期间的间歇性 404

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 10:28:52 -08:00
hailin 5b3c391340 fix(infra): 添加 Zookeeper 数据持久化卷,修复 Kafka Cluster ID 冲突
Kafka 有持久化卷但 Zookeeper 没有,导致 down/up 后 ZK 生成新的
Cluster ID,与 Kafka meta.properties 中的旧 ID 冲突。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 10:25:14 -08:00
hailin d575287713 fix(deploy): 修复 deploy.sh Debezium connector 注册失败的问题
根因:就绪检查只检测 Jetty 根路径 /,但 Kafka Connect REST API
(/connectors) 需要更长时间初始化,导致注册时返回 404。

- deploy.sh: 就绪检查改为 /connectors,等待时间从 60s 增加到 120s
- deploy.sh: 删除 250 行硬编码的 connector 配置,改为调用
  register-connectors.sh(单一数据源,JSON 文件)
- register-connectors.sh: 同步修复就绪检查

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 10:22:04 -08:00
hailin 6f668d69bd fix(infra): 添加 Kafka 数据持久化卷,防止容器重建后 Debezium connector 丢失
根因:Kafka 没有配置数据卷,容器重建后 debezium_configs/offsets 等内部
topic 丢失,导致 connector 注册信息消失。新 snapshot 的 offset 与旧
processed_events 碰撞,CDC 数据被跳过。

- docker-compose.yml: 添加 kafka_data 命名卷挂载到 /var/lib/kafka/data
- register-connectors.sh: 添加环境变量替换、幂等注册、--force/--1.0/--2.0 参数

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 10:16:07 -08:00
hailin 0f3d03d832 fix(wallet-service): 修复提现失败时不写 UNFREEZE ledger 流水的 bug
问题描述:
withdrawal-status.handler.ts 的 executeWithdrawalFailed() 方法在处理
提现失败事件时,虽然正确地将冻结余额退回到可用余额(usdt_frozen → usdt_available),
但没有在 wallet_ledger_entries 表中写入 UNFREEZE 类型的流水记录,导致审计缺口。

对比 system-withdrawal-application.service.ts 中的同名方法 handleWithdrawalFailed(),
后者在退回余额时正确地写入了 UNFREEZE ledger entry。两者逻辑应保持一致。

影响范围:
所有通过 blockchain-service Kafka 事件触发的提现失败场景(包括链上提现和内部转账),
余额变动不会被记录到流水表中,无法审计追踪。

修复内容:
在 wallet_accounts 余额更新成功后,新增 tx.ledgerEntry.create() 调用,
写入 UNFREEZE 类型的流水记录,包含:
- amount: 实际退回金额(newAvailable - currentAvailable,兼容冻结不足的边缘情况)
- memo: "提现失败退款: {error}"
- payloadJson: toAddress, chainType, error 便于排查

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 09:13:40 -08:00
hailin 758babfdf8 fix(blockchain+trading): 修复做市商区块链充值无法入账的三个 bug
1. OutboxPublisherService 未注册到 NestJS 模块,导致充值确认事件永远
   停留在 outbox_events 表 PENDING 状态,无法发布到 Kafka
2. trading-service 消费者监听的 Kafka topic 和 event type 与发布端不匹配
   (blockchain.market_maker.deposits → mining_blockchain.market_maker.deposits)
3. 消费者只更新 market_maker_config 余额,但 API 从 trading_accounts 读取
   余额,导致入账后前端仍显示 0

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 03:30:30 -08:00
hailin fe6c1b3fce fix(mining-admin-service): 修复 manual-mining 分页参数 NaN 问题
NestJS transform 会将缺失的 query 参数转为 NaN,
而 NaN ?? 1 仍然是 NaN。改用 Number(page) || 1 确保默认值生效。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 02:37:55 -08:00
hailin 3bce996dd3 fix(mining-admin-service): 修复 manual-mining 和 pending-contributions 内部调用 URL
这两个 service 调用 mining-service 时缺少 /api/v2/mining 前缀,
导致请求到达 mining-service 后 404。

修复前: ${miningServiceUrl}/admin/manual-mining/records
修复后: ${miningServiceUrl}/api/v2/mining/admin/manual-mining/records

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 02:24:00 -08:00
hailin 59efdb1f78 fix(mining-admin-web): 修复 API 请求超时和路由问题
问题:
- mining-admin-web 容器与后端服务在不同 Docker 网络, 无法通过公网 IP 回连 (hairpin NAT 失败)
- next.config.js 生产模式强制走 mapi.szaiai.com Kong 网关, 容器内无法访问
- client.ts 使用 NEXT_PUBLIC_API_URL 导致外部 URL 被 build 时内联到客户端包
- mining-service controller 有 mining/ 前缀, 直连模式 rewrite 丢失该前缀

修复:
- next.config.js: 改用 API_GATEWAY_URL 判断路由模式, 未设置则直连后端服务
- next.config.js: mining rewrite 保留 mining/ 前缀匹配 controller 路由
- client.ts: baseURL 固定为 /api, 所有请求统一走 Next.js rewrite 代理
- docker-compose.2.0.yml: 添加 TRADING_SERVICE_URL 和 MINING_SERVICE_URL 环境变量

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 01:14:19 -08:00
hailin 6443acf34a fix(deploy-mining): cdc-resnapshot 支持 standalone 模式远程操作 1.0 Debezium
standalone 模式下 source CDC connectors 在 1.0 服务器 (192.168.1.111:8084),
cdc-resnapshot 需要指向 1.0 Debezium 才能删除并重建 connector 触发全量快照。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 23:42:53 -08:00
hailin 0204f748e6 fix(debezium): outbox connector 配置支持 standalone 模式 (postgres-2)
- database.hostname 从硬编码 "postgres" 改为 ${DEBEZIUM_DB_HOST:-postgres}
- database.user/password 改为环境变量替换 ${POSTGRES_USER}/${POSTGRES_PASSWORD}
- standalone 模式设置 DEBEZIUM_DB_HOST=postgres-2
- shared 模式不设置,默认值 postgres 保持不变

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 23:01:45 -08:00
hailin 2a5b51aa8d fix(deploy-mining): ensure_kafka_image 输出到 stderr 避免被 $() 捕获
docker pull 在 group_info=$(run_kafka_cmd ...) 内执行时,stdout 被命令替换
捕获到变量中,屏幕无任何输出导致脚本看起来卡住。
- ensure_kafka_image 输出重定向到 stderr
- full_reset 开头显式预拉取镜像

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 22:42:42 -08:00
hailin 0156be8d25 fix(deploy-mining): 预拉取 Kafka CLI 镜像避免 timeout 期间拉取失败
standalone 模式下 run_kafka_cmd 使用 docker run confluentinc/cp-kafka:7.5.0,
首次运行时镜像未缓存导致 docker pull 被 timeout 30 截断,循环重试卡住。
添加 ensure_kafka_image() 在执行命令前先确保镜像已拉取。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 22:36:38 -08:00
hailin d53c2212a6 fix(deploy-mining): 修复 standalone 模式跨服务器 full-reset 卡住问题
- run_kafka_cmd 添加 timeout 30 防止跨服务器 Kafka 命令无限挂起
- CDC consumer offset 重置前先检查 group 是否存在,不存在则跳过
- 等待时间从 15s/20s 增加到 30s(匹配 KafkaJS 默认 sessionTimeout)
- max_retries 从 3 增加到 5,并输出实际 Kafka 错误信息
- 重试失败后 fallback 删除 consumer group(服务重启时自动重建)
- 同步修复 sync_reset() 和 full_reset() Step 3/Step 8 三处逻辑

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 22:33:28 -08:00
hailin 88ad3ab53d feat: 2.0 API 域名从 rwaapi.szaiai.com 迁移到 mapi.szaiai.com
- mining-admin-web: .env.production, next.config.js fallback URL
- mining-app: environment.dart baseUrl, update_config.dart checkUpdateUrl
- docker-compose.2.0.yml: mining-admin-service UPLOAD_BASE_URL

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 21:58:03 -08:00
hailin ec73541fe1 refactor(mining-blockchain): 移除 mpc-service 依赖,改为 HTTP 直调 mpc-system
将 mining-blockchain-service 的 MPC 签名通信从 Kafka 事件驱动(经由 mpc-service 中转)
改为 HTTP 直接调用 mpc-system 的 account-service (port 4000)。

## 核心变更

### mpc-signing.client.ts (重写)
- 移除 EventPublisherService、MpcEventConsumerService 依赖和 pendingRequests Map
- 移除 OnModuleInit 中的 Kafka 事件注册
- 新增 HttpService (@nestjs/axios) + JwtService (@nestjs/jwt) 依赖注入
- 签名流程改为:
  1. POST /api/v1/mpc/sign → 创建签名会话 (snake_case: username, message_hash)
  2. GET /api/v1/mpc/sessions/{session_id} → 轮询结果 (每 2s, 最多 5 分钟)
- JWT 认证: 使用 MPC_JWT_SECRET (HS256) 生成 Bearer token,匹配 mpc-system 格式
- 所有公共接口不变 (signMessage, signMessageAsXxxMarketMaker, isConfigured, getXxxAddress 等)

### 删除的文件
- mpc-event-consumer.service.ts: Kafka MPC 事件消费者 (SigningCompleted/SessionFailed/KeygenCompleted)
- mpc-keygen-completed.handler.ts: Keygen 地址派生处理器 (不再由此服务处理)

### 模块更新
- infrastructure.module.ts: 移除 MpcEventConsumerService,新增 JwtModule.register({})
- kafka/index.ts: 移除 mpc-event-consumer.service 导出
- event-handlers/index.ts: 移除 mpc-keygen-completed.handler 导出

### 部署配置
- docker-compose.2.0.yml: 新增 MPC_ACCOUNT_SERVICE_URL 和 MPC_JWT_SECRET 环境变量
- deploy-mining.sh: standalone 模式新增 export MPC_ACCOUNT_SERVICE_URL (默认 http://192.168.1.111:4000)

## 不受影响的部分
- Erc20TransferService / MpcTransferInitializerService 调用方式不变
- EventPublisherService (用于其他事件) 不变
- WithdrawalEventConsumerService 不变
- mpc-system 本身零修改

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 20:53:35 -08:00
hailin c657bf6e2b revert: 撤回 mpc-service HTTP 调用方案,改为直接调用 mpc-system
Revert "fix(deploy): export MPC_SERVICE_URL in standalone mode"
Revert "refactor(mining-blockchain): replace Kafka MPC signing with HTTP direct calls"

将改为直接调用 mpc-system (Go TSS 后端) 的 API,跳过 mpc-service 中间层。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 20:33:39 -08:00
hailin 3102f3e7fb fix(deploy): export MPC_SERVICE_URL in standalone mode
In standalone mode, mpc-service runs on the 1.0 server (192.168.1.111),
not in the local Docker network. The default docker-compose value
http://mpc-service:3006 won't resolve. Export MPC_SERVICE_URL pointing
to the 1.0 server's IP so mining-blockchain-service can reach it.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 20:30:44 -08:00
hailin 1106a40ff1 refactor(mining-blockchain): replace Kafka MPC signing with HTTP direct calls
Remove Kafka event-driven MPC signing (publish/consume pattern) and replace
with HTTP POST + polling to mpc-service, matching identity-service approach.

- Rewrite mpc-signing.client.ts: POST /api/v1/mpc/sign + poll status
- Delete mpc-event-consumer.service.ts (no longer needed)
- Delete mpc-keygen-completed.handler.ts (keygen handled elsewhere)
- Add MPC_SERVICE_URL env var to docker-compose.2.0.yml

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 20:28:26 -08:00
hailin 0d47fadf59 feat(kafka): add EXTERNAL listener on port 9093 for LAN access
Add a third Kafka listener (EXTERNAL://0.0.0.0:9093) so that
2.0 standalone services on other servers (e.g. 192.168.1.10) can
connect to 1.0's Kafka at 192.168.1.111:9093.

Listeners now:
- PLAINTEXT (kafka:29092) - internal Docker network
- PLAINTEXT_HOST (localhost:9092) - host-local access
- EXTERNAL (192.168.1.111:9093) - LAN access for remote services

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 19:49:34 -08:00
hailin ee07b52af9 feat(mining-2.0): 支持 standalone 独立部署模式,2.0 服务可脱离 1.0 单独运行
## 背景
2.0 挖矿生态需要从 1.0 服务器(192.168.1.111)迁移到独立服务器(192.168.1.10),
实现物理隔离部署。2.0 拥有独立的 PostgreSQL/Redis,通过远程 Kafka 接收 1.0 CDC 数据。

## docker-compose.2.0.yml 变更

### 网络参数化
- 网络改为 external: true + name 参数化:
  `name: ${RWA_NETWORK_NAME:-services_rwa-network}`
- shared 模式复用 1.0 网络, standalone 模式使用独立 rwa-2-network

### 基础设施地址参数化 (所有 7 个 backend service)
- DATABASE_URL: @${POSTGRES_HOST:-postgres}:${POSTGRES_PORT:-5432}
- REDIS_HOST: ${REDIS_HOST:-redis}
- KAFKA_BROKERS: ${KAFKA_BROKERS:-kafka:29092}

### 新增 3 个 standalone profile 基础设施服务
- postgres-2: PostgreSQL 16, WAL logical, init-multiple-dbs.sh 自动建库
- redis-2: Redis 7, appendonly 持久化
- debezium-2: Debezium Connect 2.4, 连接远程 Kafka(192.168.1.111:9093)
  用于 2.0 内部 outbox 模式 (服务事件 → Kafka → mining-admin-service)

### 可选依赖
- 应用 service 添加 depends_on postgres-2/redis-2 with required: false
  (Docker Compose v2.20+, shared 模式下自动跳过)

## deploy-mining.sh 变更

### 部署模式切换
- DEPLOY_MODE 环境变量: shared(默认) / standalone
- load_env() 按模式设置基础设施地址和 COMPOSE_ARGS
- shared 模式不 export 变量,避免覆盖容器侧 Docker Compose 默认值

### Kafka 远程操作支持
- run_kafka_cmd() / run_kafka_cmd_stdin(): standalone 模式用临时容器执行 Kafka CLI
- 所有 Kafka 操作函数 (sync_reset, sync_status, cdc_resnapshot, full_reset) 已适配

### 基础设施生命周期管理
- infra_up / infra_down: 独立管理 standalone 基础设施
- services_up(): standalone 模式自动先启动基础设施
- services_down(): standalone 模式同时停止基础设施
- services_clean(): fallback 列表包含 standalone 容器名

### full_reset() standalone 适配
- standalone 模式跳过 1.0 source CDC 操作 (远程 Debezium 管理)
- standalone 使用 debezium_2_offsets offset topic
- 自动启动 debezium-2 后注册 outbox connectors

### 其他
- health_check(): standalone 模式检查本地 PG/Redis 容器 + 远程 Kafka
- show_help(): 新增 DEPLOY_MODE 说明和 infra-up/infra-down 命令
- print_header(): 显示当前 DEPLOY_MODE
- 所有 ~15 处 docker compose 调用统一使用 $COMPOSE_ARGS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 19:32:03 -08:00
hailin f39fd52001 feat(c2c-bot): rename HOT_WALLET to C2C_BOT_WALLET and change dUSDT to 绿积分
- Rename env vars HOT_WALLET_ADDRESS/USERNAME to C2C_BOT_WALLET_ADDRESS/USERNAME
  in mining-blockchain-service to avoid conflict with existing hot wallet
- Update docker-compose.2.0.yml with new env var names
- Change all "dUSDT" labels to "绿积分" on C2C Bot admin page

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 08:40:45 -08:00
hailin be52ac979b fix(trading-service): add MINING_BLOCKCHAIN_SERVICE_URL to docker-compose
trading-service BlockchainClient defaults to http://localhost:3020 but
mining-blockchain-service runs on port 3026. Add the correct Docker
internal URL so the C2C Bot can reach the blockchain service.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 08:21:17 -08:00
hailin 8d7e5b17a1 fix(mining-admin-service): cast response.data to any for envelope unwrapping
TypeScript build fails because MiningServiceResponse type doesn't have
a 'data' property. The runtime response from mining-service wraps data
in a { success, data } envelope, so we need `as any` to access it.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 07:49:31 -08:00
hailin 7549b2b9a9 fix(mining-admin): 解包mining-service响应信封,取response.data.data
mining-service返回 { success, data: { ... } } 格式,
mining-admin-service需要取 .data.data 而非 .data,
否则前端读到的是信封对象而非实际数据,导致 TypeError。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 07:44:17 -08:00
hailin 48720d1846 feat(blockchain): 1.0 blockchain-service 同步添加 RPC 端点自动故障转移
与 mining-blockchain-service (2.0) 保持一致的故障转移方案:
当 RPC 端点连续失败超过 3 分钟后自动轮转到下一个备选端点。

新增文件:
- rpc-provider-manager.service.ts: RPC 故障转移管理器(与 2.0 相同逻辑)

修改文件:
- blockchain.config.ts: 新增 rpcUrls 配置字段
- chain-config.service.ts: 新增 rpcUrls 属性和 parseRpcUrls 解析方法
- domain.module.ts: 注册并导出 RpcProviderManager
- index.ts: 导出 RpcProviderManager
- evm-provider.adapter.ts: 委托 RpcProviderManager 获取 provider,
  所有方法通过 executeWithFailover 包裹
- erc20-transfer.service.ts: 移除本地 providers Map,改用 RpcProviderManager,
  新增 isRpcConnectionError 区分 RPC 网络错误与合约执行错误
- docker-compose.yml: blockchain-service 添加 KAVA_RPC_URLS 默认 4 个端点

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 07:36:02 -08:00
hailin b9e9bb6e4e fix(mining-admin): 修正调用mining-service的URL路径,补全/api/v2/mining前缀
mining-service有全局前缀api/v2和控制器前缀mining/admin,
但mining-admin-service的HTTP调用缺少这两个前缀导致404,
错误被catch静默吞掉,前端显示空数据。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 07:34:21 -08:00
hailin 3635369a8a feat(mining-blockchain): RPC端点自动故障转移,连续失败3分钟后切换备选节点
问题:Kava主网RPC (evm.kava.io) 偶发503,导致mining-blockchain-service
所有链上操作失败(转账、余额查询、区块扫描等)。

方案:新增RpcProviderManager单例服务,统一管理各链的JsonRpcProvider实例,
当某个RPC端点连续失败超过3分钟后自动轮转到下一个备选端点。

新增文件:
- rpc-provider-manager.service.ts: 核心故障转移管理器
  · 每条链维护 provider/urls/currentIndex/failureState
  · reportSuccess() 重置失败状态
  · reportFailure() 记录失败,>=3分钟触发 switchToNextUrl()
  · 轮转创建新 JsonRpcProvider,替换旧实例
  · 每30秒记录一次失败日志,避免日志刷屏

修改文件:
- blockchain.config.ts: 新增 rpcUrls 配置字段(KAVA_RPC_URLS/BSC_RPC_URLS)
- chain-config.service.ts: 解析逗号分隔的URL列表,回退到单个rpcUrl
- domain.module.ts: 注册并导出 RpcProviderManager
- index.ts: 导出 RpcProviderManager
- evm-provider.adapter.ts: 委托RpcProviderManager获取provider,
  所有公开方法通过executeWithFailover包裹,自动上报成功/失败
- erc20-transfer.service.ts: 移除本地providers Map,改用RpcProviderManager,
  新增isRpcConnectionError()区分RPC网络错误与合约执行错误
- docker-compose.2.0.yml: 添加KAVA_RPC_URLS默认4个端点
- .env.example: 添加KAVA_RPC_URLS配置说明

默认端点仍为 evm.kava.io,备选: evm.kava-rpc.com,
kava-evm-rpc.publicnode.com, rpc.ankr.com/kava_evm

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 07:06:31 -08:00
hailin ef663c0c08 fix(deploy): replace envsubst with eval heredoc for ${VAR:-default} support
GNU envsubst does not handle ${VAR:-default} bash syntax - it leaves
the entire expression unsubstituted. This caused CDC connector
registration to fail with "password authentication failed for user
${POSTGRES_USER:-rwa_user}".

Replace all envsubst calls with a substitute_env_vars() helper that
uses eval+heredoc, which natively supports bash default value syntax.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 06:22:01 -08:00
hailin ea3d256647 fix(deploy): 恢复connector JSON原样,仅在load_env中export变量修复envsubst
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 06:09:53 -08:00
hailin 5728953b41 fix(deploy): connector JSON改为硬编码凭据,与outbox connector保持一致
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 06:06:47 -08:00
hailin a4f3a8d3ab fix(deploy): 修复envsubst无法解析${VAR:-default}语法导致CDC connector注册失败
问题:
  commit 5b1f4c82 在 full-reset Step 9 中用 envsubst 替换 connector JSON 中的
  数据库凭据,但 envsubst(GNU gettext)不支持 bash 的 ${VAR:-default} 语法,
  导致 "${POSTGRES_USER:-rwa_user}" 被原样发送给 Debezium,认证失败。

修复:
  1. deploy-mining.sh load_env(): 默认值赋值改为 export,确保 envsubst 能访问
  2. connector JSON 文件: ${VAR:-default} 改为 ${VAR},默认值由脚本 export 提供

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 06:03:38 -08:00
hailin b9f803c5c8 fix(blockchain): 修复health check路径不匹配并配置C2C Bot热钱包
- app.config.ts: 添加apiPrefix读取API_PREFIX环境变量
- docker-compose: health check从api/v2改为api/v1(与trading-service一致)
- docker-compose: 配置HOT_WALLET默认值,解决"区块链服务不可用"和钱包地址不显示

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 05:46:58 -08:00
hailin c802519ec2 fix(c2c-bot): 调整purchaseOrder操作顺序,先扣余额再链上转账
问题:原流程先执行不可逆的链上dUSDT转账,再扣减卖家DB余额。
若转账成功但扣减失败(余额不足、DB异常),会导致:
- dUSDT已转出(链上不可回退)
- 订单仍为PENDING(可能被重复处理)
- 卖家余额未扣减

修复:
1. 将deductSellerBalance移至transferDusdt之前(可逆操作先行)
2. 链上转账失败时调用restoreSellerBalance回补余额
3. 新增restoreSellerBalance方法,失败时记录CRITICAL级别日志

修改后流程:扣余额(可逆) → 链上转账(不可逆) → 更新订单状态(DB)
任何步骤失败都不会导致资金损失。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 05:02:19 -08:00
hailin 251e37f772 feat(c2c-bot): 添加C2C Bot管理页面,支持运行时开关和热钱包查看
- 新增C2C Bot管理页面(mining-admin-web):Bot开关、热钱包余额/地址/QR码、统计、订单历史
- 新增admin API端点(trading-service):status/enable/disable/orders
- 重构Bot调度器enabled为Redis驱动,支持运行时开关(多实例安全)
- C2cOrderRepository新增findBotPurchasedOrders和getBotStats查询方法
- 侧边栏添加C2C Bot导航入口

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 04:47:28 -08:00
hailin bf772967f5 feat(mining): 批量补发30%分配到运营和总部账户,并添加交易筛选器
- 批量补发时将剩余30%分配到运营(12%)和总部(18%)系统账户
- SystemMiningAccountRepository.mine()支持referenceId/referenceType参数
- BatchMiningExecution新增operationAmount/headquartersAmount字段(含DB迁移)
- 三层架构(mining-service→admin-service→admin-web)全链路支持referenceType筛选
- 系统账户交易记录页面增加"全部/批量补发"筛选按钮

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 04:25:20 -08:00
hailin 338321b3a2 fix(c2c): 用updateMany+status条件防止合并时的竞态条件
findFirst找到PENDING订单后,如果被takeOrder接走(状态变MATCHED),
updateMany因status!=PENDING返回count=0,自动回退到创建新订单。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 03:29:27 -08:00
hailin 60d99add2c fix(c2c): 过期恢复时合并到已有PENDING订单,避免同maker产生重复挂单
原来每个过期的MATCHED子订单都创建独立PENDING,导致一个卖单被多人
部分接单后过期会产生多个重复挂单。现在恢复时先查找同maker/type/price
的PENDING订单,有则合并数量,无则创建新订单。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 03:25:57 -08:00
hailin 49ba2fcb19 feat(c2c): 添加expireOrder事务流程的详细调试日志
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 03:09:50 -08:00
hailin 627c3c943c refactor(c2c): expireOrder使用Prisma事务确保原子性
将 expireOrder 中的 解冻/状态更新/恢复创建 包在 prisma.$transaction 中:
- 事务失败全部回滚,不会出现半完成的不一致状态
- SELL MATCHED/PAID 过期恢复:保持冻结 + 标记EXPIRED + 创建PENDING 原子执行
- BUY MATCHED/PAID 过期恢复:解冻taker + 标记EXPIRED + 创建PENDING 原子执行
- PENDING 过期:解冻 + 标记EXPIRED 原子执行
- 删除 restoreExpiredOrder 方法,逻辑合并到事务内
- 遵循现有模式(executeTransfer 等),在事务回调中直接使用 tx 操作

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 02:43:48 -08:00
hailin 33dda98e81 fix(c2c): 修复过期恢复的竞态条件,SELL订单保持冻结避免资金窗口
- SELL MATCHED/PAID 订单过期恢复时,不再先解冻再重新冻结
- 保持 maker 的冻结不变,直接转给新 PENDING 订单
- 消除了解冻→重新冻结之间的竞态窗口(余额可能被其他操作消耗)
- 恢复失败时补充解冻,防止 maker 资金被永久冻结
- BUY 订单恢复时不复制上一个 taker 的 sellerKavaAddress

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 02:11:47 -08:00
hailin 4e4a876341 fix(c2c): MATCHED/PAID订单过期后自动恢复为新PENDING订单
当部分成交的订单过期时,将过期数量恢复到市场:
- BUY单过期:直接为maker创建新PENDING BUY单
- SELL单过期:检查maker余额,重新冻结后创建新PENDING SELL单
- 恢复失败不影响过期流程(仅记录日志)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 01:37:00 -08:00
hailin b8f8831516 feat: PENDING订单自动过期、接单显示余额、积分股金额输入
1. C2C PENDING订单24小时自动过期并解冻冻结资产
   - 新增 DEFAULT_PENDING_TIMEOUT_HOURS 常量
   - findExpiredOrders 支持 PENDING 状态查询
   - expireOrder 处理 PENDING 卖单解冻

2. C2C接单对话框显示卖方可用余额
   - 确认出售时显示用户账户可用积分值(非订单数量)
   - 新增订单数量行,方便对比

3. 积分股兑换页面新增金额输入
   - 卖出时显示金额输入框(积分值),与数量双向联动
   - 输入数量自动计算金额,输入金额自动反算数量
   - 全部按钮同步更新两个字段

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 22:15:47 -08:00
hailin 6ccc192bc6 fix(c2c): 用户无交易账户时自动创建零余额账户
createOrder 和 takeOrder 中,如果用户没有交易账户,
自动创建零余额账户而非报错"交易账户不存在"。
买单不需要余额,不应因缺少账户而无法下单。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 21:29:42 -08:00
hailin a1c3657390 fix(c2c): 修复付款水单图片无法显示的问题
1. 后端: proofs 图片端点添加 @Public() 装饰器,
   Image.network 无法携带 JWT token
2. 前端: paymentProofUrl 是相对路径,拼接 baseUrl
   构建完整 URL 供 Image.network 加载

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 21:16:53 -08:00
hailin 5b1f4c82e6 fix(deploy): full-reset 时重建 1.0 source CDC connectors 以确保完整数据同步
问题:
  执行 deploy-mining.sh full-reset 后,identity-postgres-connector 等 1.0 source
  CDC connectors 保留了旧的 Debezium offset 和 replication slot,导致 Debezium
  认为 initial snapshot 已完成而跳过重新快照。如果 connector 的 JSON 配置文件中
  新增了表(如 identity-connector.json 中的 wallet_addresses),这些表的存量数据
  永远不会被捕获到 Kafka topic,2.0 服务无法通过 CDC 同步到这些数据。

  具体表现:Kafka topic cdc.identity.public.wallet_addresses 始终为空(0条消息),
  2.0 auth-service 的 synced_wallet_addresses 表为空,用户 KAVA 地址未同步。

修复:
  在 full_reset() 的 Step 4 中,除了处理 outbox connectors,还新增了对 1.0 source
  CDC connectors (identity/referral/planting) 的处理:
  1. 删除 connector(释放 replication slot)
  2. 发送 tombstone 清除 debezium_offsets topic 中的偏移量
  3. 调用 pg_drop_replication_slot() 删除 PostgreSQL replication slot

  新增 Step 9:从 scripts/debezium/*.json 配置文件重新注册 source connectors,
  因为 offset 和 slot 都已清除,snapshot.mode=initial 会触发全新的 initial snapshot,
  确保所有配置表(包括新增的 wallet_addresses)的存量数据都被灌入 Kafka topic。

  总步骤数从 18 调整为 19。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 20:26:06 -08:00
hailin f60e3751b8 fix(c2c): 修复水单上传权限、手机号、卖方ID、资产显示
- Dockerfile: 用 su-exec 模式解决 Docker volume 权限问题
- JWT guard: 从 token 提取 phone 字段
- 订单详情: 新增卖方ID显示
- C2C市场页: 修复资产概览两列重复显示 availableCash,
  改为左列显示可用积分股、右列显示可用积分值

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 09:19:38 -08:00
hailin e783661002 fix(c2c): 修复水单上传权限、手机号显示、卖方ID显示
- Dockerfile 预创建 /app/uploads/c2c-proofs 并设置正确权限
- JWT guard 从 token payload 提取 phone 字段(之前仅提取 accountSequence)
- 订单详情页订单信息组新增卖方ID显示

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 09:13:46 -08:00
hailin 25ea0bf64e fix(trading-service): 修复 Multer 类型缺失导致构建失败
使用内联类型替代 Express.Multer.File,避免 @types/multer 依赖

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 08:58:55 -08:00
hailin ce173451f5 feat(c2c): 订单详情增强、付款水单上传、买单逻辑修复及schema对齐
- 订单详情页显示完整手机号和收款账号信息
- 新增付款水单上传功能(前后端全链路)
- 修复时间显示为本地时区格式
- 移除买单发布时的积分值余额验证(买方通过外部绿积分支付)
- 前端买单发布页隐藏余额卡片和"全部"按钮
- 补齐 Prisma migration 与 schema 差异(payment_proof_url、
  bot_purchased索引、market_maker_deposits/withdraws表)
- docker-compose 新增 trading-uploads 卷用于水单持久化

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 08:54:05 -08:00
hailin 4df23b02b8 fix(trading-service): 添加做市商钱包环境变量,修复地址未配置问题
FUSDT/EUSDT_MARKET_MAKER_ADDRESS 和 USERNAME 只传给了
mining-blockchain-service,但 trading-service 初始化时也需要
读取这些变量写入数据库,导致前端显示"做市商钱包地址未配置"。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 07:56:16 -08:00
hailin 8e63547a3e fix(transfer): 修复积分股划转到分配账户失败问题
后端:
- transfer.service.ts: Error → BadRequestException,业务错误返回HTTP 400而非500
- transfer.controller.ts: Error → UnauthorizedException,正确返回HTTP 401
- 错误信息改为中文:余额不足、账户不存在等提示更明确

前端:
- asset_display.dart: 新增 tradingAvailableShares 计算属性(总可用 - 挖矿可用)
- trading_page.dart: 划转弹窗显示可用余额(扣除冻结)而非总余额
- trading_page.dart: 划转失败时显示后端具体错误信息而非通用提示

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 06:24:35 -08:00
hailin 3cbb874503 fix(auth-service): 返回完整手机号,修复QR码扫码失败
- login/profile 接口返回 user.phone.value 替代 user.phone.masked
- 根因:QR码编码脱敏号 199****9327,正则要求纯数字匹配失败

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 06:00:47 -08:00
hailin 8c31dee000 fix(c2c): 修复买方待付款页面灰色无法操作问题
根因: c2c_order_model.dart 的 _parsePaymentMethod 不识别 GREEN_POINTS,
导致 paymentMethod=null → hasPaymentInfo=false → 收款信息卡片隐藏 → 页面不可操作

前端修复:
- C2cPaymentMethod 枚举增加 greenPoints,解析器支持 GREEN_POINTS
- 支持逗号分隔的多支付方式字符串(取第一个作为主要方式)
- 订单详情页增加绿积分图标和卖方 Kava 地址显示(买方可复制)

后端修复:
- takeOrder() 接买单时自动获取卖方 Kava 地址写入 sellerKavaAddress
- 买方在订单详情页可看到卖方 Kava 地址用于转绿积分

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 05:41:14 -08:00
hailin f167f1227c Revert "fix(trading-service): C2C卖单不再强制要求Kava钱包地址"
This reverts commit 9b8f720915.
2026-01-30 21:04:27 -08:00
hailin 9b8f720915 fix(trading-service): C2C卖单不再强制要求Kava钱包地址
executeTransfer不使用sellerKavaAddress,C2C交易是积分值划转+外部绿积分支付,
不涉及Kava链上操作。改为可选获取,失败不阻断订单创建。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 21:03:59 -08:00
hailin 7180e2ac27 fix(contribution): 算力记录按层级升序排列 L1→L2→...→L15
用户期望 L1 在前 L15 在后,将 levelDepth/bonusTier 排序从 DESC 改为 ASC

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 20:14:31 -08:00
hailin 17f8a61bcf feat(contribution-service): 贡献值明细按 L/T 降序排序
- 同伴下贡献值 (TEAM_LEVEL): 按 levelDepth DESC 排序 (L3, L2, L1)
- 同伴上贡献值 (TEAM_BONUS): 按 bonusTier DESC 排序 (T3, T2, T1)
- 全部/本人: 按 levelDepth DESC, bonusTier DESC, createdAt DESC

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 14:20:03 -08:00
hailin a31fcaa9b8 fix(mining-admin): configValue → value,修复配置读取后 fallback 到默认值
Prisma 返回的字段是 value,controller 写成了 configValue,
导致 getP2pTransferFee / getTransferEnabled 永远返回默认值

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 14:18:13 -08:00