Commit Graph

21 Commits

Author SHA1 Message Date
hailin 4be9c1fb82 refactor!: 重构账户序列号格式 (BREAKING CHANGE)
将 accountSequence 从数字类型改为字符串类型,新格式为:
- 普通用户: D + YYMMDD + 5位序号 (例: D2512120001)
- 系统账户: S + 10位序号 (例: S0000000001)

主要变更:
- identity-service: AccountSequence 值对象改为字符串类型
- identity-service: 序列号生成器改为按日期重置计数
- 所有服务: Prisma schema 字段类型从 BigInt/Int 改为 String
- 所有服务: DTO、Command、Event 中的类型定义更新
- Flutter 前端: 相关数据模型类型更新

涉及服务:
- identity-service (核心变更)
- referral-service
- authorization-service
- wallet-service
- reward-service
- blockchain-service
- backup-service
- planting-service
- mpc-service
- admin-service
- mobile-app (Flutter)

注意: 此为破坏性变更,需要清空数据库并重新运行 migration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-12 09:11:18 -08:00
hailin 8532bf6945 fix(blockchain): use amountFormatted to rebuild TokenAmount from DB
Previously used amount (raw) with hardcoded 18 decimals, which caused
incorrect formatting for USDT (6 decimals). Now uses amountFormatted
which is already correctly formatted during deposit detection.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 12:22:32 -08:00
hailin db3e0ba1bd fix(blockchain): fix deposit stuck in CONFIRMING status
The updateConfirmations logic only checked for DETECTED status
when confirming, so deposits that transitioned to CONFIRMING
would never be confirmed even with enough confirmations.

Changed condition to accept both DETECTED and CONFIRMING status.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 12:19:29 -08:00
hailin 5e670e64b3 fix(blockchain): read token decimals from contract for deposit detection
Previously decimals were hardcoded to 18, causing incorrect amount parsing
for USDT which uses 6 decimals. Now reads decimals() from ERC20 contract
when processing deposits.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 11:57:34 -08:00
hailin 12116ff164 feat(blockchain): add deposit repair service and controller
Add internal APIs to diagnose and repair historical deposit issues:
- GET /internal/deposit-repair/diagnose - Query unnotified deposits
- POST /internal/deposit-repair/repair/:depositId - Repair single deposit
- POST /internal/deposit-repair/repair-all - Batch repair all pending deposits
- POST /internal/deposit-repair/reset-failed-outbox - Reset failed outbox events

The repair service creates new outbox events for CONFIRMED deposits
that were never notified to wallet-service.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 02:19:46 -08:00
hailin 49fc68297b fix(blockchain): fix TypeScript compilation errors
- Fix brokers type narrowing issue in deposit-ack-consumer.service.ts
- Add Prisma.InputJsonValue type cast for payload in outbox-event.repository.impl.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 22:11:28 -08:00
hailin 075c9aaa48 feat(blockchain): implement Outbox Pattern for reliable event delivery
Implement Outbox Pattern with consumer ACK to ensure 100% reliable event
delivery between blockchain-service and wallet-service:

blockchain-service:
- Add OutboxEvent model to Prisma schema with status tracking
- Create outbox repository interface and implementation
- Modify deposit-detection.service to write events to outbox
- Add outbox-publisher.service with cron jobs for publishing/retry
- Add deposit-ack-consumer.service to receive ACK from wallet-service
- Add publishRaw method to event-publisher.service

wallet-service:
- Modify deposit-confirmed.handler to send ACK after successful processing
- Add wallet.deposit.credited topic mapping for ACK events

Event flow:
1. Deposit detected → written to outbox (status: PENDING)
2. Outbox publisher sends to Kafka → status: SENT
3. wallet-service processes and sends ACK → status: ACKED
4. Events without ACK are retried with exponential backoff

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 21:47:31 -08:00
hailin 2e6f22e9d8 fix(blockchain): read token decimals from contract instead of hardcoding
The balance display was incorrect because decimals were hardcoded to 18,
but USDT uses 6 decimals. Now reads decimals() from the ERC20 contract.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 06:10:36 -08:00
hailin 001b6501a0 feat(deposit): add deposit balance API and Kafka consumer for deposit events
Blockchain Service:
- Add /api/v1/deposit/balances endpoint to query on-chain USDT balances
- Add JWT authentication (passport, passport-jwt)
- Add JwtStrategy, JwtAuthGuard, Public decorator

Wallet Service:
- Add Kafka consumer for blockchain.deposits topic
- Add DepositConfirmedHandler to process deposit events and update wallet balance

Infrastructure:
- Add JWT_SECRET env var to blockchain-service in docker-compose.yml
- Add blockchain-service routes to Kong API Gateway

Frontend:
- Fix deposit_service.dart API path (remove duplicate /api prefix)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 02:29:31 -08:00
hailin cf7230457f feat(blockchain-service): KAVA EVM address derivation and system accounts support
## Address Derivation Changes
- Change KAVA from Cosmos bech32 (kava1...) to EVM format (0x...)
- KAVA now uses same EVM address as BSC for deposit monitoring
- Add KAVA to evmChains set for automatic monitoring registration

## Database Schema Updates (Migration: 20241208000000)
- MonitoredAddress: add address_type, account_sequence, system_account_type,
  system_account_id, region_code columns
- DepositTransaction: add address_type, account_sequence, system_account_type,
  system_account_id columns
- Make user_id nullable for system account support
- Create recovery_mnemonics table for account recovery
- Add indexes: idx_account_sequence, idx_type_active, idx_system_account_type,
  idx_deposit_account, and recovery_mnemonics indexes

## New Features
- Withdrawal request handler and Kafka consumer
- Test USDT deployment scripts for KAVA and BSC
- Smart contracts for TestUSDT token

## Infrastructure Updates
- Update mappers for new schema fields
- Update application and infrastructure modules

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 21:45:34 -08:00
hailin 3c2144ad7c feat(deposit): add accountSequence correlation and testnet support
blockchain-service:
- Add accountSequence to monitored_addresses and deposit_transactions
- Support BSC/KAVA testnet via NETWORK_MODE environment variable
- Add chain config service with testnet RPC endpoints
- Update deposit detection with accountSequence propagation

wallet-service:
- Add accountSequence to wallet_accounts and ledger_entries
- Fix JWT strategy to match identity-service token format
- Update deposit handling with accountSequence correlation
- Add repository methods for accountSequence-based queries

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 10:26:01 -08:00
hailin 6b85401d5c fix(mnemonic): fix recovery-by-mnemonic using hash verification instead of address matching
## Problem
MPC wallet addresses have no cryptographic relationship with recovery mnemonics,
so address-based verification always failed for account recovery.

## Solution
Changed mnemonic verification from address matching to hash-based verification:
- Mnemonic acts as identity credential, verified by hash stored in blockchain-service
- Uses accountSequence to lookup stored mnemonic hash for verification

## Changes

### blockchain-service
- recovery-mnemonic.adapter.ts:
  - generateMnemonic() now async, uses bcrypt (rounds=12) for secure hashing
  - verifyMnemonic() now async, supports both bcrypt and legacy SHA256 hashes
  - Added backward compatibility for existing SHA256 hashed mnemonics
- mnemonic-verification.service.ts:
  - await verifyMnemonic() for async bcrypt comparison
- address-derivation.service.ts:
  - await generateMnemonic() for async bcrypt hashing
- package.json: added bcrypt dependency

### identity-service
- user-application.service.ts:
  - Changed recoverByMnemonic() to use verifyMnemonicByAccount (hash verification)
  - Added rate limiting: 5 failed attempts per hour per accountSequence
  - Uses Redis to track failed verification attempts
- redis.service.ts:
  - Added incr() and expire() methods for rate limiting
  - Added updateKeygenStatusAtomic() with Lua script for atomic state transitions
- mpc-keygen-completed.handler.ts:
  - Uses atomic Redis update to prevent race conditions
- blockchain-wallet.handler.ts:
  - Uses atomic Redis update for completed status

## Security Improvements
- bcrypt with 12 rounds for mnemonic hashing (anti-brute-force)
- Rate limiting prevents brute force attacks on mnemonic recovery
- Atomic Redis operations prevent race conditions in wallet creation flow

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 09:02:24 -08:00
hailin 1bfbaa06f1 feat(mnemonic): propagate accountSequence through MPC keygen flow (DDD)
Changes across all three services to properly associate recovery mnemonics
with account sequence numbers instead of user IDs, following DDD principles:

identity-service:
- Add accountSequence to MpcKeygenRequestedEvent payload
- Pass accountSequence when publishing keygen request
- Remove direct access to recoveryMnemonic table (now in blockchain-service)
- Call blockchain-service for mnemonic backup marking
- BlockchainWalletHandler no longer saves mnemonic (stored in blockchain-service)

mpc-service:
- Add accountSequence to KeygenRequestedPayload interface
- Pass accountSequence through to blockchain-service when deriving addresses
- Include accountSequence in KeygenCompleted event extraPayload

blockchain-service:
- Add accountSequence to derive-address API and internal interfaces
- Add accountSequence to KeygenCompletedPayload extraPayload
- Add PUT /internal/mnemonic/backup API for marking mnemonic as backed up
- Store recovery mnemonic with accountSequence association

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 01:08:27 -08:00
hailin e95dc4ca57 refactor(mnemonic): move recovery_mnemonics to blockchain-service (DDD)
- Add RecoveryMnemonic model to blockchain-service with accountSequence
- Add MnemonicVerificationService for mnemonic verification logic
- Update verify-mnemonic-hash endpoint to accept accountSequence
- Remove PrismaService dependency from identity-service handler
- identity-service now calls blockchain-service for mnemonic verification

This follows DDD principles: blockchain-service owns all mnemonic-related
data and operations, identity-service only handles account identity.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 00:54:25 -08:00
hailin 0311ecf498 fix(mnemonic): use hash verification instead of address derivation for account recovery
The mnemonic recovery now uses stored hash comparison via blockchain-service
instead of trying to derive addresses from mnemonic (which never matched
because MPC wallet addresses are not derived from mnemonics).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 00:44:47 -08:00
hailin c1670d2439 feat(mnemonic): add recovery mnemonic generation and backup confirmation
Backend (blockchain-service):
- Add RecoveryMnemonicAdapter to generate 12-word BIP39 mnemonic
- Generate mnemonic when wallet addresses are derived (linked to public key)
- Include mnemonic in WalletAddressCreated event

Backend (identity-service):
- Add RecoveryMnemonic table with revocation/replacement support
- Save encrypted mnemonic to database on WalletAddressCreated event
- Add PUT /user/mnemonic/backup API to mark mnemonic as backed up
- Clear plaintext mnemonic from Redis after backup confirmation

Frontend (mobile-app):
- Update markMnemonicBackedUp() to call backend API
- Fix verify_mnemonic_page validation logic:
  - Checkbox checked → pass directly
  - Not checked → must select correct word

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 12:32:10 -08:00
hailin 34fc008f9d fix(blockchain-service): add global API prefix and increase healthcheck start_period
- Add app.setGlobalPrefix('api/v1') to main.ts so health endpoint
  is at /api/v1/health consistent with other services
- Increase healthcheck start_period to 60s to allow time for
  Prisma migrations on first startup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 01:20:35 -08:00
hailin 9eb2d5a206 fix(blockchain-service): import DomainModule for ConfirmationPolicyService 2025-12-07 01:06:45 -08:00
hailin 852073ae11 refactor: move mnemonic verification from identity-service to blockchain-service
- Add /internal/verify-mnemonic API to blockchain-service
- Add /internal/derive-from-mnemonic API to blockchain-service
- Create MnemonicDerivationAdapter for BIP39 mnemonic address derivation
- Create BlockchainClientService in identity-service to call blockchain-service
- Remove WalletGeneratorService from identity-service
- Update recover-by-mnemonic handler to use blockchain-service API

This enforces proper domain boundaries - all blockchain/crypto operations
are now handled by blockchain-service.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 00:11:06 -08:00
hailin 2e815cec6e feat: move address derivation from identity-service to blockchain-service
- Add Cosmos address derivation (bech32) to blockchain-service
  - KAVA: kava1... format
  - DST: dst1... format
  - BSC: 0x... EVM format

- Create MpcEventConsumerService in blockchain-service to consume mpc.KeygenCompleted events

- Create BlockchainEventConsumerService in identity-service to consume blockchain.WalletAddressCreated events

- Simplify identity-service MpcKeygenCompletedHandler to only manage status updates

- Add CosmosAddress value object for Cosmos chain addresses

Event flow:
1. identity-service -> mpc.KeygenRequested
2. mpc-service -> mpc.KeygenCompleted (with publicKey)
3. blockchain-service consumes mpc.KeygenCompleted, derives addresses
4. blockchain-service -> blockchain.WalletAddressCreated (with all chain addresses)
5. identity-service consumes blockchain.WalletAddressCreated, saves to user account

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 21:08:21 -08:00
hailin 50388c1115 feat(blockchain-service): implement complete blockchain service with DDD + Hexagonal architecture
- Domain layer: ChainType, EvmAddress, TxHash, TokenAmount, BlockNumber value objects
- Domain events: DepositDetected, DepositConfirmed, WalletAddressCreated, TransactionBroadcasted
- Aggregates: DepositTransaction, MonitoredAddress, TransactionRequest
- Infrastructure: Prisma ORM, Redis cache, Kafka messaging, EVM blockchain adapters
- Application services: AddressDerivation, DepositDetection, BalanceQuery
- API: Health, Balance, Internal controllers with Swagger documentation
- Deployment: Docker, docker-compose, deploy.sh, health-check scripts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 20:54:58 -08:00