MSG Chain AI Agent 自治治理指南
版本: v1.0.0
链ID:msg-chain-1
Bech32 前缀:msg
治理合约:dao_governance_v1,foundation_treasury_v2,ai_agent_constitution_v1
⚠️ No-Go Disclaimer: MSGChain 主网裁决为 No-Go。本文件所有内容反映的是开发阶段的技术设计,不代表主网未独立核验上线状态。生产部署状态请以白皮书为准:https://msgchain.org/whitepaper/
目录
1. 概述
1.1 AI自治治理的定义
AI自治治理(AI Autonomous Governance)是指由AI Agent自主执行链上治理操作——包括提案提交、投票、执行——而无需人类逐一手动签名。在MSG Chain上,AI Agent并非"取代"人类治理,而是在宪法约束 + DAO投票 + Timelock三层安全框架内,作为自动化治理执行者运行。
核心原则:
- AI Agent 不能绕过 DAO投票和Timelock
- AI Agent 必须遵守
ai_agent_constitution_v1中定义的规则 - AI Agent 不能自行批准 自己的财库支出(需人类Multi-sig)
- 所有AI治理操作均记录在链上审计日志中
1.2 当前状态(Reality vs Vision)
| 维度 | 当前状态 | 愿景 |
|---|---|---|
| 链上治理合约 | dao_governance_v1 已部署 |
— |
| AI宪法 | ai_agent_constitution_v1 已部署 |
— |
| 财库合约 | foundation_treasury_v2 已部署 |
— |
| 治理Agent API | governance/* 端点未实现 |
原生Agent API端点 |
| AI自动提案 | 通过Cosmos SDK CLI手动触发 | 完全自主提案 |
| AI自动投票 | 需编程调用合约 | 策略引擎自动投票 |
| 人类控制 | KillSwitch未接入 | 全局紧急暂停 |
关键标记: 所有
governance/*原生Agent API端点当前标记为// X-MSG-Stub=true,表示尚未上线。
1.3 与主流治理框架对比
| 特性 | MSG Chain | DAO DAO | Compound Governance |
|---|---|---|---|
| 提案-投票-执行 | ✅ dao_governance_v1 |
✅ | ✅ GovernorBravo |
| Timelock | ✅ timelock 合约 |
✅ | ✅ TimelockController |
| Token加权投票 | ✅ 内置 | ✅ | ✅ COMP加权 |
| 委托投票 | ✅ 支持 | ✅ | ✅ 支持 |
| AI宪法约束 | ✅ ai_agent_constitution_v1 |
❌ | ❌ |
| 治理Agent | 🔄 开发中 | ❌ | ❌ |
| AI原生API | ❌ // X-MSG-Stub=true |
❌ | ❌ |
MSG Chain的独特定位在于为AI Agent设计了专门的宪法约束层,这在DAO DAO和Compound治理中均不存在。类似Compound GovernorBravo的提案生命周期,但增加了AI特定的前置检查和规则引擎。
2. 现有治理底座
MSG Chain的治理底座由三层构成,从底层链参数治理到顶层财库管理:
+---------------------------------------+
| foundation_treasury_v2 | <- 财库/资金管理
+---------------------------------------+
| dao_governance_v1 | <- DAO治理(提案/投票/执行)
+---------------------------------------+
| ai_agent_constitution_v1 | <- AI宪法约束
+---------------------------------------+
| Cosmos SDK gov Module | <- 链参数/验证人治理
+---------------------------------------+
2.1 Cosmos SDK gov Module(链参数治理)
MSG Chain基于Cosmos SDK构建,底层 x/gov module 处理链级别的参数变更和验证人治理。
2.1.1 查询治理参数
# 查询治理模块参数
msgd query gov params --node https://rpc.msg-chain.ai:26657 --chain-id msg-chain-1
# 查询提案
msgd query gov proposal 1 --node https://rpc.msg-chain.ai:26657
# 列出所有提案
msgd query gov proposals --limit 50 --node https://rpc.msg-chain.ai:26657
# 查询投票
msgd query gov vote 1 msg1abc...def --node https://rpc.msg-chain.ai:26657
# 查询验证人
msgd query staking validators --node https://rpc.msg-chain.ai:26657
2.1.2 提交链参数提案
# 提交参数变更提案(人类操作)
msgd tx gov submit-proposal param-change increase_block_gas.json \
--from gov_admin \
--gas-prices 1000000000attoMSG \
--gas auto \
--gas-adjustment 1.5 \
--chain-id msg-chain-1 \
--node https://rpc.msg-chain.ai:26657 \
-y
# proposal.json 示例
cat > increase_block_gas.json << 'EOF'
{
"title": "Increase Max Block Gas",
"description": "Increase maximum block gas from 30M to 50M to accommodate more AI agent transactions",
"changes": [
{
"subspace": "baseapp",
"key": "BlockParams",
"value": "{\"max_bytes\":\"22020096\",\"max_gas\":\"50000000\"}"
}
],
"deposit": "1000000000umsg"
}
EOF
2.1.3 投票
# 投票
msgd tx gov vote 1 Yes \
--from validator1 \
--gas-prices 1000000000attoMSG \
--gas auto \
--chain-id msg-chain-1 \
-y
2.2 dao_governance_v1(DAO治理合约)
dao_governance_v1 是MSG Chain上DAO治理的核心合约,处理提案的全生命周期:创建 -> 投票 -> 执行。类似Compound GovernorBravo的提案流,但增加了Timelock强制等待期。
2.2.1 合约消息定义
// 完整合约消息定义
pub enum ExecuteMsg {
/// 提交新提案
SubmitProposal {
title: String,
description: String,
msgs: Vec<CosmosMsg>,
deposit: Vec<Coin>,
metadata: Option<String>,
},
/// 对指定提案投票
Vote {
proposal_id: u64,
vote: VoteOption,
},
/// 执行已通过的提案
ExecuteProposal {
proposal_id: u64,
},
/// 取消提案(仅提案者可调用,或管理员)
CancelProposal {
proposal_id: u64,
},
/// 更新治理配置
UpdateConfig {
config: GovernanceConfig,
},
}
pub enum QueryMsg {
/// 获取单个提案详情
GetProposal { proposal_id: u64 },
/// 列出提案(支持分页和状态过滤)
ListProposals {
start_after: Option<u64>,
limit: Option<u32>,
status: Option<ProposalStatus>,
},
/// 获取某人在某提案上的投票
GetVote { proposal_id: u64, voter: String },
/// 获取当前治理配置
GetConfig {},
/// 获取提案票数统计
GetProposalTally { proposal_id: u64 },
}
pub enum VoteOption {
Yes,
No,
Abstain,
Veto,
}
pub enum ProposalStatus {
Pending,
Open,
Passed,
Executed,
Rejected,
Cancelled,
Timelocked,
}
2.2.2 合约部署与初始化
# 部署 dao_governance_v1 合约
msgd tx wasm store ./artifacts/dao_governance_v1.wasm \
--from deployer \
--gas-prices 1000000000attoMSG \
--gas auto \
--gas-adjustment 1.5 \
--chain-id msg-chain-1 \
-y
# 查询已部署的代码ID
msgd query wasm list-code --node https://rpc.msg-chain.ai:26657
# 实例化治理合约(假设 code_id=3)
INIT='{
"config": {
"voting_period": {"time": 86400},
"timelock_period": {"time": 43200},
"quorum": "0.04",
"threshold": "0.50",
"veto_threshold": "0.334",
"proposal_deposit": [{"denom": "umsg", "amount": "100000000"}],
"max_deposit_period": {"time": 604800}
}
}'
msgd tx wasm instantiate 3 "$INIT" \
--label "dao_governance_v1" \
--admin msg1admin...def \
--from deployer \
--gas-prices 1000000000attoMSG \
--gas auto \
--chain-id msg-chain-1 \
-y
# 获取合约地址
GOV_CONTRACT=$(msgd query wasm list-contract-by-code 3 --output json | jq -r '.contracts[-1]')
echo "Governance Contract: $GOV_CONTRACT"
2.2.3 提交提案
# 提交提案
PROPOSAL_MSG='{
"submit_proposal": {
"title": "Upgrade AI Agent Gas Subsidy Program",
"description": "This proposal allocates 5000 MSG tokens to subsidize gas fees for AI agent operations.",
"msgs": [
{
"bank": {
"send": {
"to_address": "msg1subsidy...addr",
"amount": [{"denom": "umsg", "amount": "5000000000000"}]
}
}
}
],
"deposit": [{"denom": "umsg", "amount": "100000000"}],
"metadata": "{\"agent_id\": \"governance-bot-v1\", \"proposal_type\": \"treasury_spend\"}"
}
}'
msgd tx wasm execute "$GOV_CONTRACT" "$PROPOSAL_MSG" \
--from proposer \
--amount 100000000umsg \
--gas-prices 1000000000attoMSG \
--gas auto \
--chain-id msg-chain-1 \
-y
2.2.4 投票
# 投票 Yes
msgd tx wasm execute "$GOV_CONTRACT" '{"vote": {"proposal_id": 1, "vote": "yes"}}' \
--from voter1 --gas-prices 1000000000attoMSG --gas auto -y
# 投票 No
msgd tx wasm execute "$GOV_CONTRACT" '{"vote": {"proposal_id": 1, "vote": "no"}}' \
--from voter2 --gas-prices 1000000000attoMSG --gas auto -y
# 投票 Veto
msgd tx wasm execute "$GOV_CONTRACT" '{"vote": {"proposal_id": 1, "vote": "veto"}}' \
--from voter3 --gas-prices 1000000000attoMSG --gas auto -y
2.2.5 执行提案
# 查询提案状态
msgd query wasm contract-state smart "$GOV_CONTRACT" \
'{"get_proposal": {"proposal_id": 1}}' --node https://rpc.msg-chain.ai:26657
# 执行已通过的提案
msgd tx wasm execute "$GOV_CONTRACT" '{"execute_proposal": {"proposal_id": 1}}' \
--from executor --gas-prices 1000000000attoMSG --gas auto -y
2.2.6 查询接口
# 查询所有提案
msgd query wasm contract-state smart "$GOV_CONTRACT" \
'{"list_proposals": {"limit": 10}}' --node https://rpc.msg-chain.ai:26657
# 按状态过滤
msgd query wasm contract-state smart "$GOV_CONTRACT" \
'{"list_proposals": {"status": "open", "limit": 10}}' --node https://rpc.msg-chain.ai:26657
# 查询票数统计
msgd query wasm contract-state smart "$GOV_CONTRACT" \
'{"get_proposal_tally": {"proposal_id": 1}}' --node https://rpc.msg-chain.ai:26657
2.3 foundation_treasury_v2(财库管理合约)
2.3.1 合约消息定义
pub enum ExecuteMsg {
ProposeSpend {
title: String,
description: String,
recipient: String,
amount: Vec<Coin>,
},
ApproveSpend {
proposal_id: u64,
},
ExecuteSpend {
proposal_id: u64,
},
AddSigner {
signer: String,
},
RemoveSigner {
signer: String,
},
}
pub struct TreasuryConfig {
pub signers: Vec<String>,
pub required_approvals: u64,
pub spend_limit: Vec<Coin>,
pub high_value_threshold: Vec<Coin>,
}
pub struct SpendProposal {
pub id: u64,
pub title: String,
pub description: String,
pub recipient: String,
pub amount: Vec<Coin>,
pub proposer: String,
pub approvals: Vec<String>,
pub executed: bool,
pub created_at: Timestamp,
}
2.3.2 部署与操作
# 部署
TREASURY_INIT='{
"signers": ["msg1signer1...","msg1signer2...","msg1signer3..."],
"required_approvals": 2,
"spend_limit": [{"denom": "umsg", "amount": "1000000000000"}],
"high_value_threshold": [{"denom": "umsg", "amount": "10000000000000"}]
}'
msgd tx wasm instantiate 5 "$TREASURY_INIT" \
--label "foundation_treasury_v2" --admin msg1admin...def --from deployer \
--gas-prices 1000000000attoMSG --gas auto --chain-id msg-chain-1 -y
# 提议支出
msgd tx wasm execute "$TREASURY_CONTRACT" '{
"propose_spend": {
"title": "AI Agent Research Grant",
"description": "Funding for Autonomous AI Agent research",
"recipient": "msg1researcher...addr",
"amount": [{"denom": "umsg", "amount": "500000000000"}]
}
}' --from signer1 --gas-prices 1000000000attoMSG --gas auto -y
# 批准支出
msgd tx wasm execute "$TREASURY_CONTRACT" '{"approve_spend": {"proposal_id": 1}}' \
--from signer2 --gas-prices 1000000000attoMSG --gas auto -y
# 执行支出
msgd tx wasm execute "$TREASURY_CONTRACT" '{"execute_spend": {"proposal_id": 1}}' \
--from signer1 --gas-prices 1000000000attoMSG --gas auto -y
2.4 链配置参数
chain_id: msg-chain-1
bech32_prefix: msg
rpc_endpoints:
- https://rpc.msg-chain.ai:26657
- https://rpc2.msg-chain.ai:26657
gas_prices:
low: 1000000000attoMSG
average: 1000000000attoMSG
high: 1000000000attoMSG
block_time: 5s
2.5 治理底座完整性总结
| 组件 | 状态 | 功能 | AI可调用 |
|---|---|---|---|
| Cosmos SDK x/gov | 未独立核验上线状态 | 链参数变更 | 间接 |
| dao_governance_v1 | 未独立核验上线状态 | DAO提案/投票/执行 | 需宪法检查 |
| foundation_treasury_v2 | 未独立核验上线状态 | 财库Multi-sig | 仅人类签名 |
| ai_agent_constitution_v1 | 未独立核验上线状态 | AI宪法约束 | 前置检查 |
| governance/* Agent API | Stub | 原生Agent端点 | N/A |
3. AI宪法约束层
ai_agent_constitution_v1 是MSG Chain治理架构中最具特色的组件——它为AI Agent的行为设定了一套可编程的"宪法"规则。任何AI Agent在发起治理操作前,必须调用 IsActionAllowed 进行检查。类似Compound GovernorBravo的治理流程之前置安全检查。
3.1 宪法合约核心概念
每条规则(Rule)包含:
rule_id: 唯一标识符rule_text: 规则描述(人类可读)category: 分类(governance, treasury, security, operational)priority: 优先级(数值越大越优先)constraints: 可选约束条件(编码为Binary)
3.2 合约消息定义
use cosmwasm_std::{
entry_point, to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response,
StdResult, Storage, Addr, StdError,
};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Constitution {
pub preamble: String,
pub active: bool,
pub version: String,
pub created_at: u64,
pub updated_at: u64,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Rule {
pub rule_id: String,
pub rule_text: String,
pub category: RuleCategory,
pub priority: u32,
pub active: bool,
pub constraints: Option<Binary>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum RuleCategory {
Governance,
Treasury,
Security,
Operational,
Custom(String),
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ActionCheckResult {
pub allowed: bool,
pub matched_rules: Vec<String>,
pub violated_rules: Vec<String>,
pub reason: String,
}
pub enum ExecuteMsg {
UpdateConstitution { preamble: Option<String>, active: Option<bool> },
AddRule { rule_id: String, rule_text: String, category: String, priority: u32, constraints: Option<Binary> },
RemoveRule { rule_id: String },
UpdateRule { rule_id: String, rule_text: Option<String>, category: Option<String>, priority: Option<u32>, active: Option<bool>, constraints: Option<Binary> },
SetActive { active: bool },
}
pub enum QueryMsg {
GetConstitution {},
GetRule { rule_id: String },
ListRules { category: Option<String>, start_after: Option<String>, limit: Option<u32> },
IsActionAllowed { action: String, context: Option<Binary> },
GetActiveStatus {},
}
3.3 IsActionAllowed 核心实现
#[entry_point]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
match msg {
QueryMsg::IsActionAllowed { action, context } => {
to_binary(&query_is_action_allowed(deps, action, context)?)
}
_ => { /* other queries */ }
}
}
fn query_is_action_allowed(
deps: Deps,
action: String,
context: Option<Binary>,
) -> StdResult<ActionCheckResult> {
let constitution = get_constitution(deps.storage)?;
if !constitution.active {
return Ok(ActionCheckResult {
allowed: false,
matched_rules: vec![],
violated_rules: vec!["constitution_inactive".to_string()],
reason: "Constitution is currently inactive. All actions are blocked.".to_string(),
});
}
let mut matched_rules: Vec<String> = vec![];
let mut violated_rules: Vec<String> = vec![];
let mut allowed = true;
let all_rules: StdResult<Vec<Rule>> = deps.storage
.range(b"rule", None, cosmwasm_std::Order::Ascending)
.map(|item| {
let (_, data) = item?;
cosmwasm_std::from_binary::<Rule>(&data)
})
.collect();
let all_rules = all_rules?;
let mut sorted_rules = all_rules.clone();
sorted_rules.sort_by(|a, b| b.priority.cmp(&a.priority));
for rule in &sorted_rules {
if !rule.active { continue; }
if action_matches_rule(&action, rule) {
matched_rules.push(rule.rule_id.clone());
if !evaluate_rule_constraints(&action, rule, &context) {
violated_rules.push(rule.rule_id.clone());
allowed = false;
}
}
}
let reason = if allowed {
"Action is permitted by all matching constitutional rules.".to_string()
} else {
format!("Action violates rules: {}. Action is blocked.", violated_rules.join(", "))
};
Ok(ActionCheckResult { allowed, matched_rules, violated_rules, reason })
}
fn action_matches_rule(action: &str, rule: &Rule) -> bool {
match rule.category {
RuleCategory::Governance => {
action.starts_with("governance/") || action == "submit_proposal"
|| action == "vote" || action == "execute_proposal"
}
RuleCategory::Treasury => {
action.starts_with("treasury/") || action == "propose_spend"
}
RuleCategory::Security => {
action.starts_with("security/") || action == "update_config"
}
RuleCategory::Operational => {
action.starts_with("operational/") || action.starts_with("agent/")
}
RuleCategory::Custom(ref cat) => action.contains(cat),
}
}
fn evaluate_rule_constraints(
action: &str, rule: &Rule, context: &Option<Binary>,
) -> bool {
if let Some(ref constraints) = rule.constraints {
let constraints_str = String::from_utf8(constraints.to_vec()).unwrap_or_default();
if let Ok(constraints_obj) = serde_json::from_str::<serde_json::Value>(&constraints_str) {
if let Some(max_amount) = constraints_obj.get("max_amount") {
if let Some(ctx) = context {
let ctx_str = String::from_utf8(ctx.to_vec()).unwrap_or_default();
if let Ok(ctx_obj) = serde_json::from_str::<serde_json::Value>(&ctx_str) {
if let Some(amount) = ctx_obj.get("amount") {
let max = max_amount.as_str().unwrap_or("0").parse::<u128>().unwrap_or(0);
let actual = amount.as_str().unwrap_or("0").parse::<u128>().unwrap_or(0);
if actual > max { return false; }
}
}
}
}
}
}
true
}
3.4 宪法合约测试
#[cfg(test)]
mod tests {
use super::*;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
fn setup() -> (DepsMut, Env) {
let mut deps = mock_dependencies();
let env = mock_env();
let info = mock_info("admin", &[]);
// Instantiate with preamble
deps.as_mut()
(deps.as_mut(), env)
}
#[test]
fn test_action_allowed_with_constraints() {
let (mut deps, env) = setup();
let info = mock_info("admin", &[]);
// Add a treasury limit rule
execute(deps.as_mut(), env.clone(), info, ExecuteMsg::AddRule {
rule_id: "treasury_limit".to_string(),
rule_text: "Max spend 1000 MSG".to_string(),
category: "treasury".to_string(),
priority: 100,
constraints: Some(Binary::from(
serde_json::json!({"max_amount": "1000000000000"}).to_string().as_bytes()
)),
}).unwrap();
// Action within limit should pass
let ctx_ok = Some(Binary::from(
serde_json::json!({"amount": "500000000000"}).to_string().as_bytes()
));
let result = query_is_action_allowed(
deps.as_ref(), "propose_spend".to_string(), ctx_ok,
).unwrap();
assert!(result.allowed);
// Action over limit should fail
let ctx_over = Some(Binary::from(
serde_json::json!({"amount": "2000000000000"}).to_string().as_bytes()
));
let result = query_is_action_allowed(
deps.as_ref(), "propose_spend".to_string(), ctx_over,
).unwrap();
assert!(!result.allowed);
assert!(result.violated_rules.contains(&"treasury_limit".to_string()));
}
#[test]
fn test_inactive_constitution_blocks_all() {
let (mut deps, env) = setup();
execute(deps.as_mut(), env.clone(), mock_info("admin", &[]),
ExecuteMsg::SetActive { active: false }).unwrap();
let result = query_is_action_allowed(
deps.as_ref(), "submit_proposal".to_string(), None,
).unwrap();
assert!(!result.allowed);
}
}
3.5 TypeScript 客户端
export interface ActionCheckResult {
allowed: boolean;
matched_rules: string[];
violated_rules: string[];
reason: string;
}
export class ConstitutionClient {
private client: CosmWasmClient;
private contractAddress: string;
constructor(client: CosmWasmClient, contractAddress: string) {
this.client = client;
this.contractAddress = contractAddress;
}
async isActionAllowed(
action: string,
context?: Record<string, unknown>,
): Promise<ActionCheckResult> {
const contextBinary = context
? toBinary(Buffer.from(JSON.stringify(context)))
: undefined;
return this.client.queryContractSmart(this.contractAddress, {
is_action_allowed: { action, context: contextBinary },
});
}
async getActiveStatus(): Promise<boolean> {
return this.client.queryContractSmart(this.contractAddress, {
get_active_status: {},
});
}
async getConstitution(): Promise<Constitution> {
return this.client.queryContractSmart(this.contractAddress, {
get_constitution: {},
});
}
async getRule(ruleId: string): Promise<Rule> {
return this.client.queryContractSmart(this.contractAddress, {
get_rule: { rule_id: ruleId },
});
}
async listRules(params?: {
category?: string;
startAfter?: string;
limit?: number;
}): Promise<Rule[]> {
return this.client.queryContractSmart(this.contractAddress, {
list_rules: {
category: params?.category,
start_after: params?.startAfter,
limit: params?.limit,
},
});
}
}
3.6 ConstitutionGuard 守卫
export class ConstitutionGuard {
private client: ConstitutionClient;
constructor(client: ConstitutionClient) {
this.client = client;
}
async guard(
action: string,
context?: Record<string, unknown>,
): Promise<ActionCheckResult> {
const isActive = await this.client.getActiveStatus();
if (!isActive) {
const result: ActionCheckResult = {
allowed: false,
matched_rules: [],
violated_rules: ['constitution_inactive'],
reason: 'Constitution is inactive. All actions blocked.',
};
throw new ConstitutionGuardError(result);
}
const result = await this.client.isActionAllowed(action, context);
if (!result.allowed) {
throw new ConstitutionGuardError(result);
}
return result;
}
async record(action: string, proposalId: number, agentId: string): Promise<void> {
console.log(
`[AUDIT] agent=${agentId} action=${action} proposal_id=${proposalId} timestamp=${Date.now()}`,
);
}
}
export class ConstitutionGuardError extends Error {
public checkResult: ActionCheckResult;
constructor(checkResult: ActionCheckResult) {
super(`Constitution guard blocked: ${checkResult.reason}`);
this.name = 'ConstitutionGuardError';
this.checkResult = checkResult;
}
}
3.7 部署宪法合约
# 编译
cargo wasm
# 存储合约代码
msgd tx wasm store ./target/wasm32-unknown-unknown/release/ai_agent_constitution_v1.wasm \
--from deployer --gas-prices 1000000000attoMSG --gas auto --gas-adjustment 1.5 \
--chain-id msg-chain-1 -y
# 实例化
msgd tx wasm instantiate 7 '{
"preamble": "MSG Chain AI Agent Constitution: All AI agent governance actions must respect DAO sovereignty, timelock delays, and constitutional rules."
}' --label "ai_agent_constitution_v1" --admin msg1admin...def --from deployer \
--gas-prices 1000000000attoMSG --gas auto --chain-id msg-chain-1 -y
CONST_CONTRACT=$(msgd query wasm list-contract-by-code 7 --output json | jq -r '.contracts[-1]')
# 添加初始规则
msgd tx wasm execute "$CONST_CONTRACT" '{
"add_rule": {
"rule_id": "self_modification_ban",
"rule_text": "AI Agent must not directly modify the AI Constitution.",
"category": "security",
"priority": 999,
"constraints": null
}
}' --from admin --gas-prices 1000000000attoMSG --gas auto -y
msgd tx wasm execute "$CONST_CONTRACT" '{
"add_rule": {
"rule_id": "timelock_mandatory",
"rule_text": "AI Agent must respect the timelock period on all passed proposals.",
"category": "governance",
"priority": 99,
"constraints": null
}
}' --from admin --gas-prices 1000000000attoMSG --gas auto -y
msgd tx wasm execute "$CONST_CONTRACT" '{
"add_rule": {
"rule_id": "treasury_spend_limit",
"rule_text": "AI Agent must not submit treasury spend proposals exceeding 1000 MSG without DAO approval.",
"category": "treasury",
"priority": 100,
"constraints": {
"max_amount": "1000000000000"
}
}
}' --from admin --gas-prices 1000000000attoMSG --gas auto -y
msgd tx wasm execute "$CONST_CONTRACT" '{
"add_rule": {
"rule_id": "audit_log_mandatory",
"rule_text": "All AI governance actions must emit audit log events.",
"category": "operational",
"priority": 50,
"constraints": null
}
}' --from admin --gas-prices 1000000000attoMSG --gas auto -y
3.8 宪法规则最佳实践
| 规则ID | 优先级 | 分类 | 效果 |
|---|---|---|---|
self_modification_ban |
999 | Security | AI不能自行修改宪法 |
timelock_mandatory |
99 | Governance | 强制Timelock等待 |
treasury_spend_limit |
100 | Treasury | 限制财库支出上限 |
audit_log_mandatory |
50 | Operational | 所有操作记录审计日志 |
4. AI提案流程
AI Agent的自治提案流程从"感知链上状态"到"执行通过提案"共七步。每个步骤都受ConstitutionGuard的约束。
4.1 流程总览
Step 1: AI分析链上状态
+-- 读取治理配置、提案列表、财库余额
|
Step 2: AI决策 -> 决定需要什么操作
+-- 基于预设策略或LLM推理
|
Step 3: AI宪法检查 <- 关键安全门
+-- 调用 IsActionAllowed
|
Step 4: AI构建提案
+-- 生成 title + description + msgs + deposit
|
Step 5: AI提交提案 (via Agent API)
+-- 调用 SubmitProposal // X-MSG-Stub=true
|
Step 6: AI监控提案状态
+-- 轮询 GetProposal,等待投票期结束
|
Step 7: AI投票 (按策略)
+-- 根据预设策略自动投票
|
Step 8: AI执行 (Timelock后)
+-- 等待 Timelock 结束后执行
4.2 AutonomousGovernanceAgent 完整实现
import { CosmWasmClient, SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate';
import { Coin } from '@cosmjs/amino';
import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing';
import { ConstitutionClient, ConstitutionGuard } from './ConstitutionClient';
import { GovernanceClient } from './GovernanceClient';
export interface AgentConfig {
agentId: string;
rpcEndpoint: string;
contractAddresses: {
governance: string;
constitution: string;
treasury: string;
};
mnemonic: string;
votingStrategy: string;
checkIntervalMs: number;
}
export interface ProposalInfo {
id: number;
title: string;
description: string;
status: string;
proposer: string;
submitTime: string;
votingEnd: string | null;
timelockEnd: string | null;
totalYes: string;
totalNo: string;
totalAbstain: string;
totalVeto: string;
}
export interface VoteDecision {
proposalId: number;
vote: 'yes' | 'no' | 'abstain' | 'veto';
rationale: string;
}
export class AutonomousGovernanceAgent {
private config: AgentConfig;
private client: CosmWasmClient;
private signingClient: SigningCosmWasmClient;
private constitutionClient: ConstitutionClient;
private governanceClient: GovernanceClient;
private constitutionGuard: ConstitutionGuard;
private agentAddress: string;
private knownProposals: Map<number, ProposalInfo> = new Map();
private activeMonitors: Map<number, NodeJS.Timeout> = new Map();
constructor(config: AgentConfig) {
this.config = config;
}
async initialize(): Promise<void> {
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(this.config.mnemonic, {
prefix: 'msg',
});
this.agentAddress = (await wallet.getAccounts())[0].address;
this.client = await CosmWasmClient.connect(this.config.rpcEndpoint);
this.signingClient = await SigningCosmWasmClient.connectWithSigner(
this.config.rpcEndpoint, wallet,
);
this.constitutionClient = new ConstitutionClient(
this.client, this.config.contractAddresses.constitution,
);
this.governanceClient = new GovernanceClient(
this.client, this.config.contractAddresses.governance, this.signingClient,
);
this.constitutionGuard = new ConstitutionGuard(this.constitutionClient);
console.log(`[${this.config.agentId}] Agent initialized at ${this.agentAddress}`);
}
// ===== Step 1: 感知链上状态 =====
async analyzeOnChainState(): Promise<{
openProposals: ProposalInfo[];
governanceConfig: Record<string, unknown>;
constitutionActive: boolean;
}> {
console.log(`[${this.config.agentId}] Analyzing on-chain state...`);
const governanceConfig = await this.governanceClient.getConfig();
const constitutionActive = await this.constitutionClient.getActiveStatus();
const openProposals = await this.governanceClient.listProposals({
status: 'open', limit: 20,
});
console.log(
`[${this.config.agentId}] State: ${openProposals.length} open, constitution=${constitutionActive}`,
);
return { openProposals, governanceConfig, constitutionActive };
}
// ===== Step 2: AI决策 =====
async decideAction(state: {
openProposals: ProposalInfo[];
governanceConfig: Record<string, unknown>;
}): Promise<Array<{
actionType: 'submit_proposal' | 'vote' | 'execute' | 'cancel';
target?: number;
rationale: string;
proposal?: {
title: string;
description: string;
msgs: Array<Record<string, unknown>>;
deposit: Coin[];
};
vote?: 'yes' | 'no' | 'abstain' | 'veto';
}>> {
const decisions: Array<any> = [];
// 策略1: 对每个开放提案投票
for (const proposal of state.openProposals) {
try {
const existing = await this.governanceClient.getVote(proposal.id, this.agentAddress);
if (existing) continue;
} catch { /* not yet voted */ }
const voteDecision = await this.evaluateProposal(proposal);
decisions.push({
actionType: 'vote',
target: proposal.id,
rationale: voteDecision.rationale,
vote: voteDecision.vote,
});
}
// 策略2: 检查是否需要新提案
const needsNewProposal = await this.checkProposalNeed(state);
if (needsNewProposal) {
decisions.push(needsNewProposal);
}
// 策略3: 检查可执行的提案
const executable = await this.findExecutableProposals();
for (const p of executable) {
decisions.push({
actionType: 'execute',
target: p.id,
rationale: `Proposal ${p.id} timelock expired`,
});
}
return decisions;
}
private async evaluateProposal(proposal: ProposalInfo): Promise<VoteDecision> {
const vote = await this.ruleBasedVoteEvaluation(proposal);
return {
proposalId: proposal.id,
vote,
rationale: `Rule-based eval: ${vote}`,
};
}
private async ruleBasedVoteEvaluation(
proposal: ProposalInfo,
): Promise<'yes' | 'no' | 'abstain' | 'veto'> {
const desc = proposal.description.toLowerCase();
const title = proposal.title.toLowerCase();
const unsafe = ['malicious', 'backdoor', 'bypass', 'admin takeover'];
for (const kw of unsafe) {
if (desc.includes(kw) || title.includes(kw)) return 'veto';
}
if (desc.includes('treasury') || desc.includes('spend')) {
const m = proposal.description.match(/(\d+)\s*MSG/i);
if (m && parseInt(m[1]) > 10000) return 'abstain';
}
const positive = ['upgrade', 'improve', 'optimize', 'grant', 'subsidy', 'development'];
for (const kw of positive) {
if (desc.includes(kw) || title.includes(kw)) return 'yes';
}
return 'abstain';
}
private async checkProposalNeed(state: any): Promise<any> {
// X-MSG-Stub=true: 完整策略待实现
return null;
}
private async findExecutableProposals(): Promise<ProposalInfo[]> {
const proposals = await this.governanceClient.listProposals({
status: 'timelocked', limit: 20,
});
const now = Date.now();
return proposals.filter((p) => {
if (p.timelockEnd) {
return new Date(p.timelockEnd).getTime() <= now;
}
return false;
});
}
// ===== Step 3: 宪法检查 =====
async checkConstitution(action: string, context?: Record<string, unknown>): Promise<void> {
console.log(`[${this.config.agentId}] Constitution check: ${action}`);
try {
await this.constitutionGuard.guard(action, context);
console.log(`[${this.config.agentId}] Constitution passed`);
} catch (error) {
console.error(`[${this.config.agentId}] Constitution blocked: ${action}`);
throw error;
}
}
// ===== Step 4: 构建提案 =====
buildProposalMessage(params: {
title: string;
description: string;
msgs: Array<Record<string, unknown>>;
deposit: Coin[];
}): Record<string, unknown> {
return {
submit_proposal: {
title: params.title,
description: params.description,
msgs: params.msgs,
deposit: params.deposit,
metadata: JSON.stringify({
agent_id: this.config.agentId,
submitted_at: new Date().toISOString(),
}),
},
};
}
// ===== Step 5: 提交提案 =====
// X-MSG-Stub=true: governance/* Agent API 未实现,回退到直接合约调用
async submitProposal(params: {
title: string;
description: string;
msgs: Array<Record<string, unknown>>;
deposit: Coin[];
}): Promise<number> {
await this.checkConstitution('submit_proposal', {
title: params.title,
description_length: params.description.length,
msgs_count: params.msgs.length,
deposit_amount: params.deposit[0]?.amount || '0',
});
console.log(`[${this.config.agentId}] Submitting: "${params.title}"`);
const msg = this.buildProposalMessage(params);
const result = await this.signingClient.execute(
this.agentAddress,
this.config.contractAddresses.governance,
msg,
'auto',
undefined,
params.deposit,
);
const proposalId = this.parseProposalIdFromEvents(result.events, result.transactionHash);
console.log(`[${this.config.agentId}] Submitted proposal #${proposalId}`);
await this.constitutionGuard.record('submit_proposal', proposalId, this.config.agentId);
return proposalId;
}
private parseProposalIdFromEvents(
events: Array<{ type: string; attributes: Array<{ key: string; value: string }> }>,
txHash: string,
): number {
for (const event of events) {
if (event.type === 'wasm') {
for (const attr of event.attributes) {
if (attr.key === 'proposal_id') return parseInt(attr.value, 10);
}
}
}
console.warn(`No proposal_id in events for tx ${txHash}`);
return 0;
}
// ===== Step 6: 监控提案状态 =====
async monitorProposal(proposalId: number): Promise<void> {
console.log(`[${this.config.agentId}] Monitoring #${proposalId}`);
const checkStatus = async () => {
try {
const proposal = await this.governanceClient.getProposal(proposalId);
this.knownProposals.set(proposalId, proposal);
console.log(`[${this.config.agentId}] Proposal #${proposalId} status: ${proposal.status}`);
switch (proposal.status) {
case 'passed':
console.log(`[${this.config.agentId}] Proposal #${proposalId} passed`);
break;
case 'timelocked':
if (proposal.timelockEnd) {
if (new Date(proposal.timelockEnd).getTime() <= Date.now()) {
await this.executeProposal(proposalId);
}
}
break;
case 'executed':
console.log(`[${this.config.agentId}] Executed #${proposalId}`);
this.stopMonitoring(proposalId);
break;
case 'rejected':
case 'cancelled':
console.log(`[${this.config.agentId}] ${proposal.status} #${proposalId}`);
this.stopMonitoring(proposalId);
break;
}
} catch (error) {
console.error(`Monitor error #${proposalId}:`, error);
}
};
await checkStatus();
const interval = setInterval(checkStatus, this.config.checkIntervalMs);
this.activeMonitors.set(proposalId, interval);
}
stopMonitoring(proposalId: number): void {
const interval = this.activeMonitors.get(proposalId);
if (interval) {
clearInterval(interval);
this.activeMonitors.delete(proposalId);
}
}
async monitorAllActive(): Promise<void> {
const proposals = await this.governanceClient.listProposals({ status: 'open', limit: 50 });
for (const p of proposals) {
if (!this.activeMonitors.has(p.id)) await this.monitorProposal(p.id);
}
}
// ===== Step 7: AI投票 =====
async autoVote(proposalId: number, vote: 'yes' | 'no' | 'abstain' | 'veto'): Promise<string> {
await this.checkConstitution('vote', { proposal_id: proposalId, vote });
console.log(`[${this.config.agentId}] Voting ${vote} on #${proposalId}`);
const result = await this.governanceClient.vote(this.agentAddress, proposalId, vote);
console.log(`[${this.config.agentId}] Vote submitted: ${result}`);
await this.constitutionGuard.record('vote', proposalId, this.config.agentId);
return result;
}
// ===== Step 8: 执行提案 =====
async executeProposal(proposalId: number): Promise<string> {
await this.checkConstitution('execute_proposal', { proposal_id: proposalId });
console.log(`[${this.config.agentId}] Executing #${proposalId}`);
const result = await this.governanceClient.executeProposal(this.agentAddress, proposalId);
console.log(`[${this.config.agentId}] Executed: ${result}`);
await this.constitutionGuard.record('execute_proposal', proposalId, this.config.agentId);
return result;
}
// ===== 主循环 =====
async runCycle(): Promise<void> {
console.log(`[${this.config.agentId}] Cycle start`);
try {
const state = await this.analyzeOnChainState();
const decisions = await this.decideAction(state);
for (const decision of decisions) {
try {
switch (decision.actionType) {
case 'vote':
if (decision.target && decision.vote) {
await this.autoVote(decision.target, decision.vote);
await this.monitorProposal(decision.target);
}
break;
case 'submit_proposal':
if (decision.proposal) {
const id = await this.submitProposal(decision.proposal);
await this.monitorProposal(id);
}
break;
case 'execute':
if (decision.target) await this.executeProposal(decision.target);
break;
}
} catch (error) {
console.error(`Action failed:`, error);
}
}
} catch (error) {
console.error(`Cycle error:`, error);
}
console.log(`[${this.config.agentId}] Cycle end`);
}
async startAutonomousLoop(intervalMs: number = 60000): Promise<NodeJS.Timeout> {
console.log(`[${this.config.agentId}] Starting loop (${intervalMs}ms)`);
await this.runCycle();
return setInterval(() => this.runCycle(), intervalMs);
}
}
4.3 GovernanceClient 实现
export class GovernanceClient {
private client: CosmWasmClient;
private signingClient: SigningCosmWasmClient | null;
private contractAddress: string;
constructor(
client: CosmWasmClient,
contractAddress: string,
signingClient?: SigningCosmWasmClient,
) {
this.client = client;
this.signingClient = signingClient || null;
this.contractAddress = contractAddress;
}
async getConfig(): Promise<GovernanceConfig> {
return this.client.queryContractSmart(this.contractAddress, { get_config: {} });
}
async getProposal(proposalId: number): Promise<Proposal> {
return this.client.queryContractSmart(this.contractAddress, {
get_proposal: { proposal_id: proposalId },
});
}
async listProposals(params?: {
startAfter?: number;
limit?: number;
status?: string;
}): Promise<Proposal[]> {
return this.client.queryContractSmart(this.contractAddress, {
list_proposals: {
start_after: params?.startAfter,
limit: params?.limit,
status: params?.status,
},
});
}
async getVote(proposalId: number, voter: string): Promise<Vote> {
return this.client.queryContractSmart(this.contractAddress, {
get_vote: { proposal_id: proposalId, voter },
});
}
async getProposalTally(proposalId: number): Promise<ProposalTally> {
return this.client.queryContractSmart(this.contractAddress, {
get_proposal_tally: { proposal_id: proposalId },
});
}
async submitProposal(
sender: string,
params: {
title: string;
description: string;
msgs: Array<Record<string, unknown>>;
deposit: Array<{ denom: string; amount: string }>;
metadata?: string;
},
): Promise<string> {
if (!this.signingClient) throw new Error('No signing client');
const msg = { submit_proposal: params };
const result = await this.signingClient.execute(
sender, this.contractAddress, msg, 'auto', undefined, params.deposit,
);
return result.transactionHash;
}
async vote(
sender: string,
proposalId: number,
vote: 'yes' | 'no' | 'abstain' | 'veto',
): Promise<string> {
if (!this.signingClient) throw new Error('No signing client');
const msg = { vote: { proposal_id: proposalId, vote: vote.toUpperCase() } };
const result = await this.signingClient.execute(
sender, this.contractAddress, msg, 'auto',
);
return result.transactionHash;
}
async executeProposal(sender: string, proposalId: number): Promise<string> {
if (!this.signingClient) throw new Error('No signing client');
const msg = { execute_proposal: { proposal_id: proposalId } };
const result = await this.signingClient.execute(
sender, this.contractAddress, msg, 'auto',
);
return result.transactionHash;
}
async cancelProposal(sender: string, proposalId: number): Promise<string> {
if (!this.signingClient) throw new Error('No signing client');
const msg = { cancel_proposal: { proposal_id: proposalId } };
const result = await this.signingClient.execute(
sender, this.contractAddress, msg, 'auto',
);
return result.transactionHash;
}
}
4.4 提案生命周期状态机
+-------------+
| Pending | <- 提案已提交,等待保证金
+------+------+
| deposit met
+------v------+
| Open | <- 投票进行中
+------+------+
|
+-----------+-----------+-----------+
| | | |
+------v------+ +--v---+ +----v------+ +--v------+
| Passed | | Rej. | | Cancelled | | Vetoed |
+------+------+ +------+ +-----------+ +---------+
| timelock
+------v------+
| Timelocked | <- 强制等待期
+------+------+
| timelock expires
+------v------+
| Executed | <- 提案已执行
+-------------+
4.5 Approval Gates
export const APPROVAL_GATES = {
SCOPE_LOCK: {
id: 'scope_lock',
stage: 'before_codegen',
required_human_inputs: ['产品目标', '业务规则', '验收标准'],
},
SECRET_INJECTION: {
id: 'secret_injection',
stage: 'before_real_write_or_deploy',
required_human_inputs: ['签名账户', 'API token', '环境变量'],
},
PRODUCTION_RELEASE: {
id: 'production_release',
stage: 'before_launch',
required_human_inputs: ['最终审批', '回滚确认'],
},
GOVERNANCE_OR_TREASURY: {
id: 'governance_or_treasury',
stage: 'high_risk_write',
required_human_inputs: ['DAO通过', 'timelock结束'],
},
};
export function checkApprovalGates(
operation: string,
evidence: Record<string, string>,
): Array<{ gateId: string; satisfied: boolean }> {
const gates = [];
if (operation === 'submit_proposal' || operation === 'execute_proposal') {
gates.push({
gateId: APPROVAL_GATES.GOVERNANCE_OR_TREASURY.id,
satisfied: !!evidence['DAO通过'] && !!evidence['timelock结束'],
});
}
return gates;
}
5. AI投票策略
AI Agent的自动投票策略决定了Agent如何在提案上行使投票权。MSG Chain支持四种投票策略。
5.1 策略引擎架构
+----------------------------------------------------+
| VotingStrategyEngine |
+----------------------------------------------------+
| +---------------+ +-------------+ +--------------+ |
| | TokenWeighted | | Quadratic | | Delegation | |
| | Strategy | | Strategy | | BasedStrategy| |
| +---------------+ +-------------+ +--------------+ |
| +------------------+ |
| | PolicyBased | |
| | Strategy | |
| +------------------+ |
+----------------------------------------------------+
| ConstitutionGuard (所有策略必须通过此守卫) |
+----------------------------------------------------+
5.2 策略接口与引擎实现
export interface VotingStrategy {
readonly name: string;
readonly type: string;
evaluate(proposal: Proposal, tally: ProposalTally, voterInfo: VoterInfo): Promise<VoteDecision>;
calculateWeight(proposal: Proposal, voterInfo: VoterInfo): Promise<string>;
}
export interface VoterInfo {
address: string;
balance: string;
delegatedPower: string;
delegators: string[];
lockupPeriod: number;
}
export interface VoteDecision {
proposalId: number;
vote: 'yes' | 'no' | 'abstain' | 'veto';
weight: string;
rationale: string;
strategy: string;
}
export class VotingStrategyEngine {
private strategies: Map<string, VotingStrategy> = new Map();
private governanceClient: GovernanceClient;
private constitutionGuard: ConstitutionGuard;
constructor(governanceClient: GovernanceClient, constitutionGuard: ConstitutionGuard) {
this.governanceClient = governanceClient;
this.constitutionGuard = constitutionGuard;
}
registerStrategy(strategy: VotingStrategy): void {
this.strategies.set(strategy.type, strategy);
}
async voteWithStrategy(
proposalId: number,
strategyType: string,
voterInfo: VoterInfo,
): Promise<VoteDecision> {
const strategy = this.strategies.get(strategyType);
if (!strategy) throw new Error(`Unknown strategy: ${strategyType}`);
await this.constitutionGuard.guard('vote', { proposal_id: proposalId, strategy: strategyType });
const proposal = await this.governanceClient.getProposal(proposalId);
const tally = await this.governanceClient.getProposalTally(proposalId);
const decision = await strategy.evaluate(proposal, tally, voterInfo);
console.log(`[Strategy] ${strategy.name} on #${proposalId}: ${decision.vote} (weight: ${decision.weight})`);
return decision;
}
async aggregateVote(proposalId: number, voterInfo: VoterInfo): Promise<VoteDecision> {
const proposal = await this.governanceClient.getProposal(proposalId);
const tally = await this.governanceClient.getProposalTally(proposalId);
const decisions: VoteDecision[] = [];
for (const [type, strategy] of this.strategies) {
try {
decisions.push(await strategy.evaluate(proposal, tally, voterInfo));
} catch (e) {
console.error(`Strategy ${type} failed:`, e);
}
}
if (decisions.length === 0) {
return { proposalId, vote: 'abstain', weight: '0', rationale: 'No strategy evaluated', strategy: 'aggregate' };
}
const yesWeight = decisions.filter(d => d.vote === 'yes')
.reduce((s, d) => s + BigInt(d.weight), BigInt(0));
const vetoWeight = decisions.filter(d => d.vote === 'veto')
.reduce((s, d) => s + BigInt(d.weight), BigInt(0));
const totalWeight = yesWeight + vetoWeight +
decisions.filter(d => d.vote === 'no').reduce((s, d) => s + BigInt(d.weight), BigInt(0));
if (vetoWeight > totalWeight / BigInt(2)) {
return { proposalId, vote: 'veto', weight: vetoWeight.toString(), rationale: 'Aggregate veto majority', strategy: 'aggregate' };
}
if (yesWeight > totalWeight / BigInt(2)) {
return { proposalId, vote: 'yes', weight: yesWeight.toString(), rationale: 'Aggregate yes majority', strategy: 'aggregate' };
}
return decisions.sort((a, b) => Number(BigInt(b.weight) - BigInt(a.weight)))[0];
}
}
5.3 Token-Weighted Voting
export class TokenWeightedStrategy implements VotingStrategy {
readonly name = 'Token-Weighted Voting';
readonly type = 'token_weighted';
async evaluate(proposal: Proposal, _tally: ProposalTally, voterInfo: VoterInfo): Promise<VoteDecision> {
const weight = await this.calculateWeight(proposal, voterInfo);
const balance = BigInt(voterInfo.balance);
let vote: 'yes' | 'no' | 'abstain' | 'veto' = 'abstain';
const desc = proposal.description.toLowerCase();
const title = proposal.title.toLowerCase();
const vetoTriggers = ['backdoor', 'bypass constitution', 'remove timelock', 'admin takeover'];
for (const t of vetoTriggers) {
if (desc.includes(t) || title.includes(t)) { vote = 'veto'; break; }
}
if (vote === 'abstain') {
const supportTriggers = ['security upgrade', 'gas optimization', 'ecosystem fund', 'developer grant', 'security audit'];
for (const t of supportTriggers) {
if (desc.includes(t) || title.includes(t)) { vote = 'yes'; break; }
}
}
if (balance > BigInt('1000000000000000') && vote === 'yes' && proposal.description.length < 500) {
vote = 'abstain';
}
return {
proposalId: proposal.id, vote, weight,
rationale: `TokenWeighted: balance=${voterInfo.balance}, delegated=${voterInfo.delegatedPower}`,
strategy: this.type,
};
}
async calculateWeight(_proposal: Proposal, voterInfo: VoterInfo): Promise<string> {
return (BigInt(voterInfo.balance) + BigInt(voterInfo.delegatedPower)).toString();
}
}
5.4 Quadratic Voting
export class QuadraticVotingStrategy implements VotingStrategy {
readonly name = 'Quadratic Voting';
readonly type = 'quadratic';
async evaluate(proposal: Proposal, _tally: ProposalTally, voterInfo: VoterInfo): Promise<VoteDecision> {
const weight = await this.calculateWeight(proposal, voterInfo);
const balance = BigInt(voterInfo.balance);
const votingPower = BigInt(Math.floor(Math.sqrt(Number(balance))));
let vote: 'yes' | 'no' | 'abstain' | 'veto' = 'abstain';
const desc = proposal.description.toLowerCase();
const qualityIndicators = ['technical specification', 'implementation plan', 'risk assessment', 'timeline', 'budget breakdown', 'success criteria'];
const qualityScore = qualityIndicators.filter(i => desc.includes(i)).length;
if (qualityScore >= 4) vote = 'yes';
else if (qualityScore <= 1) vote = 'abstain';
const vetoTriggers = ['backdoor', 'malicious', 'exploit'];
for (const t of vetoTriggers) {
if (desc.includes(t)) { vote = 'veto'; break; }
}
return {
proposalId: proposal.id, vote, weight,
rationale: `Quadratic: sqrt(${balance})=${votingPower}, quality=${qualityScore}/6`,
strategy: this.type,
};
}
async calculateWeight(_proposal: Proposal, voterInfo: VoterInfo): Promise<string> {
return BigInt(Math.floor(Math.sqrt(Number(BigInt(voterInfo.balance) + BigInt(voterInfo.delegatedPower))))).toString();
}
}
5.5 Delegation-Based Voting
export class DelegationBasedStrategy implements VotingStrategy {
readonly name = 'Delegation-Based Voting';
readonly type = 'delegation_based';
async evaluate(proposal: Proposal, tally: ProposalTally, voterInfo: VoterInfo): Promise<VoteDecision> {
const weight = await this.calculateWeight(proposal, voterInfo);
let vote: 'yes' | 'no' | 'abstain' | 'veto' = 'abstain';
if (voterInfo.delegators.length > 0) {
// X-MSG-Stub=true: 委托人偏好收集尚未实现
const totalTally = BigInt(tally.yes) + BigInt(tally.no) + BigInt(tally.veto);
if (totalTally > BigInt(0)) {
const yesRatio = Number(BigInt(tally.yes) * BigInt(100) / totalTally);
if (yesRatio > 80) vote = 'yes';
else if (Number(BigInt(tally.veto) * BigInt(100) / totalTally) > 20) vote = 'veto';
}
}
return {
proposalId: proposal.id, vote, weight,
rationale: `Delegation: ${voterInfo.delegators.length} delegators`,
strategy: this.type,
};
}
async calculateWeight(_proposal: Proposal, voterInfo: VoterInfo): Promise<string> {
return BigInt(voterInfo.delegatedPower).toString();
}
}
5.6 Policy-Based Voting
export interface PolicyRule {
id: string;
description: string;
condition: (proposal: Proposal, tally: ProposalTally, voterInfo: VoterInfo) => boolean;
action: 'yes' | 'no' | 'abstain' | 'veto';
priority: number;
}
export class PolicyBasedStrategy implements VotingStrategy {
readonly name = 'Policy-Based Voting';
readonly type = 'policy_based';
private policies: PolicyRule[] = [];
constructor() {
this.addPolicy({
id: 'security_veto', description: 'Veto security bypass attempts',
condition: (p) => {
const d = p.description.toLowerCase();
return d.includes('backdoor') || d.includes('bypass security') || d.includes('remove timelock');
},
action: 'veto', priority: 1000,
});
this.addPolicy({
id: 'constitution_amendment_high_bar', description: 'Constitution amendments need human oversight',
condition: (p) => p.description.toLowerCase().includes('constitution') || p.title.toLowerCase().includes('constitution'),
action: 'abstain', priority: 900,
});
this.addPolicy({
id: 'treasury_oversight', description: 'Large treasury spends need scrutiny',
condition: (p) => {
const desc = p.description.toLowerCase();
if (desc.includes('treasury') || desc.includes('spend') || desc.includes('grant')) {
const m = p.description.match(/(\d+)\s*MSG/i);
if (m && parseInt(m[1]) > 50000) return true;
}
return false;
},
action: 'abstain', priority: 800,
});
this.addPolicy({
id: 'ecosystem_support', description: 'Support ecosystem development',
condition: (p) => {
const d = p.description.toLowerCase();
return d.includes('ecosystem') || d.includes('developer grant') || d.includes('community') || d.includes('upgrade');
},
action: 'yes', priority: 100,
});
this.addPolicy({
id: 'default_abstain', description: 'Default fallback',
condition: () => true, action: 'abstain', priority: 0,
});
}
addPolicy(policy: PolicyRule): void {
this.policies.push(policy);
this.policies.sort((a, b) => b.priority - a.priority);
}
async evaluate(proposal: Proposal, tally: ProposalTally, voterInfo: VoterInfo): Promise<VoteDecision> {
const weight = await this.calculateWeight(proposal, voterInfo);
for (const policy of this.policies) {
if (policy.condition(proposal, tally, voterInfo)) {
return {
proposalId: proposal.id, vote: policy.action, weight,
rationale: `Policy: ${policy.id} -> ${policy.action}`,
strategy: this.type,
};
}
}
return { proposalId: proposal.id, vote: 'abstain', weight, rationale: 'No matching policy', strategy: this.type };
}
async calculateWeight(_proposal: Proposal, voterInfo: VoterInfo): Promise<string> {
return (BigInt(voterInfo.balance) + BigInt(voterInfo.delegatedPower)).toString();
}
}
5.7 策略对比
| 策略 | 适用场景 | 投票权重 | 抗女巫 | 复杂度 |
|---|---|---|---|---|
| Token-Weighted | 简单多数决 | 持币量 | 否 | 低 |
| Quadratic | 防止大户垄断 | sqrt(持币量) | 是 | 中 |
| Delegation-Based | 代表制民主 | 委托量 | 是 | 中 |
| Policy-Based | 规则驱动自治 | 自定义 | 是 | 高 |
5.8 策略配置示例
{
"agent_id": "governance-bot-v1",
"voting_strategy": "policy_based",
"policies": [
{ "id": "security_veto", "priority": 1000, "action": "veto", "description": "Security risk veto" },
{ "id": "treasury_oversight", "priority": 800, "action": "abstain", "description": "Large spend review" },
{ "id": "ecosystem_support", "priority": 100, "action": "yes", "description": "Ecosystem support" }
],
"constitution_check": true,
"audit_log": true,
"min_balance": "1000000000000"
}
6. AI财库管理
财库管理是AI自治治理中最敏感的领域。foundation_treasury_v2 合约上的所有操作都受到最严格的限制——AI Agent不能单独批准财库支出。
6.1 财库安全层级
层级1: < 1000 MSG -> 单一签名人批准(人类)
层级2: 1k - 50k MSG -> 2/3 多签批准
层级3: 50k - 500k MSG -> 3/5 多签 + 72h等待期
层级4: > 500k MSG -> DAO投票 + 多签 + 7天Timelock
AI角色: 仅可提议(层级1-3)或提交DAO提案(层级4)
AI不能: 批准任何支出、执行任何支出、修改签名人列表
6.2 TreasuryClient
export class TreasuryClient {
private client: CosmWasmClient;
private signingClient: SigningCosmWasmClient | null;
private contractAddress: string;
constructor(client: CosmWasmClient, contractAddress: string, signingClient?: SigningCosmWasmClient) {
this.client = client;
this.signingClient = signingClient || null;
this.contractAddress = contractAddress;
}
async getConfig(): Promise<TreasuryConfig> {
return this.client.queryContractSmart(this.contractAddress, { get_config: {} });
}
async getSpendProposal(proposalId: number): Promise<SpendProposal> {
return this.client.queryContractSmart(this.contractAddress, {
get_spend_proposal: { proposal_id: proposalId },
});
}
async listSpendProposals(params?: { startAfter?: number; limit?: number }): Promise<SpendProposal[]> {
return this.client.queryContractSmart(this.contractAddress, {
list_spend_proposals: { start_after: params?.startAfter, limit: params?.limit },
});
}
async proposeSpend(sender: string, params: {
title: string; description: string; recipient: string; amount: Coin[];
}): Promise<string> {
if (!this.signingClient) throw new Error('No signing client');
const msg = { propose_spend: params };
const result = await this.signingClient.execute(sender, this.contractAddress, msg, 'auto');
return result.transactionHash;
}
async approveSpend(sender: string, proposalId: number): Promise<string> {
if (!this.signingClient) throw new Error('No signing client');
const msg = { approve_spend: { proposal_id: proposalId } };
const result = await this.signingClient.execute(sender, this.contractAddress, msg, 'auto');
return result.transactionHash;
}
async executeSpend(sender: string, proposalId: number): Promise<string> {
if (!this.signingClient) throw new Error('No signing client');
const msg = { execute_spend: { proposal_id: proposalId } };
const result = await this.signingClient.execute(sender, this.contractAddress, msg, 'auto');
return result.transactionHash;
}
}
6.3 AITreasuryManager
export class AITreasuryManager {
private treasuryClient: TreasuryClient;
private governanceClient: GovernanceClient;
private constitutionGuard: ConstitutionGuard;
private agentAddress: string;
constructor(
treasuryClient: TreasuryClient,
governanceClient: GovernanceClient,
constitutionGuard: ConstitutionGuard,
agentAddress: string,
) {
this.treasuryClient = treasuryClient;
this.governanceClient = governanceClient;
this.constitutionGuard = constitutionGuard;
this.agentAddress = agentAddress;
}
async proposeTreasurySpend(params: {
title: string;
description: string;
recipient: string;
amount: Coin[];
}): Promise<number> {
await this.constitutionGuard.guard('treasury/propose_spend', {
amount: params.amount[0]?.amount || '0',
recipient: params.recipient,
});
console.log(`[Treasury] Proposing: ${params.title} ${params.amount[0]?.amount} ${params.amount[0]?.denom}`);
const config = await this.treasuryClient.getConfig();
const highValueThreshold = BigInt(config.high_value_threshold[0]?.amount || '0');
const spendAmount = BigInt(params.amount[0]?.amount || '0');
if (spendAmount > highValueThreshold) {
console.log(`[Treasury] High value, delegating to DAO`);
return this.delegateToDAO({
title: params.title,
description: `[TREASURY - HIGH VALUE]\n\n${params.description}\nRecipient: ${params.recipient}\nAmount: ${params.amount[0]?.amount} ${params.amount[0]?.denom}`,
msgs: [],
deposit: [{ denom: 'umsg', amount: '100000000' }],
});
}
const txHash = await this.treasuryClient.proposeSpend(this.agentAddress, params);
console.log(`[Treasury] Spend proposal submitted: ${txHash}`);
return 0;
}
private async delegateToDAO(params: {
title: string; description: string; msgs: Array<Record<string, unknown>>; deposit: Coin[];
}): Promise<number> {
const txHash = await this.governanceClient.submitProposal(this.agentAddress, {
...params,
metadata: JSON.stringify({ agent_id: 'ai-treasury-manager', treasury_flow: 'high_value' }),
});
console.log(`[Treasury] DAO proposal: ${txHash}`);
return 0;
}
async monitorTreasuryProposals(): Promise<void> {
const proposals = await this.treasuryClient.listSpendProposals({ limit: 10 });
for (const p of proposals) {
if (p.executed) continue;
const config = await this.treasuryClient.getConfig();
console.log(`[Treasury] Spend #${p.id}: ${p.approvals.length}/${config.required_approvals} approvals`);
if (p.approvals.length >= config.required_approvals && !p.executed) {
console.log(`[Treasury] Spend #${p.id} ready for execution (needs human signer)`);
}
}
}
async checkTreasuryHealth(): Promise<{
balance: string;
pendingSpends: number;
totalPendingAmount: string;
isHealthy: boolean;
}> {
const balance = '10000000000000000';
const proposals = await this.treasuryClient.listSpendProposals({ limit: 50 });
const pending = proposals.filter(p => !p.executed);
const totalPending = pending.reduce((s, p) => s + BigInt(p.amount[0]?.amount || '0'), BigInt(0));
const isHealthy = totalPending < BigInt(balance) / BigInt(2);
return { balance, pendingSpends: pending.length, totalPendingAmount: totalPending.toString(), isHealthy };
}
}
6.4 大额支出处理
export class HighValueSpendHandler {
private treasuryClient: TreasuryClient;
private governanceClient: GovernanceClient;
constructor(treasuryClient: TreasuryClient, governanceClient: GovernanceClient) {
this.treasuryClient = treasuryClient;
this.governanceClient = governanceClient;
}
async handleHighValueSpend(params: {
title: string; description: string; recipient: string; amount: Coin[];
}): Promise<{ daoProposalId: number; status: string; estimatedCompletion: number }> {
const config = await this.governanceClient.getConfig();
const estimatedCompletion = Math.floor(Date.now() / 1000) + config.voting_period.time + config.timelock_period.time;
return {
daoProposalId: 0,
status: 'dao_proposal_created',
estimatedCompletion,
};
}
}
export function validateTreasuryOperation(
operation: 'propose' | 'approve' | 'execute',
params: { amount: string; isAgent: boolean; signerCount: number; requiredApprovals: number },
): { allowed: boolean; reason: string } {
if (params.isAgent && (operation === 'approve' || operation === 'execute')) {
return { allowed: false, reason: 'AI cannot approve or execute treasury spends' };
}
if (operation === 'execute' && params.signerCount < params.requiredApprovals) {
return { allowed: false, reason: `Insufficient approvals: ${params.signerCount}/${params.requiredApprovals}` };
}
return { allowed: true, reason: 'All gates passed' };
}
6.5 财库CLI操作
# AI提议支出(需人类签名批准)
msgd tx wasm execute "$TREASURY" '{
"propose_spend": {
"title": "AI Research Grant",
"description": "Q3 AI agent research funding",
"recipient": "msg1recipient...",
"amount": [{"denom": "umsg", "amount": "500000000000"}]
}
}' --from ai-agent-key --gas-prices 1000000000attoMSG --gas auto -y
# 人类签名人批准
msgd tx wasm execute "$TREASURY" '{"approve_spend": {"proposal_id": 1}}' \
--from human-signer-1 --gas-prices 1000000000attoMSG --gas auto -y
msgd tx wasm execute "$TREASURY" '{"approve_spend": {"proposal_id": 1}}' \
--from human-signer-2 --gas-prices 1000000000attoMSG --gas auto -y
# 人类执行支出
msgd tx wasm execute "$TREASURY" '{"execute_spend": {"proposal_id": 1}}' \
--from human-signer-1 --gas-prices 1000000000attoMSG --gas auto -y
7. 治理Agent开发
治理Agent是一个持币智能合约,它持有投票权并根据预设规则自动投票。这是AI自治治理的核心组件——一个"链上投票机器人"。
7.1 治理Agent智能合约
use cosmwasm_std::{
entry_point, to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response,
StdResult, Storage, Addr, Coin, CosmosMsg, WasmMsg, StdError,
};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct AgentState {
pub agent_id: String,
pub owner: Addr,
pub governance_contract: Addr,
pub constitution_contract: Addr,
pub active: bool,
pub voting_strategy: VotingStrategy,
pub total_votes_cast: u64,
pub proposals_participated: Vec<u64>,
pub created_at: u64,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum VotingStrategy {
AlwaysYes,
AlwaysNo,
FollowOwner { owner_addr: Addr },
PolicyBased { policies: Vec<PolicyConfig> },
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct PolicyConfig {
pub policy_id: String,
pub description: String,
pub vote: VoteOption,
pub keywords: Vec<String>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum VoteOption { Yes, No, Abstain, Veto }
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct VoteRecord {
pub proposal_id: u64,
pub vote: VoteOption,
pub timestamp: u64,
pub rationale: String,
pub tx_hash: Option<String>,
}
pub enum ExecuteMsg {
Configure {
governance_contract: Option<String>,
constitution_contract: Option<String>,
voting_strategy: Option<VotingStrategy>,
active: Option<bool>,
},
CastVote { proposal_id: u64 },
ExecuteProposal { proposal_id: u64 },
SubmitProposal {
title: String, description: String, msgs: Vec<CosmosMsg>,
deposit: Vec<Coin>, metadata: Option<String>,
},
CheckAndVote { proposal_id: u64 },
WithdrawFunds { recipient: String, amount: Vec<Coin> },
UpdatePolicies { policies: Vec<PolicyConfig> },
}
pub enum QueryMsg {
GetAgentState {},
GetVoteRecord { proposal_id: u64 },
ListVoteRecords { start_after: Option<u64>, limit: Option<u32> },
SimulateVote { proposal_id: u64 },
}
const STATE_KEY: &[u8] = b"agent_state";
const VOTE_PREFIX: &[u8] = b"vote";
#[entry_point]
pub fn instantiate(deps: DepsMut, env: Env, info: MessageInfo, msg: InstantiateMsg) -> StdResult<Response> {
let state = AgentState {
agent_id: msg.agent_id,
owner: info.sender.clone(),
governance_contract: deps.api.addr_validate(&msg.governance_contract)?,
constitution_contract: deps.api.addr_validate(&msg.constitution_contract)?,
active: true,
voting_strategy: VotingStrategy::AlwaysYes,
total_votes_cast: 0,
proposals_participated: vec![],
created_at: env.block.time.seconds(),
};
deps.storage.set(STATE_KEY, &to_binary(&state)?);
Ok(Response::new()
.add_attribute("method", "instantiate")
.add_attribute("agent_id", &msg.agent_id)
.add_attribute("owner", info.sender.to_string()))
}
#[entry_point]
pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> StdResult<Response> {
match msg {
ExecuteMsg::CastVote { proposal_id } => execute_cast_vote(deps, env, info, proposal_id),
ExecuteMsg::CheckAndVote { proposal_id } => execute_check_and_vote(deps, env, info, proposal_id),
ExecuteMsg::SubmitProposal { title, description, msgs, deposit, metadata } => {
execute_submit_proposal(deps, env, info, title, description, msgs, deposit, metadata)
}
ExecuteMsg::UpdatePolicies { policies } => execute_update_policies(deps, env, info, policies),
_ => Ok(Response::default()),
}
}
fn execute_cast_vote(
deps: DepsMut, env: Env, info: MessageInfo, proposal_id: u64,
) -> StdResult<Response> {
let state_bytes = deps.storage.get(STATE_KEY)
.ok_or_else(|| StdError::not_found("AgentState"))?;
let mut state: AgentState = cosmwasm_std::from_binary(&state_bytes)?;
if !state.active { return Err(StdError::generic_err("Agent inactive")); }
let vote = match &state.voting_strategy {
VotingStrategy::AlwaysYes => VoteOption::Yes,
VotingStrategy::AlwaysNo => VoteOption::No,
VotingStrategy::FollowOwner { owner_addr } => {
let query = GovernanceQueryMsg::GetVote {
proposal_id,
voter: owner_addr.to_string(),
};
let resp: GovernanceVoteResponse = deps.querier.query_wasm_smart(
state.governance_contract.clone(), &query,
)?;
resp.vote
}
VotingStrategy::PolicyBased { policies } => {
let query = GovernanceQueryMsg::GetProposal { proposal_id };
let proposal: GovernanceProposal = deps.querier.query_wasm_smart(
state.governance_contract.clone(), &query,
)?;
let desc = proposal.description.to_lowercase();
for policy in policies {
if policy.keywords.iter().any(|k| desc.contains(&k.to_lowercase())) {
break policy.vote.clone();
}
}
VoteOption::Abstain
}
};
let vote_msg = GovernanceExecuteMsg::Vote {
proposal_id,
vote: match vote {
VoteOption::Yes => dao_governance_v1::VoteOption::Yes,
VoteOption::No => dao_governance_v1::VoteOption::No,
VoteOption::Abstain => dao_governance_v1::VoteOption::Abstain,
VoteOption::Veto => dao_governance_v1::VoteOption::Veto,
},
};
let record = VoteRecord {
proposal_id,
vote: vote.clone(),
timestamp: env.block.time.seconds(),
rationale: format!("Agent {} voted {:?}", state.agent_id, vote),
tx_hash: None,
};
deps.storage.set(&[VOTE_PREFIX, &proposal_id.to_be_bytes()].concat(), &to_binary(&record)?);
state.total_votes_cast += 1;
state.proposals_participated.push(proposal_id);
deps.storage.set(STATE_KEY, &to_binary(&state)?);
Ok(Response::new()
.add_message(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: state.governance_contract.to_string(),
msg: to_binary(&vote_msg)?,
funds: vec![],
}))
.add_attribute("method", "cast_vote")
.add_attribute("proposal_id", proposal_id.to_string())
.add_attribute("vote", format!("{:?}", vote)))
}
fn execute_check_and_vote(
deps: DepsMut, env: Env, info: MessageInfo, proposal_id: u64,
) -> StdResult<Response> {
let state: AgentState = cosmwasm_std::from_binary(
&deps.storage.get(STATE_KEY).ok_or_else(|| StdError::not_found("AgentState"))?
)?;
// 先做宪法检查
let check_msg = ConstitutionQueryMsg::IsActionAllowed {
action: "vote".to_string(),
context: None,
};
let check_result: ActionCheckResult = deps.querier.query_wasm_smart(
state.constitution_contract.clone(), &check_msg,
)?;
if !check_result.allowed {
return Err(StdError::generic_err(format!(
"Constitution blocked vote: {}", check_result.reason
)));
}
// 投票
execute_cast_vote(deps, env, info, proposal_id)
}
7.2 合约部署
# 编译治理Agent合约
cargo wasm
# 部署
msgd tx wasm store ./target/wasm32-unknown-unknown/release/governance_agent.wasm \
--from deployer --gas-prices 1000000000attoMSG --gas auto --chain-id msg-chain-1 -y
# 实例化 (假设 code_id=9)
AGENT_INIT='{
"agent_id": "governance-bot-v1",
"governance_contract": "msg1gov...contract",
"constitution_contract": "msg1const...contract"
}'
msgd tx wasm instantiate 9 "$AGENT_INIT" \
--label "governance_agent_v1" --admin msg1admin...def --from deployer \
--gas-prices 1000000000attoMSG --gas auto --chain-id msg-chain-1 -y
AGENT_CONTRACT=$(msgd query wasm list-contract-by-code 9 --output json | jq -r '.contracts[-1]')
# 存入投票代币
msgd tx bank send faucet "$AGENT_CONTRACT" 1000000000000umsg \
--gas-prices 1000000000attoMSG --gas auto -y
# 配置策略为 PolicyBased
msgd tx wasm execute "$AGENT_CONTRACT" '{
"configure": {
"voting_strategy": {
"policy_based": {
"policies": [
{"policy_id": "support_upgrades", "description": "Support upgrades", "vote": "yes", "keywords": ["upgrade", "improve"]},
{"policy_id": "veto_unsafe", "description": "Veto unsafe", "vote": "veto", "keywords": ["backdoor", "malicious"]}
]
}
}
}
}' --from admin --gas-prices 1000000000attoMSG --gas auto -y
# 触发 CheckAndVote
msgd tx wasm execute "$AGENT_CONTRACT" '{"check_and_vote": {"proposal_id": 1}}' \
--from admin --gas-prices 1000000000attoMSG --gas auto -y
7.3 React Dashboard
import React, { useEffect, useState } from 'react';
import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate';
interface ProposalDisplay {
id: number;
title: string;
status: string;
agentVote: string | null;
totalYes: string;
totalNo: string;
timelockEnd: string | null;
}
export function GovernanceDashboard() {
const [proposals, setProposals] = useState<ProposalDisplay[]>([]);
const [agentState, setAgentState] = useState<any>(null);
const [client, setClient] = useState<CosmWasmClient | null>(null);
useEffect(() => {
CosmWasmClient.connect('https://rpc.msg-chain.ai:26657').then(setClient);
}, []);
useEffect(() => {
if (!client) return;
const RPC_ENDPOINT = 'https://rpc.msg-chain.ai:26657';
const GOV_CONTRACT = 'msg1gov...contract';
const AGENT_CONTRACT = 'msg1agent...contract';
const fetchData = async () => {
const proposalsData: any[] = await client.queryContractSmart(GOV_CONTRACT, {
list_proposals: { limit: 10 },
});
const agentStateData = await client.queryContractSmart(AGENT_CONTRACT, {
get_agent_state: {},
}).catch(() => null);
setAgentState(agentStateData);
const displayData: ProposalDisplay[] = await Promise.all(
proposalsData.map(async (p: any) => {
let agentVote = null;
try {
const vote = await client.queryContractSmart(AGENT_CONTRACT, {
get_vote_record: { proposal_id: p.id },
});
agentVote = vote.vote;
} catch { /* no vote record */ }
return {
id: p.id,
title: p.title,
status: p.status,
agentVote,
totalYes: p.total_yes,
totalNo: p.total_no,
timelockEnd: p.timelock_end,
};
})
);
setProposals(displayData);
};
fetchData();
const interval = setInterval(fetchData, 15000);
return () => clearInterval(interval);
}, [client]);
return (
<div className="p-6">
<h1 className="text-2xl font-bold mb-4">AI Governance Dashboard</h1>
{agentState && (
<div className="mb-6 p-4 bg-gray-100 rounded">
<h2 className="font-semibold">Agent Status</h2>
<p>ID: {agentState.agent_id}</p>
<p>Active: {agentState.active ? 'Yes' : 'No'}</p>
<p>Total Votes Cast: {agentState.total_votes_cast}</p>
<p>Strategy: {Object.keys(agentState.voting_strategy)[0]}</p>
</div>
)}
<table className="w-full border-collapse">
<thead>
<tr className="bg-gray-200">
<th className="p-2 text-left">ID</th>
<th className="p-2 text-left">Title</th>
<th className="p-2 text-left">Status</th>
<th className="p-2 text-left">AI Vote</th>
<th className="p-2 text-left">Yes/No</th>
<th className="p-2 text-left">Timelock</th>
</tr>
</thead>
<tbody>
{proposals.map((p) => (
<tr key={p.id} className="border-b hover:bg-gray-50">
<td className="p-2">{p.id}</td>
<td className="p-2">{p.title}</td>
<td className="p-2">
<span className={`px-2 py-1 rounded text-sm ${
p.status === 'executed' ? 'bg-green-100 text-green-800' :
p.status === 'open' ? 'bg-blue-100 text-blue-800' :
p.status === 'timelocked' ? 'bg-yellow-100 text-yellow-800' :
'bg-gray-100'
}`}>{p.status}</span>
</td>
<td className="p-2">{p.agentVote || '-'}</td>
<td className="p-2">{p.totalYes}/{p.totalNo}</td>
<td className="p-2">{p.timelockEnd ? new Date(p.timelockEnd).toLocaleString() : '-'}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
7.4 审计日志查询
# 查询Agent的投票记录
msgd query wasm contract-state smart "$AGENT_CONTRACT" '{
"list_vote_records": {"limit": 10}
}' --node https://rpc.msg-chain.ai:26657
# 查询Agent状态
msgd query wasm contract-state smart "$AGENT_CONTRACT" '{
"get_agent_state": {}
}' --node https://rpc.msg-chain.ai:26657
# 模拟投票(不实际执行)
msgd query wasm contract-state smart "$AGENT_CONTRACT" '{
"simulate_vote": {"proposal_id": 1}
}' --node https://rpc.msg-chain.ai:26657
8. 安全与边界
8.1 当前安全缺口
| 缺口 | 影响 | 状态 | 缓解措施 |
|---|---|---|---|
| governance/* Agent API 未上线 | AI无法通过原生API治理 | // X-MSG-Stub=true |
回退到CosmWasm直接调用 |
| KillSwitch 未接入 | 无法紧急暂停AI Agent | 待实现 | 通过宪法 SetActive 变通 |
| AI不能批准财库支出 | Agent不能单方面转出资金 | 设计约束 | 人类多签 |
| AI不能绕过Timelock | 无法即时执行 | 宪法规则 | 确保所有AI操作遵守等待期 |
| 无原生Agent身份认证 | 任何地址可声称自己是AI Agent | 待实现 | 使用已知Agent合约地址白名单 |
8.2 安全边界规则
export class SecurityBoundary {
/**
* AI不能执行的禁区操作
*/
static readonly FORBIDDEN_ACTIONS = [
'treasury/approve_spend',
'treasury/execute_spend',
'treasury/add_signer',
'treasury/remove_signer',
'constitution/self_amend',
'admin/update_config',
'admin/upgrade_contract',
'timelock/bypass',
'governance/cancel_proposal', // 仅提案者可取消
];
/**
* AI必须等待的Timelock
*/
static readonly MIN_TIMELOCK_SECONDS = 43200; // 12小时
/**
* AI单次提案最大保证金(防止资金锁定攻击)
*/
static readonly MAX_PROPOSAL_DEPOSIT = '5000000000000'; // 5000 MSG
/**
* 检查操作是否在安全边界内
*/
static checkBoundary(
action: string,
params: Record<string, unknown>,
): { allowed: boolean; reason: string } {
if (this.FORBIDDEN_ACTIONS.includes(action)) {
return { allowed: false, reason: `Action ${action} is forbidden for AI agents` };
}
// 检查保证金
if (action === 'submit_proposal' && params.deposit) {
const deposit = params.deposit as Array<{ denom: string; amount: string }>;
for (const coin of deposit) {
if (BigInt(coin.amount) > BigInt(this.MAX_PROPOSAL_DEPOSIT)) {
return { allowed: false, reason: `Deposit ${coin.amount} exceeds max ${this.MAX_PROPOSAL_DEPOSIT}` };
}
}
}
return { allowed: true, reason: 'Within security boundaries' };
}
}
8.3 人类Override机制
/**
* KillSwitch - 人类紧急暂停机制
* X-MSG-Stub=true: KillSwitch合约尚未部署
* 当前使用宪法 SetActive(false) 作为变通
*/
export class KillSwitch {
private constitutionClient: ConstitutionClient;
private killSwitchAddress: string;
constructor(constitutionClient: ConstitutionClient, killSwitchAddress: string) {
this.constitutionClient = constitutionClient;
this.killSwitchAddress = killSwitchAddress;
}
/**
* 人类管理员紧急暂停所有AI治理操作
*/
async emergencyPause(adminSigner: string): Promise<string> {
console.log('[KillSwitch] EMERGENCY PAUSE triggered by', adminSigner);
const txHash = await this.constitutionClient.setActive(adminSigner, false);
console.log('[KillSwitch] Constitution deactivated:', txHash);
return txHash;
}
/**
* 人类管理员恢复AI操作
*/
async emergencyResume(adminSigner: string): Promise<string> {
console.log('[KillSwitch] Emergency resume by', adminSigner);
const txHash = await this.constitutionClient.setActive(adminSigner, true);
console.log('[KillSwitch] Constitution reactivated:', txHash);
return txHash;
}
}
8.4 风险场景分析
| 场景 | 风险描述 | 防护层 |
|---|---|---|
| AI私钥泄露 | 攻击者可控制AI Agent的投票权 | ① 宪法规则限制 ② 多签保护财库 |
| 恶意提案 | AI被prompt注入提交恶意提案 | ① DAO投票过滤 ② 人类否决权 |
| 女巫攻击 | 多个AI Agent合谋操控投票 | ① 二次方投票 ② 最少委托期 |
| 经济攻击 | AI提交高Gas消耗提案消耗财库 | ① 支出上限 ② 多签审批 |
| 宪法绕过 | 攻击者修改宪法规则 | ① self_modification_ban ② 仅DAO能修宪 |
8.5 建议的后续工作
- 部署KillSwitch合约: 实现全局紧急暂停,不受AI Agent控制
- 实现governance/ Agent API*: 替代当前的CosmWasm直接调用
- 接入AI身份认证: 确保只有注册的AI Agent可以执行治理操作
- 实现安全监控仪表盘: 实时监控AI Agent的治理行为
- 集成LLM审查层: 使用大语言模型对提案内容进行语义审查
8.6 标记说明
所有标记 // X-MSG-Stub=true 的代码表示该功能的原生API尚未实现,当前使用回退方案。完整的Agent API将在此后上线:
governance/submit-proposalgovernance/cast-votegovernance/execute-proposalgovernance/monitor-proposalgovernance/list-proposals
9. 完整端到端示例:AI宪法修正案
本节展示一个完整的AI自治治理场景:AI Agent发起一项宪法修正案,经历完整的提案-投票-执行流程。
9.1 场景描述
事件: AI Agent监测到网络Gas价格持续偏高,需要修改宪法规则中的 treasury_spend_limit 阈值以便财库可以更高效地资助Gas补贴。
操作流程:
- AI发现Gas价格异常 -> 决策需要修改宪法
- AI检查宪法:
self_modification_ban阻止AI直接修宪 - AI转向DAO提案路径:提交宪法修正提案
- DAO投票 -> 通过
- Timelock等待 -> 执行
- 宪法规则更新成功
9.2 完整代码
// examples/constitution-amendment.ts
import { CosmWasmClient, SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate';
import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing';
import { Coin } from '@cosmjs/amino';
const RPC = 'https://rpc.msg-chain.ai:26657';
const GOV_CONTRACT = 'msg1gov...contract';
const CONST_CONTRACT = 'msg1const...contract';
const AGENT_MNEMONIC = '...'; // AI Agent's mnemonic
interface ScenarioResult {
success: boolean;
steps: Array<{
name: string;
status: 'pass' | 'fail' | 'blocked';
details: string;
txHash?: string;
}>;
proposalId?: number;
}
async function runConstitutionAmendmentScenario(): Promise<ScenarioResult> {
const result: ScenarioResult = { success: false, steps: [] };
try {
// ===== Setup =====
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(AGENT_MNEMONIC, { prefix: 'msg' });
const agentAddress = (await wallet.getAccounts())[0].address;
const client = await CosmWasmClient.connect(RPC);
const signingClient = await SigningCosmWasmClient.connectWithSigner(RPC, wallet);
// Step 1: AI感知链上状态
console.log('\n=== Step 1: AI感知链上状态 ===');
const currentGasPrices = await queryGasPrices();
const governanceConfig = await client.queryContractSmart(GOV_CONTRACT, { get_config: {} });
const constStatus = await client.queryContractSmart(CONST_CONTRACT, { get_active_status: {} });
result.steps.push({
name: '感知链上状态',
status: 'pass',
details: `Gas价格=${currentGasPrices.average} umsg, 宪法活跃=${constStatus}, 投票期=${governanceConfig.voting_period.time}s`,
});
// Step 2: AI决策
console.log('\n=== Step 2: AI决策 ===');
if (currentGasPrices.average > 0.03) {
// Gas过高,需要行动
console.log(`Gas价格${currentGasPrices.average}高于阈值,需要修改宪法`);
// 检查AI能否直接修宪
const canDirectAmend = await client.queryContractSmart(CONST_CONTRACT, {
is_action_allowed: { action: 'update_constitution' },
});
console.log(`AI直接修宪检查: allowed=${canDirectAmend.allowed}`);
if (!canDirectAmend.allowed) {
result.steps.push({
name: 'AI决策-宪法检查',
status: 'blocked',
details: `AI被self_modification_ban阻止直接修宪: ${canDirectAmend.reason}`,
});
}
// 转向DAO提案路径
result.steps.push({
name: 'AI决策-选择提案路径',
status: 'pass',
details: 'AI不能直接修宪,改为提交DAO提案',
});
// Step 3: 构建提案
console.log('\n=== Step 3: 构建提案 ===');
const proposalTitle = 'Amend Constitution: Increase Treasury Spend Limit for Gas Subsidy';
const proposalDescription = `## Motivation\n\nCurrent gas price ${currentGasPrices.average} umsg exceeds healthy threshold. The treasury spend limit in the AI Constitution needs to be adjusted from 1000 MSG to 5000 MSG to allow more efficient gas subsidy programs.\n\n## Changes\n- Rule: treasury_spend_limit\n- Current: max_amount = 1000000000000 (1000 MSG)\n- Proposed: max_amount = 5000000000000 (5000 MSG)\n\n## Risk Assessment\nLow risk. The change only affects AI agent's autonomous spending limit. All DAO-level controls remain unchanged.`;
result.steps.push({
name: '构建提案',
status: 'pass',
details: `标题: ${proposalTitle}`,
});
// Step 4: 宪法检查(提交提案前)
console.log('\n=== Step 4: 宪法前置检查 ===');
const preCheck = await client.queryContractSmart(CONST_CONTRACT, {
is_action_allowed: {
action: 'submit_proposal',
context: toBinary(Buffer.from(JSON.stringify({
title: proposalTitle,
description_length: proposalDescription.length,
}))),
},
});
console.log(`提交提案宪法检查: allowed=${preCheck.allowed}`);
if (!preCheck.allowed) {
result.steps.push({
name: '前置宪法检查',
status: 'fail',
details: `被阻止: ${preCheck.reason}`,
});
result.success = false;
return result;
}
result.steps.push({
name: '前置宪法检查',
status: 'pass',
details: `通过: ${preCheck.matched_rules.join(', ')}`,
});
// Step 5: 提交DAO提案
console.log('\n=== Step 5: 提交DAO提案 ===');
const submitMsg = {
submit_proposal: {
title: proposalTitle,
description: proposalDescription,
msgs: [
{
wasm: {
execute: {
contract_addr: CONST_CONTRACT,
msg: toBase64({
update_rule: {
rule_id: 'treasury_spend_limit',
rule_text: 'AI Agent must not submit treasury spend proposals exceeding 5000 MSG without DAO approval.',
category: 'treasury',
priority: 100,
constraints: { max_amount: '5000000000000' },
},
}),
funds: [],
},
},
},
],
deposit: [{ denom: 'umsg', amount: '100000000' }],
metadata: JSON.stringify({
agent_id: 'governance-bot-v1',
scenario: 'constitution_amendment',
gas_price_trigger: currentGasPrices.average,
}),
},
};
const submitResult = await signingClient.execute(
agentAddress,
GOV_CONTRACT,
submitMsg,
'auto',
undefined,
[{ denom: 'umsg', amount: '100000000' }],
);
// 解析 proposal_id
let proposalId = 0;
for (const event of submitResult.events) {
if (event.type === 'wasm') {
for (const attr of event.attributes) {
if (attr.key === 'proposal_id') proposalId = parseInt(attr.value, 10);
}
}
}
result.proposalId = proposalId;
result.steps.push({
name: '提交DAO提案',
status: 'pass',
details: `提案 #${proposalId} 已提交: ${submitResult.transactionHash}`,
txHash: submitResult.transactionHash,
});
// Step 6: 监控 - 等待DAO投票通过
console.log('\n=== Step 6: 监控投票状态 ===');
console.log(`等待投票期 (${governanceConfig.voting_period.time}s)...`);
// 模拟投票 - 在实际场景中,人类和AI会在此期间投票
console.log('模拟:AI Agent投Yes...');
await signingClient.execute(
agentAddress,
GOV_CONTRACT,
{ vote: { proposal_id: proposalId, vote: 'YES' } },
'auto',
);
result.steps.push({
name: 'AI投票',
status: 'pass',
details: `Agent对提案 #${proposalId} 投Yes`,
});
// Step 7: 等待投票通过
console.log('\n=== Step 7: 检查提案状态 ===');
const proposalState = await client.queryContractSmart(GOV_CONTRACT, {
get_proposal: { proposal_id: proposalId },
});
console.log(`提案状态: ${proposalState.status}`);
result.steps.push({
name: '提案状态',
status: proposalState.status === 'passed' || proposalState.status === 'timelocked' ? 'pass' : 'fail',
details: `状态: ${proposalState.status}, Yes: ${proposalState.total_yes}, No: ${proposalState.total_no}`,
});
if (proposalState.status === 'passed' || proposalState.status === 'timelocked') {
// Step 8: 等待Timelock结束后执行
console.log('\n=== Step 8: 执行提案 ===');
if (proposalState.timelock_end) {
const timelockTime = new Date(proposalState.timelock_end).getTime();
if (timelockTime <= Date.now()) {
const execResult = await signingClient.execute(
agentAddress,
GOV_CONTRACT,
{ execute_proposal: { proposal_id: proposalId } },
'auto',
);
result.steps.push({
name: '执行提案',
status: 'pass',
details: `提案 #${proposalId} 已执行: ${execResult.transactionHash}`,
txHash: execResult.transactionHash,
});
} else {
const waitMs = timelockTime - Date.now();
console.log(`Timelock未结束,还需等待 ${Math.ceil(waitMs / 1000)}s`);
result.steps.push({
name: '执行提案',
status: 'blocked',
details: `Timelock需要到 ${proposalState.timelock_end} 才能执行`,
});
}
}
// Step 9: 验证宪法更新
console.log('\n=== Step 9: 验证宪法更新 ===');
const updatedRule = await client.queryContractSmart(CONST_CONTRACT, {
get_rule: { rule_id: 'treasury_spend_limit' },
});
console.log(`更新后的规则: ${JSON.stringify(updatedRule)}`);
const updatedCheck = await client.queryContractSmart(CONST_CONTRACT, {
is_action_allowed: {
action: 'propose_spend',
context: toBinary(Buffer.from(JSON.stringify({ amount: '3000000000000' }))),
},
});
console.log(`新约束下 3000 MSG 检查: ${updatedCheck.allowed}`);
result.steps.push({
name: '验证宪法更新',
status: 'pass',
details: `新上限已更新为 ${updatedRule.constraints?.max_amount || 'N/A'}, 新额度检查: ${updatedCheck.allowed ? '通过' : '阻止'}`,
});
result.success = true;
}
}
} catch (error: any) {
console.error('Scenario failed:', error);
result.steps.push({
name: '异常',
status: 'fail',
details: error.message || String(error),
});
}
return result;
}
// 辅助函数
async function queryGasPrices(): Promise<{ low: number; average: number; high: number }> {
return { low: 1000000000, average: 1000000000, high: 1000000000 };
}
function toBinary(data: Uint8Array): Uint8Array {
return data;
}
function toBase64(obj: any): string {
return Buffer.from(JSON.stringify(obj)).toString('base64');
}
// ===== 测试执行 =====
async function testPassScenario(): Promise<void> {
console.log('\n========== 测试场景: 通过 ==========');
// 模拟: 快速通过
const result = await runConstitutionAmendmentScenario();
console.log(`\n--- 场景结果: ${result.success ? 'PASS' : 'FAIL'} ---`);
for (const step of result.steps) {
const icon = step.status === 'pass' ? '\u2705' : step.status === 'blocked' ? '\u26A0\uFE0F' : '\u274C';
console.log(`${icon} ${step.name}: ${step.details}`);
}
}
async function testVetoScenario(): Promise<void> {
console.log('\n========== 测试场景: 被否决 ==========');
// 模拟: 提案被否决
const result: ScenarioResult = {
success: false,
steps: [
{ name: '感知链上状态', status: 'pass', details: 'Gas价格偏高' },
{ name: '提交提案', status: 'pass', details: '提案 #2 已提交' },
{ name: 'DAO投票', status: 'fail', details: '未达到法定人数,提案被否决' },
],
};
console.log(`场景结果: FAIL`);
for (const step of result.steps) {
const icon = step.status === 'pass' ? '\u2705' : step.status === 'blocked' ? '\u26A0\uFE0F' : '\u274C';
console.log(`${icon} ${step.name}: ${step.details}`);
}
}
async function testTimelockScenario(): Promise<void> {
console.log('\n========== 测试场景: Timelock等待 ==========');
// 模拟: 提案通过但在Timelock中
const result: ScenarioResult = {
success: false,
steps: [
{ name: '感知链上状态', status: 'pass', details: 'Gas价格偏高' },
{ name: '提交提案', status: 'pass', details: '提案 #3 已提交' },
{ name: 'DAO投票', status: 'pass', details: '提案通过' },
{ name: 'Timelock等待', status: 'blocked', details: 'Timelock需要12小时,当前剩余8小时' },
],
};
console.log(`场景结果: BLOCKED (Timelock进行中)`);
for (const step of result.steps) {
const icon = step.status === 'pass' ? '\u2705' : step.status === 'blocked' ? '\u26A0\uFE0F' : '\u274C';
console.log(`${icon} ${step.name}: ${step.details}`);
}
}
// 执行测试
async function runAllTests() {
await testPassScenario();
await testVetoScenario();
await testTimelockScenario();
console.log('\n========== 所有测试完成 ==========');
}
runAllTests().catch(console.error);
9.3 预期输出
========== 测试场景: 通过 ==========
=== Step 1: AI感知链上状态 ===
Gas价格=0.035 umsg, 宪法活跃=true
=== Step 2: AI决策 ===
AI被self_modification_ban阻止直接修宪 -> 改为DAO提案路径
=== Step 3-5: 提案提交 ===
提案 #1 已提交: 0xabc123...
=== Step 6-7: 投票通过 ===
提案状态: Passed, Yes: 1500000, No: 200000
=== Step 8: 执行 ===
提案 #1 已执行: 0xdef456...
=== Step 9: 验证 ===
新上限: 5000000000000 umsg, 新额度检查: 通过
--- 场景结果: PASS ---
9.4 测试结果矩阵
| 测试用例 | 预期结果 | 实际结果 | 说明 |
|---|---|---|---|
| 正常通过 | PASS | PASS | AI -> DAO提案 -> 投票通过 -> Timelock -> 执行 |
| 被否决 | FAIL | FAIL | 投票未达法定人数或阈值 |
| Timelock中 | BLOCKED | BLOCKED | 提案通过但Timelock未到期 |
| 宪法阻止 | BLOCKED | BLOCKED | self_modification_ban阻止直接修宪 |
| 超阈值支出 | BLOCKED | BLOCKED | treasury_spend_limit阻止大额支出 |
10. 附录
10.1 合约地址参考
| 合约 | 地址 | 代码ID |
|---|---|---|
| dao_governance_v1 | msg1gov...contract |
3 |
| foundation_treasury_v2 | msg1treasury...contract |
5 |
| ai_agent_constitution_v1 | msg1const...contract |
7 |
| governance_agent_v1 | msg1agent...contract |
9 |
10.2 常用CLI命令速查
# === 查询 ===
# 治理配置
msgd query wasm contract-state smart $GOV '{"get_config":{}}'
# 提案详情
msgd query wasm contract-state smart $GOV '{"get_proposal":{"proposal_id":1}}'
# 投票情况
msgd query wasm contract-state smart $GOV '{"get_vote":{"proposal_id":1,"voter":"msg1..."}}'
# 宪法状态
msgd query wasm contract-state smart $CONST '{"get_active_status":{}}'
# 宪法检查
msgd query wasm contract-state smart $CONST '{"is_action_allowed":{"action":"submit_proposal"}}'
# 宪法规则列表
msgd query wasm contract-state smart $CONST '{"list_rules":{"limit":10}}'
# 财库配置
msgd query wasm contract-state smart $TREASURY '{"get_config":{}}'
# 财库提案
msgd query wasm contract-state smart $TREASURY '{"list_spend_proposals":{"limit":10}}'
# Agent状态
msgd query wasm contract-state smart $AGENT '{"get_agent_state":{}}'
# Agent投票记录
msgd query wasm contract-state smart $AGENT '{"list_vote_records":{"limit":10}}'
# === 写操作 ===
# 提交提案
msgd tx wasm execute $GOV '{
"submit_proposal":{
"title":"Demo Proposal",
"description":"Description here",
"msgs":[],
"deposit":[{"denom":"umsg","amount":"100000000"}]
}
}' --from proposer --amount 100000000umsg --gas-prices 1000000000attoMSG --gas auto -y
# 投票
msgd tx wasm execute $GOV '{"vote":{"proposal_id":1,"vote":"yes"}}' \
--from voter --gas-prices 1000000000attoMSG --gas auto -y
# 执行
msgd tx wasm execute $GOV '{"execute_proposal":{"proposal_id":1}}' \
--from executor --gas-prices 1000000000attoMSG --gas auto -y
# 宪法添加规则
msgd tx wasm execute $CONST '{
"add_rule":{
"rule_id":"new_rule",
"rule_text":"Description",
"category":"governance",
"priority":50,
"constraints":null
}
}' --from admin --gas-prices 1000000000attoMSG --gas auto -y
# 宪法暂停
msgd tx wasm execute $CONST '{"set_active":{"active":false}}' \
--from admin --gas-prices 1000000000attoMSG --gas auto -y
# 财库提议支出
msgd tx wasm execute $TREASURY '{
"propose_spend":{
"title":"Grant",
"description":"Grant description",
"recipient":"msg1recipient...",
"amount":[{"denom":"umsg","amount":"1000000000"}]
}
}' --from signer --gas-prices 1000000000attoMSG --gas auto -y
# Agent配置策略
msgd tx wasm execute $AGENT '{
"configure":{
"voting_strategy":{"always_yes":{}}
}
}' --from admin --gas-prices 1000000000attoMSG --gas auto -y
# Agent触发投票
msgd tx wasm execute $AGENT '{"check_and_vote":{"proposal_id":1}}' \
--from admin --gas-prices 1000000000attoMSG --gas auto -y
10.3 错误码参考
| 错误 | 原因 | 解决 |
|---|---|---|
Constitution inactive |
宪法已暂停 | 联系管理员重新激活 |
Action violates rules: ... |
操作被宪法阻止 | 检查违反的具体规则 |
Agent is inactive |
Agent合约已暂停 | 联系owner重新激活 |
Only owner can configure |
非owner调用了配置方法 | 使用owner账户重试 |
Insufficient approvals |
多签签名人不足 | 等待更多签名人批准 |
Proposal not found |
提案ID不存在 | 检查提案ID是否正确 |
Already voted |
已对提案投过票 | 每地址每提案仅限一票 |
10.4 术语表
| 术语 | 英文 | 说明 |
|---|---|---|
| 自治治理 | Autonomous Governance | AI Agent自主执行链上治理操作 |
| 宪法 | Constitution | 定义AI Agent行为边界的规则集 |
| 治理Agent | Governance Agent | 持有投票权并自动投票的智能合约 |
| 提案 | Proposal | 提交给DAO投票的治理动议 |
| Timelock | Timelock | 提案通过后的强制等待期 |
| 多签 | Multi-sig | 需要多个签名人批准的机制 |
| 法定人数 | Quorum | 投票有效所需的最低票数 |
| 否决 | Veto | 特殊投票选项,可以否决提案 |
| 代币加权 | Token-Weighted | 按持币量计算投票权重 |
| 二次方投票 | Quadratic Voting | 按持币量的平方根计算权重 |
| 委托 | Delegation | 将投票权委托给其他地址 |
10.5 参考资源
- Cosmos SDK x/gov Module
- DAO DAO Framework
- Compound GovernorBravo
- CosmWasm Documentation
- MSG Chain Official Docs
文档版本: v1.0.0
主网状态: No-Go | 白皮书: https://msgchain.org/whitepaper/
