企业级钱包架构设计完全指南

目录

  1. 交易所钱包业务闭环
  2. 核心概念澄清
  3. 完整业务流程
  4. 资金流转设计
  5. 架构设计思想
  6. 安全架构
  7. 系统架构实现
  8. 真实案例

交易所钱包业务闭环

核心问题先回答

在讲架构之前,先回答几个关键问题:

Q1: 用户在交易所有"钱包"吗?

❌ 常见误解:
"用户在交易所有自己的钱包和私钥"

✅ 真相:
用户在交易所只有"账户余额"(数据库记录)
交易所是托管钱包,私钥由交易所统一管理!

┌─────────────────────────────────────────────────────────┐
│              用户视角 vs 实际架构                        │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  用户看到的(前端界面):                                │
│  ┌────────────────────────────┐                        │
│  │ 我的钱包:                  │                        │
│  │ BTC 余额:1.5 BTC          │                        │
│  │ ETH 余额:10 ETH           │                        │
│  │ USDT 余额:50,000 USDT     │                        │
│  │                            │                        │
│  │ [充值] [提现] [交易]        │                        │
│  └────────────────────────────┘                        │
│                                                          │
│  实际情况(后端数据库):                                │
│  ┌────────────────────────────┐                        │
│  │ users 表:                  │                        │
│  │ user_id: user-123          │                        │
│  │                            │                        │
│  │ balances 表:               │                        │
│  │ user-123 | BTC  | 1.5      │ ← 只是数据库记录!     │
│  │ user-123 | ETH  | 10       │                        │
│  │ user-123 | USDT | 50000    │                        │
│  └────────────────────────────┘                        │
│                                                          │
│  真实的币在哪里?                                        │
│  ┌────────────────────────────┐                        │
│  │ 交易所的钱包地址:          │                        │
│  │                            │                        │
│  │ 热钱包地址:0xABCD...      │                        │
│  │ ├─ 100 BTC                 │ ← 所有用户的币        │
│  │ ├─ 5000 ETH                │    混在一起!         │
│  │ └─ 10M USDT                │                        │
│  │                            │                        │
│  │ 冷钱包地址:0x1234...      │                        │
│  │ ├─ 5000 BTC                │                        │
│  │ ├─ 50000 ETH               │                        │
│  │ └─ 500M USDT               │                        │
│  └────────────────────────────┘                        │
│                                                          │
└─────────────────────────────────────────────────────────┘

关键理解:
1. 用户余额 = 数据库数字(不是真实的链上钱包)
2. 真实的币 = 在交易所的钱包地址中
3. 所有用户的币混在一起(pooled)
4. 私钥由交易所统一管理(用户无法获取)

这就是"托管钱包"的含义!

Q2: 用户充值时发生了什么?

完整流程(重点):

┌─────────────────────────────────────────────────────────┐
│              用户充值完整流程                            │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  第 1 步:用户请求充值地址                              │
│  ┌────────────────────────────┐                        │
│  │ 用户:点击"充值 ETH"        │                        │
│  │   ↓                        │                        │
│  │ 前端:POST /api/deposit/address                     │
│  └────────────┬───────────────┘                        │
│               ▼                                          │
│  ┌────────────────────────────┐                        │
│  │ 后端:生成充值地址          │                        │
│  │                            │                        │
│  │ 方案 A(每个用户专属地址): │                        │
│  │ ├─ 从 HD 钱包派生新地址     │                        │
│  │ ├─ 路径:m/44'/60'/0'/0/用户ID                      │
│  │ ├─ 地址:0xAABB...         │                        │
│  │ ├─ 保存到数据库:           │                        │
│  │ │   user-123 → 0xAABB...   │                        │
│  │ └─ 返回给用户               │                        │
│  │                            │                        │
│  │ 方案 B(共用地址 + Memo):  │                        │
│  │ ├─ 统一地址:0xAAAA...     │                        │
│  │ ├─ 用户标识:memo=user-123 │                        │
│  │ └─ 返回给用户               │                        │
│  └────────────┬───────────────┘                        │
│               ▼                                          │
│  第 2 步:用户从外部钱包转账                            │
│  ┌────────────────────────────┐                        │
│  │ 用户在 MetaMask:           │                        │
│  │ ├─ 转账 1 ETH               │                        │
│  │ ├─ 目标:0xAABB...(交易所)│                        │
│  │ └─ 发送交易到区块链         │                        │
│  └────────────┬───────────────┘                        │
│               ▼                                          │
│  第 3 步:交易所监听区块链                              │
│  ┌────────────────────────────┐                        │
│  │ 充值监听服务(24/7运行):  │                        │
│  │                            │                        │
│  │ while true:                │                        │
│  │   监听新区块               │                        │
│  │   ↓                        │                        │
│  │   发现转账到 0xAABB...     │                        │
│  │   ↓                        │                        │
│  │   查数据库:0xAABB... = user-123                   │
│  │   ↓                        │                        │
│  │   等待 12 个确认           │                        │
│  │   ↓                        │                        │
│  │   更新数据库余额:          │                        │
│  │   user-123 的 ETH += 1     │                        │
│  │   ↓                        │                        │
│  │   通知用户:充值成功 ✅     │                        │
│  └────────────────────────────┘                        │
│                                                          │
│  资金实际位置:                                          │
│  - 链上:在交易所地址 0xAABB...                        │
│  - 用户账户:数据库 +1(只是数字)                      │
│  - 私钥:在交易所的服务器/HSM 中                        │
│                                                          │
└─────────────────────────────────────────────────────────┘

关键点:
✅ 用户充值的币到了交易所地址(链上)
✅ 用户账户余额增加(数据库)
✅ 私钥由交易所管理(不给用户)
✅ 用户只能通过交易所系统操作资金

Q3: 用户提现时发生了什么?

完整流程(重点):

┌─────────────────────────────────────────────────────────┐
│              用户提现完整流程                            │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  第 1 步:用户发起提现                                  │
│  ┌────────────────────────────┐                        │
│  │ 用户:                      │                        │
│  │ ├─ 输入目标地址:0x1234...  │                        │
│  │ ├─ 输入金额:1 ETH          │                        │
│  │ └─ 点击"提现"               │                        │
│  └────────────┬───────────────┘                        │
│               ▼                                          │
│  第 2 步:系统检查(数据库操作)                        │
│  ┌────────────────────────────┐                        │
│  │ 后端检查:                  │                        │
│  │ ├─ 用户余额够吗?           │                        │
│  │ │   SELECT balance FROM balances                    │
│  │ │   WHERE user_id='user-123' AND asset='ETH'        │
│  │ │   余额:10 ETH ✅           │                        │
│  │ │                            │                        │
│  │ ├─ KYC 验证了吗?✅          │                        │
│  │ ├─ 超过限额吗?✅            │                        │
│  │ ├─ 在白名单吗?✅            │                        │
│  │ └─ 通过检查 → 继续          │                        │
│  └────────────┬───────────────┘                        │
│               ▼                                          │
│  第 3 步:扣除用户余额(数据库)                        │
│  ┌────────────────────────────┐                        │
│  │ UPDATE balances            │                        │
│  │ SET balance = balance - 1   │                        │
│  │ WHERE user_id='user-123'   │                        │
│  │ AND asset='ETH'            │                        │
│  │                            │                        │
│  │ 现在用户余额:9 ETH         │                        │
│  └────────────┬───────────────┘                        │
│               ▼                                          │
│  第 4 步:判断使用哪个钱包签名                          │
│  ┌────────────────────────────┐                        │
│  │ 根据金额路由:              │                        │
│  │                            │                        │
│  │ 1 ETH = $3000              │                        │
│  │   ↓                        │                        │
│  │ < $10,000                  │                        │
│  │   ↓                        │                        │
│  │ 使用热钱包 ✅               │                        │
│  └────────────┬───────────────┘                        │
│               ▼                                          │
│  第 5 步:热钱包签名并发送(链上)                      │
│  ┌────────────────────────────┐                        │
│  │ 热钱包服务:                │                        │
│  │                            │                        │
│  │ 1. 从 KMS 获取私钥          │                        │
│  │    privateKey = KMS.decrypt(热钱包密钥)             │
│  │                            │                        │
│  │ 2. 构建交易                 │                        │
│  │    tx = {                  │                        │
│  │      from: 0xHOT... (热钱包地址)                    │
│  │      to: 0x1234... (用户目标地址)                   │
│  │      value: 1 ETH          │                        │
│  │    }                       │                        │
│  │                            │                        │
│  │ 3. 用私钥签名               │                        │
│  │    signedTx = sign(tx, privateKey)                 │
│  │                            │                        │
│  │ 4. 广播到区块链             │                        │
│  │    blockchain.send(signedTx)                        │
│  │                            │                        │
│  │ 5. 得到交易哈希             │                        │
│  │    txHash = 0xabcd...      │                        │
│  └────────────┬───────────────┘                        │
│               ▼                                          │
│  第 6 步:链上确认                                      │
│  ┌────────────────────────────┐                        │
│  │ 区块链:                    │                        │
│  │ ├─ 验证签名 ✅              │                        │
│  │ ├─ 检查余额 ✅              │                        │
│  │ ├─ 从热钱包扣除 1 ETH       │                        │
│  │ ├─ 转给 0x1234...(用户)   │                        │
│  │ └─ 交易成功 ✅              │                        │
│  └────────────┬───────────────┘                        │
│               ▼                                          │
│  第 7 步:更新提现状态                                  │
│  ┌────────────────────────────┐                        │
│  │ 监听到交易确认:            │                        │
│  │ ├─ 更新提现记录状态         │                        │
│  │ ├─ 通知用户:提现成功       │                        │
│  │ └─ 记录审计日志             │                        │
│  └────────────────────────────┘                        │
│                                                          │
└─────────────────────────────────────────────────────────┘

资金变化总结:
1. 用户余额(数据库):10 ETH → 9 ETH
2. 热钱包(链上):100 ETH → 99 ETH
3. 用户外部地址(链上):0 ETH → 1 ETH

私钥使用:
✅ 热钱包的私钥(交易所管理)
❌ 不是用户的私钥(用户没有私钥)

核心概念澄清

交易所钱包的本质

关键理解:

1. 交易所 = 托管服务
   ┌──────────────────────────────────┐
   │ 用户把币托管给交易所             │
   │ 交易所代为保管                   │
   │ 就像把钱存在银行                 │
   └──────────────────────────────────┘

2. 用户余额 = 数据库记录(债权)
   ┌──────────────────────────────────┐
   │ 数据库表示"交易所欠用户多少币"   │
   │ 不是用户真正拥有的链上资产       │
   │ 类似银行存款余额                 │
   └──────────────────────────────────┘

3. 交易所钱包 = 资金池(Pooled)
   ┌──────────────────────────────────┐
│  │ 所有用户的币混在一起             │
   │ 用热钱包 + 冷钱包统一管理         │
   │ 私钥由交易所控制                 │
   └──────────────────────────────────┘

类比:
┌─────────────────┬─────────────────┐
│ 交易所          │ 银行            │
├─────────────────┼─────────────────┤
│ 用户余额        │ 存款余额        │
│ 数据库记录      │ 账户数字        │
│ 充值            │ 存钱            │
│ 提现            │ 取钱            │
│ 站内转账        │ 内部转账        │
│ 私钥            │ 金库钥匙        │
└─────────────────┴─────────────────┘

完整业务流程

流程 1: 用户注册和充值

════════════════════════════════════════════════════════════
场景:新用户 Alice 注册交易所并充值
════════════════════════════════════════════════════════════

步骤 1:用户注册
┌─────────────────────────────────────┐
│ Alice 注册交易所                    │
│ ├─ 邮箱:alice@example.com         │
│ ├─ 密码:******                    │
│ └─ 创建账号                         │
└────────────┬────────────────────────┘
             ▼
┌─────────────────────────────────────┐
│ 数据库操作:                         │
│                                     │
│ INSERT INTO users (id, email)       │
│ VALUES ('user-alice', 'alice@...')  │
│                                     │
│ ✅ 账号创建完成                      │
│ ❌ 此时还没有钱包地址                │
│ ❌ 也没有生成私钥                    │
└─────────────────────────────────────┘

步骤 2:用户请求充值地址
┌─────────────────────────────────────┐
│ Alice:我要充值 ETH                 │
│   ↓                                 │
│ 点击"获取充值地址"                  │
└────────────┬────────────────────────┘
             ▼
┌─────────────────────────────────────┐
│ 后端地址生成服务:                   │
│                                     │
│ 1. 检查 Alice 是否已有 ETH 充值地址 │
│    SELECT address FROM deposit_addresses│
│    WHERE user_id='user-alice'       │
│    AND coin='ETH'                   │
│    结果:没有                        │
│                                     │
│ 2. 从交易所主 HD 钱包派生新地址     │
│    ┌────────────────────────────┐  │
│    │ 交易所 HD 钱包:            │  │
│    │ 种子:[交易所保管]          │  │
│    │   ↓                        │  │
│    │ 路径:m/44'/60'/0'/0/12345 │  │
│    │         (Alice 是第12345个用户)│
│    │   ↓                        │  │
│    │ 地址:0xALICE123...        │  │
│    └────────────────────────────┘  │
│                                     │
│ 3. 保存地址映射                     │
│    INSERT INTO deposit_addresses    │
│    (user_id, coin, address, path)   │
│    VALUES (                         │
│      'user-alice',                  │
│      'ETH',                         │
│      '0xALICE123...',              │
│      'm/44\'/60\'/0\'/0/12345'     │
│    )                                │
│                                     │
│ 4. 返回地址给 Alice                 │
│    "您的充值地址:0xALICE123..."    │
└────────────┬────────────────────────┘
             ▼
┌─────────────────────────────────────┐
│ Alice 从 MetaMask 转账:            │
│ ├─ 从:0xALICE_METAMASK...(她的MetaMask)            │
│ ├─ 到:0xALICE123...(交易所给她的地址)              │
│ ├─ 金额:2 ETH                      │
│ └─ 签名并广播(用她 MetaMask 的私钥)│
└────────────┬────────────────────────┘
             ▼
┌─────────────────────────────────────┐
│ 区块链确认(约 15 秒)              │
│ ├─ 从 0xALICE_METAMASK... 扣除 2 ETH│
│ └─ 转入 0xALICE123...(交易所地址) │
└────────────┬────────────────────────┘
             ▼
┌─────────────────────────────────────┐
│ 交易所监听服务:                     │
│                                     │
│ 1. 监听到交易:0xALICE123... 收到 2 ETH               │
│                                     │
│ 2. 查询地址归属:                   │
│    SELECT user_id FROM deposit_addresses│
│    WHERE address='0xALICE123...'    │
│    结果:user-alice                 │
│                                     │
│ 3. 等待确认(12个区块)             │
│    第 1 个确认...                   │
│    第 12 个确认... ✅               │
│                                     │
│ 4. 更新 Alice 余额(数据库):      │
│    UPDATE balances                  │
│    SET balance = balance + 2        │
│    WHERE user_id='user-alice'       │
│    AND asset='ETH'                  │
│                                     │
│    Alice 账户:0 ETH → 2 ETH ✅     │
│                                     │
│ 5. 通知 Alice:                     │
│    "充值成功:2 ETH"                │
└─────────────────────────────────────┘

现在的状态:
┌──────────────────────────────────────┐
│ Alice 在交易所的账户:               │
│ ├─ 数据库余额:2 ETH                │
│ └─ 可以在站内交易、提现              │
│                                      │
│ 链上实际情况:                       │
│ ├─ 0xALICE123...(交易所地址)有 2 ETH│
│ ├─ 私钥在交易所服务器/HSM 中         │
│ └─ Alice 无法直接控制这个地址        │
└──────────────────────────────────────┘

流程 2: 用户提现

════════════════════════════════════════════════════════════
场景:Alice 提现 1 ETH 到她的 MetaMask
════════════════════════════════════════════════════════════

步骤 1:Alice 发起提现
┌─────────────────────────────────────┐
│ Alice 输入:                        │
│ ├─ 目标地址:0xALICE_METAMASK...   │
│ ├─ 金额:1 ETH                      │
│ └─ 点击"提现"                       │
└────────────┬────────────────────────┘
             ▼
步骤 2:系统检查和扣款(数据库)
┌─────────────────────────────────────┐
│ 1. 检查余额:                       │
│    Alice 账户:2 ETH ✅              │
│                                     │
│ 2. KYC/AML/限额检查 ✅               │
│                                     │
│ 3. 先扣除余额(防止双花):          │
│    UPDATE balances                  │
│    SET balance = 2 - 1 = 1          │
│    WHERE user_id='user-alice'       │
│                                     │
│    Alice 余额:2 ETH → 1 ETH        │
│                                     │
│ 4. 创建提现记录:                   │
│    INSERT INTO withdrawals          │
│    (id, user_id, to_addr, amount, status)│
│    VALUES (                         │
│      'withdraw-001',                │
│      'user-alice',                  │
│      '0xALICE_METAMASK...',        │
│      1,                             │
│      'processing'                   │
│    )                                │
└────────────┬────────────────────────┘
             ▼
步骤 3:路由到合适的钱包
┌─────────────────────────────────────┐
│ 钱包路由器判断:                     │
│                                     │
│ 金额:1 ETH ≈ $3000                 │
│   ↓                                 │
│ < $10,000 → 使用热钱包 ✅            │
│                                     │
│ 如果 > $100,000 → 需要冷钱包        │
│ (需要 CEO+CFO 多签,24小时)       │
└────────────┬────────────────────────┘
             ▼
步骤 4:热钱包签名发送
┌─────────────────────────────────────┐
│ 热钱包服务执行:                     │
│                                     │
│ 1. 从 KMS 解密热钱包私钥            │
│    ┌─────────────────────────┐     │
│    │ AWS KMS.Decrypt()       │     │
│    │   ↓                     │     │
│    │ privateKey = 0x4c0883...│     │
│    │ (这是交易所热钱包的私钥) │     │
│    └─────────────────────────┘     │
│                                     │
│ 2. 构建以太坊交易                   │
│    tx = {                           │
│      from: 0xHOT_WALLET...  ← 交易所热钱包地址         │
│      to: 0xALICE_METAMASK... ← Alice 的 MetaMask       │
│      value: 1 ETH                   │
│      nonce: 12345                   │
│      gasPrice: 20 Gwei              │
│    }                                │
│                                     │
│ 3. 签名                             │
│    signedTx = sign(tx, privateKey)  │
│    ⚠️  用的是交易所的私钥!          │
│                                     │
│ 4. 广播到以太坊网络                 │
│    txHash = eth.sendTransaction(signedTx)              │
│                                     │
│ 5. 立即清除内存中的私钥             │
│    clearMemory(privateKey)          │
└────────────┬────────────────────────┘
             ▼
步骤 5:链上执行
┌─────────────────────────────────────┐
│ 以太坊区块链:                       │
│                                     │
│ 1. 验证交易签名 ✅                   │
│ 2. 检查 from 地址余额:              │
│    0xHOT_WALLET... 有 100 ETH ✅    │
│                                     │
│ 3. 执行转账:                       │
│    0xHOT_WALLET...: 100 → 99 ETH    │
│    0xALICE_METAMASK...: 0 → 1 ETH   │
│                                     │
│ 4. 交易成功 ✅                       │
│    TxHash: 0xabcd1234...            │
└────────────┬────────────────────────┘
             ▼
步骤 6:Alice 收到钱
┌─────────────────────────────────────┐
│ Alice 的 MetaMask:                 │
│ ├─ 自动检测到入账                   │
│ ├─ 余额:0 ETH → 1 ETH ✅            │
│ └─ 这 1 ETH 由 Alice 完全控制       │
│    (用她自己的 MetaMask 私钥)      │
└─────────────────────────────────────┘

最终状态:
┌──────────────────────────────────────┐
│ Alice 交易所账户(数据库):         │
│ └─ ETH 余额:1 ETH                  │
│                                      │
│ Alice MetaMask(链上):             │
│ └─ ETH 余额:1 ETH                  │
│                                      │
│ 交易所热钱包(链上):               │
│ └─ ETH 余额:99 ETH                 │
│    (原本 100,转出 1)               │
└──────────────────────────────────────┘

流程 3: 站内转账(用户之间)

════════════════════════════════════════════════════════════
场景:Alice 在交易所内转 0.5 ETH 给 Bob
════════════════════════════════════════════════════════════

关键点:站内转账不上链!只是数据库操作!

┌─────────────────────────────────────┐
│ Alice → Bob (站内转账)              │
└────────────┬────────────────────────┘
             ▼
┌─────────────────────────────────────┐
│ 纯数据库操作:                       │
│                                     │
│ BEGIN TRANSACTION;                  │
│                                     │
│ -- 扣除 Alice 余额                  │
│ UPDATE balances                     │
│ SET balance = balance - 0.5         │
│ WHERE user_id='user-alice'          │
│ AND asset='ETH';                    │
│ (1 ETH → 0.5 ETH)                   │
│                                     │
│ -- 增加 Bob 余额                    │
│ UPDATE balances                     │
│ SET balance = balance + 0.5         │
│ WHERE user_id='user-bob'            │
│ AND asset='ETH';                    │
│ (0 ETH → 0.5 ETH)                   │
│                                     │
│ COMMIT;                             │
│                                     │
│ ✅ 转账完成(秒级)                  │
│ ❌ 没有上链!                        │
│ ❌ 没有使用私钥!                    │
│ ❌ 不需要 Gas 费!                   │
└─────────────────────────────────────┘

链上状态:
┌──────────────────────────────────────┐
│ 完全没有变化!                       │
│                                      │
│ 交易所热钱包:99 ETH(不变)         │
│ Alice MetaMask:1 ETH(不变)        │
│ Bob MetaMask:0 ETH(不变)          │
│                                      │
│ 只有交易所数据库变了:               │
│ Alice 账户:1 → 0.5 ETH              │
│ Bob 账户:0 → 0.5 ETH                │
└──────────────────────────────────────┘

为什么站内转账不上链?
✅ 快(秒级 vs 分钟级)
✅ 免费(无 Gas 费)
✅ 隐私(链上不可见)

风险:
⚠️  完全依赖交易所信用
⚠️  如果交易所跑路,钱就没了

资金流转设计

交易所资金池模型

┌─────────────────────────────────────────────────────────┐
│              交易所资金池架构(核心)                    │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  链上层(区块链)                                        │
│  ┌────────────────────────────────────────────┐        │
│  │  交易所钱包地址(所有用户的币混在一起)    │        │
│  │                                             │        │
│  │  冷钱包(95%):                            │        │
│  │  ├─ 0xCOLD001... : 5000 ETH                │        │
│  │  ├─ 0xCOLD002... : 3000 ETH                │        │
│  │  └─ 0xCOLD003... : 2000 ETH                │        │
│  │                                             │        │
│  │  热钱包(5%):                             │        │
│  │  └─ 0xHOT001... : 500 ETH                  │        │
│  │                                             │        │
│  │  总计:10,500 ETH                           │        │
│  └────────────────────────────────────────────┘        │
│                     ↕                                    │
│              实际的币在这里!                            │
│                     ↕                                    │
│  ──────────────────────────────────────────────────     │
│                     ↕                                    │
│            映射关系(数据库)                            │
│                     ↕                                    │
│  账户层(数据库)                                        │
│  ┌────────────────────────────────────────────┐        │
│  │  用户余额表(只是数字记录)                │        │
│  │                                             │        │
│  │  user-alice  | ETH | 0.5                   │        │
│  │  user-bob    | ETH | 0.5                   │        │
│  │  user-carol  | ETH | 1.0                   │        │
│  │  user-david  | ETH | 2.0                   │        │
│  │  ... 100,000 个用户 ...                    │        │
│  │                                             │        │
│  │  总计:10,500 ETH                           │        │
│  │  (必须等于链上的总量!)                    │        │
│  └────────────────────────────────────────────┘        │
│                                                          │
│  审计检查(每天):                                      │
│  ┌────────────────────────────────────────────┐        │
│  │  链上总量 = 数据库余额总和                 │        │
│  │  10,500 = 10,500 ✅                         │        │
│  │                                             │        │
│  │  如果不等 → 有问题!                       │        │
│  │  可能原因:                                 │        │
│  │  - 系统 bug                                │        │
│  │  - 数据库被篡改                            │        │
│  │  - 资金被盗                                │        │
│  └────────────────────────────────────────────┘        │
│                                                          │
└─────────────────────────────────────────────────────────┘

关键点:
1. 链上:交易所统一管理所有用户的币(资金池)
2. 数据库:记录每个用户应得多少(账本)
3. 私钥:交易所管理(用户不知道)
4. 提现:交易所用自己的私钥签名转给用户

冷热钱包资金调拨

场景:热钱包余额不足,需要从冷钱包补充

┌─────────────────────────────────────────────────────────┐
│              冷热钱包资金调拨流程                        │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  触发条件:                                              │
│  热钱包余额 < 300 ETH(预设阈值 30%)                   │
│                                                          │
│  步骤 1:系统检测                                        │
│  ┌────────────────────────────┐                        │
│  │ 定时任务(每小时):        │                        │
│  │                            │                        │
│  │ 热钱包余额:250 ETH < 300   │                        │
│  │   ↓                        │                        │
│  │ 触发补充流程 ⚠️             │                        │
│  └────────────┬───────────────┘                        │
│               ▼                                          │
│  步骤 2:创建补充提案                                    │
│  ┌────────────────────────────┐                        │
│  │ 自动创建提案:              │                        │
│  │ ├─ 从:冷钱包 0xCOLD001    │                        │
│  │ ├─ 到:热钱包 0xHOT001     │                        │
│  │ ├─ 金额:500 ETH           │                        │
│  │ │   (补充到 750 ETH,75%) │                        │
│  │ └─ 类型:内部调拨          │                        │
│  └────────────┬───────────────┘                        │
│               ▼                                          │
│  步骤 3:多签审批(人工)                                │
│  ┌────────────────────────────┐                        │
│  │ 通知签名人(CEO/CFO/CTO): │                        │
│  │                            │                        │
│  │ CEO 审批:✅ 同意            │                        │
│  │ CFO 审批:✅ 同意            │                        │
│  │ CTO 审批:✅ 同意            │                        │
│  │                            │                        │
│  │ 3-of-5 签名已达成 ✅         │                        │
│  └────────────┬───────────────┘                        │
│               ▼                                          │
│  步骤 4:HSM 签名执行(链上)                            │
│  ┌────────────────────────────┐                        │
│  │ 1. 构建交易:               │                        │
│  │    from: 0xCOLD001...      │                        │
│  │    to: 0xHOT001...         │                        │
│  │    value: 500 ETH          │                        │
│  │                            │                        │
│  │ 2. 用 HSM 中的私钥签名:    │                        │
│  │    signedTx = HSM.sign(tx) │                        │
│  │    ⚠️  私钥在 HSM 中,永不导出│                        │
│  │                            │                        │
│  │ 3. 广播到区块链             │                        │
│  │    txHash = 0xdef...       │                        │
│  │                            │                        │
│  │ 4. 等待确认(约 3 分钟)    │                        │
│  │    确认成功 ✅              │                        │
│  └────────────┬───────────────┘                        │
│               ▼                                          │
│  结果:                                                  │
│  ┌────────────────────────────┐                        │
│  │ 冷钱包:10,000 → 9,500 ETH │                        │
│  │ 热钱包:250 → 750 ETH      │                        │
│  │                            │                        │
│  │ ✅ 热钱包资金充足            │                        │
│  │ ✅ 可以继续处理用户提现      │                        │
│  └────────────────────────────┘                        │
│                                                          │
└─────────────────────────────────────────────────────────┘

关键点:
- 这是交易所内部操作
- 用户无感知
- 链上可以看到转账记录
- 但用户余额(数据库)不变

架构设计思想

设计思想 1: 资金池模型(Pooled Model)

为什么不给每个用户独立的私钥?

方案 A:每个用户独立钱包(❌ 不可行)
┌──────────────────────────────────────┐
│ 100 万用户 = 100 万个私钥            │
│                                      │
│ 问题:                               │
│ ❌ 私钥管理复杂(100 万个)          │
│ ❌ 备份困难                          │
│ ❌ 站内转账需要上链(慢、贵)        │
│ ❌ 热钱包无法集中管理                │
│ ❌ 冷热分离困难                      │
└──────────────────────────────────────┘

方案 B:资金池模型(✅ 交易所采用)
┌──────────────────────────────────────┐
│ 100 万用户共享几个钱包地址           │
│                                      │
│ 优势:                               │
│ ✅ 私钥管理简单(只需管理几个)      │
│ ✅ 站内转账秒到(数据库操作)        │
│ ✅ 免 Gas 费(不上链)               │
│ ✅ 冷热分离容易实现                  │
│ ✅ 集中风控                          │
│                                      │
│ 实现:                               │
│ - 用户余额:数据库表                 │
│ - 真实资金:少数钱包地址             │
│ - 对账:定期检查链上 = 数据库        │
└──────────────────────────────────────┘

所以交易所 = 托管钱包
用户信任交易所管理资金

设计思想 2: 冷热分离(Hot-Cold Segregation)

核心思想:
大部分资金放冷钱包(离线),
小部分资金放热钱包(在线),
平衡安全性和流动性。

┌─────────────────────────────────────────────────────────┐
│              冷热钱包职责分工                            │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  热钱包(Hot Wallet)- 2-5% 资金                        │
│  ┌────────────────────────────────────┐                │
│  │ 职责:处理日常小额提现              │                │
│  │                                     │                │
│  │ 私钥存储:KMS 加密                  │                │
│  │ 签名方式:自动化(程序签名)        │                │
│  │ 响应时间:秒级                      │                │
│  │ 操作流程:                          │                │
│  │ ├─ 用户请求 → 检查 → 自动签名      │                │
│  │ └─ 无需人工介入                     │                │
│  │                                     │                │
│  │ 资金补充:                          │                │
│  │ - 余额 < 30% → 从温钱包补充         │                │
│  │ - 余额 > 80% → 转入冷钱包           │                │
│  └────────────────────────────────────┘                │
│                                                          │
│  温钱包(Warm Wallet)- 3-5% 资金                       │
│  ┌────────────────────────────────────┐                │
│  │ 职责:中等金额提现                  │                │
│  │                                     │                │
│  │ 私钥存储:HSM(内网隔离)           │                │
│  │ 签名方式:半自动(需要审批)        │                │
│  │ 响应时间:1-4 小时                  │                │
│  │ 操作流程:                          │                │
│  │ ├─ 用户请求 → 创建提案             │                │
│  │ ├─ 财务主管审批                     │                │
│  │ └─ 审批通过 → HSM 签名              │                │
│  └────────────────────────────────────┘                │
│                                                          │
│  冷钱包(Cold Wallet)- 90-95% 资金                     │
│  ┌────────────────────────────────────┐                │
│  │ 职责:长期存储大额资金              │                │
│  │                                     │                │
│  │ 私钥存储:HSM(物理隔离,保险柜)   │                │
│  │ 签名方式:多签(3-of-5)            │                │
│  │ 响应时间:24-72 小时                │                │
│  │ 操作流程:                          │                │
│  │ ├─ 创建提案                         │                │
│  │ ├─ CEO 审批(第 1 个签名)         │                │
│  │ ├─ CFO 审批(第 2 个签名)         │                │
│  │ ├─ CTO 审批(第 3 个签名)         │                │
│  │ ├─ 24 小时观察期                    │                │
│  │ └─ HSM 签名并执行                   │                │
│  └────────────────────────────────────┘                │
│                                                          │
└─────────────────────────────────────────────────────────┘

设计原则:
1. 流动性 vs 安全性的平衡
   - 热钱包:高流动性,低安全性
   - 冷钱包:低流动性,高安全性

2. 资金分配动态调整
   - 根据提现量动态调整
   - 节假日前增加热钱包比例

3. 多层防护
   - 热钱包被盗 → 损失有限(< 5%)
   - 冷钱包需要多人配合才能转账

设计思想 3: 地址复用 vs 专属地址

充值地址策略选择:

策略 A:每个用户专属地址(推荐)
┌──────────────────────────────────────┐
│ 通过 HD 钱包派生                     │
│                                      │
│ user-1 → m/44'/60'/0'/0/1 → 0xAAA...│
│ user-2 → m/44'/60'/0'/0/2 → 0xBBB...│
│ user-3 → m/44'/60'/0'/0/3 → 0xCCC...│
│ ...                                  │
│                                      │
│ 优点:                               │
│ ✅ 隐私好(无法关联用户)            │
│ ✅ 识别简单(地址 → 用户)           │
│ ✅ 用户体验好(固定地址)            │
│                                      │
│ 缺点:                               │
│ ❌ 需要管理很多地址                  │
│ ❌ UTXO 币种(BTC)需要归集          │
└──────────────────────────────────────┘

策略 B:共用地址 + Memo(备选)
┌──────────────────────────────────────┐
│ 所有用户共用一个地址                 │
│                                      │
│ 统一地址:0xEXCHANGE...              │
│ user-1 → memo: "12345"               │
│ user-2 → memo: "67890"               │
│                                      │
│ 优点:                               │
│ ✅ 地址管理简单                      │
│ ✅ 适合 BTC(减少 UTXO)             │
│                                      │
│ 缺点:                               │
│ ❌ 用户容易忘记填 memo               │
│ ❌ 识别复杂(需要解析 memo)         │
│ ❌ 隐私差(所有人用同一地址)        │
└──────────────────────────────────────┘

主流交易所选择:
- Ethereum:策略 A(专属地址)
- Bitcoin:策略 B 或混合

完整业务流程

用户完整生命周期

┌─────────────────────────────────────────────────────────┐
│          用户在交易所的完整资金流转                      │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  ════════ 1. 注册阶段 ════════                          │
│                                                          │
│  Alice 注册                                              │
│    ↓                                                     │
│  创建账号(数据库)                                      │
│  ┌──────────────────────────────┐                      │
│  │ user_id: alice-001           │                      │
│  │ email: alice@example.com     │                      │
│  │ 余额:0(所有币种)           │                      │
│  └──────────────────────────────┘                      │
│                                                          │
│  ❌ 此时没有生成私钥!                                   │
│  ❌ 也没有钱包地址!                                     │
│                                                          │
│  ════════ 2. 充值阶段 ════════                          │
│                                                          │
│  Alice 请求 ETH 充值地址                                │
│    ↓                                                     │
│  交易所 HD 钱包派生地址                                  │
│  ┌──────────────────────────────┐                      │
│  │ 主种子(交易所保管):         │                      │
│  │ [24 词助记词,锁在保险柜]     │                      │
│  │   ↓                          │                      │
│  │ 派生路径:m/44'/60'/0'/0/12345                      │
│  │          (Alice 是第 12345 个用户)                   │
│  │   ↓                          │                      │
│  │ 地址:0xALICE_DEPOSIT...     │                      │
│  └──────────────────────────────┘                      │
│    ↓                                                     │
│  保存映射关系(数据库)                                  │
│  ┌──────────────────────────────┐                      │
│  │ deposit_addresses 表:        │                      │
│  │ alice-001 | ETH | 0xALICE_DEPOSIT...                │
│  │ alice-001 | BTC | 1ALICEbtc...                      │
│  └──────────────────────────────┘                      │
│    ↓                                                     │
│  返回地址给 Alice                                        │
│  "您的 ETH 充值地址:0xALICE_DEPOSIT..."                │
│    ↓                                                     │
│  Alice 从 MetaMask 转 5 ETH 到此地址                    │
│    ↓                                                     │
│  链上发生(以太坊区块链):                              │
│  ┌──────────────────────────────┐                      │
│  │ From: 0xALICE_METAMASK...    │                      │
│  │ To: 0xALICE_DEPOSIT...       │                      │
│  │ Value: 5 ETH                 │                      │
│  │ ✅ 交易成功                   │                      │
│  └──────────────────────────────┘                      │
│    ↓                                                     │
│  交易所监听服务检测到                                    │
│  ┌──────────────────────────────┐                      │
│  │ 1. 监听新区块                 │                      │
│  │ 2. 发现 0xALICE_DEPOSIT... 收到 5 ETH              │
│  │ 3. 查数据库:这是 alice-001 的地址                  │
│  │ 4. 等待 12 确认               │                      │
│  │ 5. 更新 Alice 余额:          │                      │
│  │    UPDATE balances            │                      │
│  │    SET balance = 0 + 5 = 5    │                      │
│  │    WHERE user_id='alice-001'  │                      │
│  │    AND asset='ETH'            │                      │
│  │ 6. 通知 Alice:"充值成功 5 ETH"                     │
│  └──────────────────────────────┘                      │
│                                                          │
│  现在状态:                                              │
│  - Alice 数据库余额:5 ETH                              │
│  - 链上 0xALICE_DEPOSIT...:5 ETH                      │
│  - 私钥:在交易所服务器中                               │
│                                                          │
│  ════════ 3. 归集阶段(交易所内部操作)════════          │
│                                                          │
│  定时任务(每小时)将分散的充值归集到热钱包              │
│    ↓                                                     │
│  ┌──────────────────────────────┐                      │
│  │ 归集脚本:                    │                      │
│  │                              │                      │
│  │ 1. 扫描所有充值地址           │                      │
│  │    发现 0xALICE_DEPOSIT... 有 5 ETH                │
│  │                              │                      │
│  │ 2. 构建归集交易:             │                      │
│  │    from: 0xALICE_DEPOSIT...  │                      │
│  │    to: 0xHOT_WALLET...       │                      │
│  │    value: 4.99 ETH (留 0.01做 gas)                 │
│  │                              │                      │
│  │ 3. 用该地址的私钥签名:       │                      │
│  │    key = derive(path=m/44'/60'/0'/0/12345)         │
│  │    signedTx = sign(tx, key)  │                      │
│  │                              │                      │
│  │ 4. 广播                      │                      │
│  │    ✅ 归集成功                │                      │
│  └──────────────────────────────┘                      │
│                                                          │
│  现在状态:                                              │
│  - 0xALICE_DEPOSIT...:0.01 ETH(只留 gas)            │
│  - 0xHOT_WALLET...:+4.99 ETH(归集到热钱包)          │
│  - Alice 数据库余额:5 ETH(不变)                     │
│                                                          │
│  为什么要归集?                                          │
│  ✅ 集中管理资金                                         │
│  ✅ 提高提现效率                                         │
│  ✅ 减少 gas 浪费                                        │
│                                                          │
│  ════════ 4. 提现阶段 ════════                          │
│                                                          │
│  Alice 提现 2 ETH 到她的 MetaMask                       │
│    ↓                                                     │
│  (详见前面的提现流程)                                  │
│  用热钱包的私钥签名 → 转给 Alice 的 MetaMask            │
│                                                          │
└─────────────────────────────────────────────────────────┘

安全架构

多层安全防护

┌─────────────────────────────────────────────────────────┐
│              交易所钱包安全架构(纵深防御)              │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  Layer 1:冷热隔离(架构层)                            │
│  ┌────────────────────────────────────┐                │
│  │ 95% 资金在冷钱包(离线)           │                │
│  │ 即使热钱包全部被盗 → 损失 < 5%     │                │
│  └────────────────────────────────────┘                │
│                                                          │
│  Layer 2:私钥保护(存储层)                            │
│  ┌────────────────────────────────────┐                │
│  │ 热钱包:KMS 加密                   │                │
│  │ 冷钱包:HSM 物理隔离               │                │
│  │ 绝不明文存储                       │                │
│  └────────────────────────────────────┘                │
│                                                          │
│  Layer 3:多重签名(执行层)                            │
│  ┌────────────────────────────────────┐                │
│  │ 大额提现需要多人审批               │                │
│  │ CEO + CFO + CTO 任意 3 人          │                │
│  │ 单人无法作恶                       │                │
│  └────────────────────────────────────┘                │
│                                                          │
│  Layer 4:限额控制(业务层)                            │
│  ┌────────────────────────────────────┐                │
│  │ 每日限额:基于 KYC 等级            │                │
│  │ 单笔限额:基于风险评分             │                │
│  │ 自动拦截异常                       │                │
│  └────────────────────────────────────┘                │
│                                                          │
│  Layer 5:白名单(访问层)                              │
│  ┌────────────────────────────────────┐                │
│  │ 只能提现到白名单地址               │                │
│  │ 添加白名单需要审批 + 24h 等待      │                │
│  └────────────────────────────────────┘                │
│                                                          │
│  Layer 6:实时监控(检测层)                            │
│  ┌────────────────────────────────────┐                │
│  │ 异常检测:                         │                │
│  │ - 大额提现                         │                │
│  │ - 高频提现                         │                │
│  │ - 新设备登录                       │                │
│  │ - 可疑IP                           │                │
│  │ 自动告警或阻止                     │                │
│  └────────────────────────────────────┘                │
│                                                          │
│  Layer 7:审计追踪(合规层)                            │
│  ┌────────────────────────────────────┐                │
│  │ 所有操作记录审计日志               │                │
│  │ 不可篡改,保留 7 年                │                │
│  │ 可追溯每一笔资金流动               │                │
│  └────────────────────────────────────┘                │
│                                                          │
└─────────────────────────────────────────────────────────┘

防御深度:
攻击者需要突破所有 7 层才能盗取大额资金

系统架构实现

完整技术栈架构

┌────────────────────────────────────────────────────────────────┐
│              大型交易所钱包完整架构                             │
├────────────────────────────────────────────────────────────────┤
│                                                                 │
│  用户层                                                         │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐                      │
│  │ 用户充值 │ │ 用户提现 │ │ 用户交易 │                      │
│  └────┬─────┘ └────┬─────┘ └────┬─────┘                      │
│       │            │            │                             │
│       ▼            ▼            ▼                             │
│  ┌─────────────────────────────────────────┐                 │
│  │      API Gateway(Golang)               │                 │
│  │      - 认证授权                          │                 │
│  │      - Rate Limiting                     │                 │
│  │      - 请求验证                          │                 │
│  └──────────────────┬──────────────────────┘                 │
│                     │                                          │
│       ┌─────────────┼─────────────┐                           │
│       │             │             │                           │
│       ▼             ▼             ▼                           │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐                      │
│  │充值监听 │  │提现服务 │  │余额服务 │                      │
│  │服务     │  │         │  │         │                      │
│  └────┬────┘  └────┬────┘  └────┬────┘                      │
│       │            │            │                             │
│       │            │            │                             │
│       ▼            ▼            ▼                             │
│  ┌─────────────────────────────────────────┐                 │
│  │      钱包核心服务(Golang)              │                 │
│  │      ┌────────────────────────────┐     │                 │
│  │      │  地址管理                   │     │                 │
│  │      │  - HD 钱包派生              │     │                 │
│  │      │  - 地址池管理               │     │                 │
│  │      ├────────────────────────────┤     │                 │
│  │      │  签名服务                   │     │                 │
│  │      │  - 热钱包签名(自动)       │     │                 │
│  │      │  - 冷钱包签名(审批)       │     │                 │
│  │      ├────────────────────────────┤     │                 │
│  │      │  交易管理                   │     │                 │
│  │      │  - Nonce 管理               │     │                 │
│  │      │  - Gas 估算                 │     │                 │
│  │      │  - 交易广播                 │     │                 │
│  │      ├────────────────────────────┤     │                 │
│  │      │  风险控制                   │     │                 │
│  │      │  - 限额检查                 │     │                 │
│  │      │  - 白名单验证               │     │                 │
│  │      │  - 异常检测                 │     │                 │
│  │      └────────────────────────────┘     │                 │
│  └─────────────────┬───────────────────────┘                 │
│                    │                                          │
│       ┌────────────┼────────────┐                            │
│       │            │            │                            │
│       ▼            ▼            ▼                            │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐                     │
│  │热钱包   │  │温钱包   │  │冷钱包   │                     │
│  │2-5%资金 │  │3-5%资金 │  │90-95%资金│                    │
│  │         │  │         │  │         │                     │
│  │自动签名 │  │人工审批 │  │多签+HSM │                     │
│  │秒级     │  │小时级   │  │天级     │                     │
│  └─────────┘  └─────────┘  └─────────┘                     │
│                                                              │
│  数据层                                                      │
│  ┌─────────┐  ┌─────────┐  ┌──────────┐                   │
│  │PostgreSQL│  │  Redis  │  │TimescaleDB│                  │
│  │钱包数据 │  │  缓存   │  │ 审计日志 │                   │
│  └─────────┘  └─────────┘  └──────────┘                   │
│                                                              │
└────────────────────────────────────────────────────────────────┘

资金分配策略:
总资金:$1B

冷钱包($950M,95%):
├─ HSM 设备(物理隔离)
├─ 3-of-5 多签
├─ 需要 CEO + CFO + CTO 中任意 3 人
└─ 操作时间:24-72 小时

温钱包($30M,3%):
├─ HSM 设备(内网隔离)
├─ 2-of-3 多签
├─ 需要财务主管 + 运营主管
└─ 操作时间:2-4 小时

热钱包($20M,2%):
├─ KMS 加密存储
├─ 自动签名(有限额)
├─ 实时风控
└─ 操作时间:< 1 分钟

核心代码实现

1. 钱包路由器(核心逻辑)

package exchange

// WalletRouter 钱包路由器
type WalletRouter struct {
    hotWallet  *HotWallet
    warmWallet *WarmWallet
    coldWallet *ColdWallet
    
    hotWalletLimit  *big.Int  // $10,000
    warmWalletLimit *big.Int  // $100,000
}

// RouteWithdrawal 根据金额路由到不同钱包
func (wr *WalletRouter) RouteWithdrawal(
    ctx context.Context,
    withdrawal *Withdrawal,
) error {
    amount := withdrawal.Amount
    
    switch {
    case amount.Cmp(wr.hotWalletLimit) < 0:
        // < $10,000 → 热钱包(自动)
        return wr.hotWallet.ProcessWithdrawal(ctx, withdrawal)
        
    case amount.Cmp(wr.warmWalletLimit) < 0:
        // $10,000 - $100,000 → 温钱包(需审批)
        return wr.warmWallet.ProcessWithApproval(ctx, withdrawal)
        
    default:
        // > $100,000 → 冷钱包(多签)
        return wr.coldWallet.ProcessWithMultiSig(ctx, withdrawal)
    }
}

2. 热钱包服务(自动化提现)

// HotWallet 热钱包
type HotWallet struct {
    hdWallet   *HDWallet
    ethClient  *ethclient.Client
    dailyLimit *big.Int
    whitelist  map[string]bool
}

// ProcessWithdrawal 处理提现
func (hw *HotWallet) ProcessWithdrawal(
    ctx context.Context,
    withdrawal *Withdrawal,
) error {
    // 1. 安全检查
    if err := hw.securityCheck(withdrawal); err != nil {
        return err
    }
    
    // 2. 获取热钱包账户并签名
    account, _ := hw.hdWallet.DeriveEthereumAccount(0)
    
    // 3. 构建并签名交易
    tx := types.NewTransaction(...)
    signedTx, _ := types.SignTx(tx, signer, account.PrivateKey)
    
    // 4. 广播交易
    err := hw.ethClient.SendTransaction(ctx, signedTx)
    
    // 5. 记录日志
    hw.recordWithdrawal(withdrawal.ID, signedTx.Hash().Hex())
    
    return err
}

// securityCheck 安全检查
func (hw *HotWallet) securityCheck(w *Withdrawal) error {
    // 白名单、限额、频率检查
    if !hw.isWhitelisted(w.ToAddress) {
        return errors.New("address not whitelisted")
    }
    // ... 其他检查
    return nil
}

3. 冷钱包多签流程

// ColdWallet 冷钱包
type ColdWallet struct {
    hsm      *HSMClient
    multiSig *MultiSigConfig  // 3-of-5 配置
}

// ProcessWithMultiSig 多签流程
func (cw *ColdWallet) ProcessWithMultiSig(
    ctx context.Context,
    withdrawal *Withdrawal,
) error {
    // 1. 创建提案
    proposal := &WithdrawalProposal{
        ID:     uuid.New(),
        Amount: withdrawal.Amount,
        Status: "PENDING",
    }
    cw.saveProposal(proposal)
    
    // 2. 通知签名人(CEO, CFO, CTO等)
    cw.notifySigners(proposal)
    
    // 3. 等待异步审批(在另一个服务中处理)
    return nil
}

// ApproveProposal 签名人审批
func (cw *ColdWallet) ApproveProposal(
    proposalID, signerID uuid.UUID,
    approved bool,
) error {
    proposal := cw.getProposal(proposalID)
    
    // 记录审批
    proposal.Approvals = append(proposal.Approvals, Approval{
        SignerID: signerID,
        Approved: approved,
    })
    
    // 检查是否达到阈值(如 3-of-5)
    if cw.countApprovals(proposal) >= cw.multiSig.Required {
        // 使用 HSM 签名并执行
        return cw.executeWithdrawal(proposal)
    }
    
    return nil
}

MPC 架构与高可用

Fireblocks 式 MPC 架构

┌────────────────────────────────────────────────────────────────┐
│              托管服务 MPC 钱包架构                              │
├────────────────────────────────────────────────────────────────┤
│                                                                 │
│  客户层(多个机构客户)                                         │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐                         │
│  │ 客户 A  │ │ 客户 B  │ │ 客户 C  │                         │
│  └────┬────┘ └────┬────┘ └────┬────┘                         │
│       │           │           │                               │
│       └───────────┼───────────┘                               │
│                   │ API (FIX/REST/WebSocket)                  │
│                   ▼                                            │
│  ┌────────────────────────────────────────┐                  │
│  │  托管服务平台                           │                  │
│  │  ┌──────────────────────────────┐     │                  │
│  │  │  策略引擎                     │     │                  │
│  │  │  - 交易策略                   │     │                  │
│  │  │  - 白名单/黑名单              │     │                  │
│  │  │  - 限额控制                   │     │                  │
│  │  │  - 合规检查                   │     │                  │
│  │  └──────────────────────────────┘     │                  │
│  │  ┌──────────────────────────────┐     │                  │
│  │  │  MPC 签名服务                 │     │                  │
│  │  │  ├─ 密钥分片管理              │     │                  │
│  │  │  ├─ 门限签名协议              │     │                  │
│  │  │  └─ 签名聚合                  │     │                  │
│  │  └──────────────────────────────┘     │                  │
│  └────────────────────────────────────────┘                  │
│                   │                                            │
│       ┌───────────┼───────────┐                               │
│       │           │           │                               │
│       ▼           ▼           ▼                               │
│  ┌────────┐  ┌────────┐  ┌────────┐                         │
│  │MPC节点1│  │MPC节点2│  │MPC节点3│                         │
│  │分片 1  │  │分片 2  │  │分片 3  │                         │
│  │AWS     │  │GCP     │  │Azure   │  ← 多云部署             │
│  └────────┘  └────────┘  └────────┘                         │
│                                                                 │
│  特点:                                                        │
│  ✅ 私钥分片,永不完整                                         │
│  ✅ 多云部署,防止单点故障                                     │
│  ✅ 2-of-3 签名(任意 2 个节点)                              │
│  ✅ 一个节点被攻破也无法获取完整私钥                           │
│                                                                 │
└────────────────────────────────────────────────────────────────┘

高可用设计

主备架构核心思路

// WalletHA 钱包高可用管理
type WalletHA struct {
    primary   *WalletService
    backup    *WalletService
    current   *WalletService
}

// 健康检查(每 10 秒)
func (wha *WalletHA) checkHealth(service *WalletService) bool {
    // 1. 数据库连接
    if err := service.db.Ping(); err != nil {
        return false
    }
    
    // 2. 区块链节点
    if _, err := service.ethClient.BlockNumber(ctx); err != nil {
        return false
    }
    
    // 3. Redis 缓存
    if err := service.redis.Ping(ctx).Err(); err != nil {
        return false
    }
    
    return true
}

// 故障转移(自动切换)
func (wha *WalletHA) handleFailover() {
    if !wha.checkHealth(wha.current) {
        // 切换到备用服务
        wha.current = wha.backup
        log.Println("✅ 已切换到备用服务")
        wha.sendAlert()
    }
}

关键设计

  • ✅ 主备双活,实时同步
  • ✅ 自动健康检查
  • ✅ 秒级故障转移
  • ✅ 数据库读写分离

真实案例分析

案例 1:Coinbase 钱包架构

公开信息(来自 Coinbase 安全白皮书)

资金分配:
├─ 冷存储:98%
│   ├─ 地理分散的保险柜
│   ├─ 硬件钱包 + 纸钱包
│   └─ 多人物理在场才能访问
│
└─ 热钱包:2%
    ├─ 日常提现
    ├─ 多重审批
    └─ 实时监控

充值流程:
1. HD 钱包派生用户专属地址
2. 监听确认(BTC:6确认,ETH:12确认)
3. 更新用户余额
4. 定期归集到冷钱包

提现流程:
1. 风控检查
2. 小额:热钱包自动处理
3. 大额:需要人工审批 + 冷钱包多签

安全措施:
✅ 分散地理位置存储
✅ 多重签名
✅ 保险覆盖
✅ SOC2 认证
✅ 定期安全审计

案例 2:交易所钱包系统优化实战

背景

  • 日均提现:5 万笔
  • 平均金额:$2,000
  • 总资金:$5B

优化前问题

❌ 问题 1: 热钱包资金不足
   - 热钱包仅 $10M(0.2%)
   - 每日提现 $100M
   - 需要每天人工补充 10+ 次

❌ 问题 2: 大额提现慢
   - > $10K 需要冷钱包
   - 操作时间:24 小时
   - 用户抱怨严重

❌ 问题 3: Gas 费高
   - 每笔单独发送
   - 月 Gas 费:$500K

优化方案与效果

✅ 方案 1: 三层钱包架构
   热钱包:$50M(1%)   - 自动,< $1K
   温钱包:$200M(4%)  - 2小时,$1K-$50K
   冷钱包:$4.75B(95%)- 24小时,> $50K
   
   效果:95% 提现在 2 小时内完成

✅ 方案 2: 智能资金补充
   - 自动检测余额阈值
   - 从温钱包自动补充热钱包
   
   效果:人工操作从每天 10 次降到每周 1 次

✅ 方案 3: 批量提现优化
   - 每 10 分钟批量处理
   - 合并相同地址的提现
   
   效果:Gas 费从 $500K 降到 $150K/月(节省 70%)

关键收获

  1. 分层架构:平衡安全性和效率
  2. 自动化:减少人工干预和错误
  3. 批量处理:显著降低成本
  4. 监控告警:及时发现和解决问题

核心知识点总结

企业级钱包架构要点

1. 资金池模型
   - 用户余额 = 数据库记录
   - 真实资金 = 少数钱包地址
   - 站内转账不上链

2. 冷热分离
   - 95% 冷钱包(安全)
   - 5% 热钱包(流动性)
   - 动态调整比例

3. 多层防护
   - 私钥加密(KMS/HSM)
   - 多重签名(3-of-5)
   - 限额控制
   - 白名单机制

4. 业务流程
   - 充值:监听 → 确认 → 入账
   - 提现:检查 → 路由 → 签名 → 广播
   - 归集:定时 → 批量 → 到热钱包

5. 高可用设计
   - 主备双活
   - 健康检查
   - 自动故障转移
   - 数据一致性