AI Agent 网络配置预设与沙箱开发策略
本文档基于 MSG Chain
chain_config/真实配置数据编写。数据来源:
msgchain.org/whitepaper/chain_config/index.json
msgchain.org/whitepaper/chain_config/network_presets.json
msgchain.org/whitepaper/chain_config/developer_sandbox_strategy.json
msgchain.org/whitepaper/developer_capability_matrix.json
msgchain.org/whitepaper/developer_entry.json
目录
1. 概述
1.1 什么是 chain_config
chain_config/ 是 MSG Chain 白皮书中的链配置包目录,作为机器可消费的网络元数据入口,
为 AI Agent、dApp 前端和 SDK 接入提供标准化的链配置基线。
根据 developer_entry.json 的 bootstrap 顺序,chain_config/index.json 和
chain_config/developer_sandbox_strategy.json 是合约/dApp开发者的前序引导资源,
位于 quickstart 之后、api_specs 之前。
1.2 chain_config 的文件清单
根据 chain_config/index.json,该目录包含以下文件:
| 文件 | 描述 | machine_readiness |
|---|---|---|
network_presets.json |
链 ID、端点、钱包与货币默认值 | starter_ready |
keplr_chain_info.json |
Keplr 钱包链配置基线 | starter_ready |
keplr_suggest_chain.js |
Keplr suggestChain 辅助脚本 | starter_ready |
developer_sandbox_strategy.json |
沙箱/水龙头策略(fail-closed) | fail_closed_reference |
1.3 两个配置表面的能力等级
来自 developer_capability_matrix.json 的官方能力分层:
chain_config_pack(链配置与钱包注入包)
| 字段 | 值 |
|---|---|
| machine_readiness | starter_ready |
| production_supported | true |
| machine_safe_for_codegen | true |
| write_path_ready | false |
| example_available | true |
| best_for | 前端链配置生成、Keplr suggestChain、CosmJS/钱包接入初始化 |
public_sandbox_strategy(Public Devnet/Testnet/Faucet 策略)
| 字段 | 值 |
|---|---|
| machine_readiness | fail_closed_reference |
| production_supported | false |
| machine_safe_for_codegen | true |
| write_path_ready | false |
| example_available | true |
| blocking_gaps | 当前选择的是 Option B fail-closed 策略;signed disabled manifest、public faucet absence proof 与 final signatures 仍未关闭 |
1.4 核心区别:配置基线 vs 沙箱可用性
- chain_config_pack 是
starter_ready,表示链配置本身可以作为起点安全使用,
用于前端生成、钱包注入和 CosmJS 初始化。生产配置需要复核 endpoint。 - public_sandbox_strategy 是
fail_closed_reference,表示公开沙箱(testnet/devnet/faucet)
当前处于 fail-closed 状态,外部 AI Agent 不应当将其视为可用的公开端点。
1.5 为什么 AI Agent 需要理解这两个层级
AI Agent 在接入 MSG Chain 时,必须区分:
- 哪些配置是可靠的基线(chain_config_pack → 可用)
- 哪些环境可以实际发送交易(public_sandbox_strategy → 不可用)
- 本地开发是当前唯一的主路径
1.6 配置文件的元数据档案
所有 chain_config/ 文件均标记为 metadata_profile: "public_stable",
表示这些配置已经过白皮书管线的稳定发布,AI Agent 可以依赖其结构定义,
但不能替代生产环境复核。
1.7 从 developer_entry.json 看引导顺序
"recommended_contract_bootstrap_order": [
"product_delivery_entry.json",
"developer_capability_matrix.json",
"quickstart/contract_and_dapp_minimal.json",
"chain_config/index.json",
"chain_config/developer_sandbox_strategy.json",
...
]
chain_config/index.json 作为配置入口,developer_sandbox_strategy.json 作为
沙箱边界声明,两者构成了开发者在了解技术细节之前的"环境认知基座"。
1.8 网络预设的架构角色
network_presets.json 是 chain_config 的核心,它提供了:
- 主网(mainnet)的链 ID、RPC、REST、钱包配置
- 测试网(testnet)的预留域名(当前 fail-closed)
- 本地开发(local)的 localhost 端点默认值
AI Agent 应当使用 network_presets 作为配置生成的输入,但必须在运行时
根据环境变量或用户指定的目标网络进行切换。
1.9 关于 keplr 配置文件的额外说明
keplr_chain_info.json 是 Keplr 钱包的链信息配置模板,包含 suggestChain API
所需的全部字段。keplr_suggest_chain.js 是建议的辅助脚本,可直接嵌入前端项目。
这两个文件属于 starter_ready 级别,生产支持为 true,适合前端项目直接使用。
1.10 本文档的目标读者
- AI Agent 开发者:理解沙箱限制,选择正确的开发路径
- dApp 前端开发者:使用 network_presets 生成 Keplr/CosmJS 配置
- 智能合约开发者:了解本地开发环境设置和端点配置
- 协议集成方:确认主网端点和生产配置
2. 链配置与网络预设
2.1 network_presets.json 完整结构
network_presets.json 是 MSG Chain 的机器可消费网络配置预设,其顶层结构如下:
{
"schema_version": "v1",
"generated_by": "msg_whitepaper_pipeline_v1",
"chain_id": "msg-chain-1",
"numeric_chain_id": 1,
"chain_name": "MSG Chain",
"rpc": "https://rpc.msgchain.org",
"rest": "https://api.msgchain.org",
"wallet": {
"bech32": { ... },
"bip44": { ... },
"currencies": [ ... ],
"fee_currencies": [ ... ],
"stake_currency": { ... },
"features": [ "cosmwasm" ]
},
"source_files": [ ... ],
"boundary": [ ... ],
"metadata_profile": "public_stable"
}
2.2 链标识
| 参数 | 值 |
|---|---|
| chain_id | msg-chain-1 |
| numeric_chain_id | 1 |
| chain_name | MSG Chain |
| 地址前缀 (bech32) | msg |
| BIP44 coin type | 118(Cosmos 标准) |
2.3 Bech32 地址前缀配置
MSG Chain 使用标准 Cosmos bech32 地址体系:
| 角色 | 前缀 |
|---|---|
| 账户地址 | msg |
| 账户公钥 | msgpub |
| 验证者地址 | msgvaloper |
| 验证者公钥 | msgvaloperpub |
| 共识地址 | msgvalcons |
| 共识公钥 | msgvalconspub |
2.4 主网端点
| 服务 | URL |
|---|---|
| RPC | https://rpc.msgchain.org |
| REST API | https://api.msgchain.org |
当前公开的 network_presets 仅包含 mainnet 端点。testnet 和 devnet 的域名已预留
但处于 reserved_fail_closed 状态,不可用。
2.5 货币与通证配置
原生通证:MSG
| 字段 | 值 |
|---|---|
| coinDenom | MSG |
| coinMinimalDenom | umsg |
| coinDecimals | 18 |
| coinGeckoId | msg-chain |
Gas 费用阶梯
| 等级 | Gas 价格 |
|---|---|
| flat | 1,000,000,000 attoMSG/gas |
质押货币
与原生通证一致,使用 umsg(18 位小数)。
链特性
"features": ["cosmwasm"]
MSG Chain 原生支持 CosmWasm 智能合约,所有钱包配置均已包含该特性标志。
2.6 Python 配置获取示例
import requests
import json
from typing import TypedDict, Optional
NETWORK_PRESETS_URL = \
"https://msgchain.org/whitepaper/chain_config/network_presets.json"
class ChainConfig(TypedDict):
chain_id: str
bech32_prefix: str
rpc_url: str
rest_url: str
gas_price_step: dict
async def get_network_config(env: str = "mainnet") -> ChainConfig:
"""从 network_presets 获取网络配置"""
resp = requests.get(NETWORK_PRESETS_URL)
presets = resp.json()
if env == "testnet":
# 测试网域名已预留但处于 fail-closed 状态
raise RuntimeError(
"testnet endpoints are reserved_fail_closed. "
"Use 'local' for development."
)
# 当前 preset 仅包含主网配置
# 本地开发需手动指定 localhost 端点
rpc = presets["rpc"] if env == "mainnet" else "http://localhost:26657"
rest = presets["rest"] if env == "mainnet" else "http://localhost:1317"
return {
"chain_id": presets["chain_id"],
"bech32_prefix": presets["wallet"]["bech32"]["bech32PrefixAccAddr"],
"rpc_url": rpc,
"rest_url": rest,
"gas_price_step": presets["wallet"]["fee_currencies"][0]["gasPriceStep"],
}
async def main():
config = await get_network_config("mainnet")
print(f"Connected to {config['chain_id']}")
print(f"RPC: {config['rpc_url']}")
print(f"REST: {config['rest_url']}")
print(f"Prefix: {config['bech32_prefix']}")
if __name__ == "__main__":
import asyncio
asyncio.run(main())
2.7 JavaScript / TypeScript 配置获取示例
interface ChainConfig {
chainId: string;
chainName: string;
rpc: string;
rest: string;
bech32Prefix: string;
gasPriceStep: {
low: number;
average: number;
high: number;
};
}
const NETWORK_PRESETS_URL =
"https://msgchain.org/whitepaper/chain_config/network_presets.json";
async function fetchChainConfig(): Promise<ChainConfig> {
const resp = await fetch(NETWORK_PRESETS_URL);
const presets = await resp.json();
return {
chainId: presets.chain_id,
chainName: presets.chain_name,
rpc: presets.rpc,
rest: presets.rest,
bech32Prefix: presets.wallet.bech32.bech32PrefixAccAddr,
gasPriceStep: presets.wallet.fee_currencies[0].gasPriceStep,
};
}
2.8 Keplr 钱包链信息配置(keplr_chain_info.json)
Keplr 链信息配置模板,可直接用于 window.keplr.experimentalSuggestChain():
{
"$schema": "https://keplr.app/schemas/chain-info.json",
"chainId": "msg-chain-1",
"chainName": "MSG Chain",
"chainSymbolImageUrl": "https://msgchain.org/logo.png",
"rpc": "https://rpc.msgchain.org",
"rest": "https://api.msgchain.org",
"nodeProvider": {
"name": "MSG Chain Foundation",
"email": "support@msgchain.org",
"website": "https://msgchain.org"
},
"bip44": {
"coinType": 118
},
"bech32Config": {
"bech32PrefixAccAddr": "msg",
"bech32PrefixAccPub": "msgpub",
"bech32PrefixValAddr": "msgvaloper",
"bech32PrefixValPub": "msgvaloperpub",
"bech32PrefixConsAddr": "msgvalcons",
"bech32PrefixConsPub": "msgvalconspub"
},
"currencies": [
{
"coinDenom": "MSG",
"coinMinimalDenom": "umsg",
"coinDecimals": 6,
"coinGeckoId": "msg-chain"
}
],
"feeCurrencies": [
{
"coinDenom": "MSG",
"coinMinimalDenom": "umsg",
"coinDecimals": 6,
"coinGeckoId": "msg-chain",
"gasPriceStep": {
"low": 1000000000,
"average": 1000000000,
"high": 1000000000
}
}
],
"stakeCurrency": {
"coinDenom": "MSG",
"coinMinimalDenom": "umsg",
"coinDecimals": 6,
"coinGeckoId": "msg-chain"
},
"features": ["cosmwasm"]
}
2.9 Keplr suggestChain 辅助脚本
keplr_suggest_chain.js 提供了一个可直接嵌入前端项目的辅助模块:
export async function suggestMSGChain() {
if (!window.keplr) {
throw new Error("Keplr extension not found");
}
try {
await window.keplr.experimentalSuggestChain(MSG_CHAIN_INFO);
console.log("MSG Chain added to Keplr successfully");
} catch (error) {
console.error("Failed to add MSG Chain to Keplr:", error);
throw error;
}
}
export function isKeplrAvailable() {
return typeof window !== "undefined" && !!window.keplr;
}
export function getMSGChainConfig() {
return MSG_CHAIN_INFO;
}
2.10 CosmJS 接入初始化
import { SigningStargateClient } from "@cosmjs/stargate";
import { GasPrice } from "@cosmjs/stargate";
import { getMSGChainConfig } from "./keplr_suggest_chain";
async function initCosmJSClient() {
const config = getMSGChainConfig();
const gasPrice = GasPrice.fromString("1000000000attoMSG");
const client = await SigningStargateClient.connectWithSigner(
config.rpc,
window.getOfflineSigner?.(config.chainId),
{ gasPrice }
);
return client;
}
2.11 通过注册中心验证链配置
除了直接使用 network_presets,AI Agent 还可以通过 MSG Chain 的
Genesis Registry v1 验证当前链状态:
# 查询链 ID
curl -s https://rpc.msgchain.org/status | jq '.result.node_info.network'
# 查询节点状态
curl -s https://api.msgchain.org/cosmos/base/tendermint/v1beta1/node_info
# 查询区块头确认链 ID
curl -s https://rpc.msgchain.org/block?height=1 | jq '.result.block.header.chain_id'
2.12 网络预设的源文件引用
network_presets.json 的 source_files 字段记录了配置的原始来源:
"source_files": [
"configs/keplr_chain_info.json",
"configs/keplr_suggest_chain.js"
]
这意味着 network_presets 是基于仓库中的配置文件生成的 AI 友好摘要,
并非独立的配置来源。如果需要最新配置,应参考仓库中的原始文件。
2.13 network_presets 的边界声明
"boundary": [
"链配置是接入基线,不等于 live/public 端点已经被正式接受为生产网络。",
"生产接入前仍需复核 endpoint 可用性、域名控制、证书、SLO 与发布权限。"
]
2.14 配置验证函数
def validate_chain_config(config: dict) -> list[str]:
"""
验证链配置的完整性,返回缺失字段列表。
"""
required = [
"chain_id", "rpc", "rest",
"wallet.bech32.bech32PrefixAccAddr",
"wallet.bip44.coinType",
"wallet.currencies[0].coinMinimalDenom",
"wallet.fee_currencies[0].gasPriceStep",
]
missing = []
# 简化的嵌套检查
checks = {
"chain_id": config.get("chain_id"),
"rpc": config.get("rpc"),
"rest": config.get("rest"),
"prefix": config.get("wallet", {})
.get("bech32", {})
.get("bech32PrefixAccAddr"),
"coin_type": config.get("wallet", {})
.get("bip44", {})
.get("coinType"),
"denom": config.get("wallet", {})
.get("currencies", [{}])[0]
.get("coinMinimalDenom"),
"gas_steps": config.get("wallet", {})
.get("fee_currencies", [{}])[0]
.get("gasPriceStep"),
}
for key, value in checks.items():
if value is None:
missing.append(key)
return missing
2.15 网络预设的版本控制
network_presets.json 使用 schema_version: "v1" 字段进行版本管理,
当前为 v1 版本。当链配置发生结构性变更时,schema_version 应递增。
AI Agent 应检查 schema_version 以确保使用兼容的配置解析逻辑。
2.16 生成 pipeline 与配置一致性
所有 chain_config 文件均通过 msg_whitepaper_pipeline_v1 生成。
这意味着:
- 配置文件的格式和字段是机器可预测的
- 文件之间的交叉引用保持一致
- 元数据结构在所有公开配置文件中是统一的
AI Agent 可以利用这一一致性来自动解析和验证配置数据。
2.17 钱包配置的详细说明
WALLET_CONFIG = {
"bech32": {
"bech32PrefixAccAddr": "msg",
"bech32PrefixAccPub": "msgpub",
"bech32PrefixValAddr": "msgvaloper",
"bech32PrefixValPub": "msgvaloperpub",
"bech32PrefixConsAddr": "msgvalcons",
"bech32PrefixConsPub": "msgvalconspub",
},
"bip44": {
"coinType": 118, # Cosmos 标准 HD 路径
},
"currencies": [{
"coinDenom": "MSG",
"coinMinimalDenom": "umsg",
"coinDecimals": 6,
"coinGeckoId": "msg-chain",
}],
"features": ["cosmwasm"],
}
2.18 验证者与委托相关的前缀
开发者在使用 MSG Chain 的验证者相关功能时,需要注意地址前缀的区分:
| 场景 | 地址前缀 | 示例地址开头 |
|---|---|---|
| 用户转账 | msg | msg1... |
| 验证者注册 | msgvaloper | msgvaloper1... |
| 共识签名 | msgvalcons | msgvalcons1... |
| 公钥展示 | msgpub | msgpub1... |
2.19 从网络预设到前端注入的完整链路
network_presets.json
│
├── keplr_chain_info.json
│ │
│ └── keplr_suggest_chain.js
│ │
│ └── window.keplr.experimentalSuggestChain()
│
├── CosmJS 客户端初始化
│ │
│ └── SigningStargateClient.connectWithSigner()
│
└── 前端组件配置注入
│
└── chainProvider / WalletProvider 初始化
2.20 各环境对应的 chain_id
| 环境 | chain_id | 状态 |
|---|---|---|
| mainnet | msg-chain-1 | production,端点可用 |
| testnet | msg-chain-testnet-1 | reserved_fail_closed,不可用 |
| local | msg-chain-local-1 | 本地开发,需自行启动节点 |
3. 开发者沙箱策略
3.1 概述:什么是 fail-closed 策略
根据 developer_sandbox_strategy.json,MSG Chain 当前选择的沙箱策略是
Option B: disabled public sandbox with explicit local development path,
即"禁用公开沙箱,明确本地开发路径"的 fail-closed 策略。
fail-closed 意味着所有公开环境(testnet、devnet、faucet)默认关闭,
除非有 signed manifest 证明它们已通过验收。
3.2 策略的完整 JSON 结构
{
"schema_version": "v1",
"mainnet_verdict": "No-Go",
"mainnet_ready_claim": false,
"selected_strategy": "option_b_disabled_public_sandbox",
"public_sandbox_enabled": false,
"public_faucet_enabled": false,
"public_testnet_enabled": false,
"signed_disabled_manifest_claim": false,
"strategy": {
"option": "B",
"name": "disabled public sandbox with explicit local development path",
"production_ready": false,
"public_endpoint_enabled": false,
"default_sdk_enabled": false,
"faucet_mode": "disabled_public_faucet",
"testnet_preset_mode": "unverified_fail_closed",
"devnet_preset_mode": "not_public",
"local_development_path": "examples/ai-agent-dapp-starter with explicit endpoints only",
"required_sdk_guards": [ ... ],
"failure_mode": "fail-closed until a signed disabled manifest ..."
}
}
3.3 策略的核心开关
| 开关 | 值 | 含义 |
|---|---|---|
| public_sandbox_enabled | false | 公开沙箱未开放 |
| public_faucet_enabled | false | 公开水龙头未开放 |
| public_testnet_enabled | false | 公开测试网未开放 |
| signed_disabled_manifest_claim | false | 未签署关闭声明 |
| mainnet_ready_claim | false | 未宣称主网就绪 |
3.4 fail_closed_reference 的含义
来自 developer_capability_matrix.json 的官方定义:
public_sandbox_strategy的machine_readiness为fail_closed_reference,
production_supported为false。
这个等级意味着:
- 仅可作为参考:沙箱策略文件的内容可供 AI Agent 读取,用于理解当前环境状态
- 不可用于生成可执行代码:不能基于此策略生成向 public testnet 发送交易的代码
- 通道未打开:testnet/devnet/faucet 的通道未通过生产验收
3.5 策略的阻塞项(known_blockers)
当前有五个已知阻塞项阻止公开沙箱就绪:
| 阻塞项 | 缺失的证据 |
|---|---|
| signed_disabled_public_sandbox_manifest | signed disabled manifest + release signer key + Dilithium signature |
| sdk_preset_fail_closed_public_evidence | SDK mainnet/testnet preset fail-closed proof + indexer proof |
| local_development_runbook_evidence | local starter command output + endpoint override warning + no-secret scan |
| public_faucet_absence_boundary | public faucet disabled statement + admin faucet not public proof |
| external_audit_and_final_signatures | external audit final report + final readiness signatures + C total Go-No-Go |
每个阻塞项都带有 failure_mode: "fail-closed until ..." 声明,
意味着在提供完整证据之前,该功能不可用。
3.6 五个生产要求(production_requirements)
{
"production_requirements": [
{
"id": "signed_disabled_public_sandbox_manifest",
"status": "missing_production_evidence",
"failure_mode": "fail-closed until signed disabled public sandbox manifest is accepted"
},
{
"id": "sdk_preset_fail_closed_public_evidence",
"status": "missing_production_evidence",
"failure_mode": "fail-closed until SDK preset fail-closed proof is accepted"
},
{
"id": "local_development_runbook_evidence",
"status": "missing_production_evidence",
"failure_mode": "fail-closed until local development runbook evidence is accepted"
},
{
"id": "public_faucet_absence_boundary",
"status": "missing_production_evidence",
"failure_mode": "fail-closed until public faucet absence boundary is signed and accepted"
},
{
"id": "external_audit_and_final_signatures",
"status": "missing_production_evidence",
"failure_mode": "fail-closed until external audit, final signatures, and C total Go-No-Go are accepted"
}
]
}
3.7 预留域名(reserved_testnet_domains)
虽然 testnet 功能未开放,但其域名架构已经预定:
| 域名 | 用途 |
|---|---|
| testnet-rpc.msgchain.org | Testnet RPC 端点 |
| testnet-nodes.msgchain.org | Testnet 节点发现/控制面 |
| testnet-api.msgchain.org | Testnet REST/API 网关 |
| testnet-grpc.msgchain.org | Testnet gRPC 端点 |
| testnet-indexer.msgchain.org | Testnet indexer API |
| testnet-explorer.msgchain.org | Testnet 浏览器 |
| testnet-faucet.msgchain.org | Testnet 水龙头 |
| testnet-wallet.msgchain.org | Testnet 钱包前端 |
| testnet-agent.msgchain.org | Testnet AI Agent 网关 |
| testnet-agents.msgchain.org | Testnet AI Agent 网关别名 |
所有域名的当前状态均为 reserved_fail_closed,附注均为 testnet_not_launched_fail_closed。
3.8 SDK 防护守卫
当前策略要求 SDK 和 indexer 在 fail-closed 模式下必须包含以下防护:
"required_sdk_guards": [
"mainnet_preset_verified_false",
"testnet_preset_verified_false",
"client_rejects_unverified_presets_by_default",
"indexer_rejects_unverified_presets_by_default"
]
这意味着:
- SDK 中的 mainnet 预设标记为
verified: false - SDK 中的 testnet 预设标记为
verified: false - 客户端默认拒绝未验证的预设
- Indexer 默认拒绝未验证的预设
3.9 本地开发路径
当前策略明确指出的本地开发路径为:
examples/ai-agent-dapp-starter with explicit endpoints only
开发者在本地运行时必须显式指定端点,不能依赖 SDK 默认的主网/测试网预设。
3.10 对 AI Agent 的实际影响
AI Agent 在读取 developer_sandbox_strategy.json 后,应当:
SANDOX_VERDICT = {
"public_testnet_available": False,
"public_devnet_available": False,
"public_faucet_available": False,
"local_development_required": True,
"reason": "Option B fail-closed strategy; all 5 production requirements missing evidence",
"local_path": "examples/ai-agent-dapp-starter with explicit endpoints only",
"sdk_auto_connect": False,
"sdk_guard_active": True,
}
def get_sandbox_status() -> dict:
"""
返回当前沙箱策略的状态总结。
AI Agent 应调用此函数而非直接访问公开端点。
"""
return SANDOX_VERDICT
3.11 本地沙箱启动示例
# 本地开发环境启动(示例)
git clone https://github.com/msgchain/ai-agent-dapp-starter
cd ai-agent-dapp-starter
# 安装依赖
npm install
# 配置本地端点(必须显式指定)
export MSG_RPC_ENDPOINT="http://localhost:26657"
export MSG_REST_ENDPOINT="http://localhost:1317"
# 启动本地开发链(需要本地节点)
# 请参考 chain_config/network_presets.json 的 local 配置
npm run dev
3.12 沙箱策略的源文件引用
developer_sandbox_strategy.json 的 source_files 字段记录了策略的源代码来源:
"source_files": [
{ "path": "sdk/src/types.ts", "role": "sdk_network_presets" },
{ "path": "sdk/src/client/index.ts", "role": "sdk_unverified_network_guard" },
{ "path": "sdk/src/indexer/index.ts", "role": "sdk_indexer_unverified_network_guard" },
{ "path": "release/developer_capability_manifest.json", "role": "..." },
{ "path": "release/developer_dapp_starter_e2e_manifest.json", "role": "..." },
{ "path": "examples/ai-agent-dapp-starter/README.md", "role": "local_dapp_starter_runbook" }
]
3.13 策略的白皮书模块依赖
"whitepaper_modules": [
"sdk_dev_surface",
"agent_api_surface",
"l4_l5_acceptance_matrix",
"ecosystem_platform_extensibility",
"observability_monitoring"
]
沙箱策略不是一个独立决策,而是与 SDK 表面、Agent API 表面、验收矩阵、
生态平台扩展性和可观测性监控等多个模块协同的结果。
3.14 关闭边界声明
"closing_boundary": "This manifest chooses the conservative Option B local fail-closed
strategy only. It does not provide a public devnet, public testnet, public faucet,
signed disabled manifest, public SDK preset, external audit, final signatures,
or C total Go-No-Go."
3.15 对于水龙头(Faucet)的限制
当前 faucet_mode 为 disabled_public_faucet。这意味着:
- 公开水龙头不可用
- 管理员水龙头不可公开访问
- SDK 中的水龙头路径已禁用
- 外部开发者无法通过公开渠道获取测试代币
如果 AI Agent 的代码中包含水龙头调用逻辑,在未确认 public faucet 已开放前,
必须跳过或报错。
3.16 策略的技术背景:为什么选择 fail-closed
根据 developer_sandbox_strategy.json 的完整上下文,选择 fail-closed 策略的
原因包括:
- 签名清单缺失:没有经过签名的 disabled sandbox manifest
- SDK 预设未验证:SDK 中的 mainnet 和 testnet 预设均标记为未验证
- 本地开发验证缺失:本地开发启动器的运行证据尚未收集
- 水龙头边界未签名:公开水龙头的关闭声明未经签名确认
- 外部审计未完成:最终的外部审计报告和签名未关闭
3.17 AI Agent 的环境检测函数
type EnvironmentStatus = "available" | "fail_closed" | "local_only";
interface EnvironmentInfo {
status: EnvironmentStatus;
chainId: string;
endpoints: string[];
faucetAvailable: boolean;
notes: string[];
}
function checkEnvironment(env: string): EnvironmentInfo {
const sandboxStatus = {
status: "fail_closed" as EnvironmentStatus,
chainId: "msg-chain-testnet-1",
endpoints: [
"testnet-rpc.msgchain.org (reserved_fail_closed)",
"testnet-api.msgchain.org (reserved_fail_closed)",
],
faucetAvailable: false,
notes: [
"Testnet is NOT launched; all domains are reserved_fail_closed",
"Use local development path instead",
"See: chain_config/developer_sandbox_strategy.json",
],
};
const localInfo = {
status: "local_only" as EnvironmentStatus,
chainId: "msg-chain-local-1",
endpoints: [
"http://localhost:26657",
"http://localhost:1317",
],
faucetAvailable: false,
notes: [
"Local development only",
"You must run a local node",
"No public testnet faucet available",
],
};
const mainnetInfo = {
status: "available" as EnvironmentStatus,
chainId: "msg-chain-1",
endpoints: [
"https://rpc.msgchain.org",
"https://api.msgchain.org",
],
faucetAvailable: false,
notes: [
"Mainnet is available for production",
"Do NOT use mainnet for testing",
"Transactions cost real MSG tokens",
],
};
switch (env) {
case "mainnet": return mainnetInfo;
case "testnet": return sandboxStatus;
case "local": return localInfo;
default: return localInfo;
}
}
3.18 策略的消费边界
"public_consumption_boundary": [
"当前公开口径是 Option B: disabled public sandbox with explicit local development path。",
"未看到 signed disabled manifest、public faucet absence proof 与 final signatures 前,外部 AI 必须把 public devnet/testnet/faucet 视为不可用。"
]
AI Agent 必须将这两条边界声明作为消费沙箱策略文件的前提条件。
3.19 从 fail-closed 到公开的路径
如果未来策略从 Option B 切换到开放状态,需要以下条件全部满足:
- 所有五个 production_requirements 的状态从
missing_production_evidence变为accepted signed_disabled_manifest_claim变为truepublic_sandbox_enabled变为truemainnet_ready_claim变为truemainnet_verdict从No-Go变为Go
在此之前,AI Agent 必须假设所有公开非主网环境不可用。
3.20 本地开发入口点
"local_baseline_entry_points": [
"chain_config/network_presets.json",
"chain_config/keplr_chain_info.json",
"examples/index.json",
"release_pack/developer_dapp_starter_e2e_manifest.json",
"release_pack/developer_public_sandbox_strategy_manifest.json"
]
4. 网络配置生产指引
4.1 主网配置
NETWORK_CONFIGS = {
"mainnet": {
"chain_id": "msg-chain-1",
"chain_name": "MSG Chain",
"rpc": "https://rpc.msgchain.org",
"rest": "https://api.msgchain.org",
"grpc": "msgchain-grpc.msgchain.org:9090",
"bech32_prefix": "msg",
"coin_denom": "MSG",
"coin_minimal_denom": "umsg",
"coin_decimals": 6,
"gas_low": 1000000000,
"gas_average": 1000000000,
"gas_high": 1000000000,
"features": ["cosmwasm"],
"bip44_coin_type": 118,
},
"testnet": {
"chain_id": "msg-chain-testnet-1",
"chain_name": "MSG Chain Testnet",
"rpc": "testnet-rpc.msgchain.org",
"rest": "testnet-api.msgchain.org",
"grpc": "testnet-grpc.msgchain.org:9090",
"bech32_prefix": "msg",
"status": "reserved_fail_closed",
"available": False,
},
"local": {
"chain_id": "msg-chain-local-1",
"chain_name": "MSG Chain Local",
"rpc": "http://localhost:26657",
"rest": "http://localhost:1317",
"grpc": "localhost:9090",
"bech32_prefix": "msg",
"coin_denom": "MSG",
"coin_minimal_denom": "umsg",
"coin_decimals": 6,
"gas_low": 1000000000,
"gas_average": 1000000000,
"gas_high": 1000000000,
},
}
4.2 主网接入的类型化配置
interface MainnetConfig {
chainId: "msg-chain-1";
chainName: "MSG Chain";
rpc: "https://rpc.msgchain.org";
rest: "https://api.msgchain.org";
grpc: "msgchain-grpc.msgchain.org:9090";
bech32Prefix: "msg";
currencies: Array<{
coinDenom: "MSG";
coinMinimalDenom: "umsg";
coinDecimals: 6;
}>;
gasPriceStep: {
low: 1000000000;
average: 1000000000;
high: 1000000000;
};
features: ["cosmwasm"];
}
const MAINNET_CONFIG: MainnetConfig = {
chainId: "msg-chain-1",
chainName: "MSG Chain",
rpc: "https://rpc.msgchain.org",
rest: "https://api.msgchain.org",
grpc: "msgchain-grpc.msgchain.org:9090",
bech32Prefix: "msg",
currencies: [{
coinDenom: "MSG",
coinMinimalDenom: "umsg",
coinDecimals: 6,
}],
gasPriceStep: {
low: 1000000000,
average: 1000000000,
high: 1000000000,
},
features: ["cosmwasm"],
};
4.3 CosmJS 生产客户端初始化
import { SigningStargateClient, StargateClient } from "@cosmjs/stargate";
import { GasPrice } from "@cosmjs/stargate";
async function createMainnetReadClient(): Promise<StargateClient> {
return StargateClient.connect(MAINNET_CONFIG.rpc);
}
async function createMainnetSigningClient(
signer: OfflineSigner
): Promise<SigningStargateClient> {
const gasPrice = GasPrice.fromString("1000000000attoMSG");
return SigningStargateClient.connectWithSigner(
MAINNET_CONFIG.rpc,
signer,
{ gasPrice }
);
}
4.4 测试网配置的 fail-closed 处理
由于 testnet 处于 reserved_fail_closed 状态,代码必须包含防护逻辑:
function getTestnetConfig(): never {
throw new Error(
"Testnet is NOT available. " +
"All testnet domains (testnet-rpc/api/grpc.msgchain.org) " +
"are reserved_fail_closed. " +
"Use local development (msg-chain-local-1) instead. " +
"See: chain_config/developer_sandbox_strategy.json"
);
}
4.5 本地开发环境完整配置
# local-dev-config.yaml
chain:
id: msg-chain-local-1
name: MSG Chain Local
endpoints:
rpc: http://localhost:26657
rest: http://localhost:1317
grpc: localhost:9090
bech32_prefix: msg
wallet:
bip44_coin_type: 118
denom: umsg
decimals: 6
gas:
low: 1000000000
average: 1000000000
high: 1000000000
faucet:
available: false
note: "Public faucet disabled. Use local node --faucet flag if supported."
4.6 多环境配置选择器
import os
from enum import Enum
class NetworkEnvironment(Enum):
MAINNET = "mainnet"
TESTNET = "testnet"
LOCAL = "local"
def resolve_network_config() -> dict:
"""
根据环境变量 MSG_NETWORK 解析网络配置。
默认使用 local 环境,防止误触主网。
"""
env_name = os.getenv("MSG_NETWORK", "local").lower()
try:
env = NetworkEnvironment(env_name)
except ValueError:
print(f"Warning: Unknown network {env_name}, falling back to local")
env = NetworkEnvironment.LOCAL
configs = {
NetworkEnvironment.MAINNET: {
"chain_id": "msg-chain-1",
"rpc": "https://rpc.msgchain.org",
"rest": "https://api.msgchain.org",
"bech32_prefix": "msg",
"is_production": True,
"require_confirmation": True,
},
NetworkEnvironment.TESTNET: {
"chain_id": "msg-chain-testnet-1",
"rpc": None,
"rest": None,
"bech32_prefix": "msg",
"is_production": False,
"available": False,
"error": "Testnet is reserved_fail_closed. Not available.",
},
NetworkEnvironment.LOCAL: {
"chain_id": "msg-chain-local-1",
"rpc": "http://localhost:26657",
"rest": "http://localhost:1317",
"bech32_prefix": "msg",
"is_production": False,
"require_confirmation": False,
},
}
return configs[env]
4.7 Rust SDK 环境配置示例
use std::env;
#[derive(Debug)]
pub enum MsgNetwork {
Mainnet,
Testnet,
Local,
}
#[derive(Debug)]
pub struct MsgChainConfig {
pub chain_id: String,
pub rpc_url: String,
pub rest_url: String,
pub bech32_prefix: String,
}
impl MsgChainConfig {
pub fn from_env() -> Result<Self, String> {
let network = env::var("MSG_NETWORK")
.unwrap_or_else(|_| "local".to_string());
match network.as_str() {
"mainnet" => Ok(Self {
chain_id: "msg-chain-1".into(),
rpc_url: "https://rpc.msgchain.org".into(),
rest_url: "https://api.msgchain.org".into(),
bech32_prefix: "msg".into(),
}),
"testnet" => Err(
"Testnet is reserved_fail_closed. Use local.".into()
),
"local" => Ok(Self {
chain_id: "msg-chain-local-1".into(),
rpc_url: "http://localhost:26657".into(),
rest_url: "http://localhost:1317".into(),
bech32_prefix: "msg".into(),
}),
_ => Err(format!("Unknown network: {}", network)),
}
}
}
4.8 Keplr 生产配置注入
import { MAINNET_CONFIG } from "./network-config";
async function suggestMainnetToKeplr() {
if (!window.keplr) {
throw new Error("Please install Keplr extension");
}
await window.keplr.experimentalSuggestChain({
chainId: MAINNET_CONFIG.chainId,
chainName: MAINNET_CONFIG.chainName,
rpc: MAINNET_CONFIG.rpc,
rest: MAINNET_CONFIG.rest,
bip44: { coinType: 118 },
bech32Config: {
bech32PrefixAccAddr: MAINNET_CONFIG.bech32Prefix,
bech32PrefixAccPub: MAINNET_CONFIG.bech32Prefix + "pub",
bech32PrefixValAddr: MAINNET_CONFIG.bech32Prefix + "valoper",
bech32PrefixValPub: MAINNET_CONFIG.bech32Prefix + "valoperpub",
bech32PrefixConsAddr: MAINNET_CONFIG.bech32Prefix + "valcons",
bech32PrefixConsPub: MAINNET_CONFIG.bech32Prefix + "valconspub",
},
currencies: MAINNET_CONFIG.currencies,
feeCurrencies: MAINNET_CONFIG.currencies.map(c => ({
...c,
gasPriceStep: MAINNET_CONFIG.gasPriceStep,
})),
stakeCurrency: MAINNET_CONFIG.currencies[0],
features: MAINNET_CONFIG.features,
});
await window.keplr.enable(MAINNET_CONFIG.chainId);
}
4.9 gRPC 端点配置
对于需要使用 gRPC 的应用(如 indexer 或事件监听服务):
GRPC_ENDPOINTS = {
"mainnet": {
"host": "msgchain-grpc.msgchain.org",
"port": 9090,
"tls": True,
},
"local": {
"host": "localhost",
"port": 9090,
"tls": False,
},
}
4.10 生产配置复核清单
在将 chain_config 的配置用于生产之前,必须复核以下项目:
## 生产配置复核清单
- [ ] endpoint 可用性:RPC/REST/gRPC 端点是否可访问
- [ ] 域名控制:域名是否在生产 DNS 控制之下
- [ ] 证书有效期:TLS 证书是否有效、未过期
- [ ] SLO:端点是否有服务等级目标
- [ ] 发布权限:配置变更是否有发布审批流程
- [ ] chain_id:与实际链上区块头的 chain_id 是否一致
- [ ] bech32 前缀:生成的地址前缀是否正确
- [ ] gas 价格:当前的 gas 价格阶梯是否合理
- [ ] coin decimals:通证精度是否正确(18 位)
- [ ] 特性标志:features 是否包含 cosmwasm
4.11 从链上验证配置的脚本
#!/bin/bash
# verify-chain-config.sh
# 验证 chain_config 中的端点配置是否与链上一致
set -e
RPC_ENDPOINT=${1:-"https://rpc.msgchain.org"}
EXPECTED_CHAIN_ID="msg-chain-1"
echo "Verifying chain config at $RPC_ENDPOINT ..."
# 验证链 ID
CHAIN_ID=$(curl -s "$RPC_ENDPOINT/status" | \
python3 -c "import sys,json; print(json.load(sys.stdin)['result']['node_info']['network'])")
if [ "$CHAIN_ID" != "$EXPECTED_CHAIN_ID" ]; then
echo "ERROR: Expected chain_id=$EXPECTED_CHAIN_ID, got $CHAIN_ID"
exit 1
fi
echo "OK: chain_id=$CHAIN_ID"
# 验证 REST API
REST_ENDPOINT=${2:-"https://api.msgchain.org"}
echo "Verifying REST API at $REST_ENDPOINT ..."
curl -s "$REST_ENDPOINT/cosmos/base/tendermint/v1beta1/node_info" > /dev/null
echo "OK: REST API reachable"
# 验证 bech32 地址前缀
echo "Verifying bech32 prefix ..."
ACCOUNT_RESP=$(curl -s "$REST_ENDPOINT/cosmos/auth/v1beta1/accounts?pagination.limit=1")
PREFIX=$(echo "$ACCOUNT_RESP" | python3 -c "
import sys,json
data = json.load(sys.stdin)
addr = data['accounts'][0]['address']
print(addr[:3])
" 2>/dev/null || echo "unknown")
if [ "$PREFIX" != "msg" ]; then
echo "WARNING: Expected bech32 prefix 'msg', got '$PREFIX'"
fi
echo "OK: bech32_prefix=$PREFIX"
echo ""
echo "All checks passed!"
4.12 环境变量配置模式
# .env.mainnet
MSG_NETWORK=mainnet
MSG_CHAIN_ID=msg-chain-1
MSG_RPC_URL=https://rpc.msgchain.org
MSG_REST_URL=https://api.msgchain.org
MSG_GRPC_HOST=msgchain-grpc.msgchain.org
MSG_GRPC_PORT=9090
MSG_BECH32_PREFIX=msg
MSG_GAS_PRICE=0.025
MSG_GAS_DENOM=umsg
# .env.local
MSG_NETWORK=local
MSG_CHAIN_ID=msg-chain-local-1
MSG_RPC_URL=http://localhost:26657
MSG_REST_URL=http://localhost:1317
MSG_GRPC_HOST=localhost
MSG_GRPC_PORT=9090
MSG_BECH32_PREFIX=msg
MSG_GAS_PRICE=0.01
MSG_GAS_DENOM=umsg
4.13 网络配置的热切换
对于需要在运行时切换网络的应用:
type NetworkName = "mainnet" | "testnet" | "local";
class NetworkManager {
private currentNetwork: NetworkName = "local";
setNetwork(network: NetworkName): void {
if (network === "testnet") {
throw new Error(
"Testnet is reserved_fail_closed. Cannot switch to testnet."
);
}
this.currentNetwork = network;
console.log(`Switched to ${network}`);
}
getConfig() {
const configs: Record<NetworkName, object> = {
mainnet: {
chainId: "msg-chain-1",
rpc: "https://rpc.msgchain.org",
rest: "https://api.msgchain.org",
},
testnet: {
chainId: "msg-chain-testnet-1",
available: false,
},
local: {
chainId: "msg-chain-local-1",
rpc: "http://localhost:26657",
rest: "http://localhost:1317",
},
};
return configs[this.currentNetwork];
}
}
4.14 生产环境的安全配置建议
PRODUCTION_SAFETY_RULES = {
"never_use_mainnet_for_testing": True,
"require_user_confirmation_for_mainnet_tx": True,
"log_all_mainnet_transactions": True,
"rate_limit_mainnet_queries": True,
"validate_chain_id_before_signing": True,
"check_bech32_prefix_before_signing": True,
"gas_price_minimum": 1000000000,
"max_gas_per_tx": 500_000,
}
4.15 配置错误处理模式
class NetworkConfigError(Exception):
"""网络配置相关的错误基类"""
pass
class TestnetNotAvailableError(NetworkConfigError):
"""测试网不可用错误"""
def __init__(self):
super().__init__(
"Testnet is reserved_fail_closed. "
"See developer_sandbox_strategy.json for details."
)
class MainnetConfirmationRequired(NetworkConfigError):
"""主网操作需要确认"""
def __init__(self, action: str):
super().__init__(
f"Operation '{action}' targets mainnet (msg-chain-1). "
"User confirmation required."
)
5. AI Agent 网络配置最佳实践
5.1 核心原则
AI Agent 在使用 MSG Chain 的链配置时,必须遵循以下五个核心原则:
- 以 local 为默认开发环境:除非用户明确指定 mainnet,否则所有开发活动
应基于msg-chain-local-1 - mainnet 需要确认:任何涉及主网的操作必须经过用户确认,且不得自动执行
- testnet 不可用:测试网域名已预留但处于 fail-closed 状态,代码中不应包含
自动连接到 testnet 的逻辑 - 配置需验证:chain_config 的配置数据应作为生成起点,而非最终权威来源
- faucet 不可用:公开水龙头不存在,不可在代码中假设有免费测试代币
5.2 AI Agent 的网络选择流程
async def select_network(agent_context: dict) -> dict:
"""
AI Agent 的网络选择决策流程。
根据用户意图、环境变量和安全约束选择合适的网络。
"""
# 步骤 1:读取用户意图
user_intent = agent_context.get("intent", "development")
# 步骤 2:检查环境变量
env_override = agent_context.get("env", {}).get("MSG_NETWORK")
# 步骤 3:根据意图选择
if user_intent == "production":
# 生产环境必须使用 mainnet,但需确认
if not agent_context.get("user_confirmed_mainnet", False):
return {
"selected": "mainnet",
"status": "pending_confirmation",
"message": "Production deployment requires explicit user confirmation",
}
return _get_mainnet_config()
elif user_intent == "development":
# 开发环境默认使用 local
return _get_local_config()
elif user_intent == "testing":
# 测试环境不能使用 testnet(fail-closed)
# 建议用户搭建本地节点
return {
"selected": "local",
"status": "testnet_unavailable",
"message": (
"Testnet is reserved_fail_closed. "
"Please use local development with a local node."
),
}
else:
# 未知意图,默认 local
return _get_local_config()
def _get_mainnet_config() -> dict:
return {
"chain_id": "msg-chain-1",
"rpc": "https://rpc.msgchain.org",
"rest": "https://api.msgchain.org",
"bech32_prefix": "msg",
"warning": "MAINNET - real assets. Confirm before transactions.",
}
def _get_local_config() -> dict:
return {
"chain_id": "msg-chain-local-1",
"rpc": "http://localhost:26657",
"rest": "http://localhost:1317",
"bech32_prefix": "msg",
"note": "Local development only.",
}
5.3 沙箱检测机制
AI Agent 应实现沙箱检测函数,用于在运行时确认当前环境是否为已授权的沙箱:
def is_sandbox_available(environment: str) -> bool:
"""
检测指定环境的沙箱是否可用。
基于 developer_sandbox_strategy.json 的真实策略。
"""
sandbox_checklist = {
"mainnet": {
"available": True,
"faucet": False,
"note": "Production network. REAL tokens.",
},
"testnet": {
"available": False,
"faucet": False,
"note": "reserved_fail_closed - NOT launched",
"blockers": [
"signed_disabled_manifest_missing",
"sdk_preset_fail_closed_evidence_missing",
"public_faucet_absence_boundary_missing",
],
},
"devnet": {
"available": False,
"faucet": False,
"note": "not_public per strategy",
},
"local": {
"available": True,
"faucet": False,
"note": "Local development - requires local node",
"manual_setup_required": True,
},
}
return sandbox_checklist.get(environment, {}).get("available", False)
5.4 链配置验证函数
interface VerificationResult {
valid: boolean;
errors: string[];
warnings: string[];
}
function verifyChainConfig(config: any): VerificationResult {
const errors: string[] = [];
const warnings: string[] = [];
// 必填字段检查
if (!config.chainId) errors.push("Missing chainId");
if (!config.rpc) errors.push("Missing RPC endpoint");
if (!config.rest) errors.push("Missing REST endpoint");
// chain_id 格式检查
if (config.chainId && !config.chainId.startsWith("msg-chain-")) {
errors.push(`Invalid chain_id format: ${config.chainId}`);
}
// 端点格式检查
if (config.rpc && !config.rpc.startsWith("http")) {
errors.push(`Invalid RPC URL format: ${config.rpc}`);
}
// bech32 前缀检查
if (config.bech32Prefix) {
if (config.bech32Prefix !== "msg") {
errors.push(`Unexpected bech32 prefix: ${config.bech32Prefix}. Expected: msg`);
}
} else {
// 检查嵌套的 bech32 配置
const prefix = config.bech32Config?.bech32PrefixAccAddr;
if (prefix && prefix !== "msg") {
errors.push(`Unexpected bech32 prefix: ${prefix}. Expected: msg`);
}
}
// 安全警告
if (config.chainId === "msg-chain-1") {
warnings.push("MAINNET CONFIG - this is the production network");
}
return { valid: errors.length === 0, errors, warnings };
}
5.5 安全:避免误用主网
import hashlib
import json
class MainnetGuard:
"""
主网防护守卫。
在执行任何链上操作前验证环境,防止误触主网。
"""
MAINNET_CHAIN_ID = "msg-chain-1"
@staticmethod
def require_confirmation(config: dict, operation: str) -> bool:
"""要求用户确认主网操作"""
if config.get("chain_id") != MainnetGuard.MAINNET_CHAIN_ID:
return True # 非主网不需要确认
print(f"""
╔══════════════════════════════════════════════════╗
║ MAINNET CONFIRMATION REQUIRED ║
╠══════════════════════════════════════════════════╣
║ Operation: {operation:<40}║
║ Network: {config.get('chain_id'):<40}║
║ RPC: {config.get('rpc'):<40}║
╠══════════════════════════════════════════════════╣
║ WARNING: This is the MAINNET. Real assets ║
║ will be affected. Confirm to proceed. ║
╚══════════════════════════════════════════════════╝
""")
response = input("Type 'yes' to confirm: ")
return response.lower() == "yes"
@staticmethod
def fingerprint_config(config: dict) -> str:
"""生成配置指纹,用于追踪配置的来源"""
serialized = json.dumps(config, sort_keys=True)
return hashlib.sha256(serialized.encode()).hexdigest()[:16]
5.6 AI Agent 的配置加载与缓存
class ChainConfigService {
private cache: Map<string, any> = new Map();
private refreshInterval: number = 5 * 60 * 1000; // 5 分钟
private lastFetch: number = 0;
async getConfig(network: "mainnet" | "local"): Promise<any> {
const cacheKey = `chain_config_${network}`;
// 检查缓存
if (this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
if (Date.now() - this.lastFetch < this.refreshInterval) {
return cached;
}
}
// 从 network_presets 获取
try {
const resp = await fetch(
"https://msgchain.org/whitepaper/chain_config/network_presets.json"
);
const presets = await resp.json();
this.cache.set(cacheKey, presets);
this.lastFetch = Date.now();
return presets;
} catch (error) {
// 降级到缓存或默认值
if (this.cache.has(cacheKey)) {
console.warn("Failed to refresh config, using cached version");
return this.cache.get(cacheKey);
}
throw error;
}
}
}
5.7 交易前验证流程
async def preflight_check(config: dict, tx_payload: dict) -> dict:
"""
交易发送前的安全检查。
返回是否允许发送以及原因。
"""
checks = []
# 1. 验证 chain_id 一致性
chain_id_check = await verify_chain_id(config.get("rpc"), config.get("chain_id"))
checks.append(("chain_id", chain_id_check))
# 2. 检查接收方地址前缀
if "recipient" in tx_payload:
addr = tx_payload["recipient"]
if not addr.startswith("msg"):
checks.append(("recipient_prefix", {
"passed": False,
"message": f"Recipient address does not start with 'msg': {addr}"
}))
else:
checks.append(("recipient_prefix", {"passed": True}))
# 3. 检查 gas 价格是否在合理范围
gas_check = validate_gas_price(
tx_payload.get("gas_price", 0),
config.get("gas_price_step", {})
)
checks.append(("gas_price", gas_check))
# 4. 如果是 mainnet,要求确认
if config.get("chain_id") == "msg-chain-1":
checks.append(("mainnet_confirmation", {
"passed": False,
"requires_user_input": True,
"message": "Mainnet transaction requires user confirmation",
}))
# 汇总结果
all_passed = all(c[1].get("passed", False) for c in checks)
return {
"passed": all_passed,
"checks": checks,
"blocking_issues": [
c[1]["message"] for c in checks
if not c[1].get("passed", False) and "message" in c[1]
],
}
async def verify_chain_id(rpc_url: str, expected_chain_id: str) -> dict:
"""通过 RPC 验证链 ID"""
import aiohttp
try:
async with aiohttp.ClientSession() as session:
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "status",
"params": [],
}
async with session.post(rpc_url, json=payload) as resp:
data = await resp.json()
actual = data.get("result", {}).get("node_info", {}).get("network")
if actual == expected_chain_id:
return {"passed": True}
else:
return {
"passed": False,
"message": f"Chain ID mismatch: expected {expected_chain_id}, got {actual}",
}
except Exception as e:
return {
"passed": False,
"message": f"Failed to verify chain ID: {e}",
}
def validate_gas_price(gas_price: float, gas_price_step: dict) -> dict:
"""验证 gas 价格是否在合理范围"""
if not gas_price_step:
return {"passed": True, "message": "No gas price step config for comparison"}
low = gas_price_step.get("low", 0)
high = gas_price_step.get("high", 1000000000)
if gas_price < low:
return {
"passed": False,
"message": f"Gas price {gas_price} below minimum {low}",
}
if gas_price > high * 10:
return {
"passed": False,
"message": f"Gas price {gas_price} seems excessively high (max recommended: {high})",
}
return {"passed": True}
5.8 AI Agent 的代码生成规则
当 AI Agent 生成与 MSG Chain 交互的代码时,应遵守以下规则:
AI_CODE_GENERATION_RULES = {
"network_selection": {
"default": "local",
"require_confirmation_for": ["mainnet"],
"never_auto_select": ["testnet"],
},
"endpoint_usage": {
"never_hardcode": False,
"prefer_env_vars": True,
"fallback_to_config": True,
},
"faucet_calls": {
"never_auto_call": True,
"document_as_unavailable": True,
},
"transaction_generation": {
"include_chain_id_validation": True,
"include_address_prefix_check": True,
"include_gas_price_bounds": True,
},
"sdk_usage": {
"respect_verified_flag": True,
"do_not_bypass_unverified_guard": True,
},
}
5.9 地址生成的验证
def validate_msg_address(address: str) -> bool:
"""
验证 MSG Chain 地址的格式。
地址应为 bech32 格式,以 'msg' 开头。
"""
if not address:
return False
if not address.startswith("msg"):
return False
if len(address) < 20 or len(address) > 63:
return False
# bech32 字符集:qpzry9x8gf2tvdw0s3jn54khce6mua7l
valid_chars = set("qpzry9x8gf2tvdw0s3jn54khce6mua7l")
# 跳过前缀和分隔符 '1'
data_part = address.split("1")[-1] if "1" in address else address
for c in data_part:
if c not in valid_chars:
return False
return True
5.10 Gas 价格管理
def get_gas_price_for_priority(priority: str = "average") -> str:
"""
根据优先级获取 gas 价格字符串。
用于 CosmJS SigningStargateClient 的 GasPrice 初始化。
"""
gas_steps = {
"low": 1000000000,
"average": 1000000000,
"high": 1000000000,
}
price = gas_steps.get(priority, 1000000000)
return f"{price}attoMSG"
5.11 AI Agent 的配置决策树
flowchart TD
A[AI Agent 需要连接 MSG Chain] --> B{用户指定了网络?}
B -->|是| C[使用指定网络]
B -->|否| D{开发/生产?}
D -->|开发| E[local: msg-chain-local-1]
D -->|生产| F[mainnet: msg-chain-1]
D -->|测试| G[testnet 不可用<br/>fallback 到 local]
C --> H{指定了 testnet?}
H -->|是| I[报错: testnet fail-closed]
H -->|否| J[使用指定配置]
E --> K[验证 localhost 可达]
F --> L[要求用户确认]
L -->|确认| M[配置 mainnet 连接]
L -->|拒绝| N[不可执行操作]
5.12 默认配置与用户指定配置的合并
def merge_network_config(
default_config: dict,
user_overrides: dict,
) -> dict:
"""
合并默认配置与用户指定的覆盖配置。
用户覆盖优先。
"""
merged = default_config.copy()
for key, value in user_overrides.items():
if key in merged and isinstance(merged[key], dict) and isinstance(value, dict):
merged[key] = {**merged[key], **value}
else:
merged[key] = value
return merged
5.13 环境变量驱动的配置模式
import os
def config_from_environment() -> dict:
"""
从环境变量读取网络配置。
如果未设置环境变量,返回默认的 local 配置。
"""
network = os.getenv("MSG_NETWORK", "local")
if network == "mainnet":
return {
"chain_id": os.getenv("MSG_CHAIN_ID", "msg-chain-1"),
"rpc": os.getenv("MSG_RPC_URL", "https://rpc.msgchain.org"),
"rest": os.getenv("MSG_REST_URL", "https://api.msgchain.org"),
"grpc_host": os.getenv("MSG_GRPC_HOST", "msgchain-grpc.msgchain.org"),
"grpc_port": int(os.getenv("MSG_GRPC_PORT", "9090")),
"bech32_prefix": os.getenv("MSG_BECH32_PREFIX", "msg"),
}
elif network == "local":
return {
"chain_id": os.getenv("MSG_CHAIN_ID", "msg-chain-local-1"),
"rpc": os.getenv("MSG_RPC_URL", "http://localhost:26657"),
"rest": os.getenv("MSG_REST_URL", "http://localhost:1317"),
"grpc_host": os.getenv("MSG_GRPC_HOST", "localhost"),
"grpc_port": int(os.getenv("MSG_GRPC_PORT", "9090")),
"bech32_prefix": os.getenv("MSG_BECH32_PREFIX", "msg"),
}
else:
raise ValueError(f"Unknown MSG_NETWORK: {network}")
5.14 对 AI Agent 的最终建议
AI_AGENT_RECOMMENDATIONS = [
"始终从 chain_config/network_presets.json 获取链元数据基线",
"不要硬编码端点 URL,除非是从 verified source 获取",
"生成代码时默认使用 local 环境(msg-chain-local-1)",
"testnet 相关域名不可用,不要生成连接 testnet 的代码",
"不要在代码中假设有公开 faucet",
"生产部署前复核 endpoint 可用性、域名和证书",
"使用 chain_id 验证来确认连接的是正确的网络",
"每次生成交易代码时包含地址前缀验证",
"mainnet 操作必须要求用户确认",
"保持 SDK 的 verified 标记检查机制,不要绕过",
]
6. 边界声明
6.1 核心边界:公开沙箱未就绪
当前默认口径不是 public sandbox ready,而是 disabled/fail-closed + 明确 local development path。
来自 developer_sandbox_strategy.json 的原始边界:
当前公开口径是 Option B: disabled public sandbox with explicit local development path。
未看到 signed disabled manifest、public faucet absence proof 与 final signatures 前,
外部 AI 必须把 public devnet/testnet/faucet 视为不可用。
6.2 开发者能力矩阵中的边界
来自 developer_capability_matrix.json 中 public_sandbox_strategy 的边界:
当前默认口径不是 public sandbox ready,而是 disabled/fail-closed + 明确 local development path。
判断 public sandbox 是否可用 | 决定走 public testnet 还是 local-only starter |
避免把 admin/local faucet 误读成 public developer faucet
6.3 chain_config_pack 的边界
当前链配置来自仓库配置基线,生产接入前仍应复核 endpoint 可用性。
6.4 network_presets.json 的边界声明
"boundary": [
"链配置是接入基线,不等于 live/public 端点已经被正式接受为生产网络。",
"生产接入前仍需复核 endpoint 可用性、域名控制、证书、SLO 与发布权限。"
]
6.5 sandbox 策略的关闭边界
"closing_boundary": "This manifest chooses the conservative Option B local fail-closed
strategy only. It does not provide a public devnet, public testnet, public faucet,
signed disabled manifest, public SDK preset, external audit, final signatures,
or C total Go-No-Go."
6.6 五个已知阻塞项
来自 developer_sandbox_strategy.json 的 known_blockers:
| # | 阻塞项 | 状态 |
|---|---|---|
| 1 | signed_disabled_public_sandbox_manifest_missing | 未关闭 |
| 2 | sdk_preset_fail_closed_public_evidence_missing | 未关闭 |
| 3 | local_development_runbook_evidence_missing | 未关闭 |
| 4 | public_faucet_absence_boundary_missing | 未关闭 |
| 5 | external_audit_final_signatures_missing | 未关闭 |
AI Agent 需要注意:所有五个阻塞仍处于 missing 状态,
任何关于 testnet 或 faucet 可用的断言都是错误的。
6.7 留域名的 fail-closed 声明
所有 testnet 域名的状态均为 reserved_fail_closed,附注均为
testnet_not_launched_fail_closed。这意味着:
{
"testnet-rpc.msgchain.org": {
"state": "reserved_fail_closed",
"note": "testnet_not_launched_fail_closed"
},
"testnet-api.msgchain.org": {
"state": "reserved_fail_closed",
"note": "testnet_not_launched_fail_closed"
},
"testnet-faucet.msgchain.org": {
"state": "reserved_fail_closed",
"note": "testnet_not_launched_fail_closed"
},
"testnet-agent.msgchain.org": {
"state": "reserved_fail_closed",
"note": "testnet_not_launched_fail_closed"
}
}
6.8 水龙头不可用声明
| 项目 | 值 |
|---|---|
| faucet_mode | disabled_public_faucet |
| public_faucet_enabled | false |
| admin faucet not public | true(需证明) |
| SDK faucet path | disabled |
没有公开开发者水龙头。任何 AI 生成的代码中如果出现了水龙头调用,
应当被标记为潜在错误。
6.9 主网未就绪声明
"mainnet_verdict": "No-Go",
"mainnet_ready_claim": false
尽管主网端点(https://rpc.msgchain.org)在 network_presets 中列出,
但开发者沙箱策略中明确标记 mainnet verdict 为 "No-Go"。
这意味着:
- 端点存在但不等于"主网正式就绪"
- 生产接入仍需要做完整的验收
- AI Agent 不应自动假设主网是可用的生产环境
6.10 SDK 预设未验证
SDK 中的网络预设标记为 unverified:
mainnet_preset_verified_falsetestnet_preset_verified_false
SDK 的客户端默认拒绝未验证的预设:
client_rejects_unverified_presets_by_defaultindexer_rejects_unverified_presets_by_default
AI Agent 在使用 SDK 时,不应绕过这些防护。
如果需要连接到指定端点,应使用显式的端点参数而非 SDK 默认预设。
6.11 本地开发优先
local_development_path: "examples/ai-agent-dapp-starter with explicit endpoints only"
本地开发是当前唯一推荐的开发路径。
没有公开的 testnet、devnet 或 faucet 可用。
对于 AI Agent,这意味着:
- 生成的所有开发代码应以 localhost 端点为默认
- 不要假设可以连接到公共测试网
- 不要假设有公共水龙头可以获取测试代币
6.12 配置文件的元数据边界
所有 chain_config 文件标记为 metadata_profile: "public_stable",
但这仅表示文件的格式和结构已稳定,不代表其中引用的端点已就绪。
6.13 开发者引导中的边界
来自 developer_entry.json 的 current_boundaries:
当前开发协议层可显著提升 AI coding 的可执行性,
但仍不能诚实承诺"只靠入口即可 100% 自动完成任何产品上线"。
当前已补 Quick Start、source-backed 合约消费索引、正式 API/Schema 契约索引
与 fail-closed sandbox 策略,但仍不等于 signed public SDK、public sandbox
或 not independently verified for production 交付。
涉及私钥、部署权限、生产域名、资金操作、DAO/timelock/threshold 的动作,
必须保留人类确认与审批门禁。
6.14 需要人工输入的环节
来自 developer_entry.json 的 human_inputs_required:
[
"产品目标与业务规则",
"真实部署权限与签名账户",
"生产环境变量、域名、CI/CD 或发布权限",
"治理、多签、金库、审批等高风险动作的授权与窗口"
]
AI Agent 不能替代人类在这些环节中的决策。
6.15 本文档的边界说明
本文档基于以下真实数据源编写:
chain_config/index.jsonchain_config/network_presets.jsonchain_config/developer_sandbox_strategy.jsondeveloper_capability_matrix.jsondeveloper_entry.json
所有数据均取自 msgchain.org/whitepaper/ 的公开白皮书。
读者应直接参考上述源文件获取最新信息,本文档可能落后于源文件的更新。
6.16 对于 AI Agent 的最后边界声明
╔══════════════════════════════════════════════════════════════╗
║ AI AGENT BOUNDARY SUMMARY ║
╠══════════════════════════════════════════════════════════════╣
║ chain_config_pack → starter_ready, production: True ║
║ public_sandbox_strategy → fail_closed_ref, production: No ║
╠══════════════════════════════════════════════════════════════╣
║ Available: mainnet (needs confirmation), local ║
║ NOT available: testnet, devnet, public faucet ║
║ Primary dev path: local development only ║
║ SDK presets: unverified (do not bypass guards) ║
║ All testnet domains: reserved_fail_closed ║
╚══════════════════════════════════════════════════════════════╝
7. 附录:完整配置文件参考
7.1 chain_config/index.json
{
"schema_version": "v1",
"generated_by": "msg_whitepaper_pipeline_v1",
"files": [
{
"id": "network_presets",
"path": "chain_config/network_presets.json",
"public_url": "https://msgchain.org/whitepaper/chain_config/network_presets.json",
"description": "Machine-friendly MSG chain ID, endpoints, wallets, and currency defaults."
},
{
"id": "keplr_chain_info",
"path": "chain_config/keplr_chain_info.json",
"public_url": "https://msgchain.org/whitepaper/chain_config/keplr_chain_info.json",
"description": "Copied Keplr chain info baseline from repo configs."
},
{
"id": "keplr_suggest_chain",
"path": "chain_config/keplr_suggest_chain.js",
"public_url": "https://msgchain.org/whitepaper/chain_config/keplr_suggest_chain.js",
"description": "Keplr suggestChain helper copied from repo configs."
},
{
"id": "developer_sandbox_strategy",
"path": "chain_config/developer_sandbox_strategy.json",
"public_url": "https://msgchain.org/whitepaper/chain_config/developer_sandbox_strategy.json",
"description": "Current fail-closed public sandbox, testnet, and faucet strategy."
}
],
"metadata_profile": "public_stable"
}
7.2 developer_capability_matrix.json 相关条目
chain_config_pack
{
"surface_id": "chain_config_pack",
"title": "链配置与钱包注入包",
"machine_readiness": "starter_ready",
"machine_safe_for_codegen": true,
"write_path_ready": false,
"schema_available": true,
"example_available": true,
"production_supported": true,
"best_for": [
"前端链配置生成",
"Keplr suggestChain",
"CosmJS/钱包接入初始化"
],
"blocking_gaps": [
"缺少从 live/public 节点自动探测并签名确认的网络元数据机制"
],
"boundaries": [
"当前链配置来自仓库配置基线,生产接入前仍应复核 endpoint 可用性。"
]
}
public_sandbox_strategy
{
"surface_id": "public_sandbox_strategy",
"title": "Public Devnet /Testnet /Faucet 策略",
"machine_readiness": "fail_closed_reference",
"machine_safe_for_codegen": true,
"write_path_ready": false,
"schema_available": true,
"example_available": true,
"production_supported": false,
"best_for": [
"判断 public sandbox 是否可用",
"决定走 public testnet 还是 local-only starter",
"避免把 admin/local faucet 误读成 public developer faucet"
],
"blocking_gaps": [
"当前选择的是 Option B fail-closed 策略",
"signed disabled manifest、public faucet absence proof 与 final signatures 仍未关闭"
],
"boundaries": [
"当前默认口径不是 public sandbox ready,而是 disabled/fail-closed + 明确 local development path。"
]
}
7.3 developer_entry.json 中的引导顺序
"recommended_contract_bootstrap_order": [
"product_delivery_entry.json",
"developer_capability_matrix.json",
"quickstart/contract_and_dapp_minimal.json",
"chain_config/index.json",
"chain_config/developer_sandbox_strategy.json",
"api_specs/rpc_methods.json",
"api_specs/openapi/contract_surface.yaml",
"api_specs/formal_contracts.json",
"contract_reference/index.json",
"contract_reference/core_contracts.json",
"contract_templates/index.json",
"recipes/contract_minimal.json",
"execution_pack/index.json",
"execution_pack/command_registry.json",
"e2e_fixtures/index.json",
"modules/contract.html",
"modules/registry.html",
"modules/rpc.html",
"module_exports/contract.json"
]
7.4 常用工具命令速查
# 获取链状态
curl -s https://rpc.msgchain.org/status | jq .
# 获取链 ID
curl -s https://rpc.msgchain.org/status | jq -r '.result.node_info.network'
# 查询最新区块
curl -s https://rpc.msgchain.org/block | jq .
# 查询地址余额(替换地址)
curl -s https://api.msgchain.org/cosmos/bank/v1beta1/balances/msg1...
# 验证 bech32 地址格式
echo "msg1..." | grep -E '^msg[0-9a-z]{38,45}$'
# 本地开发节点(需要独立安装)
# msgd start --rpc.laddr tcp://0.0.0.0:26657
7.5 术语对照表
| 英文 | 中文 | 说明 |
|---|---|---|
| chain_config | 链配置 | MSG Chain 的机器可消费配置包 |
| network_presets | 网络预设 | 包含链 ID、端点、钱包、货币的预设文件 |
| sandbox strategy | 沙箱策略 | 关于 testnet/devnet/faucet 的可用性策略 |
| fail-closed | 故障关闭 | 默认关闭,除非明确证明可用 |
| reserved_fail_closed | 预留故障关闭 | 域名已预留但不可用 |
| starter_ready | 入门就绪 | 可以作为开发起点使用 |
| fail_closed_reference | 故障关闭参考 | 仅可读取参考,不可用于生成执行代码 |
| signed manifest | 签名清单 | 经过数字签名确认的声明文件 |
| production_ready | 生产就绪 | 经过完整验收,可用于生产环境 |
| bech32 prefix | 地址前缀 | Cosmos 标准地址的人类可读前缀部分 |
文档版本: v1.0
数据源: msgchain.org/whitepaper/
⚠️ No-Go Disclaimer: MSGChain 主网裁决为 No-Go。本文件所有内容反映的是开发阶段的技术设计,不代表主网未独立核验上线状态。生产部署状态请以白皮书为准:https://msgchain.org/whitepaper/
数据截止: chain_config 文件以public_stable元数据配置管线上一次发布为准
免责声明: 本文档基于公开数据编写,不构成 MSG Chain 的官方承诺。
所有配置和策略以 msgchainorg 上的最新版本为准。
