docs: update blockchain-service guide with address derivation responsibilities
- Add public key → address derivation as primary responsibility - Add AddressDerivationAdapter for EVM/Cosmos address derivation - Add WalletAddressCreated event definition - Add MPC event consumption (mpc.KeygenCompleted) - Add MpcKeygenCompletedHandler for processing keygen events - Add section 17: MPC integration event flow with diagrams - Update document version to 1.2.0 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
23043d5d79
commit
6150617c14
|
|
@ -6,12 +6,46 @@
|
||||||
|
|
||||||
blockchain-service 是 RWA 榴莲女皇平台的区块链基础设施服务,负责:
|
blockchain-service 是 RWA 榴莲女皇平台的区块链基础设施服务,负责:
|
||||||
|
|
||||||
|
- **公钥→地址派生**:从 MPC 公钥派生多链钱包地址 (EVM/Cosmos)
|
||||||
- **链上事件监听**:监听 ERC20 Transfer 事件,检测用户充值
|
- **链上事件监听**:监听 ERC20 Transfer 事件,检测用户充值
|
||||||
- **充值入账触发**:检测到充值后通知 wallet-service 入账
|
- **充值入账触发**:检测到充值后通知 wallet-service 入账
|
||||||
- **余额查询**:查询链上 USDT/原生代币余额
|
- **余额查询**:查询链上 USDT/原生代币余额
|
||||||
- **交易广播**:提交签名后的交易到链上
|
- **交易广播**:提交签名后的交易到链上
|
||||||
- **地址管理**:管理平台充值地址池
|
- **地址管理**:管理平台充值地址池
|
||||||
|
|
||||||
|
### 1.4 与其他服务的关系
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||||
|
│ identity-service│ │ mpc-service │ │blockchain-service│
|
||||||
|
├─────────────────┤ ├─────────────────┤ ├─────────────────┤
|
||||||
|
│ - 用户账户 │ │ - 密钥分片生成 │ │ - 公钥→地址派生 │
|
||||||
|
│ - 设备绑定 │ │ - 签名协调 │ │ - 充值检测 │
|
||||||
|
│ - KYC验证 │ │ - 分片存储 │ │ - 交易广播 │
|
||||||
|
│ - 身份认证 │ │ - 阈值策略 │ │ - 余额查询 │
|
||||||
|
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
|
||||||
|
│ │ │
|
||||||
|
│ MpcKeygenRequested │ KeygenCompleted │
|
||||||
|
│──────────────────────>│ (with publicKey) │
|
||||||
|
│ │──────────────────────>│
|
||||||
|
│ │ │ derive address
|
||||||
|
│ WalletAddressCreated │
|
||||||
|
│<──────────────────────────────────────────────│
|
||||||
|
│ (存储 userId ↔ walletAddress 关联) │
|
||||||
|
│ │ │
|
||||||
|
│ wallet-service │
|
||||||
|
│ │ │
|
||||||
|
│ WalletAddressCreated │
|
||||||
|
│<──────────────────────────────────────────────│
|
||||||
|
│ (存储钱包地址、管理余额) │
|
||||||
|
```
|
||||||
|
|
||||||
|
**职责边界原则**:
|
||||||
|
- **identity-service**:只关心用户身份,不处理区块链技术细节
|
||||||
|
- **mpc-service**:只关心 MPC 协议,生成公钥后发布事件
|
||||||
|
- **blockchain-service**:封装所有区块链技术,包括地址派生、链交互
|
||||||
|
- **wallet-service**:管理用户钱包的业务逻辑,不直接与链交互
|
||||||
|
|
||||||
### 1.2 技术栈
|
### 1.2 技术栈
|
||||||
|
|
||||||
| 组件 | 技术选型 |
|
| 组件 | 技术选型 |
|
||||||
|
|
@ -119,7 +153,8 @@ blockchain-service/
|
||||||
│ │ │ ├── deposit-detection.service.ts
|
│ │ │ ├── deposit-detection.service.ts
|
||||||
│ │ │ ├── balance-query.service.ts
|
│ │ │ ├── balance-query.service.ts
|
||||||
│ │ │ ├── transaction-broadcast.service.ts
|
│ │ │ ├── transaction-broadcast.service.ts
|
||||||
│ │ │ └── address-registry.service.ts
|
│ │ │ ├── address-registry.service.ts
|
||||||
|
│ │ │ └── address-derivation.service.ts # 公钥→地址派生
|
||||||
│ │ ├── commands/
|
│ │ ├── commands/
|
||||||
│ │ │ ├── register-address/
|
│ │ │ ├── register-address/
|
||||||
│ │ │ │ ├── register-address.command.ts
|
│ │ │ │ ├── register-address.command.ts
|
||||||
|
|
@ -155,6 +190,7 @@ blockchain-service/
|
||||||
│ │ │ ├── deposit-detected.event.ts
|
│ │ │ ├── deposit-detected.event.ts
|
||||||
│ │ │ ├── deposit-confirmed.event.ts
|
│ │ │ ├── deposit-confirmed.event.ts
|
||||||
│ │ │ ├── transaction-broadcasted.event.ts
|
│ │ │ ├── transaction-broadcasted.event.ts
|
||||||
|
│ │ │ ├── wallet-address-created.event.ts # 地址派生完成事件
|
||||||
│ │ │ └── index.ts
|
│ │ │ └── index.ts
|
||||||
│ │ ├── repositories/
|
│ │ ├── repositories/
|
||||||
│ │ │ ├── deposit-transaction.repository.interface.ts
|
│ │ │ ├── deposit-transaction.repository.interface.ts
|
||||||
|
|
@ -182,6 +218,7 @@ blockchain-service/
|
||||||
│ │ │ ├── event-listener.service.ts
|
│ │ │ ├── event-listener.service.ts
|
||||||
│ │ │ ├── block-scanner.service.ts
|
│ │ │ ├── block-scanner.service.ts
|
||||||
│ │ │ ├── transaction-sender.service.ts
|
│ │ │ ├── transaction-sender.service.ts
|
||||||
|
│ │ │ ├── address-derivation.adapter.ts # 地址派生适配器
|
||||||
│ │ │ └── blockchain.module.ts
|
│ │ │ └── blockchain.module.ts
|
||||||
│ │ ├── persistence/
|
│ │ ├── persistence/
|
||||||
│ │ │ ├── prisma/
|
│ │ │ ├── prisma/
|
||||||
|
|
@ -1137,6 +1174,51 @@ export { TxHash } from './tx-hash.vo';
|
||||||
|
|
||||||
### 4.4 领域事件
|
### 4.4 领域事件
|
||||||
|
|
||||||
|
### 4.6 WalletAddressCreated 事件
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// src/domain/events/wallet-address-created.event.ts
|
||||||
|
|
||||||
|
import { DomainEvent } from './domain-event.base';
|
||||||
|
|
||||||
|
export interface WalletAddressCreatedPayload {
|
||||||
|
userId: string;
|
||||||
|
username: string;
|
||||||
|
publicKey: string; // 压缩公钥 (33 bytes hex)
|
||||||
|
addresses: Array<{
|
||||||
|
chainType: string; // BSC, KAVA, DST
|
||||||
|
address: string; // 派生的地址
|
||||||
|
addressType: string; // EVM 或 COSMOS
|
||||||
|
}>;
|
||||||
|
mpcSessionId: string; // MPC 会话 ID
|
||||||
|
delegateShare?: {
|
||||||
|
partyId: string;
|
||||||
|
partyIndex: number;
|
||||||
|
encryptedShare: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WalletAddressCreatedEvent extends DomainEvent {
|
||||||
|
constructor(public readonly payload: WalletAddressCreatedPayload) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
get eventType(): string {
|
||||||
|
return 'WalletAddressCreated';
|
||||||
|
}
|
||||||
|
|
||||||
|
get aggregateId(): string {
|
||||||
|
return this.payload.userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
get aggregateType(): string {
|
||||||
|
return 'WalletAddress';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// src/domain/events/deposit-detected.event.ts
|
// src/domain/events/deposit-detected.event.ts
|
||||||
|
|
||||||
|
|
@ -1484,7 +1566,127 @@ export class EventListenerService implements OnModuleInit, OnModuleDestroy {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5.3 区块扫描器(补扫服务)
|
### 5.3 地址派生适配器
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// src/infrastructure/blockchain/address-derivation.adapter.ts
|
||||||
|
|
||||||
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
|
import { createHash } from 'crypto';
|
||||||
|
import { bech32 } from 'bech32';
|
||||||
|
import { ethers } from 'ethers';
|
||||||
|
import * as secp256k1 from 'secp256k1';
|
||||||
|
|
||||||
|
export enum AddressType {
|
||||||
|
EVM = 'EVM',
|
||||||
|
COSMOS = 'COSMOS',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DerivedAddress {
|
||||||
|
chainType: string;
|
||||||
|
address: string;
|
||||||
|
addressType: AddressType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 地址派生适配器
|
||||||
|
*
|
||||||
|
* 从压缩的 secp256k1 公钥派生多链钱包地址
|
||||||
|
* - EVM 链 (BSC, KAVA EVM): 使用 keccak256(uncompressed_pubkey[1:])[-20:]
|
||||||
|
* - Cosmos 链 (KAVA, DST): 使用 bech32(ripemd160(sha256(compressed_pubkey)))
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddressDerivationAdapter {
|
||||||
|
private readonly logger = new Logger(AddressDerivationAdapter.name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从压缩公钥派生所有支持链的地址
|
||||||
|
* @param compressedPubKeyHex 33 字节压缩公钥 (hex 格式,不含 0x 前缀)
|
||||||
|
*/
|
||||||
|
deriveAllAddresses(compressedPubKeyHex: string): DerivedAddress[] {
|
||||||
|
const pubKeyBytes = Buffer.from(compressedPubKeyHex, 'hex');
|
||||||
|
|
||||||
|
if (pubKeyBytes.length !== 33) {
|
||||||
|
throw new Error(`Invalid compressed public key length: ${pubKeyBytes.length}, expected 33`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const addresses: DerivedAddress[] = [];
|
||||||
|
|
||||||
|
// EVM 地址 (BSC, KAVA EVM)
|
||||||
|
const evmAddress = this.deriveEvmAddress(pubKeyBytes);
|
||||||
|
addresses.push({ chainType: 'BSC', address: evmAddress, addressType: AddressType.EVM });
|
||||||
|
addresses.push({ chainType: 'KAVA', address: evmAddress, addressType: AddressType.EVM });
|
||||||
|
|
||||||
|
// Cosmos 地址 (KAVA Native 使用 kava 前缀,DST 使用 dst 前缀)
|
||||||
|
const kavaCosmosAddress = this.deriveCosmosAddress(pubKeyBytes, 'kava');
|
||||||
|
const dstAddress = this.deriveCosmosAddress(pubKeyBytes, 'dst');
|
||||||
|
addresses.push({ chainType: 'KAVA_COSMOS', address: kavaCosmosAddress, addressType: AddressType.COSMOS });
|
||||||
|
addresses.push({ chainType: 'DST', address: dstAddress, addressType: AddressType.COSMOS });
|
||||||
|
|
||||||
|
this.logger.log(`Derived ${addresses.length} addresses from public key`);
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 派生 EVM 地址
|
||||||
|
* 1. 解压公钥 (33 bytes → 65 bytes)
|
||||||
|
* 2. 取非压缩公钥去掉前缀 (64 bytes)
|
||||||
|
* 3. keccak256 哈希后取后 20 bytes
|
||||||
|
*/
|
||||||
|
private deriveEvmAddress(compressedPubKey: Buffer): string {
|
||||||
|
// 使用 secp256k1 解压公钥
|
||||||
|
const uncompressedPubKey = Buffer.from(
|
||||||
|
secp256k1.publicKeyConvert(compressedPubKey, false)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 去掉 0x04 前缀,取 64 bytes
|
||||||
|
const pubKeyWithoutPrefix = uncompressedPubKey.slice(1);
|
||||||
|
|
||||||
|
// keccak256 哈希后取后 20 bytes
|
||||||
|
const hash = ethers.keccak256(pubKeyWithoutPrefix);
|
||||||
|
const address = '0x' + hash.slice(-40);
|
||||||
|
|
||||||
|
return ethers.getAddress(address); // 返回 checksum 格式
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 派生 Cosmos 地址
|
||||||
|
* 1. SHA256(compressed_pubkey)
|
||||||
|
* 2. RIPEMD160(sha256_result)
|
||||||
|
* 3. bech32 编码
|
||||||
|
*/
|
||||||
|
private deriveCosmosAddress(compressedPubKey: Buffer, prefix: string): string {
|
||||||
|
// SHA256
|
||||||
|
const sha256Hash = createHash('sha256').update(compressedPubKey).digest();
|
||||||
|
|
||||||
|
// RIPEMD160
|
||||||
|
const ripemd160Hash = createHash('ripemd160').update(sha256Hash).digest();
|
||||||
|
|
||||||
|
// Bech32 编码
|
||||||
|
const words = bech32.toWords(ripemd160Hash);
|
||||||
|
return bech32.encode(prefix, words);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证地址格式
|
||||||
|
*/
|
||||||
|
validateAddress(chainType: string, address: string): boolean {
|
||||||
|
switch (chainType) {
|
||||||
|
case 'BSC':
|
||||||
|
case 'KAVA':
|
||||||
|
return ethers.isAddress(address);
|
||||||
|
case 'KAVA_COSMOS':
|
||||||
|
return /^kava1[a-z0-9]{38}$/.test(address);
|
||||||
|
case 'DST':
|
||||||
|
return /^dst1[a-z0-9]{38}$/.test(address);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.4 区块扫描器(补扫服务)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// src/infrastructure/blockchain/block-scanner.service.ts
|
// src/infrastructure/blockchain/block-scanner.service.ts
|
||||||
|
|
@ -1986,16 +2188,126 @@ export class BalanceQueryService {
|
||||||
// src/infrastructure/kafka/event-publisher.service.ts
|
// src/infrastructure/kafka/event-publisher.service.ts
|
||||||
|
|
||||||
export const BLOCKCHAIN_TOPICS = {
|
export const BLOCKCHAIN_TOPICS = {
|
||||||
|
// 地址派生完成事件 (发给 identity-service, wallet-service)
|
||||||
|
WALLET_ADDRESS_CREATED: 'blockchain.WalletAddressCreated',
|
||||||
|
|
||||||
|
// 充值相关事件
|
||||||
DEPOSIT_DETECTED: 'blockchain.DepositDetected',
|
DEPOSIT_DETECTED: 'blockchain.DepositDetected',
|
||||||
DEPOSIT_CONFIRMED: 'blockchain.DepositConfirmed',
|
DEPOSIT_CONFIRMED: 'blockchain.DepositConfirmed',
|
||||||
|
|
||||||
|
// 交易相关事件
|
||||||
TRANSACTION_BROADCASTED: 'blockchain.TransactionBroadcasted',
|
TRANSACTION_BROADCASTED: 'blockchain.TransactionBroadcasted',
|
||||||
TRANSACTION_CONFIRMED: 'blockchain.TransactionConfirmed',
|
TRANSACTION_CONFIRMED: 'blockchain.TransactionConfirmed',
|
||||||
|
|
||||||
|
// 区块扫描事件
|
||||||
BLOCK_SCANNED: 'blockchain.BlockScanned',
|
BLOCK_SCANNED: 'blockchain.BlockScanned',
|
||||||
} as const;
|
} as const;
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7.2 消费的事件
|
### 7.2 消费的事件
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// src/infrastructure/kafka/mpc-event-consumer.service.ts
|
||||||
|
|
||||||
|
// 消费 MPC 服务发布的事件
|
||||||
|
export const MPC_CONSUME_TOPICS = {
|
||||||
|
KEYGEN_COMPLETED: 'mpc.KeygenCompleted',
|
||||||
|
SESSION_FAILED: 'mpc.SessionFailed',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export interface KeygenCompletedPayload {
|
||||||
|
sessionId: string;
|
||||||
|
partyId: string;
|
||||||
|
publicKey: string; // 33 bytes 压缩公钥 (hex)
|
||||||
|
shareId: string;
|
||||||
|
threshold: string; // "2-of-3"
|
||||||
|
extraPayload?: {
|
||||||
|
userId: string;
|
||||||
|
username: string;
|
||||||
|
delegateShare?: {
|
||||||
|
partyId: string;
|
||||||
|
partyIndex: number;
|
||||||
|
encryptedShare: string;
|
||||||
|
};
|
||||||
|
serverParties?: string[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.3 MPC Keygen 完成事件处理
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// src/application/event-handlers/mpc-keygen-completed.handler.ts
|
||||||
|
|
||||||
|
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
||||||
|
import { MpcEventConsumerService, KeygenCompletedPayload } from '@/infrastructure/kafka/mpc-event-consumer.service';
|
||||||
|
import { AddressDerivationAdapter } from '@/infrastructure/blockchain/address-derivation.adapter';
|
||||||
|
import { EventPublisherService } from '@/infrastructure/kafka/event-publisher.service';
|
||||||
|
import { WalletAddressCreatedEvent } from '@/domain/events';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MpcKeygenCompletedHandler implements OnModuleInit {
|
||||||
|
private readonly logger = new Logger(MpcKeygenCompletedHandler.name);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly mpcEventConsumer: MpcEventConsumerService,
|
||||||
|
private readonly addressDerivation: AddressDerivationAdapter,
|
||||||
|
private readonly eventPublisher: EventPublisherService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async onModuleInit() {
|
||||||
|
this.mpcEventConsumer.onKeygenCompleted(this.handleKeygenCompleted.bind(this));
|
||||||
|
this.logger.log('Registered KeygenCompleted event handler');
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleKeygenCompleted(payload: KeygenCompletedPayload): Promise<void> {
|
||||||
|
const userId = payload.extraPayload?.userId;
|
||||||
|
const username = payload.extraPayload?.username;
|
||||||
|
const publicKey = payload.publicKey;
|
||||||
|
|
||||||
|
if (!userId || !username || !publicKey) {
|
||||||
|
this.logger.error('Missing required fields in KeygenCompleted payload');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.log(`[DERIVE] Processing keygen completion for userId=${userId}`);
|
||||||
|
this.logger.log(`[DERIVE] PublicKey: ${publicKey.substring(0, 20)}...`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 从公钥派生所有链的地址
|
||||||
|
const addresses = this.addressDerivation.deriveAllAddresses(publicKey);
|
||||||
|
|
||||||
|
this.logger.log(`[DERIVE] Derived ${addresses.length} addresses:`);
|
||||||
|
addresses.forEach(addr => {
|
||||||
|
this.logger.log(`[DERIVE] ${addr.chainType}: ${addr.address}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 发布 WalletAddressCreated 事件
|
||||||
|
const event = new WalletAddressCreatedEvent({
|
||||||
|
userId,
|
||||||
|
username,
|
||||||
|
publicKey,
|
||||||
|
addresses: addresses.map(a => ({
|
||||||
|
chainType: a.chainType,
|
||||||
|
address: a.address,
|
||||||
|
addressType: a.addressType,
|
||||||
|
})),
|
||||||
|
mpcSessionId: payload.sessionId,
|
||||||
|
delegateShare: payload.extraPayload?.delegateShare,
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.eventPublisher.publish(event);
|
||||||
|
this.logger.log(`[DERIVE] Published WalletAddressCreated event for userId=${userId}`);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(`[DERIVE] Failed to derive addresses: ${error.message}`, error.stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.4 消费的 Identity/Wallet 事件
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// src/infrastructure/kafka/event-consumer.controller.ts
|
// src/infrastructure/kafka/event-consumer.controller.ts
|
||||||
|
|
||||||
|
|
@ -2380,6 +2692,99 @@ constructor(
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*文档版本: 1.1.0*
|
## 17. MPC 集成事件流
|
||||||
*最后更新: 2025-12-03*
|
|
||||||
*变更说明: 添加模块化设计、聚合根基类、完整值对象定义、架构兼容性说明*
|
### 17.1 完整事件流程图
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ MPC 钱包创建事件流 │
|
||||||
|
├──────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ [1] 用户创建账户 │
|
||||||
|
│ │ │
|
||||||
|
│ ▼ │
|
||||||
|
│ ┌─────────────────┐ │
|
||||||
|
│ │ identity-service│ │
|
||||||
|
│ │ │ ────────────────────────────────────────┐ │
|
||||||
|
│ │ 发布事件: │ │ │
|
||||||
|
│ │ mpc.KeygenRequested │ │
|
||||||
|
│ └─────────────────┘ │ │
|
||||||
|
│ ▼ │
|
||||||
|
│ ┌─────────────────┐ │
|
||||||
|
│ [2] MPC 密钥生成 │ mpc-service │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ ┌────────────────────────────────────────────│ 消费事件: │ │
|
||||||
|
│ │ │ mpc.KeygenRequested │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ │ [3] 生成公钥 │ 发布事件: │ │
|
||||||
|
│ │ │ │ mpc.KeygenStarted │
|
||||||
|
│ │ │ │ mpc.KeygenCompleted │
|
||||||
|
│ │ ▼ └─────────────────┘ │
|
||||||
|
│ │ publicKey: 33 bytes │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ ▼ ▼ │
|
||||||
|
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ blockchain-service │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ [4] 消费: mpc.KeygenCompleted │ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ │ ▼ │ │
|
||||||
|
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
|
||||||
|
│ │ │ AddressDerivationAdapter │ │ │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ │ │ publicKey ──┬──> deriveEvmAddress() ──> 0x1234... │ │ │
|
||||||
|
│ │ │ │ (BSC, KAVA) │ │ │
|
||||||
|
│ │ │ │ │ │ │
|
||||||
|
│ │ │ └──> deriveCosmosAddress() ──> kava1... │ │ │
|
||||||
|
│ │ │ dst1... │ │ │
|
||||||
|
│ │ └─────────────────────────────────────────────────────────┘ │ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ │ ▼ │ │
|
||||||
|
│ │ [5] 发布: blockchain.WalletAddressCreated │ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ └───────┼──────────────────────────────────────────────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ├──────────────────────────────┐ │
|
||||||
|
│ │ │ │
|
||||||
|
│ ▼ ▼ │
|
||||||
|
│ ┌─────────────────┐ ┌─────────────────┐ │
|
||||||
|
│ │ identity-service│ │ wallet-service │ │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ │ [6] 存储关联: │ │ [7] 存储钱包: │ │
|
||||||
|
│ │ userId ↔ address│ │ 地址、余额管理 │ │
|
||||||
|
│ └─────────────────┘ └─────────────────┘ │
|
||||||
|
│ │
|
||||||
|
└──────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 17.2 事件 Topic 汇总
|
||||||
|
|
||||||
|
| Topic | 发布者 | 消费者 | 描述 |
|
||||||
|
|-------|--------|--------|------|
|
||||||
|
| `mpc.KeygenRequested` | identity-service | mpc-service | 请求生成 MPC 密钥 |
|
||||||
|
| `mpc.KeygenStarted` | mpc-service | identity-service | 密钥生成开始 |
|
||||||
|
| `mpc.KeygenCompleted` | mpc-service | blockchain-service | 密钥生成完成,包含公钥 |
|
||||||
|
| `mpc.SessionFailed` | mpc-service | identity-service, blockchain-service | 会话失败 |
|
||||||
|
| `blockchain.WalletAddressCreated` | blockchain-service | identity-service, wallet-service | 地址派生完成 |
|
||||||
|
|
||||||
|
### 17.3 关键设计决策
|
||||||
|
|
||||||
|
1. **职责分离**:
|
||||||
|
- mpc-service 只负责 MPC 协议,不了解区块链地址格式
|
||||||
|
- blockchain-service 封装所有区块链技术细节
|
||||||
|
- identity-service 不直接处理公钥→地址转换
|
||||||
|
|
||||||
|
2. **多链扩展性**:
|
||||||
|
- 新增链类型只需在 `AddressDerivationAdapter` 添加派生逻辑
|
||||||
|
- 事件格式保持不变,下游服务无需修改
|
||||||
|
|
||||||
|
3. **事件溯源**:
|
||||||
|
- 所有状态变更通过事件传递
|
||||||
|
- 支持事件重放和故障恢复
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*文档版本: 1.2.0*
|
||||||
|
*最后更新: 2025-12-06*
|
||||||
|
*变更说明: 添加公钥→地址派生职责、MPC 事件集成、AddressDerivationAdapter、WalletAddressCreated 事件*
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue