dApp Docs/AI Agent 合约模板与快速代码生成指南
Development reference. Not independently verified for production.

AI Agent 合约模板与快速代码生成指南

基于 MSG Chain 白皮书真实数据构建
文档版本: v1 · schema_version: v1
链 ID: msg-chain-1

⚠️ No-Go Disclaimer: MSGChain 主网裁决为 No-Go。本文件所有内容反映的是开发阶段的技术设计,不代表主网未独立核验上线状态。生产部署状态请以白皮书为准:https://msgchain.org/whitepaper/


目录

  1. 概述
  2. 合约模板索引
  3. 最小合约配方
  4. 合约运行时与生命周期
  5. 代码生成最佳实践
  6. 边界声明
  7. 完整示例

1. 概述

1.1 本指南的定位

本文档面向 AI Agent(大语言模型驱动的编码代理),系统说明如何利用 MSG Chain
白皮书中公开的 contract_templates/ 和 recipes/ 两大机器可消费资源,
快速生成 CosmWasm 合约代码、测试骨架和部署计划。

1.2 资源结构

MSG Chain 白皮书在 https://msgchain.org/whitepaper/ 下公开了三层机器可读资源:

资源 路径 用途
模板索引 contract_templates/index.json 发现可用模板元信息
模板包 contract_templates/counter_v1/ 实际代码文件(Cargo.toml, msg.rs, state.rs, contract.rs, tests/)
配方 recipes/contract_minimal.json 定义 AI coding 全流程的步骤、输入、产出物
模块导出 module_exports/contract.json 合约运行时模块的机器摘要
模块导出 module_exports/registry.json 创世注册中心模块的机器摘要
模块导出 module_exports/rpc.json RPC/API 接口模块的机器摘要
能力矩阵 developer_capability_matrix.json 每个开发表面的机器就绪度评分

1.3 Machine Readiness 体系

developer_capability_matrix.json 以 machine_readiness 字段标注每个表面的就绪等级。
对合约开发最相关的两个表面:

contract_template_pack — machine_readiness: starter_ready, production_supported: false

best_for:
  - 快速生成最小可运行合约
  - 补充消息 schema
  - 生成 cargo test 骨架
blocking_gaps:
  - 模板仍是 starter,不覆盖所有业务模式
  - 没有替代业务审计与测试
boundaries:
  - 模板包用于加速 AI coding,不等于官方系统合约或经过审计的业务模板。

contract_runtime — machine_readiness: assisted_codegen, production_supported: true

best_for:
  - 合约消息设计
  - 状态流转设计
  - 部署调用路径生成
  - 回执验证规划
source_modules:
  - contract.html (已实现)
  - registry.html (已实现)
  - rpc.html (已实现)

1.4 何时使用模板 vs 配方

场景 使用
需要立即写出一个可编译的合约 模板 — counter_v1 起步
需要理解完整的 AI coding 工作流 配方 — contract_minimal 的 7 步流程
需要设计消息结构和状态模型 模板 + 运行时模块导出
需要生成测试骨架 模板的 integration.rs 为起点
需要部署计划和回执验证 配方的 step 5-7
需要判断能否生产上线 能力矩阵的 blocking_gaps + boundaries

1.5 数据来源说明

本文档所有引用均来自 MSG Chain 白皮书公开文件,具体来源:


2. 合约模板索引

2.1 索引结构

contract_templates/index.json 是模板的发现入口,其 schema 为:

{
  "schema_version": "v1",
  "generated_by": "msg_whitepaper_pipeline_v1",
  "templates": [
    {
      "id": "counter_v1",
      "path": "contract_templates/counter_v1/manifest.json",
      "public_url": "https://msgchain.org/whitepaper/contract_templates/counter_v1/manifest.json",
      "description": "Minimal CosmWasm starter template for AI-assisted contract coding on MSG."
    }
  ],
  "reference_sources": [
    "contracts/cosmwasm/all/genesis_registry_v1/src/msg.rs",
    "contracts/cosmwasm/all/agent_registry_v1/src/msg.rs"
  ],
  "metadata_profile": "public_stable"
}

当前索引公开一个模板 counter_v1,类型为 starter。
reference_sources 列出两个可作为消息设计参考的真实合约源文件。

2.2 AI Agent 读取索引

import requests

TEMPLATES_INDEX = 'https://msgchain.org/whitepaper/contract_templates/index.json'

async def list_templates():
    index = await requests.get(TEMPLATES_INDEX).json()
    return index.get('templates', [])

async def resolve_template(template_id: str):
    index = await requests.get(TEMPLATES_INDEX).json()
    for t in index.get('templates', []):
        if t['id'] == template_id:
            manifest = await requests.get(t['public_url']).json()
            return manifest
    return None

2.3 模板清单结构

每个模板通过 manifest.json 描述自身:

{
  "schema_version": "v1",
  "generated_by": "msg_whitepaper_pipeline_v1",
  "template_id": "counter_v1",
  "template_kind": "starter",
  "public_url": "https://msgchain.org/whitepaper/contract_templates/counter_v1/manifest.json",
  "entry_files": [
    "contract_templates/counter_v1/Cargo.toml",
    "contract_templates/counter_v1/src/msg.rs",
    "contract_templates/counter_v1/src/state.rs",
    "contract_templates/counter_v1/src/contract.rs",
    "contract_templates/counter_v1/tests/integration.rs"
  ],
  "notices": [
    "该模板用于 AI coding 起步,不是官方系统合约。",
    "部署前必须按业务需求、权限模型、Gas 与安全审计进行重写。"
  ],
  "source_modules": ["contract.html", "registry.html", "rpc.html"],
  "metadata_profile": "public_stable"
}

entry_files 告诉 AI Agent 哪些文件需要被读取或生成本地副本。
notices 是必须传递给开发者的边界声明。
source_modules 关联的文档模块包含运行时上下文。

2.4 文件清单说明

counter_v1 模板包含 5 个文件:

文件 用途 是否必须修改
Cargo.toml 依赖声明,适配 CosmWasm 1.5 通常保留,按需加依赖
src/msg.rs InstantiateMsg / ExecuteMsg / QueryMsg 定义 核心修改点
src/state.rs 状态结构与存储键 核心修改点
src/contract.rs instantiate / execute / query 入口 核心修改点
tests/integration.rs 集成测试骨架 必须扩展

2.5 模板文件详解

Cargo.toml

[package]
name = "msg-counter-v1"
version = "0.1.0"
edition = "2021"

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

[dependencies]
cosmwasm-schema = "1.5.0"
cosmwasm-std = "1.5.0"
cw-storage-plus = "1.2.0"
serde = { version = "1.0", default-features = false, features = ["derive"] }
thiserror = "1.0"

注意:

src/msg.rs — 消息定义

use cosmwasm_schema::{cw_serde, QueryResponses};

#[cw_serde]
pub struct InstantiateMsg {
    pub owner: Option<String>,
    pub count: i32,
}

#[cw_serde]
pub enum ExecuteMsg {
    Increment {},
    Reset { count: i32 },
}

#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
    #[returns(CountResponse)]
    GetCount {},
}

#[cw_serde]
pub struct CountResponse {
    pub count: i32,
    pub owner: String,
}

这是 AI Agent 需要优先修改的文件。模板提供了一个"计数增加"的简单业务:

src/state.rs — 状态定义

use cosmwasm_schema::cw_serde;
use cw_storage_plus::Item;

#[cw_serde]
pub struct State {
    pub count: i32,
    pub owner: String,
}

pub const STATE: Item<State> = Item::new("state");

使用 cw_storage_plus::Item 作为单一存储槽。
Item::new("state") 中的字符串是存储键。

src/contract.rs — 合约入口

use cosmwasm_std::{
    entry_point, to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdError,
    StdResult,
};

use crate::msg::{CountResponse, ExecuteMsg, InstantiateMsg, QueryMsg};
use crate::state::{State, STATE};

#[entry_point]
pub fn instantiate(
    deps: DepsMut,
    _env: Env,
    info: MessageInfo,
    msg: InstantiateMsg,
) -> StdResult<Response> {
    let owner = msg.owner.unwrap_or_else(|| info.sender.to_string());
    let state = State { count: msg.count, owner: owner.clone() };
    STATE.save(deps.storage, &state)?;
    Ok(Response::new()
        .add_attribute("action", "instantiate")
        .add_attribute("owner", owner))
}

#[entry_point]
pub fn execute(
    deps: DepsMut,
    _env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> StdResult<Response> {
    match msg {
        ExecuteMsg::Increment {} => {
            STATE.update(deps.storage, |mut state| -> StdResult<_> {
                if info.sender.to_string() != state.owner {
                    return Err(StdError::generic_err("only owner can increment"));
                }
                state.count += 1;
                Ok(state)
            })?;
            Ok(Response::new().add_attribute("action", "increment"))
        }
        ExecuteMsg::Reset { count } => {
            STATE.update(deps.storage, |mut state| -> StdResult<_> {
                if info.sender.to_string() != state.owner {
                    return Err(StdError::generic_err("only owner can reset"));
                }
                state.count = count;
                Ok(state)
            })?;
            Ok(Response::new()
                .add_attribute("action", "reset")
                .add_attribute("count", count.to_string()))
        }
    }
}

#[entry_point]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
    match msg {
        QueryMsg::GetCount {} => {
            let state = STATE.load(deps.storage)?;
            to_json_binary(&CountResponse {
                count: state.count,
                owner: state.owner,
            })
        }
    }
}

三个 #[entry_point] 函数:

tests/integration.rs — 测试骨架

#[test]
fn ai_agent_should_customize_business_rules_before_deploy() {
    let goal = "replace owner-only counter logic with actual product logic";
    assert!(goal.contains("product logic"));
}

这是有意设计的"反例测试"——它不测试计数器逻辑,而是提醒 AI Agent:
这个模板的测试需要被真实的业务测试替换。

2.6 模板分类

当前的 template_kind: "starter" 表示:

starter: 提供最小可运行骨架,适合 AI coding 起步
planned: 规划中,尚未公开
production: 经过审计的开发参考级模板(当前未提供)

2.7 参考源文件

索引中的 reference_sources 指向两个真实合约的消息定义文件:

AI Agent 在设计自己的消息结构前,应该读取这些文件了解 MSG Chain 的消息设计惯例。

2.8 获取模板的 Python 函数

import requests
import os

TEMPLATE_BASE = 'https://msgchain.org/whitepaper/contract_templates/counter_v1'
FILES = ['Cargo.toml', 'src/msg.rs', 'src/state.rs', 'src/contract.rs', 'tests/integration.rs']

def fetch_counter_template(target_dir: str):
    os.makedirs(f'{target_dir}/src', exist_ok=True)
    os.makedirs(f'{target_dir}/tests', exist_ok=True)
    for f in FILES:
        url = f'{TEMPLATE_BASE}/{f}'
        content = requests.get(url).text
        with open(f'{target_dir}/{f}', 'w') as fh:
            fh.write(content)
    print(f'Template written to {target_dir}')

3. 最小合约配方

3.1 配方结构

recipes/contract_minimal.json 是整个白皮书中面向 AI Agent 最核心的资源。
它定义了一条从需求输入到部署计划输出的完整闭环。

配方顶层结构:

{
  "schema_version": "v1",
  "recipe_id": "contract_minimal",
  "title": "MSG 合约 AI Coding 最小闭环",
  "goal": "Guide an AI coding agent from requirement intake to contract code generation, testing, deployment planning, receipt verification, and guarded release review.",
  "entry_point": "developer_entry.json",
  "required_modules": [...],
  "recommended_chunks": [...],
  "required_human_inputs": [...],
  "workflow": [...],
  "success_artifacts": [...],
  "hard_boundaries": [...],
  "metadata_profile": "public_stable"
}

3.2 AI Agent 读取配方

RECIPE_URL = 'https://msgchain.org/whitepaper/recipes/contract_minimal.json'

async def load_recipe():
    recipe = await requests.get(RECIPE_URL).json()
    return recipe

3.3 必需模块

配方要求 AI Agent 先读取三个已实现的模块:

模块 文件 状态
智能合约引擎 (CosmWasm) contract.html 已实现
创世注册中心 (genesis_registry_v1) registry.html 已实现
RPC 与 API 接口 rpc.html 已实现

这些模块的机器摘要通过 module_exports/ 下的 JSON 文件提供:

3.4 推荐阅读的 Chunk

配方建议 AI Agent 读取以下 chunks 建立链路理解:

chunk_id 内容摘要
contract#1 合约执行边界、genesis registry v1 canonical key、wasm migrate/reply on/atomic rollback
contract#2 系统合约拓扑:Token → DAO → Gas → Emission → Candidate → Validator
registry#1 Canonical key 空间、active/reserved、分页查询
registry#2 分页列表与状态模型
rpc#1 共享 Mux 与多协议端点
rpc#2 认证与 API 族

3.5 必需的人类输入

配方明确列出 AI Agent 必须从开发者处获取的信息:

1. 业务目标与状态模型
2. 管理员 / 多签 / 治理控制要求
3. 部署网络与目标地址策略
4. 真实签名账户、Gas 预算与发布窗口

缺少这些输入时,AI Agent 不应尝试生成最终代码或部署计划。

3.6 7 步工作流

这是配方的核心——定义 AI Agent 从需求到部署回执的完整路径:

Step 1: 读取入口 + 能力矩阵

action: read developer_entry + capability matrix
purpose: 识别哪些面适合自动生成、哪些仍是边界面。

AI Agent 应首先理解自己的能力边界。developer_capability_matrix.json
给出了每个开发表面的 machine_readiness,告诉 AI 哪些可以写代码,
哪些只能做参考,哪些还不能碰。

Step 2: 读取模块与 Chunk

action: read contract/rpc/registry modules and chunks
purpose: 建立 Instantiate / Execute / Query / wasm_migrate / canonical key 的链路理解。

从 module_exports/ 获取模块摘要,从 module_chunks/ 获取详细证据。
目标是理解:

Step 3: 生成合约消息与状态设计

action: generate contract message and state design
purpose: 输出 Rust 合约骨架、消息定义、状态结构与权限模型。

基于模板(counter_v1)的业务逻辑替换:

Step 4: 生成测试与失败场景

action: generate cargo tests and failure cases
purpose: 覆盖 happy path、权限拒绝、回滚、reply/submessage 等关键路径。

替换模板中的反例测试,生成:

Step 5: 准备部署计划

action: prepare deploy plan
purpose: 形成 StoreCode / Instantiate / Query / Execute / Receipt 校验计划,
        而不是只写代码。

部署计划应包括:

  1. 编译合约:cargo wasm
  2. 优化 wasm:cargo run-script optimize
  3. StoreCode 交易:广播 wasm 字节码
  4. Instantiate 交易:初始化合约状态
  5. Query 验证:确认状态正确
  6. Execute 测试:执行写操作
  7. Receipt 校验:解析交易回执

Step 6: 收集交易证据

action: collect tx hash, receipt, query replay, evidence refs
purpose: 把部署结果回写到可验证证据链。

部署后的证据收集:

Step 7: 人类上线门禁

action: human release gate
purpose: 由人类确认密钥、治理条件、上线窗口与生产风险。

AI Agent 不能独立上生产。必须经过人类确认:

3.7 成功产出物

按配方执行完成后,AI Agent 应交付:

1. 合约源码目录
2. cargo test 输出
3. 部署与调用脚本
4. tx hash / receipt / query replay
5. 上线前边界说明

3.8 硬边界

配方的 hard_boundaries 是 AI Agent 必须遵守的限制:

1. 当前 starter template pack 只提供起步骨架,不等于业务合约已自动完成。
2. 没有真实钱包、私钥、部署权限与 Gas 预算,AI 不能独立完成最终上链。
3. 高价值或治理相关动作必须经过人类审批与门禁验证。

3.9 Python 配方引擎实现

import requests
import json
import os
from typing import Optional

RECIPE_URL = 'https://msgchain.org/whitepaper/recipes/contract_minimal.json'
COUNTER_MANIFEST_URL = 'https://msgchain.org/whitepaper/contract_templates/counter_v1/manifest.json'

async def scaffold_contract(name: str, template: str = 'counter_v1') -> dict:
    recipe = await requests.get(RECIPE_URL).json()
    manifest = await requests.get(COUNTER_MANIFEST_URL).json()

    template_files = {}
    for filepath in manifest['entry_files']:
        url = f'https://msgchain.org/whitepaper/{filepath}'
        template_files[filepath] = await requests.get(url).text()

    return {
        'recipe': recipe['recipe_id'],
        'workflow': recipe['workflow'],
        'required_human_inputs': recipe['required_human_inputs'],
        'hard_boundaries': recipe['hard_boundaries'],
        'template_files': template_files,
        'notices': manifest['notices'],
    }

def write_scaffold(target_dir: str, scaffold: dict):
    for filepath, content in scaffold['template_files'].items():
        relpath = filepath.replace('contract_templates/counter_v1/', '')
        fullpath = os.path.join(target_dir, relpath)
        os.makedirs(os.path.dirname(fullpath), exist_ok=True)
        with open(fullpath, 'w') as f:
            f.write(content)

    notices_path = os.path.join(target_dir, 'NOTICES.md')
    with open(notices_path, 'w') as f:
        for notice in scaffold['notices']:
            f.write(f'- {notice}\n')

    print(f'[scaffold] {len(scaffold["template_files"])} files written to {target_dir}')
    print(f'[scaffold] workflow: {len(scaffold["workflow"])} steps')
    print(f'[scaffold] required inputs: {scaffold["required_human_inputs"]}')

4. 合约运行时与生命周期

4.1 模块总览

合约运行时涉及三个已实现的模块,它们构成了 AI Agent 理解 MSG Chain
合约执行时必须掌握的知识基底。

模块 模块导出 状态
智能合约引擎 (CosmWasm) module_exports/contract.json 已实现
创世注册中心 module_exports/registry.json 已实现
RPC 与 API 接口 module_exports/rpc.json 已实现

4.2 contract.html — 智能合约引擎

模块导出 contract.json 的关键信息:

{
  "title": "智能合约引擎 (CosmWasm)",
  "status": "implemented",
  "group": "control",
  "tags": ["金库", "多签", "阈值", "治理", "时间锁", "提案", "注册中心", "规范键"],
  "outlinks": ["registry.html"],
  "code_refs": [
    "pkg/wasm/core_contracts_e2e_test.go",
    "pkg/quantum/node.go",
    "pkg/wasm/real_vm.go",
    "pkg/quantum/transaction_executor.go",
    "pkg/quantum/tendermint_rpc.go"
  ]
}

执行时主路径

合约执行流程:

Tx (StoreCode / Instantiate / Execute / Query / wasm_migrate)
  → CosmWasm VM 沙箱
    → GasMeter / Env / Context / State Access
      → atomic root / child checkpoint rollback
        → Submessage / reply on / CosmWasm reply
          → Badger 状态 / WasmInstance 映射 / Contract KV
            → 回执 / 事件 / failed receipt
              → 成功 → Quantum Node 合约集成器
              → 失败 → 合约错误 / Gas / Query 异常 → fail-closed / 失败回执

核心系统合约拓扑

当前已部署的系统级合约及其依赖关系:

msg token cw20
  → dar rating v1
  → dao governance v1
  → gas fee distribution v2
  → emission schedule v2

block time schedule v1 → emission schedule v2
gas fee distribution v2 → candidate node staking v2
candidate node staking v2 → validator qualification v2
dar rating v1 → foundation treasury v2
dao governance v1 → foundation treasury v2

genesis registry v1
  → foundation treasury v2
  → dao governance v1
  → gas fee distribution v2
  → emission schedule v2
  → block time schedule v1
  → candidate node staking v2
  → validator qualification v2

Canonical Key 空间

dao governance        → genesis registry v1
foundation treasury   → genesis registry v1
gas fee distribution  → genesis registry v1
economic constitution → genesis registry v1 (reserved)
block time schedule   → genesis registry v1
emission schedule     → genesis registry v1

运行时边界

合约寻址(contract + registry 分界)

4.3 registry.html — 创世注册中心

模块导出 registry.json 的关键信息:

{
  "title": "创世注册中心 (genesis_registry_v1)",
  "status": "implemented",
  "group": "control",
  "tags": ["金库", "多签", "阈值", "治理", "时间锁", "提案", "注册中心", "规范键"],
  "outlinks": ["dao.html", "foundation.html", "emission.html"],
  "code_refs": [
    "pkg/quantum/node.go",
    "pkg/quantum/contract_integrator_v1.go"
  ]
}

Canonical Key 查询

get contract by canonical key(gas fee distribution) =>
{
  "canonical key": "gas fee distribution",
  "status": "active",
  "contract name": "gas fee distribution v2",
  "contract address": "msg1gasv20000000000000000000000000000000000",
  "updated at height": 12345,
  "updated at time": "redacted"
}

get contract by canonical key(economic constitution) =>
{
  "canonical key": "economic constitution",
  "status": "reserved",
  "contract name": null,
  "contract address": null,
  "updated at height": 12345,
  "updated at time": "redacted"
}

关键语义:

分页查询

list contracts(limit=5) =>
{
  "contracts": [
    {"contract name": "block time schedule v1"},
    {"contract name": "msg token cw20"},
    {"contract name": "candidate node staking v2"},
    {"contract name": "emission schedule v2"},
    {"contract name": "challenge slashing v1"}
  ],
  "total contracts": 12
}

list contracts(limit=5, start after="challenge slashing v1") =>
{
  "contracts": [
    {"contract name": "dao governance v1"},
    {"contract name": "dar rating v1"},
    {"contract name": "emission schedule v2"},
    {"contract name": "foundation treasury v2"},
    {"contract name": "gas fee distribution v2"}
  ],
  "total contracts": 12
}

节点运行时解析流程

Node 启动 → delayed refresh
  → normalizeContractRoleAliases(addresses, canonicalRole, aliases...)
    → contractAddressForRole(canonical role)
      → 成功: 写入 merged contractAddresses
      → 失败: 记录日志并继续,不伪装成已解析

4.4 rpc.html — RPC 与 API 接口

模块导出 rpc.json 的关键信息:

{
  "title": "RPC 与 API 接口",
  "status": "implemented",
  "group": "runtime",
  "tags": ["铸造", "奖励", "结算", "接口", "查询", "P2P", "组网", "NAT"],
  "code_refs": [
    "pkg/quantum/tendermint_rpc.go"
  ]
}

支持端点族

端点族 方法
Tendermint RPC broadcast_tx_commit, broadcast_tx_sync, broadcast_tx_async, abci_query, tx, block, blockchain, net_info
Explorer /api/v1/blocks/latest, /api/v1/blocks, /api/v1/txs, /api/v1/receipts, /api/v1/address
Contracts /api/v1/contracts/deploy, /api/v1/contracts/instantiate, /api/v1/contracts/execute
Server-side signing /api/v1/tx/transfer, /api/v1/tx/delegate, /api/v1/tx/undelegate, /api/v1/tx/send
Cosmos REST /api/v1/bank/balances, /api/v1/staking/validators, /api/v1/auth/accounts
Tunnel status /api/v1/status → libp2p peer id / libp2p addrs

部署推荐

4.5 合约代码生成与运行时对接

AI Agent 生成的合约代码需要与运行时正确对接:

StoreCode

import requests
import json

RPC_ENDPOINT = 'https://rpc.msgchain.org'

def build_store_code_tx(wasm_bytecode: bytes, sender: str) -> dict:
    return {
        'jsonrpc': '2.0',
        'method': 'broadcast_tx_commit',
        'params': {
            'tx': {
                'type': 'wasm/StoreCode',
                'value': {
                    'sender': sender,
                    'wasm_byte_code': wasm_bytecode.hex(),
                }
            }
        },
        'id': 1
    }

Instantiate

def build_instantiate_tx(code_id: int, msg: dict, sender: str, label: str, admin: str) -> dict:
    return {
        'jsonrpc': '2.0',
        'method': 'broadcast_tx_commit',
        'params': {
            'tx': {
                'type': 'wasm/Instantiate',
                'value': {
                    'sender': sender,
                    'code_id': str(code_id),
                    'msg': msg,
                    'label': label,
                    'admin': admin,
                    'funds': []
                }
            }
        },
        'id': 1
    }

Execute

def build_execute_tx(contract_addr: str, msg: dict, sender: str) -> dict:
    return {
        'jsonrpc': '2.0',
        'method': 'broadcast_tx_commit',
        'params': {
            'tx': {
                'type': 'wasm/Execute',
                'value': {
                    'sender': sender,
                    'contract': contract_addr,
                    'msg': msg,
                    'funds': []
                }
            }
        },
        'id': 1
    }

Query

def build_query_request(contract_addr: str, msg: dict) -> dict:
    return {
        'jsonrpc': '2.0',
        'method': 'abci_query',
        'params': {
            'path': f'/wasm/contract/{contract_addr}',
            'data': msg,
            'height': '0',
            'prove': False
        },
        'id': 1
    }

4.6 AI Agent 理解运行时语义

AI Agent 在生成合约代码时,必须理解以下运行时语义:

StoreCode 阶段:

Instantiate 阶段:

Execute 阶段:

Query 阶段:

Migrate 阶段:

4.7 生命周期边界

production_supported: true (contract_runtime)

合约运行时本身是生产就绪的,但 AI 生成的合约代码(基于 starter 模板)
需要经过业务逻辑审查和测试才能上线。


5. 代码生成最佳实践

5.1 理解 machine_readiness 等级

AI Agent 在生成代码前,必须确认自己正在操作的 surface 的 readiness 等级:

starter_ready       → 可以起步,但不能直接用于生产
assisted_codegen    → AI 辅助生成,但需要人类确认
source_backed_reference → 只能做参考,不能直接生成
guarded_integration → 集成有风险,需要谨慎
guarded_write       → 写路径受保护,AI 不能独立执行
read_only_assist    → 只读辅助
fail_closed_reference → 默认不可用
local_candidate     → 仅本地候选

5.2 模板使用三原则

原则一:模板是起点,不是终点

counter_v1  starter 模板提供的是骨架:
- 一个简单的计数逻辑
- owner 权限检查
- 一个测试文件(内容为提醒而非真实测试)

必须替换为实际业务逻辑。

原则二:不要保留模板的"反例测试"

原测试文件内容:
#[test]
fn ai_agent_should_customize_business_rules_before_deploy() {
    let goal = "replace owner-only counter logic with actual product logic";
    assert!(goal.contains("product logic"));
}

这个测试不是真正的测试——它是 AI Agent 的指令。
AI Agent 必须将其替换为真实的业务测试。

原则三:必须传递 notices

模板 manifest.json 包含:

"notices": [
    "该模板用于 AI coding 起步,不是官方系统合约。",
    "部署前必须按业务需求、权限模型、Gas 与安全审计进行重写。"
]

AI Agent 在交付生成的合约时,必须同时传递这些 notice。

5.3 消息设计模式

从 msg.rs 模板出发,修改为业务消息:

// 模板中的消息
pub struct InstantiateMsg {
    pub owner: Option<String>,
    pub count: i32,
}

// 改为业务消息示例——代币质押合约
pub struct InstantiateMsg {
    pub admin: Option<String>,
    pub unbonding_period_seconds: u64,
    pub min_stake: Uint128,
}

设计原则:

5.4 状态设计模式

// 模板中的状态
pub struct State {
    pub count: i32,
    pub owner: String,
}

// 改为业务状态——使用多个 Item + Map
use cw_storage_plus::{Item, Map};

pub struct Config {
    pub admin: String,
    pub unbonding_period_seconds: u64,
    pub min_stake: Uint128,
}

pub struct StakeInfo {
    pub amount: Uint128,
    pub start_height: u64,
}

pub const CONFIG: Item<Config> = Item::new("config");
pub const TOTAL_STAKED: Item<Uint128> = Item::new("total_staked");
pub const STAKES: Map<&Addr, StakeInfo> = Map::new("stakes");

5.5 权限模型设计

模板中的权限模式(owner check):

if info.sender.to_string() != state.owner {
    return Err(StdError::generic_err("only owner can increment"));
}

对于更复杂的业务,可能需要:

// 使用枚举定义角色
pub enum Role { Admin, Operator, User }

// 使用 Map 存储角色分配
pub const ROLES: Map<&Addr, Role> = Map::new("roles");

fn require_role(deps: &Deps, sender: &Addr, role: Role) -> Result<(), ContractError> {
    let actual = ROLES.load(deps.storage, sender)
        .map_err(|_| ContractError::Unauthorized {})?;
    if actual != role {
        return Err(ContractError::Unauthorized {});
    }
    Ok(())
}

5.6 测试生成策略

AI Agent 需要为每个合约生成以下测试:

#[cfg(test)]
mod tests {
    use super::*;
    use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
    use cosmwasm_std::{from_json, Addr};

    // 1. Happy path: Instantiate + Query
    #[test]
    fn proper_instantiation() {
        let mut deps = mock_dependencies();
        let env = mock_env();
        let info = mock_info("creator", &[]);
        let msg = InstantiateMsg {
            admin: Some("creator".to_string()),
            count: 100,
        };
        let res = instantiate(deps.as_mut(), env, info, msg).unwrap();
        assert_eq!(res.attributes.len(), 2);

        let query_res = query(deps.as_ref(), mock_env(), QueryMsg::GetCount {}).unwrap();
        let value: CountResponse = from_json(&query_res).unwrap();
        assert_eq!(value.count, 100);
    }

    // 2. Permission check: non-owner execute
    #[test]
    fn non_owner_cannot_increment() {
        let mut deps = mock_dependencies();
        let env = mock_env();
        let info = mock_info("creator", &[]);
        let msg = InstantiateMsg {
            admin: Some("creator".to_string()),
            count: 0,
        };
        instantiate(deps.as_mut(), env.clone(), info, msg).unwrap();

        let attacker = mock_info("attacker", &[]);
        let err = execute(deps.as_mut(), env, attacker, ExecuteMsg::Increment {}).unwrap_err();
        assert_eq!(err.to_string(), "only owner can increment");
    }

    // 3. Edge case: reset count
    #[test]
    fn owner_can_reset() {
        let mut deps = mock_dependencies();
        let env = mock_env();
        let info = mock_info("owner", &[]);
        let msg = InstantiateMsg {
            admin: Some("owner".to_string()),
            count: 42,
        };
        instantiate(deps.as_mut(), env.clone(), info.clone(), msg).unwrap();

        execute(deps.as_mut(), env.clone(), info, ExecuteMsg::Reset { count: 0 }).unwrap();

        let query_res = query(deps.as_ref(), env, QueryMsg::GetCount {}).unwrap();
        let value: CountResponse = from_json(&query_res).unwrap();
        assert_eq!(value.count, 0);
    }
}

5.7 错误处理模式

使用 thiserror 定义合约错误:

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

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

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

    #[error("Invalid input: {reason}")]
    InvalidInput { reason: String },

    #[error("Contract is paused")]
    ContractPaused {},
}

在 execute 函数中使用:

pub fn execute(deps: DepsMut, _env: Env, info: MessageInfo, msg: ExecuteMsg) -> Result<Response, ContractError> {
    match msg {
        ExecuteMsg::Increment {} => execute_increment(deps, info),
        ExecuteMsg::Reset { count } => execute_reset(deps, info, count),
    }
}

fn execute_increment(deps: DepsMut, info: MessageInfo) -> Result<Response, ContractError> {
    STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {
        if info.sender != state.owner {
            return Err(ContractError::Unauthorized {});
        }
        state.count += 1;
        Ok(state)
    })?;
    Ok(Response::new().add_attribute("action", "increment"))
}

5.8 使用 reference_sources 作为设计参考

模板索引中的 reference_sources 链接到真实合约的消息定义文件:

REF_SOURCES = [
    'https://msgchain.org/whitepaper/contracts/cosmwasm/all/genesis_registry_v1/src/msg.rs',
    'https://msgchain.org/whitepaper/contracts/cosmwasm/all/agent_registry_v1/src/msg.rs',
]

async def fetch_reference_messages():
    for url in REF_SOURCES:
        content = await requests.get(url).text()
        # 分析消息设计模式,用于指导自己的契约设计

5.9 生成架构检查清单

AI Agent 在交付前应检查:

[ ] 模板的 notices 已传递给开发者
[ ] 反例测试已被替换
[ ] 消息结构符合业务需求
[ ] 状态模型正确
[ ] 权限检查覆盖所有写操作
[ ] Happy path 测试通过
[ ] 权限拒绝测试通过
[ ] 边界/错误输入测试通过
[ ] 代码编译通过: cargo wasm
[ ] 单元测试通过: cargo test
[ ] 配方要求的 7 步流程已完成
[ ] hard_boundaries 已告知开发者

5.10 AI Agent 与配方交互模式

开发者输入业务需求
      ↓
AI Agent → Step 1: 读取能力矩阵(确认自己能做什么)
      ↓
AI Agent → Step 2: 读取 contract/registry/rpc 模块(建立链路理解)
      ↓
AI Agent → Step 3: 获取 counter_v1 模板 + 修改为业务合约
      ↓
AI Agent → Step 4: 生成 cargo test + 运行确认
      ↓
AI Agent → Step 5: 输出部署计划(StoreCode → Instantiate → Query → Execute)
      ↓
AI Agent → Step 6: 建议证据收集流程
      ↓
AI Agent → Step 7: 标记人类上线门禁点
      ↓
开发者确认并执行上线

6. 边界声明

6.1 starter_ready ≠ production

contract_template_pack.machine_readiness = "starter_ready"
contract_template_pack.production_supported = false

starter_ready 表示模板可以用于快速起步和原型验证,但不等于
可以直接用于生产环境。

starter_ready 的含义 production_supported false 的含义
可快速生成最小可运行合约 没有经过开发参考级审计
可用作文档示例和教学 不覆盖所有业务模式
适合集成到 AI Agent 工作流 没有替代业务审计与测试
可作为测试骨架起点 部署前必须按业务需求重写

6.2 模板包的阻塞性缺口

来自 developer_capability_matrix.json 的 blocking_gaps:

1. 模板仍是 starter,不覆盖所有业务模式
2. 没有替代业务审计与测试

这意味着:

6.3 模板包的边界

来自 developer_capability_matrix.json 的 boundaries:

模板包用于加速 AI coding,不等于官方系统合约或经过审计的业务模板。

6.4 运行时的边界

来自 contract_runtime 的 blocking_gaps:

1. 当前模板是 starter pack,不等于官方业务合约全集
2. 缺少从链实现自动导出的正式 schema 契约
3. 生产部署仍需真实权限与验收

来自 contract_runtime 的 boundaries:

运行时主线已实现,且已补 starter template,但不等于所有业务模板都已完善。
AI 可辅助生成合约代码,但仍需结合业务规则、人类审核与真实部署账户完成落地。

6.5 配方硬边界

来自 contract_minimal.json 的 hard_boundaries:

1. 当前 starter template pack 只提供起步骨架,不等于业务合约已自动完成。
2. 没有真实钱包、私钥、部署权限与 Gas 预算,AI 不能独立完成最终上链。
3. 高价值或治理相关动作必须经过人类审批与门禁验证。

6.6 认证与部署门禁

AI Agent 生成合约代码后的上线路径必须包含:

┌─────────────────────────────────────────────────────┐
│                  AI Agent 输出                       │
│  合约源码 · cargo test · 部署计划 · 边界说明        │
└──────────────────┬──────────────────────────────────┘
                   ↓
┌─────────────────────────────────────────────────────┐
│             开发者/运维工程师 检查                   │
│  - 代码审查                                         │
│  - 业务逻辑验证                                     │
│  - 权限模型确认                                     │
│  - Gas 估算                                         │
└──────────────────┬──────────────────────────────────┘
                   ↓
┌─────────────────────────────────────────────────────┐
│             签名与部署                               │
│  - 使用私钥签名交易                                 │
│  - Gas 预算配置                                     │
│  - StoreCode 广播                                   │
│  - Instantiate 广播                                │
└──────────────────┬──────────────────────────────────┘
                   ↓
┌─────────────────────────────────────────────────────┐
│             回执验证                                 │
│  - tx hash 确认                                     │
│  - query replay                                     │
│  - receipt 存储                                     │
└─────────────────────────────────────────────────────┘

6.7 不能做的事

AI Agent 在使用模板和配方时,不能:

不能做的事 原因
说模板是开发参考级 production_supported = false
说 AI 可以独立上链 没有钱包/私钥/Gas
省略 hard_boundaries 通知 配方明确要求传递
保留反例测试 测试必须替换
使用未授权的 CosmosMsg BankMsg/Gov/Staking/IBC 仍 fail-closed
绕过人类审批 治理相关动作必须审批

6.8 能力矩阵总览

以下列出 MSG Chain 所有开发表面的 machine_readiness(部分与合约开发间接相关):

surface_id machine_readiness production_supported AI Agent 建议
contract_template_pack starter_ready false 可用作代码生成起点
contract_runtime assisted_codegen true 可辅助设计但需人类确认
core_contract_reference_pack source_backed_reference false 只读参考
registry_resolution production_reference true 可在代码中引用
rpc_gateway assisted_codegen true 可生成查询/广播代码
formal_api_schema_pack source_backed_reference false 参考用,不可写
wallet_frontend guarded_integration false 谨慎集成
explorer_receipts read_only_assist false 只读辅助
agent_query_and_guarded_write guarded_write false 受保护,AI 不能写
sdk_surface local_candidate false 本地候选
chain_config_pack starter_ready true 可生成链配置
public_sandbox_strategy fail_closed_reference false 默认不可用
dapp_starter_pack starter_ready false 可作 dApp 起步

6.9 边界自查清单

AI Agent 在交付每个合约生成任务时,应逐项核对:

[ ] 我是否告知开发者:模板是 starter,不是开发参考级?
[ ] 我是否告知开发者:AI 不能独立完成最终上链?
[ ] 我是否告知开发者:高价值动作需人工审批?
[ ] 我是否已获取:业务目标与状态模型?
[ ] 我是否已获取:管理员/多签/治理控制要求?
[ ] 我是否已获取:部署网络与目标地址策略?
[ ] 我是否已获取:真实签名账户、Gas 预算与发布窗口?
[ ] 我是否有完整的 cargo test 覆盖?
[ ] 部署计划是否包含 StoreCode / Instantiate / Query / Execute / Receipt?
[ ] 是否已标记人类上线门禁点?

7. 完整示例

7.1 场景:构建一个简单的任务管理合约

本节演示从模板出发,经过配方工作流,最终形成完整合约代码的过程。

7.2 Step 1: 读取能力矩阵

import requests

MATRIX_URL = 'https://msgchain.org/whitepaper/developer_capability_matrix.json'
matrix = requests.get(MATRIX_URL).json()

for item in matrix['items']:
    sid = item['surface_id']
    ready = item['machine_readiness']
    prod = item['production_supported']
    print(f'{sid}: {ready} (prod={prod})')

AI Agent 读取后确认:

7.3 Step 2: 读取模块

CONTRACT_EXPORT = 'https://msgchain.org/whitepaper/module_exports/contract.json'
REGISTRY_EXPORT = 'https://msgchain.org/whitepaper/module_exports/registry.json'
RPC_EXPORT = 'https://msgchain.org/whitepaper/module_exports/rpc.json'

contract_mod = requests.get(CONTRACT_EXPORT).json()
registry_mod = requests.get(REGISTRY_EXPORT).json()
rpc_mod = requests.get(RPC_EXPORT).json()

print(f'Contract status: {contract_mod["status_label"]}')
print(f'Registry status: {registry_mod["status_label"]}')
print(f'RPC status: {rpc_mod["status_label"]}')

AI Agent 确认三个模块都已实现。

7.4 Step 3: 从模板生成合约

从 counter_v1 模板获取文件,然后修改为任务管理合约。

Cargo.toml(保持模板基本不变)

[package]
name = "msg-task-manager-v1"
version = "0.1.0"
edition = "2021"

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

[dependencies]
cosmwasm-schema = "1.5.0"
cosmwasm-std = "1.5.0"
cw-storage-plus = "1.2.0"
serde = { version = "1.0", default-features = false, features = ["derive"] }
thiserror = "1.0"

src/msg.rs — 业务消息定义

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

#[cw_serde]
pub struct InstantiateMsg {
    pub owner: Option<String>,
    pub task_limit: u32,
}

#[cw_serde]
pub enum ExecuteMsg {
    CreateTask {
        title: String,
        description: String,
        reward: Uint128,
    },
    CompleteTask {
        task_id: u64,
    },
    CancelTask {
        task_id: u64,
    },
    UpdateConfig {
        task_limit: u32,
    },
}

#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
    #[returns(TaskResponse)]
    GetTask { task_id: u64 },
    #[returns(TasksResponse)]
    ListTasks {},
    #[returns(ConfigResponse)]
    GetConfig {},
}

#[cw_serde]
pub struct TaskResponse {
    pub task_id: u64,
    pub creator: String,
    pub title: String,
    pub description: String,
    pub reward: Uint128,
    pub completed: bool,
    pub cancelled: bool,
}

#[cw_serde]
pub struct TasksResponse {
    pub tasks: Vec<TaskResponse>,
}

#[cw_serde]
pub struct ConfigResponse {
    pub owner: String,
    pub task_limit: u32,
    pub task_count: u64,
}

src/state.rs — 状态定义

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

#[cw_serde]
pub struct Config {
    pub owner: String,
    pub task_limit: u32,
    pub task_count: u64,
}

#[cw_serde]
pub struct Task {
    pub task_id: u64,
    pub creator: String,
    pub title: String,
    pub description: String,
    pub reward: Uint128,
    pub completed: bool,
    pub cancelled: bool,
}

pub const CONFIG: Item<Config> = Item::new("config");
pub const TASKS: Map<u64, Task> = Map::new("tasks");

src/contract.rs — 合约入口

use cosmwasm_std::{
    entry_point, to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response,
    StdError,
};
use thiserror::Error;

use crate::msg::{
    ConfigResponse, ExecuteMsg, InstantiateMsg, QueryMsg, TaskResponse, TasksResponse,
};
use crate::state::{Config, Task, CONFIG, TASKS};

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

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

    #[error("Task limit reached: {limit}")]
    TaskLimitReached { limit: u32 },

    #[error("Task not found: {task_id}")]
    TaskNotFound { task_id: u64 },

    #[error("Task already completed")]
    AlreadyCompleted {},

    #[error("Task already cancelled")]
    AlreadyCancelled {},
}

#[entry_point]
pub fn instantiate(
    deps: DepsMut,
    _env: Env,
    info: MessageInfo,
    msg: InstantiateMsg,
) -> Result<Response, ContractError> {
    let owner = msg.owner.unwrap_or_else(|| info.sender.to_string());
    let config = Config {
        owner,
        task_limit: msg.task_limit,
        task_count: 0,
    };
    CONFIG.save(deps.storage, &config)?;
    Ok(Response::new()
        .add_attribute("action", "instantiate")
        .add_attribute("owner", &config.owner))
}

#[entry_point]
pub fn execute(
    deps: DepsMut,
    _env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response, ContractError> {
    match msg {
        ExecuteMsg::CreateTask { title, description, reward } => {
            execute_create_task(deps, info, title, description, reward)
        }
        ExecuteMsg::CompleteTask { task_id } => execute_complete_task(deps, info, task_id),
        ExecuteMsg::CancelTask { task_id } => execute_cancel_task(deps, info, task_id),
        ExecuteMsg::UpdateConfig { task_limit } => execute_update_config(deps, info, task_limit),
    }
}

fn execute_create_task(
    deps: DepsMut,
    info: MessageInfo,
    title: String,
    description: String,
    reward: Uint128,
) -> Result<Response, ContractError> {
    let mut config = CONFIG.load(deps.storage)?;

    if config.task_count >= config.task_limit {
        return Err(ContractError::TaskLimitReached {
            limit: config.task_limit,
        });
    }

    let task_id = config.task_count + 1;
    let task = Task {
        task_id,
        creator: info.sender.to_string(),
        title,
        description,
        reward,
        completed: false,
        cancelled: false,
    };

    TASKS.save(deps.storage, task_id, &task)?;
    config.task_count = task_id;
    CONFIG.save(deps.storage, &config)?;

    Ok(Response::new()
        .add_attribute("action", "create_task")
        .add_attribute("task_id", task_id.to_string())
        .add_attribute("creator", &task.creator))
}

fn execute_complete_task(
    deps: DepsMut,
    info: MessageInfo,
    task_id: u64,
) -> Result<Response, ContractError> {
    let config = CONFIG.load(deps.storage)?;

    if info.sender.to_string() != config.owner {
        return Err(ContractError::Unauthorized {});
    }

    let mut task = TASKS.load(deps.storage, task_id)
        .map_err(|_| ContractError::TaskNotFound { task_id })?;

    if task.completed {
        return Err(ContractError::AlreadyCompleted {});
    }

    if task.cancelled {
        return Err(ContractError::AlreadyCancelled {});
    }

    task.completed = true;
    TASKS.save(deps.storage, task_id, &task)?;

    Ok(Response::new()
        .add_attribute("action", "complete_task")
        .add_attribute("task_id", task_id.to_string()))
}

fn execute_cancel_task(
    deps: DepsMut,
    info: MessageInfo,
    task_id: u64,
) -> Result<Response, ContractError> {
    let mut task = TASKS.load(deps.storage, task_id)
        .map_err(|_| ContractError::TaskNotFound { task_id })?;

    if info.sender.to_string() != task.creator {
        return Err(ContractError::Unauthorized {});
    }

    if task.completed {
        return Err(ContractError::AlreadyCompleted {});
    }

    if task.cancelled {
        return Err(ContractError::AlreadyCancelled {});
    }

    task.cancelled = true;
    TASKS.save(deps.storage, task_id, &task)?;

    Ok(Response::new()
        .add_attribute("action", "cancel_task")
        .add_attribute("task_id", task_id.to_string()))
}

fn execute_update_config(
    deps: DepsMut,
    info: MessageInfo,
    task_limit: u32,
) -> Result<Response, ContractError> {
    let mut config = CONFIG.load(deps.storage)?;

    if info.sender.to_string() != config.owner {
        return Err(ContractError::Unauthorized {});
    }

    config.task_limit = task_limit;
    CONFIG.save(deps.storage, &config)?;

    Ok(Response::new()
        .add_attribute("action", "update_config")
        .add_attribute("task_limit", task_limit.to_string()))
}

#[entry_point]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<Binary, ContractError> {
    match msg {
        QueryMsg::GetTask { task_id } => query_task(deps, task_id),
        QueryMsg::ListTasks {} => query_list_tasks(deps),
        QueryMsg::GetConfig {} => query_config(deps),
    }
}

fn query_task(deps: Deps, task_id: u64) -> Result<Binary, ContractError> {
    let task = TASKS.load(deps.storage, task_id)
        .map_err(|_| ContractError::TaskNotFound { task_id })?;
    Ok(to_json_binary(&TaskResponse {
        task_id: task.task_id,
        creator: task.creator,
        title: task.title,
        description: task.description,
        reward: task.reward,
        completed: task.completed,
        cancelled: task.cancelled,
    })?)
}

fn query_list_tasks(deps: Deps) -> Result<Binary, ContractError> {
    let tasks: Vec<TaskResponse> = TASKS
        .range(deps.storage, None, None, cosmwasm_std::Order::Ascending)
        .map(|item| {
            let (_, task) = item.unwrap();
            TaskResponse {
                task_id: task.task_id,
                creator: task.creator,
                title: task.title,
                description: task.description,
                reward: task.reward,
                completed: task.completed,
                cancelled: task.cancelled,
            }
        })
        .collect();
    Ok(to_json_binary(&TasksResponse { tasks })?)
}

fn query_config(deps: Deps) -> Result<Binary, ContractError> {
    let config = CONFIG.load(deps.storage)?;
    Ok(to_json_binary(&ConfigResponse {
        owner: config.owner,
        task_limit: config.task_limit,
        task_count: config.task_count,
    })?)
}

7.5 Step 4: 生成测试

#[cfg(test)]
mod tests {
    use super::*;
    use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
    use cosmwasm_std::{from_json, Uint128};

    fn setup_contract() -> (cosmwasm_std::OwnedDeps<cosmwasm_std::MemoryStorage, cosmwasm_std::testing::MockApi, cosmwasm_std::testing::MockQuerier>, cosmwasm_std::Env) {
        let mut deps = mock_dependencies();
        let env = mock_env();
        let info = mock_info("admin", &[]);
        let msg = InstantiateMsg {
            owner: Some("admin".to_string()),
            task_limit: 10,
        };
        instantiate(deps.as_mut(), env.clone(), info, msg).unwrap();
        (deps, env)
    }

    #[test]
    fn proper_instantiation() {
        let (deps, _) = setup_contract();
        let config: ConfigResponse = from_json(
            &query(deps.as_ref(), mock_env(), QueryMsg::GetConfig {}).unwrap()
        ).unwrap();
        assert_eq!(config.owner, "admin");
        assert_eq!(config.task_limit, 10);
        assert_eq!(config.task_count, 0);
    }

    #[test]
    fn create_and_query_task() {
        let (mut deps, env) = setup_contract();
        let creator = mock_info("creator", &[]);

        execute(
            deps.as_mut(),
            env.clone(),
            creator,
            ExecuteMsg::CreateTask {
                title: "Build AI Agent".to_string(),
                description: "Design agent for contract codegen".to_string(),
                reward: Uint128::new(1000),
            },
        ).unwrap();

        let task: TaskResponse = from_json(
            &query(deps.as_ref(), env.clone(), QueryMsg::GetTask { task_id: 1 }).unwrap()
        ).unwrap();
        assert_eq!(task.title, "Build AI Agent");
        assert_eq!(task.creator, "creator");
        assert_eq!(task.reward, Uint128::new(1000));
        assert!(!task.completed);
        assert!(!task.cancelled);
    }

    #[test]
    fn non_admin_cannot_complete_task() {
        let (mut deps, env) = setup_contract();
        let creator = mock_info("creator", &[]);
        execute(
            deps.as_mut(),
            env.clone(),
            creator.clone(),
            ExecuteMsg::CreateTask {
                title: "Task 1".to_string(),
                description: "Test task".to_string(),
                reward: Uint128::new(500),
            },
        ).unwrap();

        let attacker = mock_info("attacker", &[]);
        let err = execute(
            deps.as_mut(),
            env.clone(),
            attacker,
            ExecuteMsg::CompleteTask { task_id: 1 },
        ).unwrap_err();
        assert!(matches!(err, ContractError::Unauthorized {}));
    }

    #[test]
    fn creator_can_cancel_own_task() {
        let (mut deps, env) = setup_contract();
        let creator = mock_info("creator", &[]);
        execute(
            deps.as_mut(),
            env.clone(),
            creator.clone(),
            ExecuteMsg::CreateTask {
                title: "Cancellable".to_string(),
                description: "Will be cancelled".to_string(),
                reward: Uint128::new(100),
            },
        ).unwrap();

        execute(
            deps.as_mut(),
            env.clone(),
            creator,
            ExecuteMsg::CancelTask { task_id: 1 },
        ).unwrap();

        let task: TaskResponse = from_json(
            &query(deps.as_ref(), env, QueryMsg::GetTask { task_id: 1 }).unwrap()
        ).unwrap();
        assert!(task.cancelled);
    }

    #[test]
    fn task_limit_enforced() {
        let (mut deps, env) = setup_contract();
        let creator = mock_info("creator", &[]);

        for i in 0..10 {
            execute(
                deps.as_mut(),
                env.clone(),
                creator.clone(),
                ExecuteMsg::CreateTask {
                    title: format!("Task {}", i),
                    description: "test".to_string(),
                    reward: Uint128::new(1),
                },
            ).unwrap();
        }

        let err = execute(
            deps.as_mut(),
            env.clone(),
            creator,
            ExecuteMsg::CreateTask {
                title: "Overflow".to_string(),
                description: "Should fail".to_string(),
                reward: Uint128::new(1),
            },
        ).unwrap_err();
        assert!(matches!(err, ContractError::TaskLimitReached { .. }));
    }

    #[test]
    fn list_tasks() {
        let (mut deps, env) = setup_contract();
        let creator = mock_info("creator", &[]);

        execute(
            deps.as_mut(),
            env.clone(),
            creator.clone(),
            ExecuteMsg::CreateTask {
                title: "Task A".to_string(),
                description: "First".to_string(),
                reward: Uint128::new(100),
            },
        ).unwrap();

        execute(
            deps.as_mut(),
            env.clone(),
            creator,
            ExecuteMsg::CreateTask {
                title: "Task B".to_string(),
                description: "Second".to_string(),
                reward: Uint128::new(200),
            },
        ).unwrap();

        let list: TasksResponse = from_json(
            &query(deps.as_ref(), env, QueryMsg::ListTasks {}).unwrap()
        ).unwrap();
        assert_eq!(list.tasks.len(), 2);
        assert_eq!(list.tasks[0].title, "Task A");
        assert_eq!(list.tasks[1].title, "Task B");
    }
}

7.6 Step 5: 部署计划

"""
部署计划: msg-task-manager-v1

链 ID: msg-chain-1
网络: msg-chain-1

=== 步骤 1: 编译 ===
cargo wasm
# 输出: target/wasm32-unknown-unknown/release/msg_task_manager_v1.wasm

=== 步骤 2: 优化 ===
cargo run-script optimize
# 输出: artifacts/msg_task_manager_v1.wasm

=== 步骤 3: StoreCode ===
# 使用 CosmJS 或直接 RPC 广播
wasm_bytecode = open('artifacts/msg_task_manager_v1.wasm', 'rb').read()
tx = {
    'jsonrpc': '2.0',
    'method': 'broadcast_tx_commit',
    'params': {
        'tx': {
            'type': 'wasm/StoreCode',
            'value': {
                'sender': '<DEPLOYER_ADDRESS>',
                'wasm_byte_code': wasm_bytecode.hex(),
            }
        }
    },
    'id': 1
}
# 响应中的 code_id 用于下一步

=== 步骤 4: Instantiate ===
code_id = 1  # 从上一步获取
instantiate_msg = {
    'owner': None,  # 默认为部署者
    'task_limit': 100,
}
tx = {
    'jsonrpc': '2.0',
    'method': 'broadcast_tx_commit',
    'params': {
        'tx': {
            'type': 'wasm/Instantiate',
            'value': {
                'sender': '<DEPLOYER_ADDRESS>',
                'code_id': str(code_id),
                'msg': instantiate_msg,
                'label': 'msg-task-manager-v1',
                'admin': '<DEPLOYER_ADDRESS>',
                'funds': []
            }
        }
    },
    'id': 1
}
# 响应中的 contract_address 用于后续调用

=== 步骤 5: Query 验证 ===
contract_addr = '<CONTRACT_ADDRESS>'
query = {
    'jsonrpc': '2.0',
    'method': 'abci_query',
    'params': {
        'path': f'/wasm/contract/{contract_addr}',
        'data': {'get_config': {}},
        'height': '0',
        'prove': False
    },
    'id': 1
}

=== 步骤 6: Execute 测试 ===
execute_msg = {
    'create_task': {
        'title': 'Test Task',
        'description': 'Verify deployment',
        'reward': '1000'
    }
}
tx = {
    'jsonrpc': '2.0',
    'method': 'broadcast_tx_commit',
    'params': {
        'tx': {
            'type': 'wasm/Execute',
            'value': {
                'sender': '<USER_ADDRESS>',
                'contract': contract_addr,
                'msg': execute_msg,
                'funds': []
            }
        }
    },
    'id': 1
}

=== 步骤 7: Receipt 校验 ===
tx_hash = '<TX_HASH>'
receipt_query = {
    'jsonrpc': '2.0',
    'method': 'tx',
    'params': [tx_hash, True],
    'id': 1
}
"""

7.7 Step 6: 证据收集建议

"""
证据收集清单:

1. tx_hash:
   - StoreCode: <从 broadcast_tx_commit 响应获取>
   - Instantiate: <从 broadcast_tx_commit 响应获取>
   - Execute: <从 broadcast_tx_commit 响应获取>

2. receipt:
   - 每个交易对应的 receipt JSON

3. query replay:
   - abci_query 返回的合约状态 JSON

4. evidence refs:
   - contract.html: https://msgchain.org/whitepaper/module_exports/contract.json
   - registry.html: https://msgchain.org/whitepaper/module_exports/registry.json
   - rpc.html: https://msgchain.org/whitepaper/module_exports/rpc.json
   - recipe: https://msgchain.org/whitepaper/recipes/contract_minimal.json
   - template: https://msgchain.org/whitepaper/contract_templates/counter_v1/manifest.json
"""

7.8 Step 7: 人类上线门禁通知

HUMAN_GATE_NOTICE = """
=== 人类上线门禁检查清单 ===

请确认以下事项后再执行部署:

[ ] 1. 密钥安全:
    - 部署账户的私钥已安全存储
    - 测试环境与生产环境使用不同的密钥
    - 多签账户的阈值已确认

[ ] 2. 治理条件:
    - 如果是治理相关合约,提案已通过
    - 如果是系统合约,已获得相应授权

[ ] 3. 上线窗口:
    - 当前网络无异常
    - Gas 价格稳定
    - 无正在进行的紧急维护

[ ] 4. 生产风险:
    - 合约代码已通过同行审查
    - 测试覆盖了 happy path 和错误路径
    - Gas 消耗在可接受范围内
    - 合约管理员在必要时可以暂停或升级

[ ] 5. 回滚计划:
    - 如果部署失败,已知回滚步骤
    - 旧版本的 code_id 仍可访问
    - 必要时可以重新 Instantiate 旧版本

=== 模板通知(来自 counter_v1 manifest) ===
- 该模板用于 AI coding 起步,不是官方系统合约。
- 部署前必须按业务需求、权限模型、Gas 与安全审计进行重写。

=== 配方硬边界(来自 contract_minimal.json) ===
- 当前 starter template pack 只提供起步骨架,不等于业务合约已自动完成。
- 没有真实钱包、私钥、部署权限与 Gas 预算,AI 不能独立完成最终上链。
- 高价值或治理相关动作必须经过人类审批与门禁验证。
"""

7.9 完整的 AI Agent 工作流脚本

#!/usr/bin/env python3
"""
MSG Chain 合约 AI Coding 最小闭环
基于 recipes/contract_minimal.json 的 7 步工作流
"""

import requests
import json
import os
import sys
from typing import Optional

BASE = 'https://msgchain.org/whitepaper'
MATRIX_URL = f'{BASE}/developer_capability_matrix.json'
RECIPE_URL = f'{BASE}/recipes/contract_minimal.json'
TEMPLATE_INDEX_URL = f'{BASE}/contract_templates/index.json'
COUNTER_MANIFEST_URL = f'{BASE}/contract_templates/counter_v1/manifest.json'

async def step1_read_capability_matrix():
    matrix = await requests.get(MATRIX_URL).json()
    relevant = [i for i in matrix['items']
                if i['surface_id'] in ('contract_template_pack', 'contract_runtime')]
    for item in relevant:
        print(f"[{item['surface_id']}] readiness={item['machine_readiness']}, "
              f"prod={item['production_supported']}")
    return relevant

async def step2_read_modules():
    modules = [
        f'{BASE}/module_exports/contract.json',
        f'{BASE}/module_exports/registry.json',
        f'{BASE}/module_exports/rpc.json',
    ]
    for url in modules:
        mod = await requests.get(url).json()
        print(f"[module] {mod['title']}: {mod['status_label']}")
    return True

async def step3_generate_contract(name: str, target_dir: str):
    manifest = await requests.get(COUNTER_MANIFEST_URL).json()
    for filepath in manifest['entry_files']:
        url = f'{BASE}/{filepath}'
        content = await requests.get(url).text
        relpath = filepath.replace('contract_templates/counter_v1/', '')
        fullpath = os.path.join(target_dir, relpath)
        os.makedirs(os.path.dirname(fullpath), exist_ok=True)
        with open(fullpath, 'w') as f:
            f.write(content)
    print(f"[generate] {len(manifest['entry_files'])} files written to {target_dir}")
    return True

async def run_workflow(name: str, target_dir: str):
    print("=== Step 1: 读取能力矩阵 ===")
    await step1_read_capability_matrix()

    print("\n=== Step 2: 读取模块 ===")
    await step2_read_modules()

    print(f"\n=== Step 3: 生成合约骨架 ===")
    await step3_generate_contract(name, target_dir)

    print(f"\n=== Step 4: 编写测试(手动) ===")
    print(f"编辑 {target_dir}/tests/integration.rs 添加业务测试")

    print(f"\n=== Step 5: 部署计划 ===")
    print(f"人工编写 {target_dir}/DEPLOY_PLAN.md")

    print(f"\n=== Step 6: 证据收集 ===")
    print(f"部署后收集 tx hash / receipt / query replay")

    print(f"\n=== Step 7: 人类上线门禁 ===")
    print(f"参考 recipe 中的 hard_boundaries 通知开发者")

if __name__ == '__main__':
    import asyncio
    asyncio.run(run_workflow('msg-task-manager-v1', './output/msg-task-manager-v1'))

7.10 完整产出物清单

output/msg-task-manager-v1/
├── Cargo.toml                  # 编译配置
├── src/
│   ├── msg.rs                  # 消息定义
│   ├── state.rs                # 状态模型
│   └── contract.rs             # 合约入口 + 业务逻辑
├── tests/
│   └── integration.rs          # 完整测试覆盖
├── DEPLOY_PLAN.md              # 部署计划
├── EVIDENCE.md                 # 证据收集指导
└── HUMAN_GATE.md               # 人类上线门禁清单

7.11 边界提醒

FINAL_NOTICE = """
本合约代码基于 MSG Chain `counter_v1` starter 模板生成,
并按照 `contract_minimal.json` 配方的 7 步工作流交付。

⚠️ 边界提醒:
1. 模板是 starter,不是开发参考级代码。
2. AI 不能独立完成最终上链。
3. 高价值或治理相关动作必须经过人类审批。

请完成以下操作后再上线:
1. 同行代码审查
2. 业务逻辑验证
3. 权限模型确认
4. Gas 消耗评估
5. 安全审计(高价值场景)
"""

附录 A: 数据来源摘要

A.1 contract_templates/index.json

{
  "schema_version": "v1",
  "templates": [
    {
      "id": "counter_v1",
      "public_url": "https://msgchain.org/whitepaper/contract_templates/counter_v1/manifest.json",
      "description": "Minimal CosmWasm starter template for AI-assisted contract coding on MSG."
    }
  ],
  "reference_sources": [
    "contracts/cosmwasm/all/genesis_registry_v1/src/msg.rs",
    "contracts/cosmwasm/all/agent_registry_v1/src/msg.rs"
  ],
  "metadata_profile": "public_stable"
}

A.2 contract_templates/counter_v1/manifest.json

{
  "template_id": "counter_v1",
  "template_kind": "starter",
  "entry_files": [
    "contract_templates/counter_v1/Cargo.toml",
    "contract_templates/counter_v1/src/msg.rs",
    "contract_templates/counter_v1/src/state.rs",
    "contract_templates/counter_v1/src/contract.rs",
    "contract_templates/counter_v1/tests/integration.rs"
  ],
  "notices": [
    "该模板用于 AI coding 起步,不是官方系统合约。",
    "部署前必须按业务需求、权限模型、Gas 与安全审计进行重写。"
  ],
  "metadata_profile": "public_stable"
}

A.3 recipes/contract_minimal.json

{
  "recipe_id": "contract_minimal",
  "title": "MSG 合约 AI Coding 最小闭环",
  "workflow": [
    {"step": 1, "action": "read developer_entry + capability matrix"},
    {"step": 2, "action": "read contract/rpc/registry modules and chunks"},
    {"step": 3, "action": "generate contract message and state design"},
    {"step": 4, "action": "generate cargo tests and failure cases"},
    {"step": 5, "action": "prepare deploy plan"},
    {"step": 6, "action": "collect tx hash, receipt, query replay, evidence refs"},
    {"step": 7, "action": "human release gate"}
  ],
  "hard_boundaries": [
    "当前 starter template pack 只提供起步骨架,不等于业务合约已自动完成。",
    "没有真实钱包、私钥、部署权限与 Gas 预算,AI 不能独立完成最终上链。",
    "高价值或治理相关动作必须经过人类审批与门禁验证。"
  ],
  "metadata_profile": "public_stable"
}

A.4 developer_capability_matrix.json (相关条目)

{
  "surface_id": "contract_template_pack",
  "machine_readiness": "starter_ready",
  "production_supported": false,
  "best_for": ["快速生成最小可运行合约", "补充消息 schema", "生成 cargo test 骨架"],
  "blocking_gaps": ["模板仍是 starter,不覆盖所有业务模式", "没有替代业务审计与测试"],
  "boundaries": ["模板包用于加速 AI coding,不等于官方系统合约或经过审计的业务模板。"]
}

{
  "surface_id": "contract_runtime",
  "machine_readiness": "assisted_codegen",
  "production_supported": true,
  "best_for": ["合约消息设计", "状态流转设计", "部署调用路径生成", "回执验证规划"],
  "blocking_gaps": [
    "当前模板是 starter pack,不等于官方业务合约全集",
    "缺少从链实现自动导出的正式 schema 契约",
    "生产部署仍需真实权限与验收"
  ]
}

附录 B: 常用 API 端点速查

用途 端点 方法
广播交易 POST /broadcast_tx_commit JSON-RPC
ABCI 查询 GET /abci_query JSON-RPC
合约部署 POST /api/v1/contracts/deploy REST
合约实例化 POST /api/v1/contracts/instantiate REST
合约执行 POST /api/v1/contracts/execute REST
账户余额 GET /api/v1/bank/balances REST
回执查询 GET /api/v1/receipts REST

附录 C: 术语表

术语 说明
CosmWasm Cosmos 生态的 WebAssembly 智能合约引擎
canonical key 注册中心中的规范合约键名
store_code 上传合约 wasm 字节码到链上
instantiate 从已存储的代码创建合约实例
execute 调用合约的写操作
query 调用的合约读操作
migrate 更新合约到新的代码版本
submessage 合约内部发起的子消息调用
reply submessage 执行后的回调处理
receipt 交易执行后的回执
fail-closed 默认拒绝的安全策略
starter_ready 可以用于起步但不能直接上生产
assisted_codegen AI 辅助代码生成但需人类确认

本文档基于 MSG Chain 白皮书公开数据编写。
所有代码示例仅供学习参考,部署生产前请务必经过审计。
链 ID: msg-chain-1