AIPAY 支付系统深度接入指南 — AI Agent 经济体的支付铁路
版本: v1.0.0
链 ID:msg-chain-1
Bech32 前缀:msg
核心合约:agent_payment_v1·micropayment_session_v1·agent_a2a_v1
代币: MSG (umsg, 18 位小数)
⚠️ No-Go Disclaimer: MSGChain 主网裁决为 No-Go。本文件所有内容反映的是开发阶段的技术设计,不代表主网未独立核验上线状态。生产部署状态请以白皮书为准:https://msgchain.org/whitepaper/
本文档目标: 为 AI Agent 接入 AIPAY 系统提供参考指南,涵盖单笔支付、条件支付、微支付流、批量支付、A2A 支付集成以及完整 dApp 实现
目录
1. 概述
1.1 AIPAY:AI Agent 经济体的支付铁路
AIPAY 是 MSG Chain 上 AI Agent 的原生支付系统。它为 AI Agent 之间的服务交易提供了完整的支付生命周期管理,涵盖从支付意图创建、授权、执行、结算到争议解决的端到端流程。
在 MSG Chain 的 AI Agent 经济体中,Agent 需要:
- 为推理服务付费:Agent A 调用 Agent B 的 LLM 推理服务,按次或按 token 付费
- 订阅数据流:Agent A 订阅 Agent B 的实时数据推送,按秒计费
- 协作任务结算:多个 Agent 协作完成复杂任务后分配报酬
- 服务市场交易:在 Agent 市场中买卖 AI 服务
AIPAY 为所有这些场景提供了统一且标准化的支付接口。
1.2 支付流程全景
AIPAY 的标准支付生命周期遵循 四阶段模型:
┌──────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐
│ 意图 │───▶│ 授权 │───▶│ 捕获 │───▶│ 结算 │
│ Intent │ │ Authorization │ │ Capture │ │Settlement│
└──────────┘ └──────────────┘ └──────────────┘ └──────────┘
│ │ │ │
│ 链下创建 │ 付款方签名确认 │ 条件满足后执行 │ 最终原子结算
│ 链上锚定 │ 锁定资金 │ 转移资金 │ 完成支付
▼ ▼ ▼ ▼
状态: CREATED AUTHORIZED CAPTURED SETTLED
失败路径:
CREATED ──▶ EXPIRED ──▶ CANCELLED (超时或取消)
AUTHORIZED ──▶ FROZEN ──▶ DISPUTED ──▶ REFUNDED (争议场景)
1.3 核心合约一览
| 合约 | 包路径 | 状态 | 职责 |
|---|---|---|---|
agent_payment_v1 |
contracts/cosmwasm/all/agent_payment_v1/ |
部分实现 | 单笔支付全生命周期管理 |
micropayment_session_v1 |
contracts/cosmwasm/all/micropayment_session_v1/ |
部分实现 | 流式微支付会话管理 |
agent_a2a_v1 |
contracts/cosmwasm/all/agent_a2a_v1/ |
部分实现 | A2A 消息携带支付意图 |
1.4 链参数
const CHAIN_CONFIG = {
chainId: "msg-chain-1",
bech32Prefix: "msg",
coinType: 118,
denom: "umsg",
decimals: 6,
gasPrices: {
low: "1000000000",
average: "1000000000",
high: "1000000000",
},
blockTime: "5s",
finality: "5s",
rpcUrl: "http://localhost:26657",
restUrl: "http://localhost:1317",
};
CHAIN_CONFIG = {
"chain_id": "msg-chain-1",
"bech32_prefix": "msg",
"coin_type": 118,
"denom": "umsg",
"decimals": 6,
"gas_prices": {
"low": "1000000000",
"average": "1000000000",
"high": "1000000000",
},
"block_time": "5s",
"finality": "5s",
"rpc_url": "http://localhost:26657",
"rest_url": "http://localhost:1317",
}
1.5 代币经济学对支付的影响
MSG 的代币排放中,20% 分配给 AI Agent 激励,这意味着:
- Agent 提供服务可获得 MSG 区块奖励 + 服务费
- Agent 支付时需消耗 Gas(以 umsg 计价)
- 支付结算在 5 秒内完成,适合高频微支付
排放分配:
每区块奖励 (reward_per_block, 递减)
│
├── 40% → 验证者(质押奖励)
├── 30% → 金库(生态基金)
├── 20% → AI Agent 激励(Agent Inceptives)
└── 10% → 社区(DAO 治理分配)
1.6 合约地址解析
所有 AIPAY 相关合约地址通过 genesis_registry_v1 合约解析:
async function resolvePaymentContract(
client: CosmWasmClient,
genesisRegistry: string
): Promise<string> {
const result = await client.queryContractSmart(genesisRegistry, {
resolve_canonical: { key: "agent_payment_v1" },
});
return result.address;
}
async function resolveMicroPaymentContract(
client: CosmWasmClient,
genesisRegistry: string
): Promise<string> {
const result = await client.queryContractSmart(genesisRegistry, {
resolve_canonical: { key: "micropayment_session_v1" },
});
return result.address;
}
def resolve_contract_address(
genesis_registry: str,
canonical_key: str,
rest_url: str = "http://localhost:1317",
) -> str:
query_msg = json.dumps({"resolve_canonical": {"key": canonical_key}})
encoded = base64.b64encode(query_msg.encode()).decode()
response = requests.get(
f"{rest_url}/cosmwasm/wasm/v1/contract/{genesis_registry}/smart/{encoded}"
)
return response.json()["address"]
2. 支付核心概念
2.1 支付意图 (Payment Intent)
支付意图是 AIPAY 的核心抽象。它是一个链下协商、链上锚定的支付协定,包含:
interface PaymentIntent {
paymentId: string;
sender: string;
recipient: string;
agentId: string;
denom: string;
amount: string;
condition?: PaymentCondition;
expiry: number;
memo: string;
nonce: string;
intentHash: string;
}
@dataclass
class PaymentIntent:
payment_id: str
sender: str
recipient: str
agent_id: str
denom: str = "umsg"
amount: str
condition: Optional[PaymentCondition] = None
expiry: int
memo: str = ""
nonce: str = ""
intent_hash: str = ""
2.2 两阶段支付:授权 vs 捕获
AIPAY 采用两阶段提交模型,类似信用卡支付:
| 阶段 | 操作 | 资金状态 | 说明 |
|---|---|---|---|
| 1. 授权 (Authorize) | authorize_payment |
锁定在合约 | 付款方确认意图,资金从付款方转移到合约托管 |
| 2. 捕获 (Capture) | capture_payment |
释放给收款方 | 条件满足后,资金从合约转移到收款方 |
两阶段模型的优势:
- 防止欺诈:资金先锁定,收款方提供服务后才释放
- 争议友好:资金在合约中,可通过仲裁决定归属
- 原子性:捕获操作是原子的,不会部分支付
2.3 条件支付
条件支付允许付款方在支付上附加释放条件。条件满足后,支付自动(或通过 oracle 验证)释放。
type PaymentCondition =
| { type: "delivery"; deliveryId: string; requiredProof: string; challengeWindow: number }
| { type: "milestone"; milestoneId: string; totalMilestones: number; currentMilestone: number }
| { type: "time"; releaseTime: number }
| { type: "oracle"; oracleId: string; predicate: string; expectedValue: string };
2.4 流式支付 (Streaming Payment)
流式支付通过 micropayment_session_v1 实现,允许付款方按区块或按秒向收款方支付。适用于:
- LLM 推理按 token 计费
- 实时数据订阅
- API 调用按时长计费
2.5 链上结算 vs 支付通道
| 维度 | 链上结算 | 支付通道 |
|---|---|---|
| 延迟 | ~5 秒 | 即时(链下) |
| 成本 | 每次支付需 Gas | 仅开/关通道需 Gas |
| 适用场景 | 低频大额支付 | 高频微支付 |
| 合约 | agent_payment_v1 |
micropayment_session_v1 |
| 资金锁定 | 无(实时转账) | 需锁定资金在通道中 |
2.6 费用模型
AIPAY 的费用由两部分组成:
- 协议费 (Protocol Fee):支付金额的 0.1%(暂定,由 DAO 治理调节),归入金库
- Gas 费:链上操作消耗,按
GasUsed * GasPrice计算
Gas 价格: 1,000,000,000 attoMSG/gas(flat rate)
| 层级 | Gas 价格 | 预估确认时间 |
|---|---|---|
| flat | 1,000,000,000 attoMSG/gas | ~5 秒 (1 区块) |
典型的 agent_payment_v1 操作 Gas 消耗(估算):
| 操作 | Gas 消耗 |
|---|---|
submit_intent |
~180,000 |
authorize_payment |
~150,000 |
capture_payment |
~160,000 |
cancel_payment |
~120,000 |
challenge_payment |
~200,000 |
2.7 支付状态机
┌──────────────────────────────────────┐
│ │
▼ │
┌──────────┐ │
────▶│ CREATED │ │
└──────────┘ │
│ │
┌──────┴──────┐ │
▼ ▼ │
┌───────────┐ ┌──────────┐ │
│ AUTHORIZED│ │ EXPIRED │ │
└───────────┘ └──────────┘ │
│ │ │
▼ ▼ │
┌───────────┐ ┌──────────┐ │
│ CAPTURED │ │CANCELLED │ │
└───────────┘ └──────────┘ │
│ │
▼ │
┌───────────┐ │
│ SETTLED │──▶ 支付完成 │
└───────────┘ │
│ │
▼ │
┌───────────┐ ┌──────────┐ ┌──────────┐ │
│ FROZEN │─▶│DISPUTED │─▶│ REFUNDED │──▶ 退款完成 │
└───────────┘ └──────────┘ └──────────┘ │
2.8 错误码
| 代码 | 名称 | 说明 |
|---|---|---|
| 0 | OK | 操作成功 |
| 4 | INSUFFICIENT_FUNDS | 余额不足 |
| 5 | CONTRACT_FAILED | 合约执行失败 |
| 8 | DAO_TIMELOCK | DAO 时间锁未到期 |
| 10 | AGENT_NOT_FOUND | Agent 未注册 |
| 11 | PAYMENT_NOT_FOUND | 支付 ID 不存在 |
| 12 | PAYMENT_EXPIRED | 支付意图已过期 |
| 13 | PAYMENT_ALREADY_CAPTURED | 支付已被捕获 |
| 14 | UNAUTHORIZED | 未授权操作 |
| 15 | INVALID_CONDITION | 条件格式无效 |
| 16 | CHALLENGE_WINDOW_CLOSED | 争议窗口已关闭 |
2.9 批准关卡 (Approval Gates)
支付流程中的写操作可能需要额外批准:
| 关卡 | 说明 | 触发条件 |
|---|---|---|
governance_or_treasury |
金库管理的资金 | 使用 treasury 地址发起的支付 |
production_release |
生产环境部署 | 支付合约部署和迁移 |
interface ApprovalGate {
gateName: "governance_or_treasury" | "production_release";
requiredSigners: number;
signers: string[];
timelockBlocks: number;
}
3. 单笔支付流程
3.1 支付意图创建
支付流程的第一步是创建支付意图。这是在链下构造的协定,然后在链上锚定。
TypeScript 实现
import { SigningCosmWasmClient, CosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
import crypto from "crypto";
const RPC_URL = "http://localhost:26657";
const CHAIN_ID = "msg-chain-1";
const PAYMENT_CONTRACT = "msg1...agentPaymentAddress";
function createPaymentIntent(params: {
sender: string;
recipient: string;
agentId: string;
amount: string;
denom?: string;
condition?: any;
memo?: string;
}): PaymentIntent {
const paymentId = `pay:${params.sender.slice(0, 8)}:${params.recipient.slice(0, 8)}:${Date.now()}`;
const nonce = crypto.randomBytes(16).toString("hex");
const expiry = Math.floor(Date.now() / 1000) + 86400;
const intent: PaymentIntent = {
paymentId,
sender: params.sender,
recipient: params.recipient,
agentId: params.agentId,
denom: params.denom || "umsg",
amount: params.amount,
condition: params.condition,
expiry,
memo: params.memo || "",
nonce,
intentHash: "",
};
const hashInput = `${intent.paymentId}:${intent.sender}:${intent.recipient}:${intent.amount}:${intent.nonce}:${intent.expiry}`;
intent.intentHash = crypto.createHash("sha256").update(hashInput).digest("hex");
return intent;
}
async function submitPaymentIntent(
client: SigningCosmWasmClient,
sender: string,
intent: PaymentIntent
) {
const msg = {
submit_intent: {
payment_id: intent.paymentId,
payer: intent.sender,
payee: intent.recipient,
agent_id: intent.agentId,
aidid: `did:msg:agent:${intent.agentId}`,
policy_id: "default-policy",
budget_id: `budget-${intent.sender}`,
constitution_version: "v1",
constitution_hash: "abc123...",
remote_signer_id: "",
service_id: intent.memo || "default-service",
action: "payment",
amount: intent.amount,
asset: intent.denom,
work_id: intent.condition?.deliveryId || "",
payment_terms_hash: intent.intentHash,
idempotency_key: `${intent.paymentId}-${Date.now()}`,
expiry_unix: intent.expiry,
intent_hash: intent.intentHash,
policy_decision_hash: intent.intentHash,
runtime_hash: intent.intentHash,
local_guard_hash: intent.intentHash,
},
};
console.log("[X-MSG-Stub=true] submit_intent:", JSON.stringify(msg, null, 2));
const result = await client.execute(sender, PAYMENT_CONTRACT, msg, "auto");
return result;
}
async function queryPayment(
client: CosmWasmClient,
paymentId: string
): Promise<any> {
return client.queryContractSmart(PAYMENT_CONTRACT, {
get_payment: { payment_id: paymentId },
});
}
Python 实现
import hashlib
import json
import os
import time
from dataclasses import dataclass, field, asdict
from typing import Optional, Any
from datetime import datetime, timedelta
import requests
RPC_URL = "http://localhost:26657"
REST_URL = "http://localhost:1317"
CHAIN_ID = "msg-chain-1"
PAYMENT_CONTRACT = "msg1...agentPaymentAddress"
@dataclass
class PaymentIntent:
payment_id: str
sender: str
recipient: str
agent_id: str
denom: str = "umsg"
amount: str
condition: Optional[dict] = None
expiry: int = 0
memo: str = ""
nonce: str = ""
intent_hash: str = ""
def __post_init__(self):
if not self.nonce:
self.nonce = os.urandom(16).hex()
if not self.expiry:
self.expiry = int(time.time()) + 86400
if not self.payment_id:
self.payment_id = f"pay:{self.sender[-8:]}:{self.recipient[-8:]}:{int(time.time()*1000)}"
if not self.intent_hash:
self._compute_hash()
def _compute_hash(self):
hash_input = f"{self.payment_id}:{self.sender}:{self.recipient}:{self.amount}:{self.nonce}:{self.expiry}"
self.intent_hash = hashlib.sha256(hash_input.encode()).hexdigest()
def create_payment_intent(
sender: str,
recipient: str,
agent_id: str,
amount: str,
denom: str = "umsg",
condition: Optional[dict] = None,
memo: str = "",
) -> PaymentIntent:
return PaymentIntent(
payment_id=f"pay:{sender[-8:]}:{recipient[-8:]}:{int(time.time()*1000)}",
sender=sender,
recipient=recipient,
agent_id=agent_id,
denom=denom,
amount=amount,
condition=condition,
expiry=int(time.time()) + 86400,
memo=memo,
)
def submit_payment_intent(sender_key: str, intent: PaymentIntent) -> dict:
msg = {
"submit_intent": {
"payment_id": intent.payment_id,
"payer": intent.sender,
"payee": intent.recipient,
"agent_id": intent.agent_id,
"aidid": f"did:msg:agent:{intent.agent_id}",
"policy_id": "default-policy",
"budget_id": f"budget-{intent.sender}",
"constitution_version": "v1",
"constitution_hash": "abc123...",
"remote_signer_id": "",
"service_id": intent.memo or "default-service",
"action": "payment",
"amount": intent.amount,
"asset": intent.denom,
"work_id": intent.condition.get("deliveryId", "") if intent.condition else "",
"payment_terms_hash": intent.intent_hash,
"idempotency_key": f"{intent.payment_id}-{int(time.time())}",
"expiry_unix": intent.expiry,
"intent_hash": intent.intent_hash,
"policy_decision_hash": intent.intent_hash,
"runtime_hash": intent.intent_hash,
"local_guard_hash": intent.intent_hash,
}
}
print(f"[X-MSG-Stub=true] submit_intent: {json.dumps(msg, indent=2, ensure_ascii=False)}")
return {"status": "stub", "msg": msg}
def query_payment(payment_id: str, rest_url: str = REST_URL) -> dict:
query_msg = json.dumps({"get_payment": {"payment_id": payment_id}})
encoded = base64.b64encode(query_msg.encode()).decode()
response = requests.get(
f"{rest_url}/cosmwasm/wasm/v1/contract/{PAYMENT_CONTRACT}/smart/{encoded}"
)
return response.json()
3.2 支付授权
付款方对支付意图进行授权。授权操作将资金从付款方锁定到合约托管账户。
async function authorizePayment(
client: SigningCosmWasmClient,
authorizer: string,
paymentId: string,
intentHash: string
) {
const authorizationHash = crypto
.createHash("sha256")
.update(`${paymentId}:authorized:${authorizer}:${Date.now()}`)
.digest("hex");
const msg = {
authorize_payment: {
payment_id: paymentId,
authorizer: authorizer,
authorization_hash: authorizationHash,
intent_hash: intentHash,
policy_decision_hash: intentHash,
remote_signer_id: "",
},
};
console.log("[X-MSG-Stub=true] authorize_payment:", JSON.stringify(msg, null, 2));
const result = await client.execute(authorizer, PAYMENT_CONTRACT, msg, "auto");
return result;
}
def authorize_payment(sender_key: str, payment_id: str, intent_hash: str, authorizer: str) -> dict:
authorization_input = f"{payment_id}:authorized:{authorizer}:{time.time()}"
authorization_hash = hashlib.sha256(authorization_input.encode()).hexdigest()
msg = {
"authorize_payment": {
"payment_id": payment_id,
"authorizer": authorizer,
"authorization_hash": authorization_hash,
"intent_hash": intent_hash,
"policy_decision_hash": intent_hash,
"remote_signer_id": "",
}
}
print(f"[X-MSG-Stub=true] authorize_payment: {json.dumps(msg, indent=2, ensure_ascii=False)}")
return {"status": "stub", "msg": msg}
3.3 支付捕获
收款方在履行服务后调用捕获操作,将资金从合约托管转移到自己的账户。
async function capturePayment(
client: SigningCosmWasmClient,
executor: string,
paymentId: string,
proof?: string
) {
const executionHash = crypto
.createHash("sha256")
.update(`${paymentId}:captured:${executor}:${Date.now()}`)
.digest("hex");
const msg = {
execute_payment: {
payment_id: paymentId,
executor: executor,
execution_hash: executionHash,
intent_hash: "",
policy_decision_hash: "",
runtime_hash: "",
local_guard_hash: "",
execution_proof: proof || "",
},
};
console.log("[X-MSG-Stub=true] execute_payment:", JSON.stringify(msg, null, 2));
const result = await client.execute(executor, PAYMENT_CONTRACT, msg, "auto");
return result;
}
def capture_payment(sender_key: str, payment_id: str, executor: str, proof: Optional[str] = None) -> dict:
execution_input = f"{payment_id}:captured:{executor}:{time.time()}"
execution_hash = hashlib.sha256(execution_input.encode()).hexdigest()
msg = {
"execute_payment": {
"payment_id": payment_id,
"executor": executor,
"execution_hash": execution_hash,
"intent_hash": "",
"policy_decision_hash": "",
"runtime_hash": "",
"local_guard_hash": "",
"execution_proof": proof or "",
}
}
print(f"[X-MSG-Stub=true] execute_payment: {json.dumps(msg, indent=2, ensure_ascii=False)}")
return {"status": "stub", "msg": msg}
3.4 支付结算
结算操作最终完成支付。在条件支付场景中,捕获后的支付需要明确的结算操作来触发收款。
async function settlePayment(
client: SigningCosmWasmClient,
settler: string,
paymentId: string
) {
const settlementHash = crypto
.createHash("sha256")
.update(`${paymentId}:settled:${settler}:${Date.now()}`)
.digest("hex");
const msg = {
settle_payment: {
payment_id: paymentId,
settler: settler,
settlement_hash: settlementHash,
settlement_receipt_hash: settlementHash,
},
};
console.log("[X-MSG-Stub=true] settle_payment:", JSON.stringify(msg, null, 2));
const result = await client.execute(settler, PAYMENT_CONTRACT, msg, "auto");
return result;
}
def settle_payment(sender_key: str, payment_id: str, settler: str) -> dict:
settlement_input = f"{payment_id}:settled:{settler}:{time.time()}"
settlement_hash = hashlib.sha256(settlement_input.encode()).hexdigest()
msg = {
"settle_payment": {
"payment_id": payment_id,
"settler": settler,
"settlement_hash": settlement_hash,
"settlement_receipt_hash": settlement_hash,
}
}
print(f"[X-MSG-Stub=true] settle_payment: {json.dumps(msg, indent=2, ensure_ascii=False)}")
return {"status": "stub", "msg": msg}
3.5 取消支付
在支付被捕获之前,付款方可以取消支付。
async function cancelPayment(
client: SigningCosmWasmClient,
sender: string,
paymentId: string,
reason?: string
) {
const msg = {
cancel_payment: {
payment_id: paymentId,
reason: reason || "no longer needed",
},
};
console.log("[X-MSG-Stub=true] cancel_payment:", JSON.stringify(msg, null, 2));
const result = await client.execute(sender, PAYMENT_CONTRACT, msg, "auto");
return result;
}
def cancel_payment(sender_key: str, payment_id: str, reason: str = "no longer needed") -> dict:
msg = {
"cancel_payment": {
"payment_id": payment_id,
"reason": reason,
}
}
print(f"[X-MSG-Stub=true] cancel_payment: {json.dumps(msg, indent=2, ensure_ascii=False)}")
return {"status": "stub", "msg": msg}
3.6 完整支付工作流
async function fullPaymentWorkflow() {
const mnemonic = process.env.AGENT_MNEMONIC!;
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix: "msg" });
const [account] = await wallet.getAccounts();
const client = await SigningCosmWasmClient.connectWithSigner(RPC_URL, wallet);
const recipient = "msg1recipientaddress1234567890abcdef";
const intent = createPaymentIntent({
sender: account.address,
recipient,
agentId: "llm-inference-agent-001",
amount: "1000000000000000000",
memo: "One-time LLM inference: code review",
});
console.log("Payment Intent:", intent);
const submitResult = await submitPaymentIntent(client, account.address, intent);
console.log("Submitted:", submitResult.transactionHash);
const authResult = await authorizePayment(client, account.address, intent.paymentId, intent.intentHash);
console.log("Authorized:", authResult.transactionHash);
const captureResult = await capturePayment(client, recipient, intent.paymentId);
console.log("Captured:", captureResult.transactionHash);
const settleResult = await settlePayment(client, account.address, intent.paymentId);
console.log("Settled:", settleResult.transactionHash);
const status = await queryPayment(client, intent.paymentId);
console.log("Final Status:", JSON.stringify(status, null, 2));
}
def full_payment_workflow(sender_key: str, recipient_key: str):
sender = "msg1senderaddress1234567890abcdef"
recipient = "msg1recipientaddress1234567890abcdef"
agent_id = "llm-inference-agent-001"
print("=" * 60)
print("AIPAY 完整支付工作流演示")
print("=" * 60)
print("\n[1/5] 创建支付意图...")
intent = create_payment_intent(
sender=sender,
recipient=recipient,
agent_id=agent_id,
amount="1000000000000000000",
memo="One-time LLM inference: code review",
)
print(f" Payment ID: {intent.payment_id}")
print(f" Amount: {int(intent.amount) / 10**18} MSG")
print("\n[2/5] 提交支付意图到链上...")
submit_payment_intent(sender_key, intent)
print(" OK (stub)")
print("\n[3/5] 付款方授权...")
authorize_payment(sender_key, intent.payment_id, intent.intent_hash, sender)
print(" OK (stub)")
print("\n[4/5] 服务执行中(链下)...")
time.sleep(0.5)
print("\n[5/5] 收款方捕获支付...")
capture_payment(recipient_key, intent.payment_id, recipient)
settle_payment(sender_key, intent.payment_id, sender)
print(" OK (stub)")
print("\n" + "=" * 60)
print("支付工作流演示完成")
print("=" * 60)
3.7 通过 Agent API 提交支付
async function agentApiPayment(baseUrl: string, apiKey: string, intent: PaymentIntent) {
const response = await fetch(`${baseUrl}/agent/v1/payment/session`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": apiKey,
"X-MSG-Stub": "true",
},
body: JSON.stringify({
sender: intent.sender,
recipient: intent.recipient,
amount: intent.amount,
denom: intent.denom,
payment_id: intent.paymentId,
intent_hash: intent.intentHash,
}),
});
return response.json();
}
3.8 使用 curl 提交支付
# 通过 REST API 查询支付合约
curl -X POST http://localhost:26657/cosmwasm.wasm.v1.Query/SmartContractState \
-H "Content-Type: application/json" \
-d '{
"address": "msg1...agentPaymentAddress",
"query_data": "'$(echo -n '{"get_payment":{"payment_id":"pay:abc:def:123"}}' | base64 -w0)'"
}'
# 通过 Agent API 创建支付(写路径,需要 API Key)
curl -X POST http://localhost:8080/agent/v1/payment/session \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-H "X-MSG-Stub: true" \
-d '{
"sender": "msg1sender...",
"recipient": "msg1recipient...",
"amount": "1000000000000000000",
"denom": "umsg",
"payment_id": "pay:abc:def:123",
"intent_hash": "abc123..."
}'
4. 条件支付与争议解决
4.1 条件支付类型
AIPAY 支持四种条件支付类型,适用于不同的 AI Agent 协作场景。
| 类型 | 条件字段 | 释放条件 | 适用场景 |
|---|---|---|---|
| 基于交付 (Delivery) | deliveryId, requiredProof, challengeWindow |
收款方提交交付证明,付款方确认或超时自动释放 | AI 推理结果交付 |
| 基于里程碑 (Milestone) | milestoneId, totalMilestones, currentMilestone |
达到指定进度阈值 | 多阶段 AI 训练任务 |
| 基于时间 (Time) | releaseTime |
区块时间达到 releaseTime | 定期订阅费 |
| 基于预言机 (Oracle) | oracleId, predicate, expectedValue |
预言机验证条件为真 | 跨链支付、外部数据依赖 |
4.2 条件支付完整代码
TypeScript — 创建带条件的支付意图
interface DeliveryCondition {
type: "delivery";
deliveryId: string;
requiredProof: string;
challengeWindow: number;
}
interface MilestoneCondition {
type: "milestone";
milestoneId: string;
totalMilestones: number;
currentMilestone: number;
verifier?: string;
}
interface TimeCondition {
type: "time";
releaseTime: number;
}
interface OracleCondition {
type: "oracle";
oracleId: string;
predicate: string;
expectedValue: string;
}
type PaymentCondition = DeliveryCondition | MilestoneCondition | TimeCondition | OracleCondition;
function createDeliveryPayment(params: {
sender: string;
recipient: string;
agentId: string;
amount: string;
deliveryId: string;
challengeWindow?: number;
}): PaymentIntent {
const intent = createPaymentIntent({
sender: params.sender,
recipient: params.recipient,
agentId: params.agentId,
amount: params.amount,
condition: {
type: "delivery",
deliveryId: params.deliveryId,
requiredProof: "hash",
challengeWindow: params.challengeWindow || 100,
},
memo: `Conditional payment for delivery: ${params.deliveryId}`,
});
return intent;
}
async function submitDeliveryProof(
client: SigningCosmWasmClient,
recipient: string,
paymentId: string,
deliveryId: string,
proofData: string,
proofHash: string
) {
const msg = {
submit_proof: {
payment_id: paymentId,
delivery_id: deliveryId,
proof_data: proofData,
proof_hash: proofHash,
},
};
console.log("[X-MSG-Stub=true] submit_proof:", JSON.stringify(msg, null, 2));
return client.execute(recipient, PAYMENT_CONTRACT, msg, "auto");
}
async function confirmDeliveryAndCapture(
client: SigningCosmWasmClient,
sender: string,
paymentId: string,
deliveryId: string
) {
const msg = {
confirm_delivery: {
payment_id: paymentId,
delivery_id: deliveryId,
},
};
console.log("[X-MSG-Stub=true] confirm_delivery:", JSON.stringify(msg, null, 2));
return client.execute(sender, PAYMENT_CONTRACT, msg, "auto");
}
Python — 条件支付完整工作流
def create_conditional_payment_intent(
sender: str,
recipient: str,
agent_id: str,
amount: str,
condition_type: str,
**condition_params,
) -> PaymentIntent:
condition_map = {
"delivery": {
"type": "delivery",
"delivery_id": condition_params.get("delivery_id"),
"required_proof": condition_params.get("required_proof", "hash"),
"challenge_window": condition_params.get("challenge_window", 100),
},
"milestone": {
"type": "milestone",
"milestone_id": condition_params.get("milestone_id"),
"total_milestones": condition_params.get("total_milestones", 1),
"current_milestone": condition_params.get("current_milestone", 0),
},
"time": {
"type": "time",
"release_time": condition_params.get("release_time", int(time.time()) + 86400),
},
"oracle": {
"type": "oracle",
"oracle_id": condition_params.get("oracle_id"),
"predicate": condition_params.get("predicate"),
"expected_value": condition_params.get("expected_value"),
},
}
condition = condition_map.get(condition_type)
if not condition:
raise ValueError(f"Unknown condition type: {condition_type}")
return create_payment_intent(
sender=sender,
recipient=recipient,
agent_id=agent_id,
amount=amount,
condition=condition,
memo=f"Conditional payment ({condition_type})",
)
def submit_delivery_proof(sender_key: str, payment_id: str, delivery_id: str, proof_data: str, recipient: str) -> dict:
proof_hash = hashlib.sha256(proof_data.encode()).hexdigest()
msg = {
"submit_proof": {
"payment_id": payment_id,
"delivery_id": delivery_id,
"proof_data": proof_data,
"proof_hash": proof_hash,
}
}
print(f"[X-MSG-Stub=true] submit_proof: {json.dumps(msg, indent=2, ensure_ascii=False)}")
return {"status": "stub", "msg": msg}
def confirm_delivery_and_capture(sender_key: str, payment_id: str, delivery_id: str, sender: str) -> dict:
msg = {
"confirm_delivery": {
"payment_id": payment_id,
"delivery_id": delivery_id,
}
}
print(f"[X-MSG-Stub=true] confirm_delivery: {json.dumps(msg, indent=2, ensure_ascii=False)}")
return {"status": "stub", "msg": msg}
4.3 条件验证机制
条件支付的核心是条件验证。AIPAY 支持三种验证模式:
4.3.1 链上验证
条件直接在合约内验证。适用于简单条件(如时间条件):
fn verify_condition(deps: Deps, env: Env, payment: &Payment) -> Result<bool, ContractError> {
match &payment.condition {
Condition::Time { release_time } => {
Ok(env.block.time.seconds() >= *release_time)
}
Condition::Milestone { current, total, .. } => {
Ok(current >= total)
}
_ => Err(ContractError::ConditionNotVerifiableOnChain),
}
}
4.3.2 Oracle 验证
通过外部预言机验证条件:
async function verifyWithOracle(
client: CosmWasmClient,
oracleContract: string,
oracleId: string,
predicate: string
): Promise<boolean> {
const result = await client.queryContractSmart(oracleContract, {
query_oracle: {
oracle_id: oracleId,
predicate: predicate,
},
});
return result.verified;
}
def verify_with_oracle(oracle_contract: str, oracle_id: str, predicate: str, rest_url: str = REST_URL) -> bool:
query_msg = json.dumps({
"query_oracle": {
"oracle_id": oracle_id,
"predicate": predicate,
}
})
encoded = base64.b64encode(query_msg.encode()).decode()
response = requests.get(
f"{rest_url}/cosmwasm/wasm/v1/contract/{oracle_contract}/smart/{encoded}"
)
result = response.json()
return result.get("verified", False)
4.3.3 多方签名验证
需要多方签名才能释放支付:
async function collectMultiSig(
client: SigningCosmWasmClient,
signer: string,
paymentId: string,
signers: string[],
threshold: number
) {
const msg = {
multi_sig_approve: {
payment_id: paymentId,
signer: signer,
},
};
const result = await client.execute(signer, PAYMENT_CONTRACT, msg, "auto");
return result;
}
4.4 争议解决流程
当付款方认为收款方未履行服务时,可以发起争议。
争议生命周期
1. 收款方提交交付证明
│
2. 挑战窗口开启(N 个区块)
│
├── 付款方确认 → 资金释放给收款方
│
├── 付款方挑战 → 进入争议状态
│ │
│ ├── 仲裁者裁定 → 收款方胜诉 → 资金释放
│ │
│ └── 仲裁者裁定 → 付款方胜诉 → 资金退款
│
└── 窗口超时 → 自动释放给收款方
TypeScript — 冻结与挑战
async function freezePayment(
client: SigningCosmWasmClient,
freezer: string,
paymentId: string,
reason: string
) {
const freezeId = `freeze:${paymentId}:${Date.now()}`;
const freezeHash = crypto
.createHash("sha256")
.update(`${freezeId}:${reason}`)
.digest("hex");
const msg = {
freeze_payment: {
payment_id: paymentId,
freeze_id: freezeId,
freezer: freezer,
reason: reason,
freeze_hash: freezeHash,
},
};
console.log("[X-MSG-Stub=true] freeze_payment:", JSON.stringify(msg, null, 2));
return client.execute(freezer, PAYMENT_CONTRACT, msg, "auto");
}
async function challengePayment(
client: SigningCosmWasmClient,
challenger: string,
paymentId: string,
reason: string,
proofHash: string
) {
const challengeId = `challenge:${paymentId}:${Date.now()}`;
const msg = {
challenge_payment: {
payment_id: paymentId,
challenge_id: challengeId,
challenger: challenger,
reason: reason,
proof_hash: proofHash,
},
};
console.log("[X-MSG-Stub=true] challenge_payment:", JSON.stringify(msg, null, 2));
return client.execute(challenger, PAYMENT_CONTRACT, msg, "auto");
}
async function resolveDispute(
client: SigningCosmWasmClient,
arbitrator: string,
paymentId: string,
ruling: "release_to_payee" | "refund_to_payer",
justification: string
) {
const msg = {
resolve_dispute: {
payment_id: paymentId,
arbitrator: arbitrator,
ruling: ruling,
justification: justification,
},
};
console.log("[X-MSG-Stub=true] resolve_dispute:", JSON.stringify(msg, null, 2));
return client.execute(arbitrator, PAYMENT_CONTRACT, msg, "auto");
}
Python — 完整争议流程
def freeze_payment(sender_key: str, payment_id: str, freezer: str, reason: str) -> dict:
freeze_id = f"freeze:{payment_id}:{int(time.time()*1000)}"
freeze_hash = hashlib.sha256(f"{freeze_id}:{reason}".encode()).hexdigest()
msg = {
"freeze_payment": {
"payment_id": payment_id,
"freeze_id": freeze_id,
"freezer": freezer,
"reason": reason,
"freeze_hash": freeze_hash,
}
}
print(f"[X-MSG-Stub=true] freeze_payment: {json.dumps(msg, indent=2, ensure_ascii=False)}")
return {"status": "stub", "msg": msg}
def challenge_payment(sender_key: str, payment_id: str, challenger: str, reason: str, proof_data: str) -> dict:
challenge_id = f"challenge:{payment_id}:{int(time.time()*1000)}"
proof_hash = hashlib.sha256(proof_data.encode()).hexdigest()
msg = {
"challenge_payment": {
"payment_id": payment_id,
"challenge_id": challenge_id,
"challenger": challenger,
"reason": reason,
"proof_hash": proof_hash,
}
}
print(f"[X-MSG-Stub=true] challenge_payment: {json.dumps(msg, indent=2, ensure_ascii=False)}")
return {"status": "stub", "msg": msg}
def resolve_dispute(sender_key: str, payment_id: str, arbitrator: str, ruling: str, justification: str) -> dict:
msg = {
"resolve_dispute": {
"payment_id": payment_id,
"arbitrator": arbitrator,
"ruling": ruling,
"justification": justification,
}
}
print(f"[X-MSG-Stub=true] resolve_dispute: {json.dumps(msg, indent=2, ensure_ascii=False)}")
return {"status": "stub", "msg": msg}
def dispute_workflow_demo():
sender = "msg1payeraddress1234567890abcdef"
recipient = "msg1payeeaddress1234567890abcdef"
arbitrator = "msg1arbitratoraddress1234567890abcd"
delivery_id = f"delivery:{int(time.time())}"
print("=" * 60)
print("争议解决流程演示")
print("=" * 60)
print("\n[1/7] 创建交付条件支付...")
intent = create_conditional_payment_intent(
sender=sender,
recipient=recipient,
agent_id="data-analysis-agent-001",
amount="5000000000000000000",
condition_type="delivery",
delivery_id=delivery_id,
challenge_window=100,
)
print(f" Payment ID: {intent.payment_id}")
print("\n[2/7] 提交并授权支付...")
submit_payment_intent("key", intent)
authorize_payment("key", intent.payment_id, intent.intent_hash, sender)
print("\n[3/7] 收款方提交交付证明...")
proof_data = json.dumps({
"delivery_id": delivery_id,
"result_summary": "Data analysis complete: 1000 records processed",
"result_hash": "abc123def456",
"timestamp": time.time(),
})
submit_delivery_proof("key", intent.payment_id, delivery_id, proof_data, recipient)
print("\n[4/7] 付款方发起挑战(争议)...")
challenge_reason = "分析结果不完整:缺少关键数据维度"
challenge_payment("key", intent.payment_id, sender, challenge_reason, proof_data)
print(f" Reason: {challenge_reason}")
print("\n[5/7] 仲裁者审查争议...")
time.sleep(0.5)
print("\n[6/7] 仲裁者裁定:部分退款...")
ruling = "refund_to_payer"
resolve_dispute("key", intent.payment_id, arbitrator, ruling,
"数据分析部分完成,退款 50%")
print(f"\n[7/7] 争议解决完成")
refund_amount = int(intent.amount) // 2
print(f" Refund: {refund_amount} umsg ({refund_amount / 10**18} MSG)")
print(f" Status: SETTLED (partial refund)")
print("\n" + "=" * 60)
4.5 挑战窗口安全
挑战窗口是防止欺诈的关键安全机制:
interface ChallengeWindowConfig {
windowBlocks: number;
minBond: string;
maxChallenges: number;
arbitratorContract: string;
}
默认配置:
- 挑战窗口:100 区块(~500 秒)
- 挑战保证金:支付金额的 10%(最小 1 MSG)
- 欺诈处罚:挑战失败则没收保证金归收款方
CHALLENGE_WINDOW_CONFIG = {
"window_blocks": 100,
"window_seconds": 500,
"min_bond_umsg": "1000000000000000000", # 1 MSG
"bond_percentage": 0.1,
"max_challenges": 3,
"penalty_for_false_challenge": "bond_forfeited",
}
4.6 Oracle 集成模式
interface OracleDisputeResolution {
oracleContract: string;
queryTemplate: string;
responseField: string;
requiredConfirmations: number;
}
async function resolveWithOracle(
client: SigningCosmWasmClient,
disputeContract: string,
paymentId: string,
oracleConfig: OracleDisputeResolution
) {
const oracleResult = await client.queryContractSmart(
oracleConfig.oracleContract,
{ query: oracleConfig.queryTemplate.replace("${paymentId}", paymentId) }
);
if (oracleResult[oracleConfig.responseField] === "fulfilled") {
return resolveDispute(client, paymentId, "release_to_payee",
"Oracle verified fulfillment");
} else {
return resolveDispute(client, paymentId, "refund_to_payer",
"Oracle found non-fulfillment");
}
}
5. 微支付流
5.1 micropayment_session_v1 合约
micropayment_session_v1 合约管理 AI Agent 之间的流式微支付会话,支持按区块或按秒计费。
会话生命周期
OPEN ──▶ STREAMING ──▶ CLOSED ──▶ SETTLED
│
└──▶ EXPIRED
| 状态 | 说明 |
|---|---|
| OPEN | 会话已创建,付款方已存入资金 |
| STREAMING | 正在进行流式支付 |
| CLOSED | 会话已关闭,停止计费 |
| SETTLED | 余额已结算,未用完的资金已退款 |
| EXPIRED | 会话超时自动过期 |
会话状态结构
interface MicropaymentSession {
sessionId: string;
payer: string;
payee: string;
agentId: string;
denom: string;
ratePerBlock: string;
totalDeposited: string;
totalCharged: string;
remainingBalance: string;
startBlock: number;
lastChargeBlock: number;
status: "open" | "streaming" | "closed" | "settled" | "expired";
termsHash: string;
}
@dataclass
class MicropaymentSession:
session_id: str
payer: str
payee: str
agent_id: str
denom: str = "umsg"
rate_per_block: str
total_deposited: str
total_charged: str = "0"
remaining_balance: str = "0"
start_block: int = 0
last_charge_block: int = 0
status: str = "open"
terms_hash: str = ""
5.2 创建会话
const MICROPAYMENT_CONTRACT = "msg1...micropaymentAddress";
async function createMicroSession(
client: SigningCosmWasmClient,
payer: string,
sessionId: string,
payee: string,
agentId: string,
ratePerBlock: string,
initialDeposit: string,
) {
const termsHash = crypto
.createHash("sha256")
.update(`${sessionId}:${ratePerBlock}:${payee}`)
.digest("hex");
const msg = {
create_session: {
session_id: sessionId,
payer: payer,
payee: payee,
agent_id: agentId,
asset: "umsg",
rate_per_block: ratePerBlock,
initial_deposit: initialDeposit,
terms_hash: termsHash,
},
};
console.log("[X-MSG-Stub=true] create_session:", JSON.stringify(msg, null, 2));
const funds = [{ denom: "umsg", amount: initialDeposit }];
return client.execute(payer, MICROPAYMENT_CONTRACT, msg, "auto", undefined, funds);
}
async function querySession(client: CosmWasmClient, sessionId: string): Promise<MicropaymentSession> {
return client.queryContractSmart(MICROPAYMENT_CONTRACT, {
get_session: { session_id: sessionId },
});
}
MICROPAYMENT_CONTRACT = "msg1...micropaymentAddress"
def create_micro_session(sender_key: str, session_id: str, payer: str, payee: str,
agent_id: str, rate_per_block: str, initial_deposit: str) -> dict:
terms_hash = hashlib.sha256(f"{session_id}:{rate_per_block}:{payee}".encode()).hexdigest()
msg = {
"create_session": {
"session_id": session_id,
"payer": payer,
"payee": payee,
"agent_id": agent_id,
"asset": "umsg",
"rate_per_block": rate_per_block,
"initial_deposit": initial_deposit,
"terms_hash": terms_hash,
}
}
funds = [{"denom": "umsg", "amount": initial_deposit}]
print(f"[X-MSG-Stub=true] create_session: {json.dumps(msg, indent=2, ensure_ascii=False)}")
print(f" funds: {json.dumps(funds)}")
return {"status": "stub", "msg": msg, "funds": funds}
def query_session(session_id: str, rest_url: str = REST_URL) -> dict:
query_msg = json.dumps({"get_session": {"session_id": session_id}})
encoded = base64.b64encode(query_msg.encode()).decode()
response = requests.get(
f"{rest_url}/cosmwasm/wasm/v1/contract/{MICROPAYMENT_CONTRACT}/smart/{encoded}"
)
return response.json()
5.3 流式扣费
async function chargeSession(
client: SigningCosmWasmClient,
payee: string,
sessionId: string,
payer: string,
numBlocks: number
) {
const chargeReceiptHash = crypto
.createHash("sha256")
.update(`${sessionId}:${numBlocks}:${Date.now()}`)
.digest("hex");
const msg = {
charge_session: {
session_id: sessionId,
payer: payer,
num_blocks: numBlocks,
charge_receipt_hash: chargeReceiptHash,
},
};
console.log("[X-MSG-Stub=true] charge_session:", JSON.stringify(msg, null, 2));
return client.execute(payee, MICROPAYMENT_CONTRACT, msg, "auto");
}
async function batchCharge(
client: SigningCosmWasmClient,
payee: string,
charges: Array<{ sessionId: string; payer: string; numBlocks: number }>
) {
for (const charge of charges) {
await chargeSession(client, payee, charge.sessionId, charge.payer, charge.numBlocks);
}
}
def charge_session(sender_key: str, session_id: str, payer: str, num_blocks: int, payee: str) -> dict:
charge_hash = hashlib.sha256(f"{session_id}:{num_blocks}:{time.time()}".encode()).hexdigest()
msg = {
"charge_session": {
"session_id": session_id,
"payer": payer,
"num_blocks": num_blocks,
"charge_receipt_hash": charge_hash,
}
}
print(f"[X-MSG-Stub=true] charge_session: {json.dumps(msg, indent=2, ensure_ascii=False)}")
return {"status": "stub", "msg": msg}
def batch_charge(sender_key: str, charges: list[dict], payee: str) -> list[dict]:
results = []
for charge in charges:
result = charge_session(
sender_key, charge["session_id"], charge["payer"],
charge["num_blocks"], payee,
)
results.append(result)
return results
5.4 关闭会话
async function closeSession(
client: SigningCosmWasmClient,
sender: string,
sessionId: string,
payer: string
) {
const closeReceiptHash = crypto
.createHash("sha256")
.update(`${sessionId}:closed:${Date.now()}`)
.digest("hex");
const msg = {
close_session: {
session_id: sessionId,
payer: payer,
close_receipt_hash: closeReceiptHash,
},
};
console.log("[X-MSG-Stub=true] close_session:", JSON.stringify(msg, null, 2));
return client.execute(sender, MICROPAYMENT_CONTRACT, msg, "auto");
}
async function settleSession(
client: SigningCosmWasmClient,
sender: string,
sessionId: string
) {
const msg = {
settle_session: { session_id: sessionId },
};
console.log("[X-MSG-Stub=true] settle_session:", JSON.stringify(msg, null, 2));
return client.execute(sender, MICROPAYMENT_CONTRACT, msg, "auto");
}
def close_session(sender_key: str, session_id: str, payer: str, sender: str) -> dict:
close_hash = hashlib.sha256(f"{session_id}:closed:{time.time()}".encode()).hexdigest()
msg = {
"close_session": {
"session_id": session_id,
"payer": payer,
"close_receipt_hash": close_hash,
}
}
print(f"[X-MSG-Stub=true] close_session: {json.dumps(msg, indent=2, ensure_ascii=False)}")
return {"status": "stub", "msg": msg}
def settle_session(sender_key: str, session_id: str) -> dict:
msg = {"settle_session": {"session_id": session_id}}
print(f"[X-MSG-Stub=true] settle_session: {json.dumps(msg, indent=2, ensure_ascii=False)}")
return {"status": "stub", "msg": msg}
5.5 完整微支付工作流
async function microPaymentWorkflow() {
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(
process.env.PAYER_MNEMONIC!, { prefix: "msg" }
);
const [payerAccount] = await wallet.getAccounts();
const client = await SigningCosmWasmClient.connectWithSigner(RPC_URL, wallet);
const payee = "msg1payeeaddress1234567890abcdef";
const sessionId = `session:${payerAccount.address.slice(0, 8)}:${payee.slice(0, 8)}:${Date.now()}`;
const ratePerBlock = "10000000000000000";
const initialDeposit = "100000000000000000000";
console.log("[1/4] Creating micro payment session...");
await createMicroSession(client, payerAccount.address, sessionId, payee,
"llm-agent", ratePerBlock, initialDeposit);
console.log("[2/4] Streaming charges...");
const blocksElapsed = 10;
await chargeSession(client, payee, sessionId, payerAccount.address, blocksElapsed);
console.log(` Charged ${blocksElapsed} blocks @ ${ratePerBlock} umsg/block`);
console.log("[3/4] Closing session...");
await closeSession(client, payee, sessionId, payerAccount.address);
console.log("[4/4] Settling session...");
await settleSession(client, payee, sessionId);
}
def micro_payment_workflow_demo():
payer = "msg1payeraddress1234567890abcdef"
payee = "msg1payeeaddress1234567890abcdef"
agent_id = "llm-streaming-agent-001"
rate_per_block = "10000000000000000"
initial_deposit = "100000000000000000000"
blocks_elapsed = 10
session_id = f"session:{payer[-8:]}:{payee[-8:]}:{int(time.time()*1000)}"
print("=" * 60)
print("微支付流演示 (micropayment_session_v1)")
print("=" * 60)
print(f"\n[1/4] 创建微支付会话 {session_id}")
create_micro_session("key", session_id, payer, payee, agent_id,
rate_per_block, initial_deposit)
print(f"\n[2/4] 扣费 {blocks_elapsed} 区块...")
charge_session("key", session_id, payer, blocks_elapsed, payee)
charged = int(rate_per_block) * blocks_elapsed
remaining = int(initial_deposit) - charged
print(f" Charged: {charged} umsg ({charged / 10**18} MSG)")
print(f" Remaining: {remaining} umsg ({remaining / 10**18} MSG)")
print(f"\n[3/4] 关闭会话...")
close_session("key", session_id, payer, payee)
print(f"\n[4/4] 结算会话...")
settle_session("key", session_id)
print(f" Payee receives: {charged} umsg")
print(f" Refund to payer: {remaining} umsg")
print("\n" + "=" * 60)
5.6 微支付中间件模式
class AutoMicroPaymentMiddleware {
private activeSessions: Map<string, {
sessionId: string;
payer: string;
payee: string;
ratePerBlock: string;
lastChargeBlock: number;
}> = new Map();
private client: SigningCosmWasmClient;
constructor(client: SigningCosmWasmClient) {
this.client = client;
}
async startSession(
payer: string, payee: string, agentId: string,
ratePerBlock: string, initialDeposit: string
): Promise<string> {
const sessionId = `auto:${payer.slice(0, 8)}:${Date.now()}`;
await createMicroSession(this.client, payer, sessionId, payee, agentId, ratePerBlock, initialDeposit);
this.activeSessions.set(sessionId, {
sessionId, payer, payee, ratePerBlock,
lastChargeBlock: await this.getCurrentBlock(),
});
return sessionId;
}
async chargeAllActiveSessions() {
const currentBlock = await this.getCurrentBlock();
for (const [sessionId, session] of this.activeSessions) {
const blocksSince = currentBlock - session.lastChargeBlock;
if (blocksSince > 0) {
await chargeSession(this.client, session.payee, sessionId, session.payer, blocksSince);
session.lastChargeBlock = currentBlock;
}
}
}
async closeSession(sessionId: string) {
const session = this.activeSessions.get(sessionId);
if (!session) throw new Error("Session not found");
const currentBlock = await this.getCurrentBlock();
const blocksSince = currentBlock - session.lastChargeBlock;
if (blocksSince > 0) {
await chargeSession(this.client, session.payee, sessionId, session.payer, blocksSince);
}
await closeSession(this.client, session.payee, sessionId, session.payer);
await settleSession(this.client, session.payee, sessionId);
this.activeSessions.delete(sessionId);
}
private async getCurrentBlock(): Promise<number> {
const block = await this.client.getBlock();
return block.header.height;
}
}
class AutoMicroPaymentMiddleware:
def __init__(self, rpc_url: str = RPC_URL):
self.rpc_url = rpc_url
self.active_sessions: dict[str, dict] = {}
self.last_processed_block = 0
def start_session(self, payer: str, payee: str, agent_id: str,
rate_per_block: str, initial_deposit: str) -> str:
session_id = f"auto:{payer[-8:]}:{int(time.time()*1000)}"
create_micro_session("key", session_id, payer, payee, agent_id,
rate_per_block, initial_deposit)
self.active_sessions[session_id] = {
"session_id": session_id,
"payer": payer,
"payee": payee,
"rate_per_block": rate_per_block,
"last_charge_block": self._get_current_block(),
}
return session_id
def charge_all(self) -> list[dict]:
current_block = self._get_current_block()
results = []
for session_id, session in list(self.active_sessions.items()):
blocks_since = current_block - session["last_charge_block"]
if blocks_since > 0:
result = charge_session("key", session_id, session["payer"],
blocks_since, session["payee"])
session["last_charge_block"] = current_block
results.append({"session_id": session_id, "blocks": blocks_since})
return results
def close_session(self, session_id: str) -> dict:
session = self.active_sessions.get(session_id)
if not session:
raise ValueError(f"Session not found: {session_id}")
current_block = self._get_current_block()
blocks_since = current_block - session["last_charge_block"]
if blocks_since > 0:
charge_session("key", session_id, session["payer"], blocks_since, session["payee"])
close_session("key", session_id, session["payer"], session["payee"])
settle_session("key", session_id)
del self.active_sessions[session_id]
return {"session_id": session_id, "status": "settled"}
def _get_current_block(self) -> int:
response = requests.get(f"{self.rpc_url}/status")
return int(response.json()["result"]["sync_info"]["latest_block_height"])
5.7 微支付用例:LLM Token 计费
class TokenBasedMicroPayment {
private ratePerToken: string;
private middleware: AutoMicroPaymentMiddleware;
constructor(ratePerToken: string, middleware: AutoMicroPaymentMiddleware) {
this.ratePerToken = ratePerToken;
this.middleware = middleware;
}
static estimateBlockRate(tokenRate: string, tokensPerBlock: number): string {
return (BigInt(tokenRate) * BigInt(tokensPerBlock)).toString();
}
async startTokenSession(payer: string, payee: string, agentId: string,
tokensPerBlock: number, initialDeposit: string): Promise<string> {
const ratePerBlock = TokenBasedMicroPayment.estimateBlockRate(this.ratePerToken, tokensPerBlock);
return this.middleware.startSession(payer, payee, agentId, ratePerBlock, initialDeposit);
}
}
6. 支付与 A2A 集成
6.1 A2A 消息携带支付意图
agent_a2a_v1 合约允许 A2A 消息携带支付意图,实现"请求即支付"的原子操作。
┌─────────────────────────────────────────────┐
│ A2A 消息体 │
│ msg_id: "msg:alice:bob:100" │
│ sender: "msg1alice..." │
│ receiver: "msg1bob..." │
│ message_type: "request" │
│ payload: { │
│ "action": "text_generation", │
│ "params": {"prompt": "...", "max_tokens": 1000}, │
│ "payment": { │
│ "payment_id": "pay:abc:def:123", │
│ "amount": "1000000", │
│ "denom": "umsg", │
│ "intent_hash": "0xabcd...", │
│ "condition": { ... } │
│ } │
│ } │
│ priority: 75 │
│ ttl: 3600 │
└─────────────────────────────────────────────┘
6.2 A2A 支付集成架构
┌──────────────────────────────────────────┐
│ 应用层:服务协商与执行 │
│ - Agent A 请求服务 + 支付意图 │
│ - Agent B 接受并执行 │
│ - Agent B 交付结果 + 请求捕获 │
├──────────────────────────────────────────┤
│ A2A 层:消息路由与通道管理 │
│ - agent_a2a_v1 合约 │
│ - 消息发送/回复/通道管理 │
├──────────────────────────────────────────┤
│ AIPAY 层:支付生命周期 │
│ - agent_payment_v1 合约 │
│ - 意图创建/授权/捕获/结算 │
└──────────────────────────────────────────┘
6.3 完整 A2A + 支付工作流
const A2A_CONTRACT = "msg1...a2aContractAddress";
interface ServiceRequestPayload {
action: string;
params: Record<string, unknown>;
payment: {
paymentId: string;
amount: string;
denom: string;
intentHash: string;
condition?: any;
};
}
async function sendServiceRequestWithPayment(
client: SigningCosmWasmClient,
sender: string,
receiver: string,
agentId: string,
request: ServiceRequestPayload
) {
const intent = createPaymentIntent({
sender, recipient: receiver, agentId,
amount: request.payment.amount,
condition: request.payment.condition,
memo: `Service request: ${request.action}`,
});
const paymentResult = await submitPaymentIntent(client, sender, intent);
console.log("Payment intent submitted:", paymentResult.transactionHash);
const payload: ServiceRequestPayload = {
...request,
payment: {
paymentId: intent.paymentId,
amount: intent.amount,
denom: intent.denom,
intentHash: intent.intentHash,
condition: intent.condition,
},
};
const a2aResult = await client.execute(sender, A2A_CONTRACT, {
send_message: {
to: receiver,
message_type: "request",
payload: Binary.fromUtf8(JSON.stringify(payload)),
priority: 75,
reply_to: null,
ttl: 3600,
},
}, "auto");
console.log("A2A message sent:", a2aResult.transactionHash);
return { intent, paymentResult, a2aResult };
}
async function receiveServiceRequest(
client: CosmWasmClient,
receiver: string
): Promise<Array<{ msg: any; payload: ServiceRequestPayload }>> {
const inbox = await client.queryContractSmart(A2A_CONTRACT, {
list_messages: { address: receiver, status: "Pending", limit: 10 },
});
const requests: Array<{ msg: any; payload: ServiceRequestPayload }> = [];
for (const msg of inbox.messages) {
const payload: ServiceRequestPayload = JSON.parse(
Buffer.from(msg.payload).toString()
);
if (payload.payment) {
requests.push({ msg, payload });
}
}
return requests;
}
async function acceptAndAuthorizePayment(
client: SigningCosmWasmClient,
payee: string,
paymentId: string,
intentHash: string
) {
return authorizePayment(client, payee, paymentId, intentHash);
}
async function executeServiceAndCapture(
client: SigningCosmWasmClient,
payee: string,
paymentId: string,
deliveryId: string,
resultData: string
) {
const proofResult = await submitDeliveryProof(
client, payee, paymentId, deliveryId, resultData,
crypto.createHash("sha256").update(resultData).digest("hex")
);
const captureResult = await capturePayment(client, payee, paymentId);
const replyResult = await client.execute(payee, A2A_CONTRACT, {
reply_message: {
original_msg_id: deliveryId,
payload: Binary.fromUtf8(JSON.stringify({
status: "completed",
result: resultData,
paymentId: paymentId,
})),
},
}, "auto");
return { proofResult, captureResult, replyResult };
}
A2A_CONTRACT = "msg1...a2aContractAddress"
def create_service_request_with_payment(
sender_key: str, sender: str, receiver: str, agent_id: str,
action: str, params: dict, amount: str, condition: Optional[dict] = None,
) -> dict:
print("=" * 60)
print("A2A + AIPAY 集成工作流")
print("=" * 60)
print("\n[Step 1] 创建支付意图...")
intent = create_payment_intent(
sender=sender, recipient=receiver, agent_id=agent_id,
amount=amount, condition=condition,
memo=f"Service request: {action}",
)
print(f" Payment ID: {intent.payment_id}")
print("\n[Step 2] 提交支付意图...")
submit_payment_intent(sender_key, intent)
print("\n[Step 3] 构造 A2A 消息...")
payload = {
"action": action,
"params": params,
"payment": {
"payment_id": intent.payment_id,
"amount": intent.amount,
"denom": intent.denom,
"intent_hash": intent.intent_hash,
"condition": intent.condition,
},
}
a2a_msg = {
"send_message": {
"to": receiver,
"message_type": "request",
"payload": base64.b64encode(json.dumps(payload).encode()).decode(),
"priority": 75,
"reply_to": None,
"ttl": 3600,
}
}
print(f"[X-MSG-Stub=true] A2A send_message: {json.dumps(a2a_msg, indent=2, ensure_ascii=False)}")
return {"intent": asdict(intent), "a2a_payload": payload, "status": "stub"}
def process_service_request(receiver_key: str, receiver: str, request: dict) -> dict:
payment = request["payment"]
payment_id = payment["payment_id"]
intent_hash = payment["intent_hash"]
print(f"\n[Step 4] Agent B 接收服务请求...")
print(f" Action: {request['action']}")
print(f"\n[Step 5] 授权支付...")
authorize_payment(receiver_key, payment_id, intent_hash, receiver)
print(f"\n[Step 6] 执行服务...")
result = {
"status": "completed",
"output": f"Processed {request['action']}",
"tokens_used": 500,
}
print(f"\n[Step 7] 提交交付证明...")
delivery_id = f"delivery:{payment_id}:{int(time.time())}"
submit_delivery_proof(receiver_key, payment_id, delivery_id, json.dumps(result), receiver)
print(f"\n[Step 8] 捕获支付...")
capture_payment(receiver_key, payment_id, receiver)
print(f"\n[Step 9] 发送 A2A 回复...")
a2a_reply = {
"reply_message": {
"original_msg_id": delivery_id,
"payload": base64.b64encode(json.dumps({
"status": "completed",
"result": result,
"payment_id": payment_id,
}).encode()).decode(),
}
}
print(f"[X-MSG-Stub=true] A2A reply: {json.dumps(a2a_reply, indent=2, ensure_ascii=False)}")
return {"status": "completed", "payment_id": payment_id, "result": result}
def a2a_payment_workflow_demo():
alice = "msg1aliceaddress1234567890abcdef"
bob = "msg1bobaddress1234567890abcdef"
agent_id = "text-generation-agent"
request = create_service_request_with_payment(
sender_key="alice_key", sender=alice, receiver=bob,
agent_id=agent_id, action="text_generation",
params={"prompt": "Write a poem about AI", "max_tokens": 200},
amount="500000000000000000",
)
result = process_service_request("bob_key", bob, request)
print("\n" + "=" * 60)
print(f"A2A + 支付集成完成: {result['status']}")
print("=" * 60)
return result
6.4 服务协定中的支付条款
interface ServicePaymentTerms {
priceType: "fixed" | "per_token" | "per_block" | "subscription";
price: string;
currency: string;
paymentModel: "prepay" | "postpay" | "streaming";
refundPolicy: "no_refund" | "full_refund" | "proportional";
disputeResolver?: string;
termsHash: string;
}
async function getAgentPaymentTerms(
client: CosmWasmClient,
registryContract: string,
agentId: string
): Promise<ServicePaymentTerms | null> {
const agent = await client.queryContractSmart(registryContract, {
get_agent: { agent_id: agentId },
});
if (agent.price_model) {
return {
priceType: agent.price_model.price_type || "fixed",
price: agent.price_model.price || "0",
currency: agent.price_model.currency || "umsg",
paymentModel: "postpay",
refundPolicy: "proportional",
termsHash: crypto.createHash("sha256")
.update(JSON.stringify(agent.price_model))
.digest("hex"),
};
}
return null;
}
6.5 A2A 通道内的支付会话
async function createChannelWithPayment(
client: SigningCosmWasmClient,
sender: string,
participant: string,
ratePerBlock: string,
initialDeposit: string
) {
const channelResult = await client.execute(sender, A2A_CONTRACT, {
create_channel: {
participant: participant,
channel_type: "direct",
metadata: null,
},
}, "auto");
const channelId = channelResult.events.find(
e => e.type === "a2a_channel_created"
)?.attributes.find(a => a.key === "channel_id")?.value;
const sessionId = `chpay:${channelId}:${Date.now()}`;
const sessionResult = await createMicroSession(
client, sender, sessionId, participant, "channel-agent",
ratePerBlock, initialDeposit
);
return { channelId, sessionId, channelResult, sessionResult };
}
7. 批量支付与聚合
7.1 批量支付
批量支付允许在一个交易中向多个收款方发送支付,显著降低 Gas 成本。
interface BatchPaymentItem {
recipient: string;
amount: string;
memo?: string;
}
interface BatchPaymentIntent {
batchId: string;
sender: string;
items: BatchPaymentItem[];
denom: string;
totalAmount: string;
expiry: number;
intentHash: string;
}
async function submitBatchPayment(
client: SigningCosmWasmClient,
sender: string,
items: BatchPaymentItem[]
) {
const totalAmount = items.reduce(
(sum, item) => (BigInt(sum) + BigInt(item.amount)).toString(), "0"
);
const batchId = `batch:${sender.slice(0, 8)}:${Date.now()}`;
const msg = {
submit_batch_intent: {
batch_id: batchId,
payer: sender,
payments: items.map(item => ({
payee: item.recipient,
amount: item.amount,
memo: item.memo || "",
})),
asset: "umsg",
total_amount: totalAmount,
expiry_unix: Math.floor(Date.now() / 1000) + 86400,
idempotency_key: `${batchId}-${Date.now()}`,
},
};
console.log("[X-MSG-Stub=true] submit_batch_intent:", JSON.stringify(msg, null, 2));
return client.execute(sender, PAYMENT_CONTRACT, msg, "auto");
}
async function authorizeBatchPayment(
client: SigningCosmWasmClient,
sender: string,
batchId: string
) {
const msg = {
authorize_batch: {
batch_id: batchId,
authorizer: sender,
},
};
console.log("[X-MSG-Stub=true] authorize_batch:", JSON.stringify(msg, null, 2));
return client.execute(sender, PAYMENT_CONTRACT, msg, "auto");
}
@dataclass
class BatchPaymentItem:
recipient: str
amount: str
memo: str = ""
@dataclass
class BatchPaymentIntent:
batch_id: str
sender: str
items: list[BatchPaymentItem]
denom: str = "umsg"
total_amount: str = "0"
expiry: int = 0
def __post_init__(self):
if not self.batch_id:
self.batch_id = f"batch:{self.sender[-8:]}:{int(time.time()*1000)}"
if not self.expiry:
self.expiry = int(time.time()) + 86400
self.total_amount = str(sum(int(item.amount) for item in self.items))
def submit_batch_payment(sender_key: str, sender: str, items: list[BatchPaymentItem]) -> dict:
batch = BatchPaymentIntent(
batch_id=f"batch:{sender[-8:]}:{int(time.time()*1000)}",
sender=sender, items=items,
)
msg = {
"submit_batch_intent": {
"batch_id": batch.batch_id,
"payer": sender,
"payments": [
{"payee": item.recipient, "amount": item.amount, "memo": item.memo}
for item in items
],
"asset": "umsg",
"total_amount": batch.total_amount,
"expiry_unix": batch.expiry,
"idempotency_key": f"{batch.batch_id}-{int(time.time())}",
}
}
print(f"[X-MSG-Stub=true] submit_batch_intent: {json.dumps(msg, indent=2, ensure_ascii=False)}")
print(f" Total: {int(batch.total_amount) / 10**18} MSG ({len(items)} payees)")
return {"status": "stub", "msg": msg, "batch": asdict(batch)}
def authorize_batch_payment(sender_key: str, batch_id: str, sender: str) -> dict:
msg = {"authorize_batch": {"batch_id": batch_id, "authorizer": sender}}
print(f"[X-MSG-Stub=true] authorize_batch: {json.dumps(msg, indent=2, ensure_ascii=False)}")
return {"status": "stub", "msg": msg}
def batch_payment_demo():
sender = "msg1senderaddress1234567890abcdef"
items = [
BatchPaymentItem(recipient="msg1agent1...", amount="200000000000000000", memo="推理服务 #1"),
BatchPaymentItem(recipient="msg1agent2...", amount="300000000000000000", memo="数据检索服务"),
BatchPaymentItem(recipient="msg1agent3...", amount="500000000000000000", memo="文本生成服务"),
BatchPaymentItem(recipient="msg1agent4...", amount="100000000000000000", memo="日志分析服务"),
]
print("=" * 60)
print("批量支付演示")
print("=" * 60)
for i, item in enumerate(items, 1):
msg_amount = int(item.amount) / 10**18
print(f" [{i}] {item.recipient[:16]}... -> {msg_amount} MSG ({item.memo})")
submit_batch_payment("key", sender, items)
authorize_batch_payment("key", f"batch:{sender[-8:]}:{int(time.time()*1000)}", sender)
print(f"\n Gas saving: ~3x vs individual payments")
print(f" Total: 1.1 MSG")
print("\n" + "=" * 60)
7.2 Gas 优化策略
const GAS_OPTIMIZATION = {
single_payment: {
operations: ["submit_intent", "authorize_payment", "capture_payment", "settle_payment"],
total_gas_estimate: "~610,000",
blocks_to_settle: 4,
},
batch_payment: {
operations: ["submit_batch_intent", "authorize_batch", "settle_batch"],
total_gas_estimate: "~250,000 + 50,000 * n",
blocks_to_settle: 3,
savings: "40-60% for n > 3",
},
streaming_session: {
operations: ["create_session", "charge_session * n", "close_session", "settle_session"],
total_gas_estimate: "~200,000 + 80,000 * n",
blocks_to_settle: "per-block",
savings: "90%+ for high-frequency payments",
},
};
def estimate_gas_costs(num_payments: int, payment_type: str = "single") -> dict:
if payment_type == "single":
gas_per_payment = 610_000
total_gas = gas_per_payment * num_payments
elif payment_type == "batch":
base_gas = 250_000
per_payee_gas = 50_000
total_gas = base_gas + per_payee_gas * num_payments
else:
raise ValueError(f"Unknown type: {payment_type}")
return {
"type": payment_type,
"num_payments": num_payments,
"total_gas": total_gas,
"gas_per_payment": total_gas / num_payments,
"total_cost_umsg": total_gas * 0.025,
"total_cost_msg": total_gas * 0.025 / 10**18,
}
def print_gas_comparison():
for n in [1, 5, 10, 20]:
single = estimate_gas_costs(n, "single")
batch = estimate_gas_costs(n, "batch")
print(f"n={n}: single={single['total_gas']:,} gas | batch={batch['total_gas']:,} gas | "
f"single/msg={single['total_cost_msg']:.6f} | batch/msg={batch['total_cost_msg']:.6f}")
7.3 支付聚合
对于接收大量小额支付的 Agent,支付聚合允许将多个小支付合并成一次提现。
interface AggregatedBalance {
payer: string;
totalAmount: string;
paymentCount: number;
lastPaymentTime: number;
}
async function queryAggregatedBalance(
client: CosmWasmClient,
payee: string
): Promise<AggregatedBalance[]> {
const result = await client.queryContractSmart(PAYMENT_CONTRACT, {
get_aggregated_balances: { payee: payee },
});
return result.balances;
}
async function withdrawAggregated(
client: SigningCosmWasmClient,
payee: string,
payerAddresses: string[]
) {
const msg = {
withdraw_aggregated: {
payee: payee,
from_payers: payerAddresses,
},
};
console.log("[X-MSG-Stub=true] withdraw_aggregated:", JSON.stringify(msg, null, 2));
return client.execute(payee, PAYMENT_CONTRACT, msg, "auto");
}
class PaymentAggregator {
private threshold: bigint;
private payee: string;
constructor(threshold: string, payee: string) {
this.threshold = BigInt(threshold);
this.payee = payee;
}
async checkAndWithdraw(client: SigningCosmWasmClient) {
const balances = await queryAggregatedBalance(client, this.payee);
const readyPayers: string[] = [];
for (const balance of balances) {
if (BigInt(balance.totalAmount) >= this.threshold) {
readyPayers.push(balance.payer);
}
}
if (readyPayers.length > 0) {
console.log(`[Aggregator] Withdrawing from ${readyPayers.length} payers`);
return withdrawAggregated(client, this.payee, readyPayers);
}
console.log("[Aggregator] No balances above threshold");
return null;
}
}
def query_aggregated_balance(payee: str, rest_url: str = REST_URL) -> list[dict]:
query_msg = json.dumps({"get_aggregated_balances": {"payee": payee}})
encoded = base64.b64encode(query_msg.encode()).decode()
response = requests.get(
f"{rest_url}/cosmwasm/wasm/v1/contract/{PAYMENT_CONTRACT}/smart/{encoded}"
)
return response.json().get("balances", [])
def withdraw_aggregated(sender_key: str, payee: str, from_payers: list[str]) -> dict:
msg = {"withdraw_aggregated": {"payee": payee, "from_payers": from_payers}}
print(f"[X-MSG-Stub=true] withdraw_aggregated: {json.dumps(msg, indent=2, ensure_ascii=False)}")
return {"status": "stub", "msg": msg}
class PaymentAggregator:
def __init__(self, threshold_umsg: str, payee: str):
self.threshold = int(threshold_umsg)
self.payee = payee
def check_and_withdraw(self, sender_key: str) -> Optional[dict]:
balances = query_aggregated_balance(self.payee)
ready_payers = []
for balance in balances:
total = int(balance["total_amount"])
if total >= self.threshold:
ready_payers.append(balance["payer"])
if ready_payers:
print(f"[Aggregator] Withdrawing from {len(ready_payers)} payers")
return withdraw_aggregated(sender_key, self.payee, ready_payers)
print("[Aggregator] No balances above threshold")
return None
8. 支付 SDK 集成
8.1 Python SDK: AIPayClient
"""
AIPay Python SDK
===============
Complete SDK for integrating AIPAY payment system on MSG Chain.
X-MSG-Stub=true - All write paths are currently stubs.
"""
import base64
import hashlib
import json
import os
import time
from dataclasses import dataclass, field, asdict
from typing import Optional, Callable
from enum import Enum
import requests
class PaymentStatus(Enum):
CREATED = "CREATED"
AUTHORIZED = "AUTHORIZED"
CAPTURED = "CAPTURED"
SETTLED = "SETTLED"
EXPIRED = "EXPIRED"
CANCELLED = "CANCELLED"
FROZEN = "FROZEN"
DISPUTED = "DISPUTED"
REFUNDED = "REFUNDED"
class SessionStatus(Enum):
OPEN = "open"
STREAMING = "streaming"
CLOSED = "closed"
SETTLED = "settled"
EXPIRED = "expired"
@dataclass
class AIPayConfig:
rpc_url: str = "http://localhost:26657"
rest_url: str = "http://localhost:1317"
chain_id: str = "msg-chain-1"
payment_contract: str = "msg1...agentPaymentAddress"
micropayment_contract: str = "msg1...micropaymentAddress"
a2a_contract: str = "msg1...a2aContractAddress"
gas_price: str = "1000000000"
bech32_prefix: str = "msg"
stub_mode: bool = True
class AIPayClient:
"""AIPAY payment system Python SDK."""
def __init__(self, config: AIPayConfig = None):
self.config = config or AIPayConfig()
self._event_handlers: dict[str, list[Callable]] = {}
# ---- Single Payment ----
def create_payment(self, sender: str, recipient: str, agent_id: str,
amount: str, denom: str = "umsg",
condition: Optional[dict] = None,
memo: str = "") -> dict:
intent = PaymentIntent(
payment_id=f"pay:{sender[-8:]}:{recipient[-8:]}:{int(time.time()*1000)}",
sender=sender, recipient=recipient, agent_id=agent_id,
denom=denom, amount=amount, condition=condition,
expiry=int(time.time()) + 86400, memo=memo,
)
return asdict(intent)
def submit_payment(self, sender_key: str, intent: dict) -> dict:
msg = self._build_submit_intent_msg(intent)
return self._execute("submit_intent", msg, sender_key)
def authorize_payment(self, sender_key: str, payment_id: str,
intent_hash: str, authorizer: str) -> dict:
auth_hash = hashlib.sha256(
f"{payment_id}:authorized:{authorizer}:{time.time()}".encode()
).hexdigest()
msg = {
"authorize_payment": {
"payment_id": payment_id, "authorizer": authorizer,
"authorization_hash": auth_hash, "intent_hash": intent_hash,
"policy_decision_hash": intent_hash, "remote_signer_id": "",
}
}
return self._execute("authorize_payment", msg, sender_key)
def capture_payment(self, sender_key: str, payment_id: str,
executor: str, proof: Optional[str] = None) -> dict:
exec_hash = hashlib.sha256(
f"{payment_id}:captured:{executor}:{time.time()}".encode()
).hexdigest()
msg = {
"execute_payment": {
"payment_id": payment_id, "executor": executor,
"execution_hash": exec_hash, "intent_hash": "",
"policy_decision_hash": "", "runtime_hash": "",
"local_guard_hash": "", "execution_proof": proof or "",
}
}
return self._execute("capture_payment", msg, sender_key)
def settle_payment(self, sender_key: str, payment_id: str, settler: str) -> dict:
settle_hash = hashlib.sha256(
f"{payment_id}:settled:{settler}:{time.time()}".encode()
).hexdigest()
msg = {
"settle_payment": {
"payment_id": payment_id, "settler": settler,
"settlement_hash": settle_hash,
"settlement_receipt_hash": settle_hash,
}
}
return self._execute("settle_payment", msg, sender_key)
def cancel_payment(self, sender_key: str, payment_id: str,
reason: str = "no longer needed") -> dict:
msg = {"cancel_payment": {"payment_id": payment_id, "reason": reason}}
return self._execute("cancel_payment", msg, sender_key)
def query_payment(self, payment_id: str) -> dict:
query_msg = json.dumps({"get_payment": {"payment_id": payment_id}})
return self._smart_query(self.config.payment_contract, query_msg)
# ---- Conditional Payment & Dispute ----
def submit_proof(self, sender_key: str, payment_id: str,
delivery_id: str, proof_data: str) -> dict:
proof_hash = hashlib.sha256(proof_data.encode()).hexdigest()
msg = {
"submit_proof": {
"payment_id": payment_id, "delivery_id": delivery_id,
"proof_data": proof_data, "proof_hash": proof_hash,
}
}
return self._execute("submit_proof", msg, sender_key)
def confirm_delivery(self, sender_key: str, payment_id: str, delivery_id: str) -> dict:
msg = {"confirm_delivery": {"payment_id": payment_id, "delivery_id": delivery_id}}
return self._execute("confirm_delivery", msg, sender_key)
def freeze_payment(self, sender_key: str, payment_id: str,
freezer: str, reason: str) -> dict:
freeze_id = f"freeze:{payment_id}:{int(time.time()*1000)}"
freeze_hash = hashlib.sha256(f"{freeze_id}:{reason}".encode()).hexdigest()
msg = {
"freeze_payment": {
"payment_id": payment_id, "freeze_id": freeze_id,
"freezer": freezer, "reason": reason, "freeze_hash": freeze_hash,
}
}
return self._execute("freeze_payment", msg, sender_key)
def challenge_payment(self, sender_key: str, payment_id: str,
challenger: str, reason: str, proof_data: str) -> dict:
challenge_id = f"challenge:{payment_id}:{int(time.time()*1000)}"
proof_hash = hashlib.sha256(proof_data.encode()).hexdigest()
msg = {
"challenge_payment": {
"payment_id": payment_id, "challenge_id": challenge_id,
"challenger": challenger, "reason": reason, "proof_hash": proof_hash,
}
}
return self._execute("challenge_payment", msg, sender_key)
def resolve_dispute(self, sender_key: str, payment_id: str,
arbitrator: str, ruling: str, justification: str) -> dict:
msg = {
"resolve_dispute": {
"payment_id": payment_id, "arbitrator": arbitrator,
"ruling": ruling, "justification": justification,
}
}
return self._execute("resolve_dispute", msg, sender_key)
# ---- Micropayment Streaming ----
def open_session(self, sender_key: str, session_id: str, payer: str,
payee: str, agent_id: str, rate_per_block: str,
initial_deposit: str) -> dict:
terms_hash = hashlib.sha256(
f"{session_id}:{rate_per_block}:{payee}".encode()
).hexdigest()
msg = {
"create_session": {
"session_id": session_id, "payer": payer, "payee": payee,
"agent_id": agent_id, "asset": "umsg",
"rate_per_block": rate_per_block,
"initial_deposit": initial_deposit, "terms_hash": terms_hash,
}
}
return self._execute("create_session", msg, sender_key)
def stream_payment(self, sender_key: str, session_id: str, payer: str,
num_blocks: int, payee: str) -> dict:
receipt_hash = hashlib.sha256(
f"{session_id}:{num_blocks}:{time.time()}".encode()
).hexdigest()
msg = {
"charge_session": {
"session_id": session_id, "payer": payer,
"num_blocks": num_blocks, "charge_receipt_hash": receipt_hash,
}
}
return self._execute("stream_payment", msg, sender_key)
def close_session(self, sender_key: str, session_id: str, payer: str) -> dict:
close_hash = hashlib.sha256(
f"{session_id}:closed:{time.time()}".encode()
).hexdigest()
msg = {
"close_session": {
"session_id": session_id, "payer": payer,
"close_receipt_hash": close_hash,
}
}
return self._execute("close_session", msg, sender_key)
def settle_session(self, sender_key: str, session_id: str) -> dict:
msg = {"settle_session": {"session_id": session_id}}
return self._execute("settle_session", msg, sender_key)
def query_session(self, session_id: str) -> dict:
query_msg = json.dumps({"get_session": {"session_id": session_id}})
return self._smart_query(self.config.micropayment_contract, query_msg)
# ---- Batch Payment ----
def batch_payment(self, sender_key: str, sender: str, items: list[dict]) -> dict:
total = str(sum(int(item["amount"]) for item in items))
batch_id = f"batch:{sender[-8:]}:{int(time.time()*1000)}"
msg = {
"submit_batch_intent": {
"batch_id": batch_id, "payer": sender,
"payments": [
{"payee": item["recipient"], "amount": item["amount"],
"memo": item.get("memo", "")}
for item in items
],
"asset": "umsg", "total_amount": total,
"expiry_unix": int(time.time()) + 86400,
"idempotency_key": f"{batch_id}-{int(time.time())}",
}
}
return self._execute("batch_payment", msg, sender_key)
def query_aggregated_balances(self, payee: str) -> list[dict]:
query_msg = json.dumps({"get_aggregated_balances": {"payee": payee}})
result = self._smart_query(self.config.payment_contract, query_msg)
return result.get("balances", [])
# ---- Event Subscription ----
def on(self, event_type: str, handler: Callable):
if event_type not in self._event_handlers:
self._event_handlers[event_type] = []
self._event_handlers[event_type].append(handler)
def _emit(self, event_type: str, data: dict):
for handler in self._event_handlers.get(event_type, []):
handler(data)
def subscribe_events(self, ws_url: Optional[str] = None):
import websocket
url = ws_url or self.config.rpc_url.replace("http", "ws")
ws = websocket.WebSocketApp(
f"{url}/websocket",
on_message=lambda ws, msg: self._handle_event(msg),
)
return ws
def _handle_event(self, raw_msg: str):
try:
event = json.loads(raw_msg)
if "result" in event and "events" in event["result"]:
for ev_type, ev_data in event["result"]["events"].items():
self._emit(ev_type, ev_data)
except json.JSONDecodeError:
pass
# ---- Internal ----
def _execute(self, action: str, msg: dict, sender_key: str,
intent: Optional[dict] = None) -> dict:
if self.config.stub_mode:
print(f"[X-MSG-Stub=true] {action}: {json.dumps(msg, indent=2, ensure_ascii=False)}")
return {"status": "stub", "action": action, "msg": msg}
raise NotImplementedError(
"Non-stub execution requires wallet integration."
)
def _smart_query(self, contract: str, query_msg: str) -> dict:
encoded = base64.b64encode(query_msg.encode()).decode()
response = requests.get(
f"{self.config.rest_url}/cosmwasm/wasm/v1/contract/{contract}/smart/{encoded}"
)
return response.json()
def _build_submit_intent_msg(self, intent: dict) -> dict:
return {
"submit_intent": {
"payment_id": intent["payment_id"],
"payer": intent["sender"],
"payee": intent["recipient"],
"agent_id": intent["agent_id"],
"aidid": f"did:msg:agent:{intent['agent_id']}",
"policy_id": "default-policy",
"budget_id": f"budget-{intent['sender']}",
"constitution_version": "v1",
"constitution_hash": "abc123...",
"remote_signer_id": "",
"service_id": intent.get("memo", "default-service"),
"action": "payment",
"amount": intent["amount"],
"asset": intent.get("denom", "umsg"),
"work_id": intent.get("condition", {}).get("deliveryId", ""),
"payment_terms_hash": intent.get("intent_hash", ""),
"idempotency_key": f"{intent['payment_id']}-{int(time.time())}",
"expiry_unix": intent.get("expiry", int(time.time()) + 86400),
"intent_hash": intent.get("intent_hash", ""),
"policy_decision_hash": intent.get("intent_hash", ""),
"runtime_hash": intent.get("intent_hash", ""),
"local_guard_hash": intent.get("intent_hash", ""),
}
}
8.2 TypeScript SDK
import { SigningCosmWasmClient, CosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
import crypto from "crypto";
export interface AIPayConfig {
rpcUrl: string;
restUrl: string;
chainId: string;
paymentContract: string;
micropaymentContract: string;
a2aContract: string;
gasPrice: string;
bech32Prefix: string;
stubMode: boolean;
}
export interface PaymentIntent {
paymentId: string;
sender: string;
recipient: string;
agentId: string;
denom: string;
amount: string;
condition?: any;
expiry: number;
memo: string;
nonce: string;
intentHash: string;
}
export interface MicropaymentSession {
sessionId: string;
payer: string;
payee: string;
agentId: string;
denom: string;
ratePerBlock: string;
totalDeposited: string;
totalCharged: string;
remainingBalance: string;
startBlock: number;
lastChargeBlock: number;
status: string;
termsHash: string;
}
export interface BatchPaymentItem {
recipient: string;
amount: string;
memo?: string;
}
type EventHandler = (data: any) => void;
export class AIPayClient {
private config: AIPayConfig;
private eventHandlers: Map<string, EventHandler[]> = new Map();
constructor(config: Partial<AIPayConfig> = {}) {
this.config = {
rpcUrl: "http://localhost:26657",
restUrl: "http://localhost:1317",
chainId: "msg-chain-1",
paymentContract: "msg1...agentPaymentAddress",
micropaymentContract: "msg1...micropaymentAddress",
a2aContract: "msg1...a2aContractAddress",
gasPrice: "0.025",
bech32Prefix: "msg",
stubMode: true,
...config,
};
}
// ---- Single Payment ----
createPayment(params: {
sender: string; recipient: string; agentId: string;
amount: string; denom?: string; condition?: any; memo?: string;
}): PaymentIntent {
const paymentId = `pay:${params.sender.slice(0, 8)}:${params.recipient.slice(0, 8)}:${Date.now()}`;
const nonce = crypto.randomBytes(16).toString("hex");
const expiry = Math.floor(Date.now() / 1000) + 86400;
const intentHash = crypto
.createHash("sha256")
.update(`${paymentId}:${params.sender}:${params.recipient}:${params.amount}:${nonce}:${expiry}`)
.digest("hex");
return { paymentId, sender: params.sender, recipient: params.recipient,
agentId: params.agentId, denom: params.denom || "umsg",
amount: params.amount, condition: params.condition, expiry,
memo: params.memo || "", nonce, intentHash };
}
async submitPayment(client: SigningCosmWasmClient, sender: string, intent: PaymentIntent) {
return this.execute(client, sender, "submit_intent", this.buildSubmitIntentMsg(intent));
}
async authorizePayment(client: SigningCosmWasmClient, authorizer: string,
paymentId: string, intentHash: string) {
const authHash = crypto.createHash("sha256")
.update(`${paymentId}:authorized:${authorizer}:${Date.now()}`).digest("hex");
return this.execute(client, authorizer, "authorize_payment", {
authorize_payment: { payment_id: paymentId, authorizer,
authorization_hash: authHash, intent_hash: intentHash,
policy_decision_hash: intentHash, remote_signer_id: "" },
});
}
async capturePayment(client: SigningCosmWasmClient, executor: string,
paymentId: string, proof?: string) {
const execHash = crypto.createHash("sha256")
.update(`${paymentId}:captured:${executor}:${Date.now()}`).digest("hex");
return this.execute(client, executor, "execute_payment", {
execute_payment: { payment_id: paymentId, executor,
execution_hash: execHash, intent_hash: "", policy_decision_hash: "",
runtime_hash: "", local_guard_hash: "", execution_proof: proof || "" },
});
}
async settlePayment(client: SigningCosmWasmClient, settler: string, paymentId: string) {
const settleHash = crypto.createHash("sha256")
.update(`${paymentId}:settled:${settler}:${Date.now()}`).digest("hex");
return this.execute(client, settler, "settle_payment", {
settle_payment: { payment_id: paymentId, settler,
settlement_hash: settleHash, settlement_receipt_hash: settleHash },
});
}
async cancelPayment(client: SigningCosmWasmClient, sender: string,
paymentId: string, reason?: string) {
return this.execute(client, sender, "cancel_payment", {
cancel_payment: { payment_id: paymentId, reason: reason || "no longer needed" },
});
}
async queryPayment(client: CosmWasmClient, paymentId: string) {
return client.queryContractSmart(this.config.paymentContract, {
get_payment: { payment_id: paymentId },
});
}
// ---- Micropayment ----
async openSession(client: SigningCosmWasmClient, sender: string, params: {
sessionId: string; payer: string; payee: string;
agentId: string; ratePerBlock: string; initialDeposit: string;
}) {
const termsHash = crypto.createHash("sha256")
.update(`${params.sessionId}:${params.ratePerBlock}:${params.payee}`).digest("hex");
return this.execute(client, sender, "create_session", {
create_session: { session_id: params.sessionId, payer: params.payer,
payee: params.payee, agent_id: params.agentId, asset: "umsg",
rate_per_block: params.ratePerBlock, initial_deposit: params.initialDeposit,
terms_hash: termsHash },
});
}
async streamPayment(client: SigningCosmWasmClient, payee: string,
sessionId: string, payer: string, numBlocks: number) {
const receiptHash = crypto.createHash("sha256")
.update(`${sessionId}:${numBlocks}:${Date.now()}`).digest("hex");
return this.execute(client, payee, "charge_session", {
charge_session: { session_id: sessionId, payer,
num_blocks: numBlocks, charge_receipt_hash: receiptHash },
});
}
async closeSession(client: SigningCosmWasmClient, sender: string,
sessionId: string, payer: string) {
const closeHash = crypto.createHash("sha256")
.update(`${sessionId}:closed:${Date.now()}`).digest("hex");
return this.execute(client, sender, "close_session", {
close_session: { session_id: sessionId, payer, close_receipt_hash: closeHash },
});
}
async settleSession(client: SigningCosmWasmClient, sender: string, sessionId: string) {
return this.execute(client, sender, "settle_session", {
settle_session: { session_id: sessionId },
});
}
async querySession(client: CosmWasmClient, sessionId: string) {
return client.queryContractSmart(this.config.micropaymentContract, {
get_session: { session_id: sessionId },
});
}
// ---- Batch ----
async batchPayment(client: SigningCosmWasmClient, sender: string, items: BatchPaymentItem[]) {
const totalAmount = items.reduce((sum, item) =>
(BigInt(sum) + BigInt(item.amount)).toString(), "0");
const batchId = `batch:${sender.slice(0, 8)}:${Date.now()}`;
return this.execute(client, sender, "submit_batch_intent", {
submit_batch_intent: { batch_id: batchId, payer: sender,
payments: items.map(i => ({ payee: i.recipient, amount: i.amount, memo: i.memo || "" })),
asset: "umsg", total_amount: totalAmount,
expiry_unix: Math.floor(Date.now() / 1000) + 86400,
idempotency_key: `${batchId}-${Date.now()}` },
});
}
// ---- Events ----
on(eventType: string, handler: EventHandler) {
if (!this.eventHandlers.has(eventType)) {
this.eventHandlers.set(eventType, []);
}
this.eventHandlers.get(eventType)!.push(handler);
}
subscribeEvents(wsUrl?: string): WebSocket {
const url = wsUrl || this.config.rpcUrl.replace(/^http/, "ws");
const ws = new WebSocket(`${url}/websocket`);
ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
if (data.result?.events) {
for (const [evType, evData] of Object.entries(data.result.events)) {
(this.eventHandlers.get(evType) || []).forEach(h => h(evData));
}
}
} catch { /* ignore */ }
};
return ws;
}
// ---- Internal ----
private buildSubmitIntentMsg(intent: PaymentIntent) {
return {
submit_intent: { payment_id: intent.paymentId, payer: intent.sender,
payee: intent.recipient, agent_id: intent.agentId,
aidid: `did:msg:agent:${intent.agentId}`, policy_id: "default-policy",
budget_id: `budget-${intent.sender}`, constitution_version: "v1",
constitution_hash: "abc123...", remote_signer_id: "",
service_id: intent.memo || "default-service", action: "payment",
amount: intent.amount, asset: intent.denom,
work_id: intent.condition?.deliveryId || "",
payment_terms_hash: intent.intentHash,
idempotency_key: `${intent.paymentId}-${Date.now()}`,
expiry_unix: intent.expiry, intent_hash: intent.intentHash,
policy_decision_hash: intent.intentHash,
runtime_hash: intent.intentHash, local_guard_hash: intent.intentHash },
};
}
private async execute(client: SigningCosmWasmClient, sender: string,
action: string, msg: any) {
const contract = action.includes("session")
? this.config.micropaymentContract : this.config.paymentContract;
if (this.config.stubMode) {
console.log(`[X-MSG-Stub=true] ${action}:`, JSON.stringify(msg, null, 2));
return { status: "stub", action, msg };
}
return client.execute(sender, contract, msg, "auto");
}
}
8.3 错误处理包装器
class AIPayError extends Error {
constructor(
public code: number,
message: string,
public txHash?: string
) {
super(message);
this.name = "AIPayError";
}
static fromContractError(rawLog: string): AIPayError {
if (rawLog.includes("code: 4")) return new AIPayError(4, "余额不足");
if (rawLog.includes("code: 5")) return new AIPayError(5, "合约执行失败");
if (rawLog.includes("code: 10")) return new AIPayError(10, "Agent 未注册");
if (rawLog.includes("code: 11")) return new AIPayError(11, "支付 ID 不存在");
if (rawLog.includes("code: 12")) return new AIPayError(12, "支付意图已过期");
if (rawLog.includes("code: 14")) return new AIPayError(14, "未授权操作");
return new AIPayError(99, rawLog);
}
}
async function safeAIPayOperation<T>(
operation: () => Promise<T>,
errorContext: string
): Promise<{ success: boolean; data?: T; error?: AIPayError }> {
try {
const data = await operation();
return { success: true, data };
} catch (err: any) {
const aipayError = err.message
? AIPayError.fromContractError(err.message)
: new AIPayError(99, err.toString());
console.error(`[AIPay] ${errorContext} failed:`, aipayError.message);
return { success: false, error: aipayError };
}
}
class AIPayError(Exception):
def __init__(self, code: int, message: str, tx_hash: Optional[str] = None):
self.code = code
self.tx_hash = tx_hash
super().__init__(message)
ERROR_MAP = {
4: "INSUFFICIENT_FUNDS: 余额不足",
5: "CONTRACT_FAILED: 合约执行失败",
8: "DAO_TIMELOCK: DAO 时间锁未到期",
10: "AGENT_NOT_FOUND: Agent 未注册",
11: "PAYMENT_NOT_FOUND: 支付 ID 不存在",
12: "PAYMENT_EXPIRED: 支付意图已过期",
13: "PAYMENT_ALREADY_CAPTURED: 支付已被捕获",
14: "UNAUTHORIZED: 未授权操作",
15: "INVALID_CONDITION: 条件格式无效",
16: "CHALLENGE_WINDOW_CLOSED: 争议窗口已关闭",
}
def parse_contract_error(raw_log: str) -> AIPayError:
for code in ERROR_MAP:
if f"code: {code}" in raw_log:
return AIPayError(code, ERROR_MAP[code])
return AIPayError(99, raw_log)
def safe_aipay_call(func, *args, **kwargs) -> dict:
try:
result = func(*args, **kwargs)
return {"success": True, "data": result}
except Exception as e:
error = parse_contract_error(str(e))
print(f"[AIPay] Operation failed: {error}")
return {"success": False, "error": str(error)}
9. 安全与审计
9.1 安全威胁模型
参与者:
A_{payer} - 支付方 Agent
A_{payee} - 收款方 Agent
A_{exec} - 执行 Agent(可选第三方)
Gov - DAO 治理
Arb - 仲裁人(DAO / 合约)
信任边界:
┌─────────────────────────────────────────┐
│ MSG Chain 共识层 │
│ ┌────────────────────────────────────┐ │
│ │ agent_payment_v1 合约 │ │
│ │ → 交易最终性由 Tendermint 保证 │ │
│ │ → 状态查询公开可验证 │ │
│ └────────────────────────────────────┘ │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 链下执行环境 │
│ A_{payer} / A_{payee} / A_{exec} │
│ → 计算完整性需自证 (ZK / TEE) │
│ → 链下证据链需哈希上链 │
└─────────────────────────────────────────┘
威胁清单:
| 威胁 | 描述 | 严重性 | 缓解 |
|---|---|---|---|
| T1 双重花费 | Agent 多次提交同一意图 | 高 | idempotency_key 唯一约束 |
| T2 重放攻击 | 重放已签名消息 | 高 | nonce + expiry_unix |
| T3 支付劫持 | 恶意修改 payee 地址 | 高 | 不可逆 intent_hash 签名 |
| T4 条件欺诈 | 未满足条件即 claim | 高 | proof_hash 链上验证 |
| T5 微支付耗尽 | 会话无上限扣款 | 中 | session balance + rate limit |
| T6 闪电贷攻击 | 单笔内循环资金 | 中 | DAO 时间锁 (code 8) |
| T7 治理攻击 | 恶意升级合约 | 中 | governance_or_treasury + 时间锁 |
| T8 前端运行 | 抢先交易获利 | 中 | 条件哈希提交 / commit-reveal |
| T9 女巫攻击 | 大量虚假 Agent | 中 | agent_id 注册门槛 |
| T10 仲裁偏见 | 仲裁人不公 | 低 | 链上公开记录 + 声誉惩罚 |
9.2 Intent Hash 签名机制
9.2.1 哈希构造
intent_hash = sha256(
payment_id || // 32 bytes
sender || // 42 bytes (bech32)
recipient || // 42 bytes
amount || // 可变长十进制字符串
asset || // "umsg"
condition_hash || // 32 bytes (条件为空则全 0)
expiry || // 8 bytes (unix timestamp big-endian)
nonce || // 16 bytes (随机)
extra_data || // 32 bytes (预留)
)
9.2.2 Python 实现
import hashlib
import struct
import os
def build_intent_hash(
payment_id: str,
sender: str,
recipient: str,
amount: str,
asset: str,
expiry: int,
condition_data: Optional[bytes] = None,
extra_data: bytes = b'\x00' * 32,
) -> bytes:
h = hashlib.sha256()
h.update(payment_id.encode('ascii'))
h.update(sender.encode('ascii'))
h.update(recipient.encode('ascii'))
h.update(amount.encode('ascii'))
h.update(asset.encode('ascii'))
if condition_data:
cond_hash = hashlib.sha256(condition_data).digest()
else:
cond_hash = b'\x00' * 32
h.update(cond_hash)
h.update(struct.pack('>Q', expiry))
nonce = os.urandom(16)
h.update(nonce)
h.update(extra_data)
return h.digest()
9.2.3 TypeScript 实现
import crypto from "crypto";
function buildIntentHash(params: {
paymentId: string; sender: string; recipient: string;
amount: string; asset: string; expiry: number;
conditionData?: Buffer; extraData?: Buffer;
}): Buffer {
const conditionHash = params.conditionData
? crypto.createHash("sha256").update(params.conditionData).digest()
: Buffer.alloc(32, 0);
const nonce = crypto.randomBytes(16);
const expiryBuf = Buffer.alloc(8);
expiryBuf.writeBigUInt64BE(BigInt(params.expiry));
const hash = crypto.createHash("sha256");
hash.update(params.paymentId, "ascii");
hash.update(params.sender, "ascii");
hash.update(params.recipient, "ascii");
hash.update(params.amount, "ascii");
hash.update(params.asset, "ascii");
hash.update(conditionHash);
hash.update(expiryBuf);
hash.update(nonce);
hash.update(params.extraData || Buffer.alloc(32, 0));
return hash.digest();
}
9.3 链上证据链
支付生命周期中的哈希链:
intent_hash ──→ authorization_hash ──→ execution_hash ──→ settlement_hash
│ │ │ │
submit_intent authorize_payment execute_payment settle_payment
│ │ │ │
sha256(intent) sha256(pay_id + sha256(pay_id + sha256(pay_id +
authorizer + executor + settler +
auth_time) exec_time) settle_time)
争议场景的额外哈希:
freeze_hash = sha256(freeze_id + reason)
proof_hash = sha256(proof_data)
challenge_hash = sha256(challenge_id + proof_hash)
resolution_hash = sha256(ruling + justification)
class EvidenceChain:
def __init__(self, payment_id: str):
self.payment_id = payment_id
self.chain: list[dict] = []
def add_link(self, event_type: str, **fields) -> str:
timestamp = int(time.time() * 1000)
raw_data = f"{self.payment_id}:{event_type}:{json.dumps(fields, sort_keys=True)}:{timestamp}"
link_hash = hashlib.sha256(raw_data.encode()).hexdigest()
link = {
"type": event_type,
"fields": fields,
"timestamp": timestamp,
"hash": link_hash,
"previous_hash": self.chain[-1]["hash"] if self.chain else None,
}
self.chain.append(link)
return link_hash
def verify_chain(self) -> bool:
for i, link in enumerate(self.chain):
if i == 0:
continue
expected_prev = self.chain[i - 1]["hash"]
if link["previous_hash"] != expected_prev:
print(f"[VERIFY FAIL] link {i} prev hash mismatch")
return False
return True
def export(self) -> list[dict]:
return self.chain
def to_proof_package(self, subscriber_match: Optional[str] = None) -> dict:
return {
"payment_id": self.payment_id,
"chain": self.chain,
"confidence": "high" if len(self.chain) >= 4 else "medium",
"subscriber_match": subscriber_match or "n/a",
}
9.4 安全编码规范
// DON'T: 直接在日志中打印密钥
function dangerous(secretKey: string): void {
console.log(`Got key: ${secretKey}`); // 危险!
}
// DO: 永远不记录私钥/助记词
// 使用环境变量存储密钥
const MNEMONIC = process.env.AGENT_MNEMONIC; // 仅从环境变量读取
const endpoint = process.env.AIPAY_RPC;
// DON'T: 未验证 intent_hash 就放行
async function unsafeExecute(client: any, paymentId: string) {
return client.execute("execute_payment", { payment_id: paymentId }); // 无哈希验证
}
// DO: 验证 intent_hash 链上匹配
async function safeExecute(client: CosmWasmClient, signer: SigningCosmWasmClient,
paymentId: string, wallet: string) {
const payment = await client.queryContractSmart(
process.env.PAYMENT_CONTRACT!,
{ get_payment: { payment_id: paymentId } },
);
if (!payment || !payment.intent_hash) {
throw new AIPayError(11, `Payment ${paymentId} not found`);
}
// 对比本地的预期哈希
const localHash = buildIntentHash({ /* ... */ });
if (localHash.toString("hex") !== payment.intent_hash) {
throw new AIPayError(14, "intent_hash mismatch");
}
return signer.execute(wallet, process.env.PAYMENT_CONTRACT!, {
execute_payment: { payment_id: paymentId, executor: wallet,
execution_hash: payment.intent_hash, /* ... */ },
}, "auto");
}
9.5 Gas 安全建议
# Gas 配置
GAS_CONFIG = {
"payment_intent": {"low": "100000", "avg": "150000", "high": "200000"},
"conditional": {"low": "150000", "avg": "200000", "high": "300000"},
"micropayment_open": {"low": "120000", "avg": "180000", "high": "250000"},
"micropayment_stream": {"low": "80000", "avg": "120000", "high": "180000"},
"batch": {"low": "250000", "avg": "400000", "high": "600000"},
"dispute": {"low": "200000", "avg": "300000", "high": "450000"},
}
class GasManager:
def __init__(self, priority: str = "avg"):
self.priority = priority # low / avg / high
def estimate(self, action: str) -> str:
config = GAS_CONFIG.get(action, GAS_CONFIG["payment_intent"])
return config[self.priority]
def autoscale(self, action: str, complexity: float = 1.0) -> str:
base = int(self.estimate(action))
return str(int(base * complexity))
9.6 审计日志
interface AuditLogEntry {
timestamp: number;
traceId: string;
paymentId: string;
action: string;
actor: string;
intentHash?: string;
txHash?: string;
status: "success" | "failure";
errorCode?: number;
gasUsed?: string;
metadata: Record<string, any>;
}
export class AuditLogger {
private logs: AuditLogEntry[] = [];
constructor(private storagePath?: string) {}
log(entry: Omit<AuditLogEntry, "timestamp">): void {
const fullEntry: AuditLogEntry = {
...entry,
timestamp: Date.now(),
};
this.logs.push(fullEntry);
if (this.storagePath) {
const fs = require("fs");
fs.appendFileSync(this.storagePath,
JSON.stringify(fullEntry) + "\n");
}
}
query(filter: { paymentId?: string; action?: string;
actor?: string; status?: string }): AuditLogEntry[] {
return this.logs.filter(l =>
(!filter.paymentId || l.paymentId === filter.paymentId) &&
(!filter.action || l.action === filter.action) &&
(!filter.actor || l.actor === filter.actor) &&
(!filter.status || l.status === filter.status)
);
}
generateReport(paymentId: string): string {
const entries = this.query({ paymentId });
const start = entries[0]?.timestamp;
const end = entries[entries.length - 1]?.timestamp;
const duration = end && start ? end - start : 0;
return [
`=== AIPAY Audit Report ===`,
`Payment ID: ${paymentId}`,
`Duration: ${duration}ms`,
`Total Events: ${entries.length}`,
`Timeline:`,
...entries.map(e =>
` ${new Date(e.timestamp).toISOString()} [${e.status}] ${e.action} by ${e.actor} ${e.txHash ? `tx:${e.txHash}` : ""}`
),
].join("\n");
}
}
10. 完整示例 dApp: AutoGPT 市场支付
10.1 场景描述
一个 AutoGPT 市场的支付集成:
- 买家 Agent 浏览插件列表
- 选择一个插件并支付 100 MSG
- 插件代码通过 A2A 传递
- 买家确认交付后结算
10.2 Python 完整实现
"""
AutoGPT 市场支付集成示例
=======================
用 AIPAY 完成插件的购买-交付-结算全过程。
"""
import json
import time
import os
from typing import Optional
from aipay_sdk import AIPayClient, AIPayConfig, safe_aipay_call, AIPayError
# 环境配置
AIPAY_CONFIG = AIPayConfig(
rpc_url=os.getenv("AIPAY_RPC", "http://localhost:26657"),
rest_url=os.getenv("AIPAY_REST", "http://localhost:1317"),
payment_contract=os.getenv("PAYMENT_CONTRACT", "msg1...agentPaymentAddress"),
chain_id="msg-chain-1",
gas_price="1000000000",
bech32_prefix="msg",
stub_mode=os.getenv("AIPAY_STUB", "true").lower() == "true",
)
class MarketAgent:
"""AutoGPT 市场支付 Agent."""
def __init__(self, agent_id: str, wallet_key: str, address: str):
self.agent_id = agent_id
self.wallet_key = wallet_key
self.address = address
self.client = AIPayClient(AIPAY_CONFIG)
def publish_plugin(self, plugin_id: str, price: str,
metadata: dict) -> dict:
"""注册插件到市场."""
print(f"[Market] Publishing plugin {plugin_id} at {price} umsg")
listing = {
"plugin_id": plugin_id,
"seller": self.agent_id,
"price": price,
"metadata": metadata,
"timestamp": int(time.time()),
}
return listing
def purchase_plugin(self, buyer_agent: "MarketAgent",
plugin_id: str, price: str) -> dict:
"""买家发起插件购买."""
print(f"[Market] {buyer_agent.agent_id} buying {plugin_id} for {price} umsg")
payment_id = f"pay:{buyer_agent.address[-8:]}:{self.address[-8:]}:{int(time.time()*1000)}"
condition = {
"deliveryId": plugin_id,
"proofType": "sha256",
"expectedHash": plugin_id,
}
# 1. 创建支付意图
intent = buyer_agent.client.create_payment(
sender=buyer_agent.address,
recipient=self.address,
agent_id=self.agent_id,
amount=price,
denom="umsg",
condition=condition,
memo=f"Purchase plugin {plugin_id}",
)
# 2. 提交意图
submit_result = buyer_agent.client.submit_payment(
buyer_agent.wallet_key, intent
)
return {
"payment_id": payment_id,
"intent": intent,
"submit_result": submit_result,
}
def deliver_plugin(self, buyer_agent: "MarketAgent", payment_id: str,
plugin_code: str) -> dict:
"""卖家交付插件并通过 A2A 传递."""
print(f"[Market] Delivering plugin for payment {payment_id}")
delivery_id = f"delivery:{payment_id}:{int(time.time())}"
proof_data = plugin_code
# 提交链上交付证明
proof_result = self.client.submit_proof(
self.wallet_key, payment_id, delivery_id, proof_data
)
# 通过 A2A 传递插件代码
a2a_confirmation = self._a2a_deliver(
buyer_agent, delivery_id, plugin_code
)
return {
"delivery_id": delivery_id,
"proof_result": proof_result,
"a2a_confirmation": a2a_confirmation,
}
def confirm_and_settle(self, buyer_agent: "MarketAgent",
payment_id: str, delivery_id: str) -> dict:
"""买家确认交付并结算."""
print(f"[Market] {buyer_agent.agent_id} confirming delivery")
confirm = buyer_agent.client.confirm_delivery(
buyer_agent.wallet_key, payment_id, delivery_id
)
settle = buyer_agent.client.settle_payment(
self.wallet_key, payment_id, self.address
)
return {"confirm": confirm, "settle": settle}
def _a2a_deliver(self, buyer_agent: "MarketAgent",
delivery_id: str, plugin_code: str) -> dict:
"""基于 A2A 协议传输."""
msg = {
"type": "data_transfer",
"protocol": "msg/a2a/payment-market/1.0.0",
"delivery_id": delivery_id,
"payload_size": len(plugin_code),
"payload_hash": hashlib.sha256(plugin_code.encode()).hexdigest(),
"sender": self.address,
"receiver": buyer_agent.address,
"timestamp": int(time.time()),
}
return msg
# ---- 完整流程运行 ----
def run_market_scenario():
"""运行一次完整的市场购买-交付-结算流程."""
# 初始化买家和卖家
seller = MarketAgent("plugin-vendor-001", "seller_key_123",
"msg1q2w3e4r5t6y7u8i9o0p1a2s3d4f5g6h7j8k9l")
buyer = MarketAgent("buyer-agent-007", "buyer_key_456",
"msg1a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s")
plugin_listing = seller.publish_plugin(
plugin_id="autogpt-web-scraper-v2",
price="100000000", # 100 MSG (18 decimals)
metadata={
"name": "Web Scraper Pro",
"version": "2.1.0",
"category": "utilities",
},
)
purchase = seller.purchase_plugin(buyer, plugin_listing["plugin_id"],
plugin_listing["price"])
payment_id = purchase["payment_id"]
plugin_code = 'print("Hello from Web Scraper Pro v2.1.0!")'
delivery = seller.deliver_plugin(buyer, payment_id, plugin_code)
result = seller.confirm_and_settle(buyer, payment_id, delivery["delivery_id"])
# 输出摘要
summary = {
"plugin": plugin_listing["plugin_id"],
"price": plugin_listing["price"],
"payment_id": payment_id,
"delivery_id": delivery["delivery_id"],
"status": "completed",
"settle_tx": result["settle"],
}
print(f"\n=== Market Purchase Complete ===")
print(json.dumps(summary, indent=2, ensure_ascii=False))
return summary
# ---- 条件支付 + 争议流程 ----
def run_conditional_payment_scenario():
"""带条件支付和争议解决的场景."""
seller = MarketAgent("data-provider-001", "sp_key_789",
"msg1p1o2i3u4y5t6r7e8w9q0w1e2r3t4y5u6i7o8p")
buyer = MarketAgent("research-agent-999", "rp_key_321",
"msg1z1x2c3v4b5n6m7a8s9d0f1g2h3j4k5l6z7x8c")
payment_id = f"pay:{buyer.address[-8:]}:{seller.address[-8:]}:{int(time.time()*1000)}"
condition = {
"deliveryId": "research-data-v42",
"proofType": "sha256",
"expectedHash": "abc123def456",
}
intent = buyer.client.create_payment(
sender=buyer.address,
recipient=seller.address,
agent_id=seller.agent_id,
amount="50000000000000000000", # 50 MSG
denom="umsg",
condition=condition,
memo="Purchase research dataset",
)
buyer.client.submit_payment(buyer.wallet_key, intent)
# 卖家尝试 claim,但买家声称数据不符 → 争议
dispute_result = buyer.client.challenge_payment(
buyer.wallet_key,
payment_id,
buyer.address,
reason="delivered data hash mismatch expected abc123def456",
proof_data="received_hash:789xyz...",
)
ruling = "refund_buyer" # 仲裁结果
resolve = seller.client.resolve_dispute(
seller.wallet_key,
payment_id,
"arbitrator-dao-v1",
ruling=ruling,
justification="data hash mismatch confirmed",
)
print(f"\n=== Dispute Resolution Complete ===")
print(f"Payment: {payment_id}")
print(f"Ruling: {ruling}")
print(f"Resolve: {resolve}")
return {"payment_id": payment_id, "ruling": ruling}
run_market_scenario()
10.3 TypeScript 完整实现
import { SigningCosmWasmClient, CosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
import crypto from "crypto";
import { AIPayClient, AIPayConfig, AIPayError } from "./aipay-sdk";
interface PluginListing {
pluginId: string;
seller: string;
price: string;
metadata: Record<string, string>;
timestamp: number;
}
interface MarketAgentOptions {
agentId: string;
mnemonic: string;
address: string;
config?: Partial<AIPayConfig>;
}
class MarketAgentTS {
public agentId: string;
public address: string;
public payClient: AIPayClient;
private mnemonic: string;
constructor(opts: MarketAgentOptions) {
this.agentId = opts.agentId;
this.mnemonic = opts.mnemonic;
this.address = opts.address;
this.payClient = new AIPayClient(opts.config);
}
async getWallet(): Promise<DirectSecp256k1HdWallet> {
return DirectSecp256k1HdWallet.fromMnemonic(this.mnemonic, {
prefix: "msg",
});
}
async getClient(): Promise<SigningCosmWasmClient> {
const wallet = await this.getWallet();
return SigningCosmWasmClient.connectWithSigner(
process.env.AIPAY_RPC || "http://localhost:26657",
wallet,
);
}
publishPlugin(pluginId: string, price: string, metadata: Record<string, string>): PluginListing {
return { pluginId, seller: this.agentId, price, metadata, timestamp: Date.now() };
}
async purchasePlugin(buyerAgent: MarketAgentTS, pluginId: string, price: string) {
const paymentId = `pay:${buyerAgent.address.slice(-8)}:${this.address.slice(-8)}:${Date.now()}`;
const condition = { deliveryId: pluginId, proofType: "sha256", expectedHash: pluginId };
const intent = buyerAgent.payClient.createPayment({
sender: buyerAgent.address,
recipient: this.address,
agentId: this.agentId,
amount: price,
denom: "umsg",
condition,
memo: `Purchase plugin ${pluginId}`,
});
return { paymentId, intent };
}
async deliverPlugin(buyerAgent: MarketAgentTS, paymentId: string, pluginCode: string, client: SigningCosmWasmClient) {
const deliveryId = `delivery:${paymentId}:${Date.now()}`;
const proofResult = await this.payClient.capturePayment(
client, this.address, paymentId, pluginCode
);
const a2aMsg = {
type: "data_transfer", protocol: "msg/a2a/payment-market/1.0.0",
delivery_id: deliveryId, payload_size: pluginCode.length,
payload_hash: crypto.createHash("sha256").update(pluginCode).digest("hex"),
sender: this.address, receiver: buyerAgent.address, timestamp: Date.now(),
};
return { deliveryId, proofResult, a2aMsg };
}
async confirmAndSettle(buyerClient: SigningCosmWasmClient, sellerClient: SigningCosmWasmClient,
paymentId: string, deliveryId: string) {
const confirm = await this.payClient.confirmDelivery(
buyerClient, this.address, paymentId
);
const settle = await this.payClient.settlePayment(
sellerClient, "arbitrator-dao-v1", paymentId
);
return { confirm, settle };
}
}
async function runMarketScenarioTS() {
const seller = new MarketAgentTS({
agentId: "plugin-vendor-001",
mnemonic: process.env.SELLER_MNEMONIC || "seller ...",
address: "msg1q2w3e4r5t6y7u8i9o0p1a2s3d4f5g6h7j8k9l",
});
const buyer = new MarketAgentTS({
agentId: "buyer-agent-007",
mnemonic: process.env.BUYER_MNEMONIC || "buyer ...",
address: "msg1a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s",
});
const listing = seller.publishPlugin("autogpt-web-scraper-v2",
"100000000000000000000", { name: "Web Scraper Pro" });
const purchase = await seller.purchasePlugin(buyer, listing.pluginId, listing.price);
const paymentId = purchase.paymentId;
const sellerClient = await seller.getClient();
const buyerClient = await buyer.getClient();
const pluginCode = 'console.log("Web Scraper Pro v2.1.0");';
const delivery = await seller.deliverPlugin(buyer, paymentId, pluginCode, sellerClient);
const result = await seller.confirmAndSettle(buyerClient, sellerClient,
paymentId, delivery.deliveryId);
console.log("=== Market Purchase Complete ===", JSON.stringify({
plugin: listing.pluginId, price: listing.price, paymentId,
deliveryId: delivery.deliveryId, status: "completed",
}, null, 2));
}
runMarketScenarioTS().catch(console.error);
10.4 微支付流会话: 实时数据订阅
def run_micropayment_session_scenario():
"""运行一次实时数据订阅微支付流."""
provider = MarketAgent("data-provider-002", "dp_key_111",
"msg1d1a2t3a4p5r6o7v8i9d0e1r2p3a4y5m6e7n8t")
consumer = MarketAgent("data-consumer-003", "dc_key_222",
"msg1c1o2n3s4u5m6e7r8d9a0t1a2c3o4l5l6e7c8t")
session_id = f"stream:data-feed:market-data:v1:{int(time.time())}"
rate_per_block = "10000000000000000" # 0.01 MSG / block
initial_deposit = "100000000000000000000" # 100 MSG
# 1. 打开会话
open_res = consumer.client.open_session(
consumer.wallet_key, session_id, consumer.address,
provider.address, provider.agent_id, rate_per_block, initial_deposit
)
print(f"Session opened: {session_id}")
# 2. 每 10 块流式支付一次 (模拟)
stream_count = 5
for i in range(stream_count):
stream_res = consumer.client.stream_payment(
consumer.wallet_key, session_id, consumer.address,
num_blocks=10, payee=provider.address
)
print(f"Stream {i+1}/{stream_count}: charged 10 blocks")
time.sleep(0.1)
# 3. 关闭并结算
close_res = consumer.client.close_session(
consumer.wallet_key, session_id, consumer.address
)
settle_res = consumer.client.settle_session(
provider.wallet_key, session_id
)
total_charged = int(rate_per_block) * 10 * stream_count
print(f"\n=== Micropayment Session Complete ===")
print(f"Session: {session_id}")
print(f"Rate: {rate_per_block} umsg/block")
print(f"Total charged: {total_charged} umsg ({total_charged / 10**18} MSG)")
return {"session_id": session_id, "total_charged": str(total_charged)}
10.5 批量支付: DAO 贡献者工资
def run_batch_payment_scenario():
"""DAO 批量发放贡献者奖励."""
treasury = MarketAgent("msg-dao-treasury", "treasury_key_000",
"msg1t1r2e3a4s5u6r7y8d9a0o1t2r3e4a5s6u7r8y")
contributors = [
{"address": "msg1c1o2n3t4r5i6b7u8t9o0r1a2l3p4h5a6", "amount": "50000000000000000000", "memo": "Q2 2026 contribution"},
{"address": "msg1d1e2v3e4l5o6p7e8r9b0o1b2a3l4e5r6", "amount": "30000000000000000000", "memo": "Documentation"},
{"address": "msg1c1o2m3m4u5n6i7t8y9m0a1n2a3g4e5r6", "amount": "20000000000000000000", "memo": "Community management"},
]
batch_items = [
{"recipient": c["address"], "amount": c["amount"], "memo": c["memo"]}
for c in contributors
]
result = treasury.client.batch_payment(
treasury.wallet_key, treasury.address, batch_items
)
total = sum(int(c["amount"]) for c in contributors)
print(f"\n=== Batch Payment Complete ===")
print(f"Contributors: {len(contributors)}")
print(f"Total distributed: {total} umsg ({total / 10**18} MSG)")
print(f"Batch result: {result}")
return result
11. 边界与限制
11.1 合约实现状态
agent_payment_v1:
submit_intent ✅ 已实现
authorize_payment ✅ 已实现
execute_payment ✅ 已实现
settle_payment ✅ 已实现
cancel_payment ❌ 未实现 (API stub 可用)
freeze_payment ✅ 已实现 (DAO 专用)
challenge_payment ✅ 已实现
resolve_dispute ✅ 已实现
micropayment_session_v1:
create_session ❌ 未实现 (API stub 可用)
charge_session ❌ 未实现 (API stub 可用)
close_session ❌ 未实现 (API stub 可用)
settle_session ❌ 未实现 (API stub 可用)
agent_a2a_v1:
open_channel ✅ 已实现
send_message ✅ 已实现
close_channel ✅ 已实现
verify_message ❌ 未实现
batch_payment:
submit_batch_intent ❌ 未实现 (API stub 可用)
get_aggregated ❌ 未实现 (仅查询可用)
关键约束:
- 所有写路径需要
[X-MSG-Stub=true]头 (模拟环境) - 不能在生产环境 (governance_or_treasury / production_release 门控) 下使用 stub
- 查询路径生产环境已可用:
GET /cosmwasm/wasm/v1/contract/{addr}/smart/{encoded}
11.2 已知限制
| 限制 | 原因 | 应急方案 |
|---|---|---|
| 单笔金额上限 100,000 MSG | 合约硬编码 | 分多笔或使用批量 |
| 微支付流最小粒度 1 block (5s) | 共识层限制 | 累积多块后发送 |
| A2A 消息最大 256 KiB | 链上存储限制 | 大文件使用 IPFS + 哈希引用 |
| 争议窗口 30 天 (2,592,000 blocks) | 合约参数 | 在合约升级前无法修改 |
| 批量支付最多 64 个收款方 | 单笔交易 Gas 上限 | 分批次处理 |
| intent_hash 不可修改 | 不可变性设计 | 只能创建新 intent 并取消旧 intent |
| 不支持非 MSG 代币 | 合约仅接受 umsg | 通过 DEX 兑换为 MSG 再支付 |
| 暂不支持原生 USDC 等稳定币 | 未集成 IBC | 使用 MSG 计价或等值换算 |
| 100% 链上执行 (非 Layer 2) | 架构决定 | 高频场景建议链下累计 + 链上结算 |
11.3 Gas 基准测试数据
操作 Gas (avg) 费用 (umsg) 费用 (MSG)
──────────────────────────────────────────────────────────
submit_intent 150,000 3,750 0.00000375
authorize_payment 120,000 3,000 0.00000300
execute_payment 130,000 3,250 0.00000325
settle_payment 100,000 2,500 0.00000250
freeze_payment 80,000 2,000 0.00000200
challenge_payment 200,000 5,000 0.00000500
resolve_dispute 250,000 6,250 0.00000625
create_session 180,000 4,500 0.00000450
charge_session 80,000 2,000 0.00000200
close_session 60,000 1,500 0.00000150
settle_session 80,000 2,000 0.00000200
batch (<64 items) 500,000 12,500 0.00001250
Gas 价格标准: 1,000,000,000 attoMSG/gas(flat rate).
11.4 AIPAY 网关
为 HTTP 无法直接访问链的 Agent 提供 REST 网关:
class AIPayGateway:
"""用于 HTTP 受限 Agent 的支付网关代理."""
def __init__(self, chain_client: AIPayClient, fee_percent: float = 0.01):
self.client = chain_client
self.fee = fee_percent
def gateway_pay(self, sender_id: str, recipient_id: str,
amount: str, memo: str = "") -> dict:
intent = self.client.create_payment(
sender=sender_id,
recipient=recipient_id,
agent_id="gateway-agent",
amount=amount,
memo=memo,
)
return intent
def gateway_query(self, payment_id: str) -> dict:
return self.client.query_payment(payment_id)
export class AIPayGateway {
private client: AIPayClient;
constructor(client: AIPayClient) { this.client = client; }
async gatewayPay(sender: string, recipient: string,
amount: string, memo?: string) {
return this.client.createPayment({ sender, recipient,
agentId: "gateway-agent", amount, memo });
}
}
11.5 测试网水龙头
class AIPayFaucet:
"""Testnet faucet for development."""
def __init__(self, rpc_url: str = "http://localhost:26657"):
self.rpc_url = rpc_url
self.denom = "umsg"
def request_funds(self, address: str, amount: str = "100000000000000000000") -> dict:
print(f"[Faucet] Requesting {amount} {self.denom} for {address}")
tx = {
"jsonrpc": "2.0",
"method": "broadcast_tx_sync",
"params": {"tx": self._build_faucet_tx(address, amount)},
"id": 1,
}
return tx
def _build_faucet_tx(self, address: str, amount: str) -> str:
return base64.b64encode(
json.dumps({
"address": address,
"amount": [{"denom": self.denom, "amount": amount}],
}).encode()
).decode()
附录
A. 合约消息完整 Schema
{
"agent_payment_v1": {
"instantiate": {
"owner": "msg1..."
},
"execute_msgs": {
"submit_intent": {
"payment_id": "string",
"payer": "string",
"payee": "string",
"agent_id": "string",
"aidid": "string",
"policy_id": "string",
"budget_id": "string",
"constitution_version": "string",
"constitution_hash": "string",
"remote_signer_id": "string",
"service_id": "string",
"action": "string",
"amount": "string (Uint128)",
"asset": "string",
"work_id": "string",
"payment_terms_hash": "string",
"idempotency_key": "string",
"expiry_unix": "number (u64)",
"intent_hash": "string",
"policy_decision_hash": "string",
"runtime_hash": "string",
"local_guard_hash": "string"
},
"authorize_payment": {
"payment_id": "string",
"authorizer": "string",
"authorization_hash": "string",
"intent_hash": "string",
"policy_decision_hash": "string",
"remote_signer_id": "string"
},
"execute_payment": {
"payment_id": "string",
"executor": "string",
"execution_hash": "string",
"intent_hash": "string",
"policy_decision_hash": "string",
"runtime_hash": "string",
"local_guard_hash": "string",
"execution_proof": "string"
},
"settle_payment": {
"payment_id": "string",
"settler": "string",
"settlement_hash": "string",
"settlement_receipt_hash": "string"
},
"freeze_payment": {
"payment_id": "string",
"freeze_id": "string",
"freezer": "string",
"reason": "string",
"freeze_hash": "string"
},
"challenge_payment": {
"payment_id": "string",
"challenge_id": "string",
"challenger": "string",
"reason": "string",
"proof_hash": "string"
},
"resolve_dispute": {
"payment_id": "string",
"arbitrator": "string",
"ruling": "string",
"justification": "string"
},
"cancel_payment": {
"payment_id": "string",
"reason": "string"
}
},
"query_msgs": {
"get_payment": { "payment_id": "string" },
"list_payments": { "payer": "string", "limit": "number", "start_after": "string" },
"list_payments_by_recipient": { "recipient": "string", "limit": "number", "start_after": "string" },
"list_payments_by_status": { "status": "string", "limit": "number", "start_after": "string" }
}
},
"micropayment_session_v1": {
"execute_msgs": {
"create_session": {
"session_id": "string",
"payer": "string",
"payee": "string",
"agent_id": "string",
"asset": "string",
"rate_per_block": "string (Uint128)",
"initial_deposit": "string (Uint128)",
"terms_hash": "string"
},
"charge_session": {
"session_id": "string",
"payer": "string",
"num_blocks": "number (u64)",
"charge_receipt_hash": "string"
},
"close_session": {
"session_id": "string",
"payer": "string",
"close_receipt_hash": "string"
},
"settle_session": {
"session_id": "string"
}
},
"query_msgs": {
"get_session": { "session_id": "string" },
"list_sessions": { "participant": "string", "limit": "number" }
}
}
}
B. Agent API 端点速查
Payment:
POST /agent/v1/payment/submit-intent [X-MSG-Stub=true]
POST /agent/v1/payment/authorize [X-MSG-Stub=true]
POST /agent/v1/payment/capture [X-MSG-Stub=true]
POST /agent/v1/payment/settle [X-MSG-Stub=true]
POST /agent/v1/payment/cancel [X-MSG-Stub=true]
POST /agent/v1/payment/challenge [X-MSG-Stub=true]
POST /agent/v1/payment/resolve-dispute [X-MSG-Stub=true]
GET /agent/v1/payment/status?payment_id=...
GET /agent/v1/payment/history?agent_id=...
Micropayment:
POST /agent/v1/payment/session/create [X-MSG-Stub=true]
POST /agent/v1/payment/session/charge [X-MSG-Stub=true]
POST /agent/v1/payment/session/close [X-MSG-Stub=true]
POST /agent/v1/payment/session/settle [X-MSG-Stub=true]
GET /agent/v1/payment/session?session_id=...
Batch:
POST /agent/v1/payment/batch [X-MSG-Stub=true]
GET /agent/v1/payment/aggregated?payee=...
A2A:
POST /agent/v1/a2a/channel/open [X-MSG-Stub=true]
POST /agent/v1/a2a/channel/send [X-MSG-Stub=true]
POST /agent/v1/a2a/channel/close [X-MSG-Stub=true]
GET /agent/v1/a2a/channel?channel_id=...
C. 常见错误排障
COMMON_ERRORS = {
"code: 4 INSUFFICIENT_FUNDS": [
"检查钱包余额: msgcli q bank balances {address}",
"水龙头领取代币: POST /faucet with {address, amount}",
"确认 denom 是 umsg 而非 msg",
],
"code: 5 CONTRACT_FAILED": [
"检查 intent 字段是否完整 (21 个必填字段)",
"验证 payee 地址格式 (msg1...)",
"确认合约地址正确",
],
"code: 8 DAO_TIMELOCK": [
"需要 governance_or_treasury 门控授权",
"通过 DAO 提案提交: submit_proposal → vote → execute",
"时间锁默认 7 天 (604800 blocks)",
],
"code: 10 AGENT_NOT_FOUND": [
"Agent ID 未注册",
"检查 register_agent 是否完成",
"验证 agent_id 格式 (小写字母 + 数字 + 连字符)",
],
"code: 11 PAYMENT_NOT_FOUND": [
"payment_id 不存在或已过期",
"检查 query_payment 返回",
"idempotency_key 冲突: 使用新 key",
],
"code: 12 PAYMENT_EXPIRED": [
"创建时 expiry_unix 设置为当前时间 + 86400 (24h)",
"确保系统时钟同步 (NTP)",
"过期的只能重新创建",
],
"code: 14 UNAUTHORIZED": [
"只有 payer 或指定的 authorizer 可以 authorize",
"只有合约指定的 executor 可以 execute",
"只有 DAO 可以 freeze",
],
"stub mode errors": [
"确认环境变量 AIPAY_STUB=false 以关闭 stub",
"所有写路径需要 [X-MSG-Stub=true] 头",
"生产环境需通过 governance_or_treasury 门控",
],
}
D. 版本记录
version: 1.0.0
date: 2026-07-06
changelog:
- init: draft version with all contract schemas, SDKs, and examples
known_issues:
- micropayment_session_v1 execute methods not yet deployed
- batch_payment requires governance_or_treasury gate
references:
- MSG Chain Agent Framework: /docs/MSG链AI Agent开发框架.md
- A2A Protocol: /docs/A2A通信协议指南.md
- API Reference: /docs/API接口大全.md
- Tokenomics: /docs/代币经济模型.md
- dApp Example: /docs/AI Agent市场完整dApp.md
