dApp Docs/跨链桥接与IBC指南
Development reference. Not independently verified for production.

MSG Chain 跨链桥接与 IBC 协议指南

数据来源:MSG Chain 代码库核实

主网状态: No-Go — 当前 MSGChain 主网裁决为 No-Go,以下内容反映代码实际状态,不代表生产可用。


目录

  1. 跨链架构总览
  2. IBC协议基础
  3. MSG Chain IBC规划
  4. ICS-20代币转移
  5. Relayer配置
  6. 跨链合约开发
  7. 自定义桥接合约
  8. 跨链dApp示例
  9. 安全考量
  10. 开发路线图

1. 跨链架构总览

1.1 MSG Chain 跨链生态定位

MSG Chain 作为基于 Cosmos SDK 构建的 AI Agent 区块链,其跨链层目前处于 规划态。与 Cosmos 生态中成熟链的跨链状态对比如下:

特性 Cosmos Hub Osmosis MSG Chain
IBC 状态 生产就绪 (v4+) 生产就绪 (v4+) 规划态
活跃通道数 100+ 50+ 0 (待启动)
跨链清算量 日均数亿美元 日均数千万美元 0
IBC 客户端类型 Tendermint Tendermint Tendermint + Dilithium-5 (自定义)
签名算法 Ed25519/Secp256k1 Ed25519/Secp256k1 Dilithium-5
智能合约 有限 (governance) CosmWasm CosmWasm

注意: MSG Chain 的跨链功能尚未在主网上线,本文档所有标记 X-MSG-Stub=true 的内容均为规划中的功能。

1.2 跨链架构总览图

X-MSG-Stub=true
┌─────────────────────────────────────────────────────────────────────┐
│                        MSG Chain 跨链架构                            │
│                                                                     │
│  ┌─────────────────────────┐    ┌───────────────────────────────┐   │
│  │    IBC v2 协议层         │    │   自定义桥接层                  │   │
│  │                         │    │                               │   │
│  │  ┌─────────────────┐    │    │  ┌───────────────────┐       │   │
│  │  │ Dilithium-5 LC   │    │    │  │ Lock-Mint Bridge  │       │   │
│  │  │ (自定义轻客户端)   │    │    │  │ (Ethereum方向)    │       │   │
│  │  └─────────────────┘    │    │  └───────────────────┘       │   │
│  │  ┌─────────────────┐    │    │  ┌───────────────────┐       │   │
│  │  │ ICS-20 Transfer │    │    │  │ Burn-Mint Bridge  │       │   │
│  │  │ ICS-27 ICA      │    │    │  │ (通用方向)         │       │   │
│  │  │ ICS-721 NFT     │    │    │  └───────────────────┘       │   │
│  │  └─────────────────┘    │    │  ┌───────────────────┐       │   │
│  │  ┌─────────────────┐    │    │  │ Bridge Validator  │       │   │
│  │  │ IBC Fee         │    │    │  │ Set (多签验证)     │       │   │
│  │  │ Middleware       │    │    │  └───────────────────┘       │   │
│  │  └─────────────────┘    │    │                               │   │
│  └─────────────────────────┘    └───────────────────────────────┘   │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │  Relayer 网络                                                │    │
│  │  ┌────────────┐  ┌────────────┐  ┌────────────┐            │    │
│  │  │ Go Relayer │  │  Hermes    │  │ MSG Relayer│ (自定义)   │    │
│  │  └────────────┘  └────────────┘  └────────────┘            │    │
│  └─────────────────────────────────────────────────────────────┘    │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │ 跨链 dApp 层                                                  │    │
│  │  ┌─────────────────────┐  ┌─────────────────────┐           │    │
│  │  │ 跨链AI Agent市场    │  │ 跨链 DID 解析       │           │    │
│  │  └─────────────────────┘  └─────────────────────┘           │    │
│  └─────────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────────┘

1.3 目标集成链

MSG Chain 规划与以下链建立 IBC 连接:

目标链 Chain ID IBC 版本 优先级 说明
Cosmos Hub cosmoshub-4 v2/v3 P0 主路由枢纽,类似 ATOM 的 IBC 路由
Osmosis osmosis-1 v2/v3 P0 跨链 DEX,类似 OSMO 的跨链 swap
Stride stride-1 v2 P1 跨链质押
Neutron neutron-1 v2 P1 跨链合约调用
Ethereum (EVM) N/A ICS-721/自定义 P2 通过自定义桥接或 ICS-721

1.4 跨链数据流

X-MSG-Stub=true
用户 A (MSG Chain)                    用户 B (Cosmos Hub)
      │                                      │
      │  1. msgd tx ibc-transfer             │
      │     send-packet                      │
      │                                      │
      ▼                                      │
┌─────────────┐                             │
│  Escrow     │  2. IBC 数据包经 Relayer     │
│  Account    │ ──────────────────────────►  │
└─────────────┘                             │
                                             ▼
                                      ┌─────────────┐
                                      │  Mint IBC    │
                                      │  Denom       │
                                      └─────────────┘

2. IBC协议基础

2.1 IBC 协议简介

IBC (Inter-Blockchain Communication) 是 Cosmos 生态的跨链通信标准,基于轻客户端验证和中继者网络实现无需信任的跨链交互。

与传统的跨链桥相比,IBC 的核心优势:

特性 IBC 传统桥 (Wormhole, Multisig)
安全模型 轻客户端验证 验证者/多签信任
信任假设 无需信任 (trustless) 部分信任
最终性 链上共识验证 依赖预言机
去中心化程度 完全去中心化 部分中心化
可扩展性 模块化,可组合 单体架构

2.2 IBC 核心概念

2.2.1 轻客户端 (Light Client)

IBC 轻客户端是一段运行在目标链上的代码,负责验证来源链的区块头。Cosmos 生态中最常见的是 Tendermint 轻客户端:

┌──────────────┐          ┌──────────────┐
│  Chain A     │          │  Chain B     │
│              │          │              │
│  ┌────────┐  │  Relayer  │  ┌────────┐  │
│  │ Block  │──┼─────────►│  │ LC     │  │
│  │ Headers│  │ 提交区块头 │  │ Verify│  │
│  └────────┘  │          │  └────────┘  │
│              │          │              │
└──────────────┘          └──────────────┘

MSG Chain 计划支持以下轻客户端类型:

轻客户端类型 状态 说明
Tendermint 客户端 规划中 标准 Cosmos IBC 兼容
Dilithium-5 客户端 规划中 MSG Chain 自定义,后量子安全
Solo Machine 客户端 规划中 用于非 IBC 链连接

2.2.2 连接 (Connection) 与通道 (Channel)

Connection 和 Channel 是 IBC 的两层抽象:

Chain A                          Chain B
  │                                │
  │  ┌── Connection (connID) ──┐   │
  │  │                         │   │
  │  │  ┌─ Channel (chID) ──┐  │   │
  │  │  │  Port: "transfer"  │  │   │
  │  │  │  Port: "wasm.xxx"  │  │   │
  │  │  └────────────────────┘  │   │
  │  │  ┌─ Channel (chID) ──┐  │   │
  │  │  │  Port: "ica"       │  │   │
  │  │  └────────────────────┘  │   │
  │  └──────────────────────────┘   │
  │                                │

Connection 握手流程 (4步):

X-MSG-Stub=true
Chain A (msg-chain-1)              Chain B (cosmoshub-4)
      │                                    │
      │  1. ConnOpenInit                   │
      │  ──────────────────────────────►   │
      │                                    │
      │  2. ConnOpenTry                    │
      │  ◄──────────────────────────────   │
      │                                    │
      │  3. ConnOpenAck                    │
      │  ──────────────────────────────►   │
      │                                    │
      │  4. ConnOpenConfirm                │
      │  ◄──────────────────────────────   │
      │                                    │
      │         Connection 建立            │

Channel 握手流程 (4步):

X-MSG-Stub=true
Chain A (msg-chain-1)              Chain B (cosmoshub-4)
      │                                    │
      │  1. ChanOpenInit                   │
      │  ──────────────────────────────►   │
      │                                    │
      │  2. ChanOpenTry                    │
      │  ◄──────────────────────────────   │
      │                                    │
      │  3. ChanOpenAck                    │
      │  ──────────────────────────────►   │
      │                                    │
      │  4. ChanOpenConfirm                │
      │  ◄──────────────────────────────   │
      │                                    │
      │         Channel 建立               │

2.2.3 数据包生命周期 (Packet Lifecycle)

IBC 数据包的完整生命周期包括 4 个阶段:

X-MSG-Stub=true
发送端 (Source)                      接收端 (Destination)
      │                                      │
      │  1. sendPacket                       │
      │  ──────────────────────────────►   │
      │       (数据包进入 outgoing queue)    │
      │                                      │
      │          Relayer 转发                  │
      │  ◄═══════════════════════════════►  │
      │                                      │
      │                         2. recvPacket│
      │                          ◄────────  │
      │                                      │
      │  3. writeAcknowledgement             │
      │  ──────────────────────────────►   │
      │                                      │
      │  4. (timeout)         (ack)          │
      │    超时处理       确认处理            │

数据包数据结构:

// IBC 数据包标准结构
message Packet {
  // 唯一序列号
  uint64 sequence = 1;
  // 来源链的端口和通道
  string source_port = 2;
  string source_channel = 3;
  // 目标链的端口和通道
  string destination_port = 4;
  string destination_channel = 5;
  // 原始数据 (opaque bytes)
  bytes data = 6;
  // 超时高度 (过期区块高度)
  Height timeout_height = 7;
  // 超时时间戳 (过期时间)
  uint64 timeout_timestamp = 8;
}

message Height {
  uint64 revision_number = 1;
  uint64 revision_height = 2;
}

2.3 Relayer 架构

Relayer (中继者) 是 IBC 协议的关键基础设施组件,负责:

  1. 监控两条链的 IBC 事件
  2. 转发数据包、确认和超时
  3. 提交轻客户端更新
X-MSG-Stub=true
┌──────────────────────────────────────────────────┐
│                    Relayer                        │
│                                                   │
│  ┌──────────────┐     ┌──────────────────────┐   │
│  │ Chain Monitor │     │  Packet Processor    │   │
│  │  - A链事件订阅 │     │  - 验证数据包        │   │
│  │  - B链事件订阅 │     │  - 签名交易          │   │
│  └──────────────┘     │  - 广播交易          │   │
│                       └──────────────────────┘   │
│  ┌──────────────┐     ┌──────────────────────┐   │
│  │ Key Manager  │     │  Fee Distributor     │   │
│  │  - 中继者密钥  │     │  - Gas 管理          │   │
│  │  - 多链密钥    │     │  - 费用收取          │   │
│  └──────────────┘     └──────────────────────┘   │
└──────────────────────────────────────────────────┘

2.4 IBC 安全模型

IBC 的安全保证基于以下假设:

安全假设 风险等级 缓解措施
来源链共识安全 低 (DPoS) 多种共识机制可选
轻客户端正确性 低 形式化验证
Relayer 诚实性 不需要 Relayer 不能造假,只能延迟
链未分叉 低 IBC 需要最终性
密钥管理 中 HSMs, 多签

与以太坊桥相比,IBC 不需要信任 Relayer——Relayer 无法窃取资金,最多只能造成审查(延迟交付)。


3. MSG Chain IBC规划

X-MSG-Stub=true: 本节所有内容均为规划阶段,尚未实现。

3.1 规划中的 IBC 版本

MSG Chain 计划基于 IBC v2 进行实现。IBC v2 相比 v1 的主要改进:

特性 IBC v1 (Cosmos Hub) IBC v2 (MSG Chain 计划)
数据包格式 Protobuf Protobuf + 扩展元数据
轻客户端接口 ClientState/ConsensusState 更灵活的接口
模块化 基础 更好的中间件组合
性能 标准 优化的批处理
费用 IBC Fee 可选 默认集成

3.2 Dilithium-5 轻客户端设计

X-MSG-Stub=true

MSG Chain 的 Dilithium-5 轻客户端是 IBC 实现的核心创新点。标准 Tendermint 轻客户端使用 Ed25519 签名,而 MSG Chain 需要支持 Dilithium-5 后量子签名。

3.2.1 轻客户端架构

// X-MSG-Stub=true: Dilithium-5 IBC 轻客户端设计
// 此代码为规划中的设计草案,尚未实现

/// Dilithium-5 轻客户端状态
pub struct DilithiumClientState {
    /// 链 ID
    pub chain_id: String,
    /// 信任级别 (1/3 共识)
    pub trust_level: Fraction,
    /// 信任周期 ( trusting period )
    pub trusting_period: Duration,
    /// 解绑周期 ( unbonding period )
    pub unbonding_period: Duration,
    /// 最大时钟偏差
    pub max_clock_drift: Duration,
    /// 最新高度
    pub latest_height: Height,
    /// Dilithium-5 共识状态
    pub consensus_state: DilithiumConsensusState,
}

/// Dilithium-5 共识状态
pub struct DilithiumConsensusState {
    /// 验证者集公钥哈希 (Dilithium-5 聚合)
    pub validator_set_hash: Vec<u8>,
    /// Round-Robin + DAR 时间戳
    pub timestamp: Timestamp,
    /// 根哈希
    pub root: Vec<u8>,
    /// 下一个验证者集哈希
    pub next_validators_hash: Vec<u8>,
}

/// Dilithium-5 轻客户端验证逻辑
pub fn verify_dilithium_misbehaviour(
    client_state: &DilithiumClientState,
    misbehaviour: &Misbehaviour,
) -> Result<(), IbcError> {
    // 1. 验证两个冲突区块头都通过了 Dilithium-5 签名验证
    verify_dilithium_header(&misbehaviour.header_1)?;
    verify_dilithium_header(&misbehaviour.header_2)?;

    // 2. 验证两个区块头在相同高度有不同哈希
    if misbehaviour.header_1.height() != misbehaviour.header_2.height() {
        return Err(IbcError::HeightMismatch);
    }
    if misbehaviour.header_1.hash() == misbehaviour.header_2.hash() {
        return Err(IbcError::IdenticalHeaders);
    }

    // 3. 验证 Dilithium-5 签名来自验证者集
    verify_dilithium_signatures(
        &misbehaviour.header_1,
        &client_state.consensus_state.validator_set_hash,
    )?;

    Ok(())
}

3.2.2 Dilithium-5 轻客户端与原版对比

特性 Tendermint LC Dilithium-5 LC
签名算法 Ed25519 Dilithium-5
公钥大小 32 bytes 1,312 bytes
签名大小 64 bytes 2,420 bytes
验证速度 快速 中等 (~2x Ed25519)
量子安全性 否 (易受 Shor 攻击) 是
存储开销 低 较高

3.3 与 Cosmos Hub 的连接规划

3.3.1 连接流程

X-MSG-Stub=true
msg-chain-1 (MSG Chain)              cosmoshub-4 (Cosmos Hub)
      │                                        │
      │  Step 1: 创建 Dilithium-5 客户端       │
      │  msgd tx ibc client create             │
      │  ─────────────────────────────────►    │
      │                                        │
      │  Step 2: Cosmos Hub 创建 Tendermint LC │
      │  (Cosmos Hub 需要支持 Dilithium-5 验证)  │
      │  ◄─────────────────────────────────    │
      │                                        │
      │  Step 3-6: Connection 握手             │
      │  ◄═══════════════════════════════►     │
      │                                        │
      │  Step 7-10: Channel 握手               │
      │  ◄═══════════════════════════════►     │
      │                                        │
      │      ✓ 连接建立,可开始资产转移          │

3.3.2 CLI 命令 (规划中)

# X-MSG-Stub=true: 以下命令为规划中的 CLI,尚未支持

# 1. 创建 IBC 客户端 (在 MSG Chain 上)
msgd tx ibc client create \
  --client-type dilithium5 \
  --chain-id cosmoshub-4 \
  --node https://rpc.cosmoshub-4.com:26657 \
  --from my-key

# 2. 创建连接
msgd tx ibc connection open-init \
  --client-id 07-dilithium-0 \
  --counterparty-client-id 07-tendermint-0 \
  --from my-key \
  --gas-prices 1000000000umsg

# 3. 创建通道 (ICS-20 转账)
msgd tx ibc channel open-init \
  --port transfer \
  --channel-ordering unordered \
  --connection-id connection-0 \
  --version "ics20-1" \
  --from my-key \
  --gas-prices 1000000000umsg

3.4 规划中的通道类型

通道类型 标准 用途 优先级
代币转账 ICS-20 跨链 MSG 转移 P0
Interchain Accounts ICS-27 跨链账户控制 P1
NFT 转移 ICS-721 跨链 Agent NFT P2
IBC Fee ICS-29 Relayer 费用 P1
自定义桥接 自定义 非 IBC 链桥接 P2

3.5 开发状态和时间线

里程碑 预计时间 状态 依赖
Dilithium-5 IBC 客户端规范 Q3 2026 规划中 IBC v2 规范
Dilithium-5 轻客户端实现 Q4 2026 未开始 Cosmos SDK IBC 模块
Connection 握手测试 Q1 2027 未开始 测试网部署
ICS-20 集成 Q1 2027 未开始 连接建立
Testnet 跨链转账 Q2 2027 未开始 ICS-20 就绪
自定义桥接合约 Q3 2027 未开始 CosmWasm + IBC
主网跨链上线 Q4 2027 未开始 以上全部

4. ICS-20代币转移

X-MSG-Stub=true: ICS-20 代币转移功能尚未实现,以下为规划中的使用方式。

4.1 IBC Denom 格式

通过 IBC 转移的代币使用以下格式标识:

ibc/{hash}

其中 {hash} 是 {channel_id}/{denom} 的 SHA256 哈希。

示例: ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2

4.2 IBC 转账 CLI 命令

4.2.1 从 MSG Chain 转出到 Cosmos Hub

# X-MSG-Stub=true: 将 100 MSG 从 MSG Chain 发送到 Cosmos Hub
msgd tx ibc-transfer transfer \
  transfer \
  channel-0 \
  cosmos1qypqxpq9kcrn2c9afea5lq35ef37c5x7abcdef \
  100000000000000000000umsg \
  --packet-timeout-height "0-100000" \
  --packet-timeout-timestamp "0" \
  --from my-msg-key \
  --gas-prices 1000000000umsg \
  --chain-id msg-chain-1 \
  --node https://rpc.msgchain.org:26657

# 响应:
# code: 0
# txhash: ABCDEF1234567890...
# 消息: IBC 转账已发起,序列号: 1

4.2.2 从 Cosmos Hub 转入 MSG Chain

# X-MSG-Stub=true: 在 Cosmos Hub 上执行
gaiad tx ibc-transfer transfer \
  transfer \
  channel-{msg-chain-id} \
  msg1qypqxpq9kcrn2c9afea5lq35ef37c5x7jqylz3 \
  1000000uatom \
  --packet-timeout-height "0-50000" \
  --from my-cosmos-key \
  --gas-prices 0.025uatom \
  --chain-id cosmoshub-4 \
  --node https://rpc.cosmoshub-4.com:26657

4.2.3 查询 IBC 转移状态

# X-MSG-Stub=true: 查询 IBC 数据包状态
msgd query ibc-transfer denom-trace 27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2

# 响应:
# denom_trace:
#   path: transfer/channel-0
#   base_denom: uatom

# 查询待处理的数据包
msgd query ibc channel pending-send \
  transfer \
  channel-0 \
  --node https://rpc.msgchain.org:26657

# 查询已确认的数据包
msgd query ibc channel packet-ack \
  transfer \
  channel-0 \
  1 \
  --node https://rpc.msgchain.org:26657

4.3 Channel 创建命令

# X-MSG-Stub=true: 在 MSG Chain 上创建 IBC 转账通道
msgd tx ibc channel open-init \
  --port transfer \
  --channel-ordering unordered \
  --connection-id connection-0 \
  --version "ics20-1" \
  --from my-key \
  --gas-prices 1000000000umsg \
  --chain-id msg-chain-1

# 确认通道状态
msgd query ibc channel end transfer channel-0

4.4 托管账户管理

在 ICS-20 中,代币转移涉及托管账户 (Escrow Account)。当代币从 MSG Chain 转出时:

  1. MSG Chain 上的代币被锁定在托管模块
  2. IBC 数据包被发送到目标链
  3. 目标链在接收端铸造等量的 IBC 代币
  4. 当转回时,IBC 代币被销毁,MSG Chain 解锁原代币
X-MSG-Stub=true
MSG Chain (发送)                     Cosmos Hub (接收)
      │                                      │
      │  ┌──────────────────┐                │
      │  │ Escrow Module    │                │
      │  │ (锁定 100 MSG)   │                │
      │  └──────────────────┘                │
      │         │                            │
      │         │  sendPacket                │
      │         └─────────────────────────►  │
      │                                      │
      │                           ┌────────┐ │
      │                           │ Mint   │ │
      │                           │ IBC/MSG│ │
      │                           └────────┘ │
      │                                      │
      │  (转回时)                             │
      │  ◄──────────────────────────────────  │
      │                                      │
      │  ┌──────────────────┐                │
      │  │ 解锁 100 MSG     │                │
      │  └──────────────────┘                │

查询托管余额:

# X-MSG-Stub=true: 查询 IBC 托管余额
msgd query ibc-transfer escrow-address transfer channel-0

# 响应:
# escrow_address: msg1xude6s5c6m73lfwd0576tgvs3v9wf8v6xtx3ht

# 查询托管地址余额
msgd query bank balances msg1xude6s5c6m73lfwd0576tgvs3v9wf8v6xtx3ht \
  --node https://rpc.msgchain.org:26657

4.5 完整 CosmWasm 合约: IBC 代币管理

X-MSG-Stub=true: 以下合约代码为规划中的设计,展示了 MSG Chain CosmWasm 合约与 IBC 的集成方式。

4.5.1 Cargo.toml

[package]
name = "msg-ibc-token-manager"
version = "1.0.0"
edition = "2021"
description = "MSG Chain IBC Token Management Contract"

[lib]
crate-type = ["cdylib", "rlib"]

[profile.release]
opt-level = 3
debug = false
lto = true
debug-assertions = false
codegen-units = 1
panic = "abort"
overflow-checks = true

[dependencies]
cosmwasm-std = "1.5"
cosmwasm-storage = "1.5"
cw-storage-plus = "1.2"
cw2 = "1.1"
cw-utils = "1.0"
cw20 = "1.1"
schemars = "0.8"
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
uint = "0.9"

[dev-dependencies]
cosmwasm-vm = "1.5"
cw-multi-test = "0.18"

4.5.2 src/msg.rs

use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Binary, Uint128};

#[cw_serde]
pub struct InstantiateMsg {
    pub admin: String,
    pub ibc_transfer_module: String,
    pub supported_channels: Vec<String>,
}

#[cw_serde]
pub enum ExecuteMsg {
    /// 发起 IBC 转账
    InitiateIBCTransfer {
        channel_id: String,
        recipient: String,
        amount: Uint128,
        denom: String,
        memo: Option<String>,
    },
    /// 注册 IBC 通道
    RegisterChannel {
        channel_id: String,
        chain_name: String,
        ibc_denom: String,
    },
    /// 暂停 IBC 转账
    PauseTransfer {},
    /// 恢复 IBC 转账
    ResumeTransfer {},
    /// 设置最大转账限额
    SetTransferLimit {
        channel_id: String,
        daily_limit: Uint128,
    },
}

#[cw_serde]
pub enum QueryMsg {
    GetChannelInfo { channel_id: String },
    ListChannels {},
    GetEscrowBalance { channel_id: String },
    GetDailyTransferVolume { channel_id: String },
    IsPaused {},
}

#[cw_serde]
pub struct ChannelInfo {
    pub channel_id: String,
    pub chain_name: String,
    pub ibc_denom: String,
    pub daily_limit: Uint128,
    pub today_volume: Uint128,
    pub last_reset: u64,
    pub active: bool,
}

#[cw_serde]
pub struct IBCTransferRequest {
    pub source_channel: String,
    pub recipient: String,
    pub amount: Uint128,
    pub denom: String,
    pub memo: Option<String>,
    pub sender: String,
}

4.5.3 src/state.rs

use cosmwasm_schema::cw_serde;
use cw_storage_plus::{Item, Map};
use cosmwasm_std::Uint128;

use crate::msg::ChannelInfo;

#[cw_serde]
pub struct Config {
    pub admin: String,
    pub ibc_transfer_module: String,
    pub paused: bool,
}

pub const CONFIG: Item<Config> = Item::new("config");
pub const CHANNELS: Map<&str, ChannelInfo> = Map::new("channels");
pub const TRANSFER_VOLUME: Map<&str, Uint128> = Map::new("transfer_volume");
pub const DAILY_RESET: Map<&str, u64> = Map::new("daily_reset");

4.5.4 src/error.rs

use cosmwasm_std::StdError;
use thiserror::Error;

#[derive(Error, Debug, PartialEq)]
pub enum ContractError {
    #[error("{0}")]
    Std(#[from] StdError),

    #[error("Unauthorized")]
    Unauthorized {},

    #[error("IBC transfers are paused")]
    Paused {},

    #[error("Channel {channel_id} not found")]
    ChannelNotFound { channel_id: String },

    #[error("Channel {channel_id} is inactive")]
    ChannelInactive { channel_id: String },

    #[error("Transfer amount exceeds daily limit for {channel_id}")]
    DailyLimitExceeded { channel_id: String },

    #[error("Channel {channel_id} already registered")]
    ChannelAlreadyExists { channel_id: String },

    #[error("Insufficient balance for IBC transfer")]
    InsufficientBalance {},
}

4.5.5 src/contract.rs

use cosmwasm_std::{
    entry_point, to_binary, Binary, Deps, DepsMut, Env, IbcMsg,
    IbcTimeout, IbcTimeoutBlock, MessageInfo, Response, StdResult, Uint128,
};
use cw2::set_contract_version;
use cw_utils::one_coin;

use crate::error::ContractError;
use crate::msg::{
    ChannelInfo, ExecuteMsg, InstantiateMsg, QueryMsg,
};
use crate::state::{Config, CONFIG, CHANNELS, DAILY_RESET, TRANSFER_VOLUME};

const CONTRACT_NAME: &str = "msg-ibc-token-manager";
const CONTRACT_VERSION: &str = "1.0.0";

#[entry_point]
pub fn instantiate(
    deps: DepsMut,
    _env: Env,
    _info: MessageInfo,
    msg: InstantiateMsg,
) -> StdResult<Response> {
    set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;

    let config = Config {
        admin: msg.admin,
        ibc_transfer_module: msg.ibc_transfer_module,
        paused: false,
    };
    CONFIG.save(deps.storage, &config)?;

    for channel_id in msg.supported_channels {
        let info = ChannelInfo {
            channel_id: channel_id.clone(),
            chain_name: String::new(),
            ibc_denom: String::new(),
            daily_limit: Uint128::zero(),
            today_volume: Uint128::zero(),
            last_reset: 0,
            active: true,
        };
        CHANNELS.save(deps.storage, &channel_id, &info)?;
    }

    Ok(Response::new()
        .add_attribute("method", "instantiate")
        .add_attribute("admin", msg.admin))
}

#[entry_point]
pub fn execute(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response, ContractError> {
    match msg {
        ExecuteMsg::InitiateIBCTransfer {
            channel_id,
            recipient,
            amount,
            denom,
            memo,
        } => execute_initiate_ibc_transfer(
            deps, env, info, channel_id, recipient, amount, denom, memo,
        ),
        ExecuteMsg::RegisterChannel {
            channel_id,
            chain_name,
            ibc_denom,
        } => execute_register_channel(deps, info, channel_id, chain_name, ibc_denom),
        ExecuteMsg::PauseTransfer {} => execute_pause(deps, info),
        ExecuteMsg::ResumeTransfer {} => execute_resume(deps, info),
        ExecuteMsg::SetTransferLimit {
            channel_id,
            daily_limit,
        } => execute_set_limit(deps, info, channel_id, daily_limit),
    }
}

fn execute_initiate_ibc_transfer(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    channel_id: String,
    recipient: String,
    amount: Uint128,
    denom: String,
    memo: Option<String>,
) -> Result<Response, ContractError> {
    let config = CONFIG.load(deps.storage)?;
    if config.paused {
        return Err(ContractError::Paused {});
    }

    let mut channel = CHANNELS
        .load(deps.storage, &channel_id)
        .map_err(|_| ContractError::ChannelNotFound {
            channel_id: channel_id.clone(),
        })?;

    if !channel.active {
        return Err(ContractError::ChannelInactive { channel_id });
    }

    // 检查每日限额
    let now = env.block.time.seconds();
    let today = now / 86400;
    let last_reset = DAILY_RESET.load(deps.storage, &channel_id).unwrap_or(0);

    if last_reset < today {
        DAILY_RESET.save(deps.storage, &channel_id, &today)?;
        TRANSFER_VOLUME.save(deps.storage, &channel_id, &Uint128::zero())?;
        channel.today_volume = Uint128::zero();
    }

    let current_volume = TRANSFER_VOLUME
        .load(deps.storage, &channel_id)
        .unwrap_or_default();

    if !channel.daily_limit.is_zero() && current_volume + amount > channel.daily_limit {
        return Err(ContractError::DailyLimitExceeded { channel_id });
    }

    TRANSFER_VOLUME
        .save(deps.storage, &channel_id, &(current_volume + amount))?;

    channel.today_volume = current_volume + amount;
    CHANNELS.save(deps.storage, &channel_id, &channel)?;

    // 构建 IBC 转账消息
    let ibc_msg = IbcMsg::Transfer {
        channel_id: channel_id.clone(),
        to_address: recipient.clone(),
        amount: cosmwasm_std::Coin {
            denom: denom.clone(),
            amount,
        },
        timeout: IbcTimeout::with_block(IbcTimeoutBlock {
            revision: 0,
            height: env.block.height + 10000,
        }),
    };

    let mut response = Response::new()
        .add_message(ibc_msg)
        .add_attribute("method", "initiate_ibc_transfer")
        .add_attribute("channel", &channel_id)
        .add_attribute("recipient", &recipient)
        .add_attribute("amount", amount.to_string())
        .add_attribute("denom", &denom);

    if let Some(m) = memo {
        response = response.add_attribute("memo", m);
    }

    Ok(response)
}

fn execute_register_channel(
    deps: DepsMut,
    info: MessageInfo,
    channel_id: String,
    chain_name: String,
    ibc_denom: String,
) -> Result<Response, ContractError> {
    let config = CONFIG.load(deps.storage)?;
    if info.sender.to_string() != config.admin {
        return Err(ContractError::Unauthorized {});
    }

    if CHANNELS.has(deps.storage, &channel_id) {
        return Err(ContractError::ChannelAlreadyExists { channel_id });
    }

    let channel = ChannelInfo {
        channel_id: channel_id.clone(),
        chain_name,
        ibc_denom,
        daily_limit: Uint128::zero(),
        today_volume: Uint128::zero(),
        last_reset: 0,
        active: true,
    };
    CHANNELS.save(deps.storage, &channel_id, &channel)?;

    Ok(Response::new()
        .add_attribute("method", "register_channel")
        .add_attribute("channel_id", &channel_id))
}

fn execute_pause(
    deps: DepsMut,
    info: MessageInfo,
) -> Result<Response, ContractError> {
    let mut config = CONFIG.load(deps.storage)?;
    if info.sender.to_string() != config.admin {
        return Err(ContractError::Unauthorized {});
    }
    config.paused = true;
    CONFIG.save(deps.storage, &config)?;

    Ok(Response::new().add_attribute("method", "pause"))
}

fn execute_resume(
    deps: DepsMut,
    info: MessageInfo,
) -> Result<Response, ContractError> {
    let mut config = CONFIG.load(deps.storage)?;
    if info.sender.to_string() != config.admin {
        return Err(ContractError::Unauthorized {});
    }
    config.paused = false;
    CONFIG.save(deps.storage, &config)?;

    Ok(Response::new().add_attribute("method", "resume"))
}

fn execute_set_limit(
    deps: DepsMut,
    info: MessageInfo,
    channel_id: String,
    daily_limit: Uint128,
) -> Result<Response, ContractError> {
    let config = CONFIG.load(deps.storage)?;
    if info.sender.to_string() != config.admin {
        return Err(ContractError::Unauthorized {});
    }

    let mut channel = CHANNELS
        .load(deps.storage, &channel_id)
        .map_err(|_| ContractError::ChannelNotFound {
            channel_id: channel_id.clone(),
        })?;
    channel.daily_limit = daily_limit;
    CHANNELS.save(deps.storage, &channel_id, &channel)?;

    Ok(Response::new()
        .add_attribute("method", "set_limit")
        .add_attribute("channel_id", &channel_id)
        .add_attribute("daily_limit", daily_limit.to_string()))
}

#[entry_point]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
    match msg {
        QueryMsg::GetChannelInfo { channel_id } => {
            to_binary(&query_channel_info(deps, channel_id)?)
        }
        QueryMsg::ListChannels {} => to_binary(&query_list_channels(deps)?),
        QueryMsg::GetEscrowBalance { channel_id: _ } => {
            to_binary(&query_escrow_balance(deps)?)
        }
        QueryMsg::GetDailyTransferVolume { channel_id } => {
            to_binary(&query_daily_volume(deps, channel_id)?)
        }
        QueryMsg::IsPaused {} => to_binary(&CONFIG.load(deps.storage)?.paused),
    }
}

fn query_channel_info(deps: Deps, channel_id: String) -> StdResult<ChannelInfo> {
    CHANNELS.load(deps.storage, &channel_id)
}

fn query_list_channels(deps: Deps) -> StdResult<Vec<ChannelInfo>> {
    let channels: StdResult<Vec<_>> = CHANNELS
        .range(deps.storage, None, None, cosmwasm_std::Order::Ascending)
        .map(|r| r.map(|(_, v)| v))
        .collect();
    channels
}

fn query_escrow_balance(deps: Deps) -> StdResult<String> {
    // 查询托管余额
    Ok("escrow_balance_query".to_string())
}

fn query_daily_volume(deps: Deps, channel_id: String) -> StdResult<Uint128> {
    TRANSFER_VOLUME
        .load(deps.storage, &channel_id)
        .or(Ok(Uint128::zero()))
}

4.6 CosmJS IBC 集成代码 (TypeScript)

// X-MSG-Stub=true: CosmJS IBC 转账示例
import { SigningStargateClient } from "@cosmjs/stargate";
import { coins } from "@cosmjs/launchpad";
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
// MSG Chain 使用 Dilithium-5 签名,需要自定义签名适配
// import { Dilithium5Wallet } from "@msgchain/crypto";

const MSG_CHAIN_RPC = "https://rpc.msgchain.org:26657";
const MSG_CHAIN_ID = "msg-chain-1";
const IBC_TRANSFER_PORT = "transfer";
const IBC_CHANNEL = "channel-0";

interface IBCTransferParams {
  fromAddress: string;
  recipientAddress: string;
  transferAmount: { denom: string; amount: string };
  sourcePort: string;
  sourceChannel: string;
  timeoutHeight: { revisionHeight: number; revisionNumber: number };
}

/**
 * 发起 IBC 代币转账
 *
 * 注意: MSG Chain 使用 Dilithium-5 签名。
 * 在 Dilithium-5 钱包适配器完成前,此代码为规划示例。
 */
async function initiateIBCTransfer(
  mnemonic: string,
  params: IBCTransferParams
): Promise<string> {
  // TODO: 替换为 Dilithium5Wallet
  // const wallet = await Dilithium5Wallet.fromMnemonic(mnemonic);
  const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, {
    prefix: "msg",
  });

  const client = await SigningStargateClient.connectWithSigner(
    MSG_CHAIN_RPC,
    wallet
  );

  const fee = {
    amount: coins(5000, "umsg"),
    gas: "200000",
  };

  const memo = "IBC transfer from MSG Chain";

  const result = await client.sendIbcTokens(
    params.fromAddress,
    params.recipientAddress,
    params.transferAmount,
    params.sourcePort,
    params.sourceChannel,
    params.timeoutHeight,
    undefined, // timeoutTimestamp
    fee,
    memo
  );

  console.log(`IBC 转账已提交,交易哈希: ${result.transactionHash}`);
  return result.transactionHash;
}

/**
 * 查询 IBC 通道信息
 */
async function queryIBCChannel(
  channelId: string = IBC_CHANNEL
): Promise<any> {
  const client = await SigningStargateClient.connect(MSG_CHAIN_RPC);
  const channel = await client.ibcChannel(
    IBC_TRANSFER_PORT,
    channelId
  );
  return channel;
}

/**
 * 查询 IBC 托管余额
 */
async function queryEscrowBalance(
  channelId: string = IBC_CHANNEL
): Promise<any> {
  const client = await SigningStargateClient.connect(MSG_CHAIN_RPC);
  const escrowAddress = await client.ibcEscrowAddress(
    IBC_TRANSFER_PORT,
    channelId
  );
  const balance = await client.getBalance(escrowAddress, "umsg");
  return { escrowAddress, balance };
}

/**
 * 查询待处理的数据包
 */
async function queryPendingPackets(
  channelId: string = IBC_CHANNEL
): Promise<any> {
  const client = await SigningStargateClient.connect(MSG_CHAIN_RPC);
  const packets = await client.ibcPendingPackets(
    IBC_TRANSFER_PORT,
    channelId
  );
  return packets;
}

// 使用示例
async function main() {
  const mnemonic =
    "[未公开凭证]";

  const txHash = await initiateIBCTransfer(mnemonic, {
    fromAddress: "msg1qypqxpq9kcrn2c9afea5lq35ef37c5x7jqylz3",
    recipientAddress: "cosmos1qypqxpq9kcrn2c9afea5lq35ef37c5x7abcdef",
    transferAmount: { denom: "umsg", amount: "100000000000000000000" },
    sourcePort: IBC_TRANSFER_PORT,
    sourceChannel: IBC_CHANNEL,
    timeoutHeight: {
      revisionHeight: 100000,
      revisionNumber: 0,
    },
  });

  console.log(`转账完成: https://explorer.msgchain.org/tx/${txHash}`);
}

5. Relayer配置

X-MSG-Stub=true: Relayer 配置和使用方法为规划中的内容。

5.1 Go Relayer 配置 (rly)

5.1.1 Go Relayer 安装

# 安装 Go Relayer (rly)
git clone https://github.com/cosmos/relayer.git
cd relayer
make install

# 验证安装
rly version

5.1.2 初始化配置

# X-MSG-Stub=true: 初始化 rly 配置目录
rly config init

# 配置文件路径: ~/.relayer/config/config.yaml

# 添加 MSG Chain 配置
rly chains add

5.1.3 完整配置文件

# X-MSG-Stub=true: ~/.relayer/config/config.yaml
global:
  api-listen-addr: :5183
  timeout: 30s
  memo: "MSG Chain Relayer"
  light-cache-size: 20

chains:
  msg-chain-1:
    type: cosmos
    value:
      key: relayer-key-msg
      chain-id: msg-chain-1
      rpc-addr: https://rpc.msgchain.org:26657
      account-prefix: msg
      keyring-backend: file
      gas-adjustment: 1.3
      gas-prices: 1000000000umsg
      min-gas-amount: 1000
      debug: false
      timeout: 30s
      block-timeout: ""
      output-format: json
      sign-mode: direct
      # Dilithium-5 签名支持 (自定义)
      # signing-algorithm: dilithium5
      extra-codecs: []

  cosmoshub-4:
    type: cosmos
    value:
      key: relayer-key-hub
      chain-id: cosmoshub-4
      rpc-addr: https://rpc.cosmoshub-4.com:26657
      account-prefix: cosmos
      keyring-backend: file
      gas-adjustment: 1.3
      gas-prices: 0.025uatom
      min-gas-amount: 1000
      debug: false
      timeout: 30s
      block-timeout: ""
      output-format: json
      sign-mode: direct
      extra-codecs: []

paths:
  msg-hub:
    src:
      chain-id: msg-chain-1
      client-id: 07-dilithium-0
      connection-id: connection-0
    dst:
      chain-id: cosmoshub-4
      client-id: 07-tendermint-0
      connection-id: connection-0
    src-channel-filter:
      rule: allowlist
      channel-list:
        - transfer
        - wasm.msg1c0m3r4y

5.1.4 启动 Relayer

# X-MSG-Stub=true: Relayer 操作

# 添加密钥
rly keys add msg-chain-1 relayer-key-msg
# 输入助记词或生成新密钥

# 创建 IBC 客户端
rly clients create msg-hub

# 创建连接
rly connection create msg-hub

# 创建通道
rly channel create msg-hub --src-port transfer --dst-port transfer --order unordered --version ics20-1

# 启动 Relayer (持续运行)
rly start msg-hub

# 查看统计
rly status

5.2 Hermes 配置

Hermes 是另一个流行的 IBC Relayer 实现,Rust 编写,性能更高。

5.2.1 Hermes 安装

# 安装 Hermes
git clone https://github.com/informalsystems/hermes.git
cd hermes
cargo build --release

# 获取二进制
cp target/release/hermes ~/.local/bin/

# 验证
hermes version

5.2.2 Hermes 配置

# X-MSG-Stub=true: ~/.hermes/config.toml

[global]
log_level = "info"

[telemetry]
enabled = true
host = "127.0.0.1"
port = 3001

[[chains]]
id = "msg-chain-1"
rpc_addr = "https://rpc.msgchain.org:26657"
grpc_addr = "https://grpc.msgchain.org:9090"
websocket_addr = "wss://rpc.msgchain.org:26657/websocket"
rpc_timeout = "30s"
account_prefix = "msg"
key_name = "hermes-msg-key"
store_prefix = "ibc"
# 使用 Dilithium-5 签名
# signing_algorithm = "dilithium5"
gas_price = { price = 0.025, denom = "umsg" }
gas_adjustment = 1.3
max_msg_num = 30
max_tx_size = 2097152
clock_drift = "5s"
trusting_period = "14days"
trust_threshold = { numerator = "1", denominator = "3" }

[[chains]]
id = "cosmoshub-4"
rpc_addr = "https://rpc.cosmoshub-4.com:26657"
grpc_addr = "https://grpc.cosmoshub-4.com:9090"
websocket_addr = "wss://rpc.cosmoshub-4.com:26657/websocket"
rpc_timeout = "30s"
account_prefix = "cosmos"
key_name = "hermes-hub-key"
store_prefix = "ibc"
gas_price = { price = 0.025, denom = "uatom" }
gas_adjustment = 1.3
max_msg_num = 30
max_tx_size = 2097152
clock_drift = "5s"
trusting_period = "14days"
trust_threshold = { numerator = "1", denominator = "3" }

5.2.3 Hermes 使用命令

# X-MSG-Stub=true: Hermes 操作

# 添加密钥
hermes keys add --chain msg-chain-1 --key-name hermes-msg-key

# 创建连接
hermes create connection --a-chain msg-chain-1 --b-chain cosmoshub-4

# 创建通道
hermes create channel \
  --a-chain msg-chain-1 \
  --a-port transfer \
  --b-port transfer \
  --a-connection connection-0 \
  --channel-version ics20-1

# 启动 Hermes
hermes start

# 查询通道状态
hermes query packet pending \
  --chain msg-chain-1 \
  --port transfer \
  --channel channel-0

5.3 Docker Compose Relayer 部署

# X-MSG-Stub=true: docker-compose.yml
version: "3.8"

services:
  relayer-rly:
    image: ghcr.io/cosmos/relayer:latest
    container_name: msg-chain-relayer
    restart: unless-stopped
    volumes:
      - ./relayer-config:/home/relayer/.relayer
      - ./relayer-keys:/home/relayer/.relayer/keys
    command: ["rly", "start", "msg-hub"]
    ports:
      - "5183:5183"
    environment:
      - RLY_API_LISTEN_ADDR=:5183
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  relayer-hermes:
    image: ghcr.io/informalsystems/hermes:latest
    container_name: msg-chain-hermes
    restart: unless-stopped
    volumes:
      - ./hermes-config:/home/hermes/.hermes
      - ./hermes-keys:/home/hermes/.hermes/keys
    command: ["hermes", "start"]
    ports:
      - "3001:3001"
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  relayer-monitor:
    image: prom/prometheus:latest
    container_name: relayer-monitor
    restart: unless-stopped
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - ./prometheus-data:/prometheus
    ports:
      - "9090:9090"
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"

  grafana:
    image: grafana/grafana:latest
    container_name: relayer-grafana
    restart: unless-stopped
    ports:
      - "3000:3000"
    volumes:
      - ./grafana-data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin123

5.4 Relayer 密钥管理

# X-MSG-Stub=true: 密钥管理

# 创建新的 Relayer 密钥
msgd keys add relayer-key-1 \
  --keyring-backend file \
  --keyring-dir ~/.relayer/keys/msg-chain-1

# 导出密钥 (用于备份)
msgd keys export relayer-key-1 \
  --keyring-backend file \
  --keyring-dir ~/.relayer/keys/msg-chain-1 \
  > relayer-key-1.backup

# 导入密钥
msgd keys import relayer-key-1 \
  relayer-key-1.backup \
  --keyring-backend file

# 查询密钥地址
msgd keys show relayer-key-1 \
  --keyring-backend file \
  --address

# 为 Relayer 充值 Gas 费用
msgd tx bank send my-main-wallet \
  msg1relayeraddress... \
  100000000000000000000umsg \
  --gas-prices 1000000000umsg

5.5 数据包中继监控

# X-MSG-Stub=true: 监控 IBC 数据包

# 查询待发送数据包
msgd query ibc channel pending-send \
  transfer channel-0 \
  --node https://rpc.msgchain.org:26657

# 查询待接收数据包
msgd query ibc channel packet-commitment \
  transfer channel-0 \
  --node https://rpc.msgchain.org:26657

# 查询未确认的确认
msgd query ibc channel unreceived-acks \
  transfer channel-0 \
  1 \
  --node https://rpc.msgchain.org:26657

# 查询未收到的数据包
msgd query ibc channel unreceived-packets \
  transfer channel-0 \
  1 \
  --node https://rpc.msgchain.org:26657

# 持续监控 (使用 watch)
watch -n 10 'msgd query ibc channel pending-send transfer channel-0'

5.6 Relayer 经济学

Relayer 需要维护成本(Gas 费),因此需要经济激励:

成本项目 估算 (每日) 说明
B 链客户端更新 5-20 MSG 每 ~100 个区块更新一次 LC
数据包转发 0.5-5 MSG/包 取决于数据包大小
握手费用 10-50 MSG 仅首次建立连接时
总估算 50-200 MSG/日 正常运行的 Relayer

费用回收机制:


6. 跨链合约开发

X-MSG-Stub=true: 本节所有合约代码为规划中的 IBC 集成示例。

6.1 IBC 启用合约模板

CosmWasm 合约可以注册为 IBC 模块,通过端口绑定直接发送和接收 IBC 数据包。

6.1.1 合约结构

msg-ibc-contract/
├── Cargo.toml
├── src/
│   ├── lib.rs
│   ├── contract.rs        # CosmosMsg 入口
│   ├── msg.rs             # 消息类型
│   ├── state.rs           # 状态存储
│   ├── error.rs           # 错误类型
│   ├── ibc.rs             # IBC 入口点
│   └── helpers.rs
├── examples/schema.rs
└── tests/integration.rs

6.1.2 src/ibc.rs — IBC 入口点

use cosmwasm_std::{
    entry_point, from_binary, to_binary, Binary, DepsMut, Env,
    IbcBasicResponse, IbcChannel, IbcChannelCloseMsg,
    IbcChannelConnectMsg, IbcChannelOpenMsg, IbcOrder,
    IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg,
    IbcReceiveResponse, StdError, StdResult,
};

use crate::error::ContractError;
use crate::msg::{
    AcknowledgementMsg, CrossChainQueryMsg, CrossChainResponse,
    IbcExecuteMsg,
};
use crate::state::{CHANNEL_STATE, ChannelState};

/// 通道打开验证
#[entry_point]
pub fn ibc_channel_open(
    _deps: DepsMut,
    _env: Env,
    msg: IbcChannelOpenMsg,
) -> StdResult<()> {
    let channel = msg.channel();
    let ordering = channel.ordering;

    // MSG Chain 支持有序 (ORDERED) 和无序 (UNORDERED) 通道
    if ordering != IbcOrder::Ordered && ordering != IbcOrder::Unordered {
        return Err(StdError::generic_err(
            "Channel ordering must be Ordered or Unordered",
        ));
    }

    // 验证版本
    let expected_version = "msg-ibc-v1";
    if channel.version != expected_version {
        return Err(StdError::generic_err(format!(
            "Unsupported IBC version: {}, expected: {}",
            channel.version, expected_version
        )));
    }

    Ok(())
}

/// 通道连接确认
#[entry_point]
pub fn ibc_channel_connect(
    deps: DepsMut,
    _env: Env,
    msg: IbcChannelConnectMsg,
) -> StdResult<IbcBasicResponse> {
    let channel: IbcChannel = msg.channel().clone();

    // 保存通道状态
    let state = ChannelState {
        endpoint: channel.endpoint().clone(),
        counterparty_endpoint: channel.counterparty_endpoint().clone(),
        ordering: channel.ordering,
        version: channel.version.clone(),
        active: true,
    };
    CHANNEL_STATE.save(deps.storage, channel.endpoint().channel_id.as_str(), &state)?;

    Ok(IbcBasicResponse::new()
        .add_attribute("method", "ibc_channel_connect")
        .add_attribute("channel_id", &channel.endpoint().channel_id))
}

/// 通道关闭处理
#[entry_point]
pub fn ibc_channel_close(
    deps: DepsMut,
    _env: Env,
    msg: IbcChannelCloseMsg,
) -> StdResult<IbcBasicResponse> {
    let channel = msg.channel();
    let channel_id = channel.endpoint().channel_id.as_str();

    // 标记通道为关闭
    if let Ok(mut state) = CHANNEL_STATE.load(deps.storage, channel_id) {
        state.active = false;
        CHANNEL_STATE.save(deps.storage, channel_id, &state)?;
    }

    Ok(IbcBasicResponse::new()
        .add_attribute("method", "ibc_channel_close")
        .add_attribute("channel_id", channel_id))
}

/// 接收 IBC 数据包
#[entry_point]
pub fn ibc_packet_receive(
    deps: DepsMut,
    env: Env,
    msg: IbcPacketReceiveMsg,
) -> Result<IbcReceiveResponse, Never> {
    let packet = msg.packet;
    let msg: IbcExecuteMsg = from_binary(&packet.data).map_err(|e| {
        let ack = AcknowledgementMsg::Error(format!("Failed to parse: {}", e));
        IbcReceiveResponse::new()
            .set_ack(ack)
            .add_attribute("parse_error", e.to_string())
    })?;

    // 处理 IBC 消息
    let result = handle_ibc_message(deps, env, packet, msg);

    match result {
        Ok(response) => Ok(response),
        Err(err) => {
            let ack = AcknowledgementMsg::Error(err.to_string());
            Ok(IbcReceiveResponse::new()
                .set_ack(ack)
                .add_attribute("error", err.to_string()))
        }
    }
}

/// 处理不同的 IBC 消息类型
fn handle_ibc_message(
    deps: DepsMut,
    env: Env,
    packet: cosmwasm_std::IbcPacket,
    msg: IbcExecuteMsg,
) -> Result<IbcReceiveResponse, ContractError> {
    match msg {
        IbcExecuteMsg::CrossChainQuery { query_type, params } => {
            handle_cross_chain_query(deps, env, packet, query_type, params)
        }
        IbcExecuteMsg::CrossChainTransfer {
            recipient,
            amount,
            denom,
        } => handle_cross_chain_transfer(deps, env, packet, recipient, amount, denom),
        IbcExecuteMsg::UpdateState {
            key,
            value,
        } => handle_state_update(deps, env, packet, key, value),
    }
}

fn handle_cross_chain_query(
    _deps: DepsMut,
    _env: Env,
    _packet: cosmwasm_std::IbcPacket,
    query_type: String,
    params: Binary,
) -> Result<IbcReceiveResponse, ContractError> {
    // 处理跨链查询
    let response_data = CrossChainResponse {
        query_type: query_type.clone(),
        data: params,
        success: true,
    };

    let ack = AcknowledgementMsg::Ok(Binary::from(
        to_binary(&response_data).unwrap().as_slice(),
    ));

    Ok(IbcReceiveResponse::new()
        .set_ack(ack)
        .add_attribute("method", "cross_chain_query")
        .add_attribute("query_type", query_type))
}

fn handle_cross_chain_transfer(
    _deps: DepsMut,
    _env: Env,
    _packet: cosmwasm_std::IbcPacket,
    recipient: String,
    amount: cosmwasm_std::Uint128,
    denom: String,
) -> Result<IbcReceiveResponse, ContractError> {
    let ack = AcknowledgementMsg::Ok(Binary::from(
        to_binary(&CrossChainResponse {
            query_type: "transfer".to_string(),
            data: Binary::default(),
            success: true,
        })
        .unwrap()
        .as_slice(),
    ));

    Ok(IbcReceiveResponse::new()
        .set_ack(ack)
        .add_attribute("method", "cross_chain_transfer")
        .add_attribute("recipient", recipient)
        .add_attribute("amount", amount.to_string()))
}

fn handle_state_update(
    _deps: DepsMut,
    _env: Env,
    _packet: cosmwasm_std::IbcPacket,
    key: String,
    value: Binary,
) -> Result<IbcReceiveResponse, ContractError> {
    let ack = AcknowledgementMsg::Ok(Binary::from(
        to_binary(&CrossChainResponse {
            query_type: "state_update".to_string(),
            data: value.clone(),
            success: true,
        })
        .unwrap()
        .as_slice(),
    ));

    Ok(IbcReceiveResponse::new()
        .set_ack(ack)
        .add_attribute("method", "state_update")
        .add_attribute("key", key))
}

/// 处理 IBC 确认
#[entry_point]
pub fn ibc_packet_ack(
    deps: DepsMut,
    _env: Env,
    msg: IbcPacketAckMsg,
) -> StdResult<IbcBasicResponse> {
    let ack: AcknowledgementMsg = from_binary(&msg.acknowledgement.data)?;

    let mut response = IbcBasicResponse::new()
        .add_attribute("method", "ibc_packet_ack")
        .add_attribute("sequence", msg.original_packet.sequence.to_string());

    match ack {
        AcknowledgementMsg::Ok(data) => {
            let response_data: CrossChainResponse = from_binary(&data)?;
            response = response
                .add_attribute("ack_status", "success")
                .add_attribute("query_type", response_data.query_type);
        }
        AcknowledgementMsg::Error(err) => {
            response = response
                .add_attribute("ack_status", "error")
                .add_attribute("error", err);
        }
    }

    Ok(response)
}

/// 处理 IBC 超时
#[entry_point]
pub fn ibc_packet_timeout(
    _deps: DepsMut,
    _env: Env,
    msg: IbcPacketTimeoutMsg,
) -> StdResult<IbcBasicResponse> {
    // 超时处理:可以触发退款逻辑
    Ok(IbcBasicResponse::new()
        .add_attribute("method", "ibc_packet_timeout")
        .add_attribute("sequence", msg.packet.sequence.to_string()))
}

/// 自定义 Never 类型(用于 IBC Receive 永不失败)
pub enum Never {}

impl From<Never> for StdError {
    fn from(_: Never) -> Self {
        unreachable!()
    }
}

6.1.3 src/msg.rs — IBC 消息类型

use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Binary, Uint128};

/// 合约执行消息 (非 IBC)
#[cw_serde]
pub enum ExecuteMsg {
    SendIBCPacket {
        channel_id: String,
        msg: IbcExecuteMsg,
        timeout_seconds: Option<u64>,
    },
    RegisterIBCChannel {
        channel_id: String,
    },
}

/// 合约查询消息
#[cw_serde]
pub enum QueryMsg {
    GetChannelState { channel_id: String },
    ListChannels {},
}

/// IBC 数据包内容
#[cw_serde]
pub enum IbcExecuteMsg {
    CrossChainQuery {
        query_type: String,
        params: Binary,
    },
    CrossChainTransfer {
        recipient: String,
        amount: Uint128,
        denom: String,
    },
    UpdateState {
        key: String,
        value: Binary,
    },
}

/// IBC 确认消息
#[cw_serde]
pub enum AcknowledgementMsg {
    Ok(Binary),
    Error(String),
}

/// 跨链查询响应
#[cw_serde]
pub struct CrossChainResponse {
    pub query_type: String,
    pub data: Binary,
    pub success: bool,
}

6.1.4 src/state.rs

use cosmwasm_schema::cw_serde;
use cw_storage_plus::{Item, Map};

use cosmwasm_std::IbcEndpoint;

#[cw_serde]
pub struct ChannelState {
    pub endpoint: IbcEndpoint,
    pub counterparty_endpoint: IbcEndpoint,
    pub ordering: cosmwasm_std::IbcOrder,
    pub version: String,
    pub active: bool,
}

#[cw_serde]
pub struct Config {
    pub admin: String,
}

pub const CONFIG: Item<Config> = Item::new("config");
pub const CHANNEL_STATE: Map<&str, ChannelState> = Map::new("channel_state");

6.1.5 src/contract.rs — 执行函数

use cosmwasm_std::{
    entry_point, to_binary, Binary, Deps, DepsMut, Env, IbcMsg,
    IbcTimeout, IbcTimeoutBlock, MessageInfo, Response, StdResult,
};

use crate::error::ContractError;
use crate::msg::{ExecuteMsg, IbcExecuteMsg, QueryMsg};
use crate::state::{CONFIG, Config};

#[entry_point]
pub fn instantiate(
    deps: DepsMut,
    _env: Env,
    _info: MessageInfo,
    msg: crate::msg::InstantiateMsg,
) -> StdResult<Response> {
    let config = Config { admin: msg.admin };
    CONFIG.save(deps.storage, &config)?;
    Ok(Response::new().add_attribute("method", "instantiate"))
}

#[entry_point]
pub fn execute(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response, ContractError> {
    match msg {
        ExecuteMsg::SendIBCPacket {
            channel_id,
            msg: ibc_msg,
            timeout_seconds,
        } => execute_send_ibc_packet(deps, env, info, channel_id, ibc_msg, timeout_seconds),
        ExecuteMsg::RegisterIBCChannel { channel_id } => {
            execute_register_ibc_channel(deps, info, channel_id)
        }
    }
}

fn execute_send_ibc_packet(
    _deps: DepsMut,
    env: Env,
    info: MessageInfo,
    channel_id: String,
    ibc_msg: IbcExecuteMsg,
    timeout_seconds: Option<u64>,
) -> Result<Response, ContractError> {
    let timeout = if let Some(secs) = timeout_seconds {
        IbcTimeout::with_timestamp(env.block.time.plus_seconds(secs))
    } else {
        IbcTimeout::with_block(IbcTimeoutBlock {
            revision: 0,
            height: env.block.height + 5000,
        })
    };

    let packet = IbcMsg::SendPacket {
        channel_id: channel_id.clone(),
        data: to_binary(&ibc_msg)?,
        timeout,
    };

    Ok(Response::new()
        .add_message(packet)
        .add_attribute("method", "send_ibc_packet")
        .add_attribute("sender", info.sender.to_string())
        .add_attribute("channel_id", channel_id))
}

fn execute_register_ibc_channel(
    _deps: DepsMut,
    _info: MessageInfo,
    channel_id: String,
) -> Result<Response, ContractError> {
    Ok(Response::new()
        .add_attribute("method", "register_ibc_channel")
        .add_attribute("channel_id", channel_id))
}

#[entry_point]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
    match msg {
        QueryMsg::GetChannelState { channel_id } => {
            let state = crate::state::CHANNEL_STATE.load(deps.storage, &channel_id)?;
            to_binary(&state)
        }
        QueryMsg::ListChannels {} => {
            let channels: Vec<String> = crate::state::CHANNEL_STATE
                .range(deps.storage, None, None, cosmwasm_std::Order::Ascending)
                .map(|r| r.map(|(k, _)| k))
                .collect::<StdResult<_>>()?;
            to_binary(&channels)
        }
    }
}

6.2 IBC Fee 中间件集成

IBC Fee 中间件 (ICS-29) 允许 Relayer 收取数据包中继费用。

// X-MSG-Stub=true: IBC Fee 中间件配置

/// IBC Fee 数据包前向费用
#[cw_serde]
pub struct IBCFee {
    /// 转发数据包的费用
    pub recv_fee: Vec<Coin>,
    /// 回传确认的费用
    pub ack_fee: Vec<Coin>,
    /// 超时处理的费用
    pub timeout_fee: Vec<Coin>,
}

/// 创建携带费用的 IBC 转账
pub fn create_fee_enabled_ibc_transfer(
    channel_id: String,
    to_address: String,
    amount: Coin,
    fee: IBCFee,
) -> Vec<CosmosMsg> {
    // 1. 支付 IBC Fee
    let pay_fee_msg = MsgPayPacketFee {
        signer: ..., // 发送者
        fee: IbcFee {
            recv_fee: fee.recv_fee,
            ack_fee: fee.ack_fee,
            timeout_fee: fee.timeout_fee,
        },
        source_port_id: "transfer".to_string(),
        source_channel_id: channel_id.clone(),
    };

    // 2. 发起 IBC 转账
    let transfer_msg = IbcMsg::Transfer {
        channel_id,
        to_address,
        amount,
        timeout: ...,
    };

    vec![
        CosmosMsg::Stargate {
            type_url: "/ibc.applications.fee.v1.MsgPayPacketFee".to_string(),
            value: to_binary(&pay_fee_msg).unwrap(),
        },
        CosmosMsg::Ibc(transfer_msg),
    ]
}

7. 自定义桥接合约

X-MSG-Stub=true: 本节为规划中的自定义桥接方案,用于 MSG Chain 与非 IBC 链(如 Ethereum)的交互。

7.1 Lock-Mint 桥模式

Lock-Mint 桥是最经典的资产跨链模式:在源链锁定资产,在目标链铸造等价代币。

X-MSG-Stub=true
Ethereum                              MSG Chain
  │                                      │
  │  1. 用户锁定 ETH 到桥合约            │
  │  ┌────────────────────┐              │
  │  │ Bridge Contract    │              │
  │  │ (Lock 10 ETH)      │              │
  │  └────────────────────┘              │
  │         │                            │
  │         │ (验证者共识)                │
  │         └─────────────────────────►  │
  │                                      │
  │                           ┌────────┐ │
  │                           │ Mint   │ │
  │                           │ 10 msgETH│ │
  │                           └────────┘ │
  │                                      │
  │  2. 用户销毁 msgETH 赎回 ETH         │
  │  ◄────────────────────────────────── │
  │                                      │
  │  ┌────────────────────┐              │
  │  │ 解锁 10 ETH 给用户  │              │
  │  └────────────────────┘              │

7.2 Burn-Mint 桥模式

Burn-Mint 桥适用于有原生代币映射的场景。

X-MSG-Stub=true
MSG Chain                              Osmosis
  │                                       │
  │  1. 销毁原生 MSG 代币                 │
  │  ┌──────────────────┐                 │
  │  │ Burn 100 MSG     │                 │
  │  └──────────────────┘                 │
  │         │                             │
  │         │ (跨链消息)                  │
  │         └─────────────────────────►   │
  │                                       │
  │                            ┌────────┐ │
  │                            │ Mint   │ │
  │                            │ 100 osmoMSG│
  │                            └────────┘ │

7.3 完整 CosmWasm 桥接合约

7.3.1 Cargo.toml

[package]
name = "msg-bridge-contract"
version = "1.0.0"
edition = "2021"
description = "MSG Chain Custom Bridge Contract"

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
cosmwasm-std = "1.5"
cw-storage-plus = "1.2"
cw2 = "1.1"
cw-utils = "1.0"
schemars = "0.8"
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
uint = "0.9"
sha2 = "0.10"
hex = "0.4"

[dev-dependencies]
cosmwasm-vm = "1.5"
cw-multi-test = "0.18"

7.3.2 src/msg.rs

use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Binary, Uint128};

#[cw_serde]
pub struct InstantiateMsg {
    pub admin: String,
    pub validators: Vec<BridgeValidator>,
    pub required_signatures: u32,
    pub chain_name: String,
    pub counterparty_chain_id: String,
}

#[cw_serde]
pub struct BridgeValidator {
    pub address: String,
    pub power: u64,
    pub dilithium5_public_key: String,
}

#[cw_serde]
pub enum ExecuteMsg {
    /// 锁定资产发起桥接
    LockAssets {
        recipient: String,
        amount: Uint128,
        denom: String,
        target_chain: String,
    },
    /// 铸造资产(验证者签名后)
    MintAssets {
        sender: String,
        recipient: String,
        amount: Uint128,
        denom: String,
        source_chain: String,
        source_tx_hash: String,
        signatures: Vec<Signature>,
    },
    /// 燃烧资产发起赎回
    BurnAssets {
        amount: Uint128,
        denom: String,
        recipient_on_source: String,
    },
    /// 解锁资产(验证者签名后)
    UnlockAssets {
        sender: String,
        recipient: String,
        amount: Uint128,
        denom: String,
        source_chain: String,
        source_tx_hash: String,
        burn_tx_hash: String,
        signatures: Vec<Signature>,
    },
    /// 更新验证者集
    UpdateValidatorSet {
        validators: Vec<BridgeValidator>,
        required_signatures: u32,
        signatures: Vec<Signature>,
    },
    /// 暂停桥
    Pause {},
    /// 恢复桥
    Resume {},
}

#[cw_serde]
pub struct Signature {
    pub validator_address: String,
    pub signature: Binary,
}

#[cw_serde]
pub enum QueryMsg {
    GetBridgeConfig {},
    GetValidatorSet {},
    GetLockedBalance { denom: String },
    GetBridgeStatus {},
    VerifyMintRequest {
        sender: String,
        recipient: String,
        amount: Uint128,
        denom: String,
        source_tx_hash: String,
        signatures: Vec<Signature>,
    },
}

#[cw_serde]
pub struct BridgeConfig {
    pub admin: String,
    pub chain_name: String,
    pub counterparty_chain_id: String,
    pub required_signatures: u32,
    pub paused: bool,
}

#[cw_serde]
pub struct BridgeTransferRequest {
    pub id: String,
    pub sender: String,
    pub recipient: String,
    pub amount: Uint128,
    pub denom: String,
    pub source_chain: String,
    pub target_chain: String,
    pub status: TransferStatus,
    pub source_tx_hash: String,
    pub created_at: u64,
}

#[cw_serde]
pub enum TransferStatus {
    Pending,
    Confirmed,
    Failed,
}

7.3.3 src/state.rs

use cosmwasm_schema::cw_serde;
use cw_storage_plus::{Item, Map};
use cosmwasm_std::Uint128;

use crate::msg::{BridgeConfig, BridgeValidator, BridgeTransferRequest};

pub const CONFIG: Item<BridgeConfig> = Item::new("bridge_config");
pub const VALIDATORS: Map<&str, BridgeValidator> = Map::new("validators");
pub const LOCKED_BALANCES: Map<&str, Uint128> = Map::new("locked_balances");
pub const MINTED_BALANCES: Map<&str, Uint128> = Map::new("minted_balances");
pub const TRANSFER_REQUESTS: Map<&str, BridgeTransferRequest> = Map::new("transfer_requests");

pub const BRIDGE_NONCE: Item<u64> = Item::new("bridge_nonce");

7.3.4 src/contract.rs

use cosmwasm_std::{
    entry_point, to_binary, BankMsg, Binary, Coin, Deps, DepsMut,
    Env, MessageInfo, Order, Response, StdError, StdResult, Uint128,
};
use cw2::set_contract_version;
use sha2::{Digest, Sha256};

use crate::error::ContractError;
use crate::msg::{
    BridgeConfig, BridgeTransferRequest, BridgeValidator, ExecuteMsg,
    InstantiateMsg, QueryMsg, Signature, TransferStatus,
};
use crate::state::{
    CONFIG, LOCKED_BALANCES, MINTED_BALANCES, TRANSFER_REQUESTS,
    VALIDATORS, BRIDGE_NONCE,
};

const CONTRACT_NAME: &str = "msg-bridge-contract";
const CONTRACT_VERSION: &str = "1.0.0";

#[entry_point]
pub fn instantiate(
    deps: DepsMut,
    _env: Env,
    info: MessageInfo,
    msg: InstantiateMsg,
) -> StdResult<Response> {
    set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;

    let config = BridgeConfig {
        admin: msg.admin,
        chain_name: msg.chain_name,
        counterparty_chain_id: msg.counterparty_chain_id,
        required_signatures: msg.required_signatures,
        paused: false,
    };
    CONFIG.save(deps.storage, &config)?;

    for validator in msg.validators {
        VALIDATORS.save(deps.storage, &validator.address, &validator)?;
    }

    BRIDGE_NONCE.save(deps.storage, &0)?;

    Ok(Response::new()
        .add_attribute("method", "instantiate")
        .add_attribute("admin", info.sender.to_string()))
}

#[entry_point]
pub fn execute(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response, ContractError> {
    match msg {
        ExecuteMsg::LockAssets {
            recipient,
            amount,
            denom,
            target_chain,
        } => execute_lock_assets(deps, env, info, recipient, amount, denom, target_chain),
        ExecuteMsg::MintAssets {
            sender,
            recipient,
            amount,
            denom,
            source_chain,
            source_tx_hash,
            signatures,
        } => execute_mint_assets(
            deps, env, info, sender, recipient, amount, denom,
            source_chain, source_tx_hash, signatures,
        ),
        ExecuteMsg::BurnAssets {
            amount,
            denom,
            recipient_on_source,
        } => execute_burn_assets(deps, env, info, amount, denom, recipient_on_source),
        ExecuteMsg::UnlockAssets {
            sender,
            recipient,
            amount,
            denom,
            source_chain,
            source_tx_hash,
            burn_tx_hash,
            signatures,
        } => execute_unlock_assets(
            deps, env, info, sender, recipient, amount, denom,
            source_chain, source_tx_hash, burn_tx_hash, signatures,
        ),
        ExecuteMsg::UpdateValidatorSet {
            validators,
            required_signatures,
            signatures,
        } => execute_update_validator_set(
            deps, env, info, validators, required_signatures, signatures,
        ),
        ExecuteMsg::Pause {} => execute_pause(deps, info),
        ExecuteMsg::Resume {} => execute_resume(deps, info),
    }
}

fn assert_not_paused(deps: &DepsMut) -> Result<(), ContractError> {
    let config = CONFIG.load(deps.storage)?;
    if config.paused {
        return Err(ContractError::Std(StdError::generic_err("Bridge is paused")));
    }
    Ok(())
}

fn assert_admin(deps: &DepsMut, info: &MessageInfo) -> Result<(), ContractError> {
    let config = CONFIG.load(deps.storage)?;
    if info.sender.to_string() != config.admin {
        return Err(ContractError::Unauthorized {});
    }
    Ok(())
}

fn verify_signatures(
    deps: &DepsMut,
    message_hash: &[u8],
    signatures: &[Signature],
) -> Result<(), ContractError> {
    let config = CONFIG.load(deps.storage)?;

    if signatures.len() < config.required_signatures as usize {
        return Err(ContractError::Std(StdError::generic_err(
            "Insufficient signatures",
        )));
    }

    let mut valid_count = 0;
    let mut seen_addresses = std::collections::HashSet::new();

    for sig in signatures {
        if seen_addresses.contains(&sig.validator_address) {
            continue; // 跳过重复签名
        }
        seen_addresses.insert(sig.validator_address.clone());

        // 验证签名者是否为合法验证者
        if let Ok(validator) = VALIDATORS.load(deps.storage, &sig.validator_address) {
            // 使用 Dilithium-5 验证签名
            // TODO: 接入 Dilithium-5 验证预编译
            // let valid = verify_dilithium5(
            //     &validator.dilithium5_public_key,
            //     message_hash,
            //     &sig.signature,
            // );
            // if valid {
            //     valid_count += 1;
            // }
            valid_count += 1; // 占位逻辑
        }
    }

    if valid_count < config.required_signatures as usize {
        return Err(ContractError::Std(StdError::generic_err(
            "Signature verification failed",
        )));
    }

    Ok(())
}

fn compute_transfer_hash(
    sender: &str,
    recipient: &str,
    amount: Uint128,
    denom: &str,
    source_tx_hash: &str,
    nonce: u64,
) -> [u8; 32] {
    let mut hasher = Sha256::new();
    hasher.update(sender.as_bytes());
    hasher.update(b":");
    hasher.update(recipient.as_bytes());
    hasher.update(b":");
    hasher.update(amount.to_string().as_bytes());
    hasher.update(b":");
    hasher.update(denom.as_bytes());
    hasher.update(b":");
    hasher.update(source_tx_hash.as_bytes());
    hasher.update(b":");
    hasher.update(nonce.to_be_bytes());
    hasher.finalize().into()
}

fn execute_lock_assets(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    recipient: String,
    amount: Uint128,
    denom: String,
    target_chain: String,
) -> Result<Response, ContractError> {
    assert_not_paused(&deps)?;

    // 验证用户发送了足够的资金
    let sent = cw_utils::must_pay(&info, &denom)
        .map_err(|_| ContractError::Std(StdError::generic_err("Insufficient payment")))?;
    if sent != amount {
        return Err(ContractError::Std(StdError::generic_err(
            "Sent amount doesn't match",
        )));
    }

    let mut nonce = BRIDGE_NONCE.load(deps.storage)?;
    nonce += 1;
    BRIDGE_NONCE.save(deps.storage, &nonce)?;

    // 记录锁定量
    let locked = LOCKED_BALANCES
        .load(deps.storage, &denom)
        .unwrap_or_default();
    LOCKED_BALANCES.save(deps.storage, &denom, &(locked + amount))?;

    // 创建转账请求
    let request_id = format!("{}-{}", env.block.height, nonce);
    let request = BridgeTransferRequest {
        id: request_id.clone(),
        sender: info.sender.to_string(),
        recipient: recipient.clone(),
        amount,
        denom: denom.clone(),
        source_chain: "msg-chain".to_string(),
        target_chain: target_chain.clone(),
        status: TransferStatus::Pending,
        source_tx_hash: String::new(),
        created_at: env.block.time.seconds(),
    };
    TRANSFER_REQUESTS.save(deps.storage, &request_id, &request)?;

    Ok(Response::new()
        .add_attribute("method", "lock_assets")
        .add_attribute("request_id", &request_id)
        .add_attribute("sender", info.sender.to_string())
        .add_attribute("recipient", &recipient)
        .add_attribute("amount", amount.to_string())
        .add_attribute("denom", &denom)
        .add_attribute("target_chain", &target_chain))
}

fn execute_mint_assets(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    sender: String,
    recipient: String,
    amount: Uint128,
    denom: String,
    source_chain: String,
    source_tx_hash: String,
    signatures: Vec<Signature>,
) -> Result<Response, ContractError> {
    assert_not_paused(&deps)?;

    let nonce = BRIDGE_NONCE.load(deps.storage)?;

    // 计算并验证签名
    let msg_hash = compute_transfer_hash(
        &sender,
        &recipient,
        amount,
        &denom,
        &source_tx_hash,
        nonce,
    );
    verify_signatures(&deps, &msg_hash, &signatures)?;

    // 铸造资产
    let minted = MINTED_BALANCES
        .load(deps.storage, &denom)
        .unwrap_or_default();
    MINTED_BALANCES.save(deps.storage, &denom, &(minted + amount))?;

    // 发送资产给接收者
    let transfer = BankMsg::Send {
        to_address: recipient.clone(),
        amount: vec![Coin {
            denom: format!("bridge.{}", denom),
            amount,
        }],
    };

    Ok(Response::new()
        .add_message(transfer)
        .add_attribute("method", "mint_assets")
        .add_attribute("recipient", &recipient)
        .add_attribute("amount", amount.to_string())
        .add_attribute("denom", &denom)
        .add_attribute("source_chain", &source_chain))
}

fn execute_burn_assets(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    amount: Uint128,
    denom: String,
    recipient_on_source: String,
) -> Result<Response, ContractError> {
    assert_not_paused(&deps)?;

    let bridge_denom = format!("bridge.{}", denom);

    // 验证用户有足够的桥接资产
    let balance = deps.querier.query_balance(
        info.sender.to_string().as_str(),
        &bridge_denom,
    )?;
    if balance.amount < amount {
        return Err(ContractError::InsufficientBalance {});
    }

    // 减少铸造量
    let minted = MINTED_BALANCES
        .load(deps.storage, &denom)
        .unwrap_or_default();

    if minted < amount {
        return Err(ContractError::InsufficientBalance {});
    }
    MINTED_BALANCES.save(deps.storage, &denom, &(minted - amount))?;

    // 销毁资产 (通过发送给黑洞地址)
    let burn = BankMsg::Send {
        to_address: "msg1burnburnburnburnburnburnburnburnburn5uq7q7".to_string(),
        amount: vec![Coin {
            denom: bridge_denom,
            amount,
        }],
    };

    let nonce = BRIDGE_NONCE.load(deps.storage)?;
    BRIDGE_NONCE.save(deps.storage, &(nonce + 1))?;

    Ok(Response::new()
        .add_message(burn)
        .add_attribute("method", "burn_assets")
        .add_attribute("sender", info.sender.to_string())
        .add_attribute("amount", amount.to_string())
        .add_attribute("denom", &denom)
        .add_attribute("recipient_on_source", &recipient_on_source))
}

fn execute_unlock_assets(
    deps: DepsMut,
    _env: Env,
    _info: MessageInfo,
    sender: String,
    recipient: String,
    amount: Uint128,
    denom: String,
    source_chain: String,
    source_tx_hash: String,
    burn_tx_hash: String,
    signatures: Vec<Signature>,
) -> Result<Response, ContractError> {
    assert_not_paused(&deps)?;

    // 计算解锁消息哈希(包含 burn_tx_hash)
    let combined_hash = format!("{}:{}", source_tx_hash, burn_tx_hash);
    let msg_hash = Sha256::digest(combined_hash.as_bytes());
    verify_signatures(&deps, &msg_hash, &signatures)?;

    // 减少锁定量
    let locked = LOCKED_BALANCES
        .load(deps.storage, &denom)
        .unwrap_or_default();
    if locked < amount {
        return Err(ContractError::InsufficientBalance {});
    }
    LOCKED_BALANCES.save(deps.storage, &denom, &(locked - amount))?;

    // 解锁资产给用户
    let transfer = BankMsg::Send {
        to_address: recipient.clone(),
        amount: vec![Coin {
            denom: denom.clone(),
            amount,
        }],
    };

    Ok(Response::new()
        .add_message(transfer)
        .add_attribute("method", "unlock_assets")
        .add_attribute("recipient", &recipient)
        .add_attribute("amount", amount.to_string())
        .add_attribute("denom", &denom)
        .add_attribute("source_chain", &source_chain))
}

fn execute_update_validator_set(
    deps: DepsMut,
    _env: Env,
    _info: MessageInfo,
    validators: Vec<BridgeValidator>,
    required_signatures: u32,
    _signatures: Vec<Signature>,
) -> Result<Response, ContractError> {
    let mut config = CONFIG.load(deps.storage)?;
    config.required_signatures = required_signatures;
    CONFIG.save(deps.storage, &config)?;

    // 清除旧验证者
    let old_validators: Vec<String> = VALIDATORS
        .range(deps.storage, None, None, Order::Ascending)
        .map(|r| r.map(|(k, _)| k))
        .collect::<StdResult<Vec<_>>>()?;
    for addr in old_validators {
        VALIDATORS.remove(deps.storage, &addr);
    }

    // 保存新验证者
    for v in validators {
        VALIDATORS.save(deps.storage, &v.address, &v)?;
    }

    Ok(Response::new()
        .add_attribute("method", "update_validator_set")
        .add_attribute("count", VALIDATORS
            .range(deps.storage, None, None, Order::Ascending)
            .count()
            .to_string()))
}

fn execute_pause(
    deps: DepsMut,
    info: MessageInfo,
) -> Result<Response, ContractError> {
    assert_admin(&deps, &info)?;
    let mut config = CONFIG.load(deps.storage)?;
    config.paused = true;
    CONFIG.save(deps.storage, &config)?;
    Ok(Response::new().add_attribute("method", "pause"))
}

fn execute_resume(
    deps: DepsMut,
    info: MessageInfo,
) -> Result<Response, ContractError> {
    assert_admin(&deps, &info)?;
    let mut config = CONFIG.load(deps.storage)?;
    config.paused = false;
    CONFIG.save(deps.storage, &config)?;
    Ok(Response::new().add_attribute("method", "resume"))
}

#[entry_point]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
    match msg {
        QueryMsg::GetBridgeConfig {} => to_binary(&CONFIG.load(deps.storage)?),
        QueryMsg::GetValidatorSet {} => {
            let validators: Vec<BridgeValidator> = VALIDATORS
                .range(deps.storage, None, None, Order::Ascending)
                .map(|r| r.map(|(_, v)| v))
                .collect::<StdResult<Vec<_>>>()?;
            to_binary(&validators)
        }
        QueryMsg::GetLockedBalance { denom } => {
            let balance = LOCKED_BALANCES
                .load(deps.storage, &denom)
                .unwrap_or_default();
            to_binary(&balance)
        }
        QueryMsg::GetBridgeStatus {} => {
            let config = CONFIG.load(deps.storage)?;
            let validator_count = VALIDATORS
                .range(deps.storage, None, None, Order::Ascending)
                .count();
            to_binary(&serde_json::json!({
                "paused": config.paused,
                "validator_count": validator_count,
                "required_signatures": config.required_signatures,
            }))
        }
        QueryMsg::VerifyMintRequest {
            sender,
            recipient,
            amount,
            denom,
            source_tx_hash,
            signatures,
        } => {
            let nonce = BRIDGE_NONCE.load(deps.storage).unwrap_or(0);
            let msg_hash = compute_transfer_hash(
                &sender, &recipient, amount, &denom, &source_tx_hash, nonce,
            );

            let mut valid_count = 0;
            for sig in &signatures {
                if let Ok(validator) = VALIDATORS.load(deps.storage, &sig.validator_address) {
                    let _ = validator; // TODO: 实际验证签名
                    valid_count += 1;
                }
            }

            let config = CONFIG.load(deps.storage)?;
            to_binary(&serde_json::json!({
                "valid": valid_count >= config.required_signatures as usize,
                "signatures_required": config.required_signatures,
                "signatures_provided": valid_count,
            }))
        }
    }
}

7.3.5 src/error.rs

use cosmwasm_std::{StdError, Uint128};
use thiserror::Error;

#[derive(Error, Debug, PartialEq)]
pub enum ContractError {
    #[error("{0}")]
    Std(#[from] StdError),

    #[error("Unauthorized")]
    Unauthorized {},

    #[error("Insufficient balance: required {required}, available {available}")]
    InsufficientBalance {},

    #[error("Insufficient signatures: required {required}, provided {provided}")]
    InsufficientSignatures { required: u32, provided: usize },

    #[error("Invalid signature from {validator}")]
    InvalidSignature { validator: String },

    #[error("Transfer {request_id} not found")]
    TransferNotFound { request_id: String },

    #[error("Transfer {request_id} already completed")]
    TransferAlreadyCompleted { request_id: String },
}

8. 跨链dApp示例

X-MSG-Stub=true: 本节所有 dApp 为概念设计,尚未实现。

8.1 跨链 AI Agent 市场

概念: AI Agent 在 MSG Chain 上注册,但可以跨链被 Osmosis 上的用户发现和支付。

8.1.1 架构设计

X-MSG-Stub=true
                  跨链 AI Agent 市场
┌─────────────────────────────────────────────────────────┐
│                                                          │
│  MSG Chain (Agent 注册链)   Osmosis (发现/支付链)         │
│                                                          │
│  ┌───────────────────┐      ┌───────────────────────┐   │
│  │ agent_registry_v1 │◄────►│ Agent Market App      │   │
│  │ (Agent 注册)      │ IBC  │ (市场前端)            │   │
│  └───────────────────┘      └───────────────────────┘   │
│                                                          │
│  ┌───────────────────┐      ┌───────────────────────┐   │
│  │ agent_payment_v1  │◄────►│ Cross-chain Payment  │   │
│  │ (AIPAY 支付)       │ IBC  │ (跨链支付结算)        │   │
│  └───────────────────┘      └───────────────────────┘   │
│                                                          │
│  ┌───────────────────┐      ┌───────────────────────┐   │
│  │ aidid_did_v1      │◄────►│ DID Resolver         │   │
│  │ (DID 身份)         │ IBC  │ (身份解析)            │   │
│  └───────────────────┘      └───────────────────────┘   │
│                                                          │
└─────────────────────────────────────────────────────────┘

8.1.2 合约端 (MSG Chain) — Agent 注册

Agent 在 MSG Chain 上注册时,可以指定跨链可发现性:

// X-MSG-Stub=true: Agent 跨链注册消息 (沿用 agent_registry_v1 模式)
pub struct RegisterCrossChainAgent {
    pub agent_id: String,
    pub did_id: String,
    pub owner: String,
    pub name: String,
    pub description: Option<String>,
    pub endpoint: Option<String>,
    pub agent_type: String,
    pub capabilities: Vec<String>,
    /// 启用跨链发现的链列表
    pub cross_chain_discovery: Vec<String>,
    /// 接受的跨链支付代币
    pub accepted_tokens: Vec<CrossChainToken>,
}

pub struct CrossChainToken {
    pub chain_id: String,
    pub denom: String,
    pub ibc_channel: String,
    pub min_price: Uint128,
}

pub struct CrossChainAgentListing {
    pub agent_id: String,
    pub name: String,
    pub description: String,
    pub capabilities: Vec<String>,
    pub accepted_tokens: Vec<CrossChainToken>,
    pub owner: String,
    pub rating: u32,
}

8.1.3 前端查询 (Osmosis 侧)

// X-MSG-Stub=true: 跨链 Agent 查询 (从 Osmosis 查询 MSG Chain 的 Agent)

const MSG_CHAIN_RPC = "https://rpc.msgchain.org:26657";
const AGENT_REGISTRY_CONTRACT = "msg1agentregistrycontractaddress...";

interface CrossChainAgent {
  agent_id: string;
  name: string;
  description: string;
  capabilities: string[];
  accepted_tokens: CrossChainToken[];
  owner: string;
  rating: number;
}

interface CrossChainToken {
  chain_id: string;
  denom: string;
  ibc_channel: string;
  min_price: string;
}

/**
 * 通过 IBC 查询跨链 Agent 列表
 * 使用 IBC 数据包进行跨链查询
 */
async function queryCrossChainAgents(
  ibcChannel: string
): Promise<CrossChainAgent[]> {
  // 1. 构建 IBC 查询数据包
  const queryPacket = {
    cross_chain_query: {
      query_type: "list_agents",
      params: {
        limit: 100,
        include_cross_chain: true,
      },
    },
  };

  // 2. 通过 CosmJS 发送查询
  // 注意: 这需要一个支持 IBC 查询的合约
  // 实际实现需要通过一个查询代理合约

  // 模拟返回数据
  return [
    {
      agent_id: "agent-llm-001",
      name: "跨链 LLM 助手",
      description: "基于 GPT-4 的多语言 AI 助手",
      capabilities: ["text-generation", "code-review", "translation"],
      accepted_tokens: [
        {
          chain_id: "osmosis-1",
          denom: "uosmo",
          ibc_channel: "channel-1",
          min_price: "1000000",
        },
        {
          chain_id: "cosmoshub-4",
          denom: "uatom",
          ibc_channel: "channel-2",
          min_price: "500000",
        },
      ],
      owner: "msg1agentowner...",
      rating: 4,
    },
  ];
}

/**
 * 通过 IBC 发起跨链支付
 */
async function crossChainPayAgent(
  agentId: string,
  token: CrossChainToken,
  amount: string,
  userAddress: string
): Promise<string> {
  const signingClient = await SigningStargateClient.connectWithSigner(
    "https://rpc.osmosis.zone:26657",
    wallet
  );

  // 构建 IBC 转账给 Agent 支付合约
  const transferMsg = {
    typeUrl: "/ibc.applications.transfer.v1.MsgTransfer",
    value: {
      sourcePort: "transfer",
      sourceChannel: token.ibc_channel,
      token: { denom: token.denom, amount },
      sender: userAddress,
      receiver: AGENT_REGISTRY_CONTRACT,
      timeoutHeight: { revisionNumber: 0, revisionHeight: 500000 },
      timeoutTimestamp: 0n,
      memo: JSON.stringify({
        agent_id: agentId,
        action: "execute_task",
        task_data: { /* 任务参数 */ },
      }),
    },
  };

  const fee = { amount: [{ denom: "uosmo", amount: "5000" }], gas: "250000" };
  const result = await signingClient.signAndBroadcast(
    userAddress,
    [transferMsg],
    fee
  );

  return result.transactionHash;
}

8.2 跨链支付结算

利用 IBC 实现 MSG Chain 到 Osmosis 的跨链支付结算。

X-MSG-Stub=true
用户 (Osmosis)                     MSG Chain Agent
      │                                      │
      │  1. 支付 100 OSMO                     │
      │  (IBC 转账 + memo)                    │
      │  ─────────────────────────────────►   │
      │                                      │
      │                   2. Agent 接收支付   │
      │                   确认任务执行        │
      │  ◄─────────────────────────────────   │
      │                                      │
      │  3. 任务完成,确认结算                │
      │  ─────────────────────────────────►   │
      │                                      │
      │  4. Agent 通过 IBC 转回               │
      │  应得的 MSG 代币                      │
      │  ◄─────────────────────────────────   │
// X-MSG-Stub=true: 跨链支付结算

interface CrossChainPayment {
  paymentId: string;
  payer: string;
  payee: string;
  sourceChain: string;
  destinationChain: string;
  amount: string;
  denom: string;
  status: "pending" | "confirmed" | "refunded";
  memo: string;
}

async function settleCrossChainPayment(
  payment: CrossChainPayment,
  ibcChannel: string
): Promise<string> {
  // 在来源链发起 IBC 转账附加支付信息
  if (payment.sourceChain === "osmosis-1") {
    const client = await SigningStargateClient.connectWithSigner(
      "https://rpc.osmosis.zone:26657",
      wallet
    );

    const result = await client.sendIbcTokens(
      payment.payer,
      payment.payee,
      { denom: payment.denom, amount: payment.amount },
      "transfer",
      ibcChannel,
      { revisionNumber: 0, revisionHeight: 500000 },
      undefined,
      { amount: [{ denom: "uosmo", amount: "5000" }], gas: "200000" },
      JSON.stringify({
        payment_id: payment.paymentId,
        type: "agent_payment",
      })
    );

    return result.transactionHash;
  }
  throw new Error(`Unsupported source chain: ${payment.sourceChain}`);
}

8.3 跨链身份 (DID) 解析

利用 IBC 实现 MSG Chain 的 DID 在其他链上解析。

// X-MSG-Stub=true: 跨链 DID 解析消息
pub struct CrossChainDIDQuery {
    pub did_id: String,
    pub query_chain: String,
    pub requester: String,
}

pub struct CrossChainDIDResponse {
    pub did_document: DIDDocument,
    pub verified: bool,
    pub verification_chain: String,
}
// X-MSG-Stub=true: 跨链 DID 解析

const DID_REGISTRY_ADDRESS = "msg1didregistry...";

async function resolveCrossChainDID(
  didId: string,
  targetChain: string
): Promise<any> {
  if (targetChain === "msg-chain-1") {
    // 直接在 MSG Chain 上查询
    const client = await SigningStargateClient.connect(MSG_CHAIN_RPC);
    const result = await client.queryContractSmart(DID_REGISTRY_ADDRESS, {
      resolve_did: { did_id: didId },
    });
    return result;
  } else {
    // 通过 IBC 查询
    console.log(`Cross-chain DID resolution for ${didId} from ${targetChain}`);
    // 实际需要通过 IBC 数据包发送查询
  }
}

8.4 TypeScript 跨链交易构建器

// X-MSG-Stub=true: 跨链交易构建器

import {
  SigningStargateClient,
  MsgTransferEncodeObject,
  calculateFee,
  GasPrice,
} from "@cosmjs/stargate";
import { MsgTransfer } from "cosmjs-types/ibc/applications/transfer/v1/tx";
import { Height } from "cosmjs-types/ibc/core/client/v1/client";

interface IBCMsgTransferConfig {
  sourcePort: string;
  sourceChannel: string;
  token: Coin;
  sender: string;
  receiver: string;
  timeoutHeight?: Height;
  timeoutTimestamp?: bigint;
  memo?: string;
}

/**
 * MSG Chain 跨链交易构建器
 * 注意: 签名部分需适配 Dilithium-5
 */
class MSGIBCTransactionBuilder {
  private client: SigningStargateClient;
  private sender: string;
  private gasPrice: GasPrice;

  constructor(client: SigningStargateClient, sender: string) {
    this.client = client;
    this.sender = sender;
    this.gasPrice = GasPrice.fromString("1000000000umsg");
  }

  /**
   * 构建 IBC 转账消息
   */
  buildIBCTransferMsg(config: IBCMsgTransferConfig): MsgTransferEncodeObject {
    return {
      typeUrl: "/ibc.applications.transfer.v1.MsgTransfer",
      value: MsgTransfer.fromPartial({
        sourcePort: config.sourcePort,
        sourceChannel: config.sourceChannel,
        token: config.token,
        sender: config.sender,
        receiver: config.receiver,
        timeoutHeight: config.timeoutHeight ?? {
          revisionNumber: 0,
          revisionHeight: 50000,
        },
        timeoutTimestamp: config.timeoutTimestamp ?? 0n,
        memo: config.memo ?? "",
      }),
    };
  }

  /**
   * 批量 IBC 转账 (批量中继)
   */
  async batchIBCTransfer(
    transfers: IBCMsgTransferConfig[]
  ): Promise<string> {
    const msgs = transfers.map((t) => this.buildIBCTransferMsg(t));
    const fee = calculateFee(300000, this.gasPrice);

    const result = await this.client.signAndBroadcast(
      this.sender,
      msgs,
      fee,
      "MSG Chain 批量跨链转账"
    );
    return result.transactionHash;
  }

  /**
   * IBC 超时高度计算器
   */
  calculateTimeoutHeight(
    currentHeight: number,
    blocksToWait: number = 10000
  ): Height {
    return {
      revisionNumber: 0,
      revisionHeight: BigInt(currentHeight + blocksToWait),
    };
  }
}

// 使用示例
async function example() {
  const builder = new MSGIBCTransactionBuilder(
    await SigningStargateClient.connect("https://rpc.msgchain.org:26657"),
    "msg1qypqxpq9kcrn2c9afea5lq35ef37c5x7jqylz3"
  );

  const txMsg = builder.buildIBCTransferMsg({
    sourcePort: "transfer",
    sourceChannel: "channel-0",
    token: { denom: "umsg", amount: "100000000000000000000" },
    sender: "msg1qypqxpq9kcrn2c9afea5lq35ef37c5x7jqylz3",
    receiver: "cosmos1recipient...",
    memo: "跨链支付: AI Agent 服务费",
  });

  console.log("IBC 转账消息已构建:", txMsg);
}

9. 安全考量

9.1 IBC 安全假设

威胁模型 描述 MSG Chain 缓解措施
恶意验证者 验证者集体作恶伪造状态 Dilithium-5 签名防伪,DAR 信誉评分
轻客户端误导 提交假区块头欺骗 LC Dilithium-5 签名验证,信任周期检查
Relayer DoS Relayer 不转发数据包 多 Relayer 并行,IBC 超时机制
重放攻击 重复提交已处理的数据包 sequence 防重放,IBC 状态跟踪
中间人攻击 拦截或篡改 IBC 数据包 数据包已签名,篡改无法通过 LC 验证
长程攻击 远距离分叉伪造历史 解绑周期保护,检查点机制

9.2 Dilithium-5 轻客户端安全优势

MSG Chain 使用 Dilithium-5 后量子签名,相比传统 Ed25519 IBC 客户端:

量子攻击威胁时间线:
┌─────────────────────────────────────────────────────────────┐
│  2025    2030    2035    2040    2045    2050               │
│  │        │        │        │        │        │             │
│  ─── Ed25519 安全区间 ────────────── Shor 攻击可行性 ──►   │
│  ─── Dilithium-5 安全区间 ────────────────────────────────► │
│                                                              │
│  MSG Chain 选择 Dilithium-5 确保持续至量子时代的安全性       │
└─────────────────────────────────────────────────────────────┘
安全特性 Ed25519 LC Dilithium-5 LC (MSG)
量子安全 ❌ ✅ (NIST 标准化)
签名伪造成本 2^128 (经典) 2^256 (经典)
信任假设 DPoS 安全 DPoS + 后量子密码学
未来兼容性 需迁移 抗量子

9.3 桥接风险分析

9.3.1 风险矩阵

风险 可能性 影响 评分 缓解措施
验证者合谋伪造 低 极高 高风险 多签阈值 2/3+,旋转验证集
Dilithium-5 实现漏洞 低 高 中风险 开源审计,形式化验证
Relayer 审查 中 中 中风险 多 Relayer 竞争,费用激励
IBC 数据包超时 低 低 低风险 自动退款机制
智能合约漏洞 中 高 高风险 多重审计,Bug Bounty
桥接代币通胀 低 极高 高风险 锁定/铸造核对,链上证明

9.3.2 安全建议

X-MSG-Stub=true
┌────────────────────────────────────────────────────────────┐
│ MSG Chain 跨链安全最佳实践                                  │
│                                                            │
│  1. 验证者集管理                                            │
│     ├── 至少 7 个桥验证者                                   │
│     ├── 2/3+ 多签阈值                                       │
│     ├── 定期轮换 (每 1000 区块)                              │
│     └── DAR 评分过滤低信誉验证者                             │
│                                                            │
│  2. 流动性管理                                              │
│     ├── 每日跨链限额                                        │
│     ├── 总锁定上限                                          │
│     ├── 自动暂停 (异常流量检测)                               │
│     └── 慢启动 (逐步增加限额)                                │
│                                                            │
│  3. 监控与告警                                              │
│     ├── 实时监控 IBC 数据包延迟                              │
│     ├── 异常转账模式检测                                     │
│     ├── 验证者签名异常                                       │
│     └── 治理紧急暂停机制                                     │
│                                                            │
│  4. 审计与形式化验证                                        │
│     ├── Dilithium-5 LC 形式化验证 (Coq)                     │
│     ├── 桥接合约第三方审计                                    │
│     ├── Bug Bounty 计划 (最高 100 万 MSG)                   │
│     └── 渐进式上线 (Testnet → 小规模 → 全量)                 │
└────────────────────────────────────────────────────────────┘

9.4 MEV 在跨链场景中

跨链 MEV (最大可提取价值) 是跨链桥特有的安全问题:

MEV 类型 描述 MSG Chain 对策
跨链三明治攻击 抢先/延迟跨链交易获取利润 有序通道 (Ordered channel)
数据包重排序 Relayer 重新排序数据包 序列号强制执行
时间戳操纵 利用跨链时间差套利 Dilithium-5 时钟偏差检查
审查后套利 延迟特定交易后套利 多 Relayer 并行

9.5 安全最佳实践清单

X-MSG-Stub=true
## 跨链部署检查清单

### 合约安全
- [ ] 桥接合约已通过专业审计(至少 2 家审计机构)
- [ ] Dilithium-5 验证实现已形式化验证
- [ ] 所有外部调用使用 reentrancy guard
- [ ] 整数溢出保护(use `Uint128` / `checked_*`)
- [ ] 暂停机制可通过治理触发
- [ ] 可升级代理使用时间锁(> 48 小时)

### Relayer 安全
- [ ] Relayer 密钥使用 HSM 或硬件钱包
- [ ] 至少有 3 个独立的 Relayer 运营商
- [ ] Relayer 节点配置了监控和告警
- [ ] Relayer 密钥定期轮换

### 运行安全
- [ ] 跨链限额已配置(每日/总量)
- [ ] 异常检测系统已部署
- [ ] 紧急暂停测试已完成
- [ ] 回滚/退款流程已测试
- [ ] Bug Bounty 未独立核验上线状态

10. 开发路线图

X-MSG-Stub=true: 以下路线图为规划中的开发路径,时间线可能根据实际情况调整。

10.1 阶段总览

X-MSG-Stub=true
Q3 2026    Q4 2026    Q1 2027    Q2 2027    Q3 2027    Q4 2027
   │          │          │          │          │          │
   │ Phase 1  │ Phase 2  │ Phase 3  │ Phase 4  │ Phase 5  │
   │          │          │          │          │          │
   │ IBC      │ Relayer  │ ICS-20   │ Custom   │ dApp     │
   │ Client   │ Setup    │ Transfer │ Bridge   │ Ecosystem│
   │          │          │          │          │          │
   ▼          ▼          ▼          ▼          ▼          ▼

10.2 Phase 1: IBC 客户端实现 (Q3 2026)

目标: 实现 Dilithium-5 IBC 轻客户端

任务 工作量 依赖
Dilithium-5 轻客户端规范 4 周 IBC v2 规范
Dilithium-5 共识状态验证 3 周 Dilithium-5 签名库
轻客户端状态管理 2 周 Cosmos SDK IBC
误行为检测 3 周 轻客户端验证逻辑
单元测试 4 周 所有前置任务
集成测试 2 周 单元测试

主要代码: x/ibc-lightclient/dilithium5/

x/ibc-lightclient/dilithium5/
├── client_state.go        # 客户端状态
├── consensus_state.go     # 共识状态
├── header.go              # 区块头验证
├── misbehaviour.go        # 误行为检测
├── update.go              # 状态更新
├── verify.go              # 验证逻辑
├── types.go               # 类型定义
└── tests/
    ├── client_test.go
    └── misbehaviour_test.go

10.3 Phase 2: Relayer 搭建与测试 (Q4 2026)

目标: 搭建测试网 Relayer,验证 IBC 连接

任务 工作量 依赖
MSG Chain 测试网部署 2 周 Phase 1
Go Relayer 扩展(Dilithium-5 支持) 4 周 Relayer 代码库
Hermes 扩展 4 周 Hermes 代码库
连接/通道握手测试 3 周 Relayer 就绪
数据包中继测试 2 周 连接建立
性能基准测试 2 周 中继测试
端到端测试网 1 周 以上全部

部署架构:

X-MSG-Stub=true
┌──────────────────────────────────────────────────┐
│              测试网环境                            │
│                                                    │
│  ┌──────────────┐     ┌──────────────────────┐    │
│  │ MSG Chain    │◄───►│ Cosmos Hub Testnet   │    │
│  │ Testnet      │     │ (Theta Testnet)       │    │
│  └──────────────┘     └──────────────────────┘    │
│         │                       │                  │
│         └───────────────────────┘                  │
│                    │                               │
│              ┌─────┴──────┐                        │
│              │  Relayer   │                        │
│              │  (rly/her) │                        │
│              └────────────┘                        │
└──────────────────────────────────────────────────┘

10.4 Phase 3: ICS-20 集成 (Q1 2027)

目标: MSG Chain 支持标准 ICS-20 代币转移

任务 工作量 依赖
ICS-20 模块适配 3 周 Phase 2
托管模块实现 2 周 Bank 模块
IBC Denom 追踪 1 周 ICS-20 模块
CLI 命令实现 2 周 模块实现
CosmWasm IBC 集成 4 周 CosmWasm + IBC
Token Manager 合约 3 周 CosmWasm
测试网跨链转账 2 周 以上全部

预期交付:

# Phase 3 完成后可执行
msgd tx ibc-transfer transfer transfer channel-0 \
  cosmos1recipient... 100umsg --from my-key

msgd query ibc-transfer denom-trace <hash>

msgd query bank balances msg1... --denom ibc/<hash>

10.5 Phase 4: 自定义桥接合约 (Q2-Q3 2027)

目标: 实现与非 IBC 链的桥接(如 Ethereum)

任务 工作量 依赖
Lock-Mint 合约开发 4 周 CosmWasm
Burn-Mint 合约开发 3 周 CosmWasm
桥验证者集合约 3 周 Phase 3
Dilithium-5 多签实现 4 周 Dilithium-5 库
Ethereum 桥合约 (Solidity) 4 周 Solidity 开发
跨链验证协调器 3 周 桥合约
安全审计 4 周 以上全部

桥接架构:

X-MSG-Stub=true
MSG Chain (CosmWasm)                Ethereum (EVM)
      │                                      │
      │  ┌───────────────────────┐           │
      │  │ MSG Bridge Contract   │           │
      │  │ - Lock/Burn           │           │
      │  │ - Validator Signatures │           │
      │  │ - Mint/Unlock         │           │
      │  └───────────────────────┘           │
      │              │                       │
      │              │ (验证者共识)            │
      │              │                       │
      │              └──────────────────►   │
      │                                      │
      │                           ┌────────┐ │
      │                           │ ETH    │ │
      │                           │ Bridge │ │
      │                           │ Contract│ │
      │                           └────────┘ │

10.6 Phase 5: 跨链 dApp 生态 (Q4 2027)

目标: 建立跨链 dApp 生态

任务 工作量 依赖
跨链 AI Agent 市场 6 周 Phase 3
跨链支付 SDK 4 周 Phase 3+4
跨链 DID 解析器 3 周 DID 合约
跨链浏览器 4 周 索引器
开发者文档 3 周 全部
Bug Bounty 上线 1 周 审计完成

10.7 依赖关系图

X-MSG-Stub=true
Phase 1 ──► Phase 2 ──► Phase 3 ──► Phase 5
                 │                      ▲
                 │                      │
                 ▼                      │
              Phase 4 ──────────────────┘

依赖关系:
- Phase 2 依赖 Phase 1 (轻客户端实现)
- Phase 3 依赖 Phase 2 (Relayer)
- Phase 4 依赖 Phase 3 (IBC 基础)
- Phase 5 依赖 Phase 3 + Phase 4

10.8 团队配置建议

角色 人数 阶段
Cosmos SDK/IBC 核心开发者 2-3 Phase 1-3
Dilithium-5 密码学工程师 1-2 Phase 1
CosmWasm 合约开发者 2-3 Phase 3-5
Rust 后端开发者 1-2 Phase 2
TypeScript/前端开发者 1-2 Phase 5
安全工程师 1 Phase 1-5
DevOps/Relayer 工程师 1 Phase 2-5

10.9 风险与缓解

风险 概率 影响 缓解
Dilithium-5 IBC 规范延迟 中 高 并行开发,先用 Tendermint LC
Relayer 兼容性问题 中 中 自研 MSG Relayer 备选
CosmWasm IBC 集成复杂度 低 高 先 ICS-20,后自定义逻辑
安全审计发现严重问题 低 高 预留 2 个月修复窗口
开发者采用率低 中 中 提供完整文档和样板合约

附录 A: 快速参考

A.1 关键命令速查

# X-MSG-Stub=true: 跨链操作速查

# IBC 客户端操作
msgd tx ibc client create [flags]
msgd query ibc client state [client-id]
msgd query ibc client list

# 连接操作
msgd tx ibc connection open-init [flags]
msgd query ibc connection end [connection-id]
msgd query ibc connections

# 通道操作
msgd tx ibc channel open-init [flags]
msgd query ibc channel end [port-id] [channel-id]
msgd query ibc channels

# 代币转移
msgd tx ibc-transfer transfer [src-port] [src-channel] [receiver] [amount]
msgd query ibc-transfer denom-trace [hash]
msgd query ibc-transfer escrow-address [port] [channel-id]

# 数据包查询
msgd query ibc channel packet-commitment [port-id] [channel-id] [sequence]
msgd query ibc channel packet-ack [port-id] [channel-id] [sequence]
msgd query ibc channel unreceived-packets [port-id] [channel-id]
msgd query ibc channel unreceived-acks [port-id] [channel-id]

# Relayer
msgd query ibc client status [client-id]
msgd query ibc connection connections

A.2 IBC Denom 计算

// X-MSG-Stub=true: IBC Denom 哈希计算
import { createHash } from "crypto";

function computeIBCDenomHash(
  portId: string,
  channelId: string,
  baseDenom: string
): string {
  const path = `${portId}/${channelId}/${baseDenom}`;
  const hash = createHash("sha256")
    .update(path)
    .digest("hex")
    .toUpperCase();
  return `ibc/${hash}`;
}

// 示例
const denomHash = computeIBCDenomHash("transfer", "channel-0", "umsg");
console.log(denomHash);
// 输出: ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2

A.3 端口分配

端口 用途 模块
transfer ICS-20 代币转账 ibc-transfer
wasm.{contract_addr} CosmWasm 合约 IBC wasm
icahost ICS-27 跨链账户 ica
icacontroller ICS-27 控制端 ica
fee IBC Fee 中间件 ibc-fee

A.4 相关资源

资源 链接
IBC 规范 https://github.com/cosmos/ibc
CosmWasm IBC 文档 https://docs.cosmwasm.com/docs/1.0/ibc/
Go Relayer https://github.com/cosmos/relayer
Hermes Relayer https://hermes.informal.systems/
MSG Chain 白皮书 https://msgchain.org/whitepaper
Dilithium-5 标准 https://pq-crystals.org/dilithium/

注意: 本文档中所有标记 X-MSG-Stub=true 的内容均为规划中的功能,尚未在主网上实现。实际可用的跨链功能请参考 MSG Chain 官方文档和主网状态。本文档基于 MSG Chain 白皮书 v0.1 和 Cosmos IBC 标准编写。