返回 Expert 笔记
Expert Day 161

Agent on Web3——x402 支付、Session Keys、链上行动、Virtuals

x402(Coinbase + Cloudflare 2025)协议;ERC-7715 session keys;ERC-4337 smart accounts;Virtuals/ElizaOS/GOAT 框架定位

2026-10-09
Phase 3 - Agent架构与多Agent (Day 149-162)
x402SessionKeysERC7715ERC4337VirtualsElizaOSOnchainAgent

日期: 2026-10-09 方向: AI系统工程 / Agent 阶段: Phase 3 - Agent架构与多Agent (Day 149-162) 标签: #x402 #SessionKeys #ERC7715 #ERC4337 #Virtuals #ElizaOS #OnchainAgent


今日目标

类型内容
学习x402(Coinbase + Cloudflare 2025)协议;ERC-7715 session keys;ERC-4337 smart accounts;Virtuals/ElizaOS/GOAT 框架定位
实操实现一个 agent:① 用 session key 限权;② 调付费 API 时自动 x402 settle;③ 链上 swap 前 simulate + sign
产出onchain_agent.py(约 600 行)+ session key 演示

一、x402 协议——agent 经济基础设施

1.1 背景

HTTP 状态码 402(Payment Required)保留了 30 多年没真正用。2025 年 5 月 Coinbase + Cloudflare 推出 x402 协议:基于 HTTP 402 + 稳定币 onchain settlement,让 API 可以按调用收费,agent 可以无 KYC 自动支付。

1.2 流程

agent ──GET /api/data──► server
       ◄──402 Payment Required + payment_requirements──
       │  {"asset":"USDC","amount":"0.001",
       │   "facilitator":"https://x402.coinbase.com",
       │   "chain":"base","recipient":"0x..."}
       │
       │  agent: sign EIP-3009 transferWithAuthorization
       │
       ──GET /api/data + X-PAYMENT header──► server
       │  X-PAYMENT: base64(signed_authorization)
       │
       │  server validates with facilitator
       │
       ◄──200 OK──

1.3 关键特性

  • No-KYC——agent 钱包就是 ID
  • Sub-cent——最小 $0.0001 调用
  • Atomic——支付与 API 调用在一个 HTTP 往返
  • EIP-3009——稳定币原生支持 transferWithAuthorization
  • Facilitator——Coinbase 提供 settlement,server 不需要自己跑链
  • Chain:Base, Solana, etc.

1.4 适合场景

  • AI 模型调用按 token 收费
  • 数据 API 按 query 收费
  • 代理 agent 互相付费
  • 防 DDoS(每个请求要钱)

二、Session Keys(ERC-7715)

2.1 问题

传统:agent 需要私钥才能签交易。但永远不应该把主钱包私钥给 agent——一旦泄漏全财产丢失。

2.2 ERC-7715 Session Keys

Session key = 临时、范围受限的密钥,由主账户授权,只能做指定动作。

2.3 限制维度

  • 合约白名单:仅能调 Uniswap router
  • 方法白名单:仅 swapExactTokensForTokens
  • 金额上限:单笔 < 1 ETH,日累 < 5 ETH
  • 时间窗口:从 T 起 7 天内有效
  • 次数上限:100 次
  • Receiver 白名单:只能转给 self

2.4 配套技术栈

  • ERC-4337(账户抽象):smart account 是合约,可以编程化定义"什么 key 能做什么"
  • EIP-7702(2025 主网):让 EOA 也能临时 act as smart account,session key UX 大改善
  • Permissions(Privy / ZeroDev / Biconomy SDK):包装 session key 创建 + 验证

2.5 为什么对 agent 关键

  • 主账户在 hardware wallet 永远离线
  • 给 agent 一个有限 session key
  • agent 跑飞最多损失"上限金额"
  • key 过期自动失效

三、ERC-4337 Smart Accounts

3.1 ELI5

EOA = 一个私钥控制一切。Smart Account = 一个合约控制资产,合约逻辑可任意:

  • 多签
  • Session keys
  • 社交恢复
  • 限额
  • Plugin 系统(Kernel / Safe 7579)

3.2 关键参与者

  • UserOperation:用户的 intent
  • Bundler:把多个 UserOp 打包成一笔 tx
  • EntryPoint:链上验证 + 执行入口
  • Paymaster:第三方付 gas(让 agent 用稳定币付 gas,不需要 ETH)

3.3 SDK 选择

SDK特色
viem + permissionless标准、灵活
ZeroDev SDKsession key 完善
Biconomypaymaster 完善
Privyembedded wallet UX
Alchemy AA SDK集成度高

四、Onchain Agent 框架

4.1 Virtuals Protocol

  • 2024 出,专做 agent token + agent commerce
  • 框架 G.A.M.E(Generative Autonomous Multimodal Entity)
  • 每个 agent 有 ERC-20 token,可被持有/治理
  • 主要在 Base 上

4.2 ElizaOS(前 ai16z)

  • 开源 agent 框架(TypeScript)
  • 多 plugin 生态(Twitter/Discord/Solana/EVM)
  • 角色驱动(character files)
  • 链无关(plugins 决定)

4.3 GOAT (Great Onchain Agent Toolkit)

  • Crossmint 维护
  • 给 LLM agent 一系列 onchain "actions"(like tools)
  • 支持 Solana / EVM / Sui / Cosmos
  • 与 Vercel AI SDK / LangChain 集成

4.4 Olas Network

  • DAO 化的 agent infrastructure
  • Pearl(runtime)+ Mech(service marketplace)
  • 链上 service 注册 + 收益分配

4.5 选型

你要做
Twitter / 社交 agent + tokenVirtuals 或 ElizaOS
纯 onchain action (DeFi / NFT)GOAT + viem
去中心化 agent serviceOlas
自定义业务 agentviem + 自家 framework

五、架构图

┌──────────────────────────────────────────────────────────────────┐
│                  Onchain Agent (Day 161)                         │
│                                                                  │
│   User wallet (cold/hardware)                                    │
│       │                                                          │
│       │ signs once: createSessionKey(scope, limit, expiry)        │
│       ▼                                                          │
│   Smart Account (ERC-4337 / 7702)                                │
│       │                                                          │
│       │ holds:                                                    │
│       │   - main key (cold)                                       │
│       │   - session key #SK-1 (agent uses this)                   │
│       │                                                          │
│       ▼                                                          │
│   ┌────────────────────────────────────────────────────────┐     │
│   │              Agent Runtime                              │     │
│   │                                                         │     │
│   │   tools:                                                │     │
│   │     - get_balance(addr)         (read RPC)              │     │
│   │     - get_quote(token, amt)     (Uniswap)               │     │
│   │     - simulate_swap(...)        (eth_call + bundler sim)│     │
│   │     - execute_swap(...)         (sign with SK + bundler)│     │
│   │     - call_paid_api(url)        (auto x402 if 402)      │     │
│   │                                                         │     │
│   │   guardrails:                                           │     │
│   │     - all destructive: simulate first                   │     │
│   │     - amount > $5k: require user re-confirm             │     │
│   │     - per-task USD cap                                  │     │
│   └────────────────────────────────────────────────────────┘     │
│                                                                  │
│   Bundler ─────► EntryPoint ─────► Smart Account ─────► DEX     │
└──────────────────────────────────────────────────────────────────┘

六、代码——onchain_agent.py

# onchain_agent.py
"""
Day 161 - An onchain agent with:
  - Session key (ERC-7715-style scope limits)
  - x402 auto-settle for paid APIs
  - Simulate-before-execute for swaps
  - Per-task budget guardrail

Pip install:
  pip install web3 anthropic httpx eth-account
"""
from __future__ import annotations
import base64
import json
import os
import time
from dataclasses import dataclass, field
from typing import Any, Callable, Optional

import httpx
from anthropic import Anthropic
from eth_account import Account
from eth_account.messages import encode_typed_data
from web3 import Web3

# ====================================================================
# Config
# ====================================================================
RPC_URL = os.environ.get("RPC_URL", "https://mainnet.base.org")
w3 = Web3(Web3.HTTPProvider(RPC_URL))
USDC = Web3.to_checksum_address("0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913")  # Base USDC

# ====================================================================
# Session Key
# ====================================================================
@dataclass
class SessionKey:
    address: str               # session key EOA
    private_key: str           # held by agent runtime ONLY
    smart_account: str         # the smart account this SK is registered on
    allowed_targets: set[str]  # contract addresses agent can call
    allowed_selectors: set[str] # 4-byte fn selectors (e.g. swap)
    max_per_call_usd: float
    max_per_day_usd: float
    used_today_usd: float = 0.0
    expires_ts: int = 0

    @classmethod
    def create(
        cls,
        smart_account: str,
        allowed_targets: list[str],
        allowed_selectors: list[str],
        max_per_call_usd: float = 1000,
        max_per_day_usd: float = 5000,
        valid_days: int = 7,
    ) -> "SessionKey":
        acct = Account.create()
        return cls(
            address=acct.address,
            private_key=acct.key.hex(),
            smart_account=smart_account,
            allowed_targets={Web3.to_checksum_address(a) for a in allowed_targets},
            allowed_selectors=set(allowed_selectors),
            max_per_call_usd=max_per_call_usd,
            max_per_day_usd=max_per_day_usd,
            expires_ts=int(time.time()) + valid_days * 86400,
        )

    def authorize(self, target: str, selector: str, value_usd: float) -> Optional[str]:
        """Return None if allowed, else error string."""
        if time.time() > self.expires_ts:
            return "session_expired"
        target = Web3.to_checksum_address(target)
        if target not in self.allowed_targets:
            return f"target_not_allowed: {target}"
        if selector not in self.allowed_selectors:
            return f"selector_not_allowed: {selector}"
        if value_usd > self.max_per_call_usd:
            return f"per_call_limit: ${value_usd} > ${self.max_per_call_usd}"
        if self.used_today_usd + value_usd > self.max_per_day_usd:
            return f"daily_limit: would exceed ${self.max_per_day_usd}"
        return None

    def commit(self, value_usd: float):
        self.used_today_usd += value_usd

# ====================================================================
# x402 client
# ====================================================================
@dataclass
class X402Wallet:
    """Holds a USDC-funded EOA used for x402 micropayments."""
    private_key: str
    address: str

    @classmethod
    def from_env(cls) -> "X402Wallet":
        pk = os.environ["X402_PRIVATE_KEY"]
        return cls(private_key=pk, address=Account.from_key(pk).address)

    def sign_authorization(self, requirements: dict) -> str:
        """EIP-3009 transferWithAuthorization signature."""
        # USDC token contract on Base
        domain = {
            "name": "USD Coin",
            "version": "2",
            "chainId": int(requirements.get("chain_id", 8453)),
            "verifyingContract": requirements["asset_address"],
        }
        types = {
            "TransferWithAuthorization": [
                {"name": "from", "type": "address"},
                {"name": "to", "type": "address"},
                {"name": "value", "type": "uint256"},
                {"name": "validAfter", "type": "uint256"},
                {"name": "validBefore", "type": "uint256"},
                {"name": "nonce", "type": "bytes32"},
            ],
        }
        message = {
            "from": self.address,
            "to": requirements["recipient"],
            "value": int(float(requirements["amount"]) * 10**6),  # USDC has 6 decimals
            "validAfter": 0,
            "validBefore": int(time.time()) + 600,
            "nonce": os.urandom(32).hex(),
        }
        signed = Account.sign_typed_data(self.private_key, domain, types, message)
        # Encode for X-PAYMENT header
        payload = {
            "scheme": "exact",
            "domain": domain,
            "message": message,
            "signature": signed.signature.hex(),
        }
        return base64.b64encode(json.dumps(payload).encode()).decode()

class X402Client:
    def __init__(self, wallet: X402Wallet, max_per_call_usd: float = 0.50):
        self.wallet = wallet
        self.max_per_call_usd = max_per_call_usd
        self.client = httpx.Client(timeout=30)

    def get(self, url: str) -> dict:
        r = self.client.get(url)
        if r.status_code == 200:
            return r.json()
        if r.status_code == 402:
            req = r.json()  # payment_requirements
            amount = float(req["amount"])
            if amount > self.max_per_call_usd:
                raise RuntimeError(f"x402 amount ${amount} exceeds cap ${self.max_per_call_usd}")
            x_payment = self.wallet.sign_authorization(req)
            r2 = self.client.get(url, headers={"X-PAYMENT": x_payment})
            r2.raise_for_status()
            return r2.json()
        r.raise_for_status()

# ====================================================================
# Tools
# ====================================================================
@dataclass
class Tool:
    name: str
    description: str
    input_schema: dict
    handler: Callable[[dict], Any]

def _t_get_balance(args):
    addr = Web3.to_checksum_address(args["address"])
    bal = w3.eth.get_balance(addr)
    return {"address": addr, "eth_wei": bal, "eth": bal / 1e18}

def _t_get_usdc_balance(args):
    USDC_ABI = [{"constant": True, "inputs": [{"name": "owner", "type": "address"}],
                 "name": "balanceOf", "outputs": [{"name": "", "type": "uint256"}],
                 "type": "function"}]
    c = w3.eth.contract(address=USDC, abi=USDC_ABI)
    bal = c.functions.balanceOf(Web3.to_checksum_address(args["address"])).call()
    return {"usdc": bal / 1e6}

def _t_simulate_swap(args):
    """eth_call simulate without spending gas. Returns expected min_out."""
    # Stub: production calls Uniswap quoter
    return {"min_out_estimate": float(args["amount_in"]) * 0.998}

# ====================================================================
# Onchain Agent
# ====================================================================
ONCHAIN_TOOLS = [
    Tool(name="get_balance", description="Get ETH balance of an address.",
         input_schema={"type":"object","properties":{"address":{"type":"string"}},"required":["address"]},
         handler=_t_get_balance),
    Tool(name="get_usdc_balance", description="Get USDC balance.",
         input_schema={"type":"object","properties":{"address":{"type":"string"}},"required":["address"]},
         handler=_t_get_usdc_balance),
    Tool(name="simulate_swap",
         description="Simulate (does NOT execute) a Uniswap swap. Returns expected output. ALWAYS call before execute_swap.",
         input_schema={"type":"object","properties":{
             "from_token":{"type":"string"}, "to_token":{"type":"string"},
             "amount_in":{"type":"string"}, "recipient":{"type":"string"},
         },"required":["from_token","to_token","amount_in","recipient"]},
         handler=_t_simulate_swap),
]

class OnchainAgent:
    def __init__(self, session_key: SessionKey, x402: X402Client | None = None,
                 task_budget_usd: float = 5.0):
        self.client = Anthropic()
        self.session_key = session_key
        self.x402 = x402
        self.task_budget_usd = task_budget_usd
        self.tools = {t.name: t for t in ONCHAIN_TOOLS}
        self._spent_usd = 0.0

    SYSTEM = (
        "You are an onchain DeFi assistant. You have access to read-only tools "
        "and a session key with strict limits. RULES:\n"
        "1. ALWAYS simulate_swap before any execute_swap.\n"
        "2. Reject swaps where simulated min_out is < 99% of expected.\n"
        "3. NEVER hardcode addresses; always read from user input.\n"
        "4. If session key denies an action, report and stop.\n"
        "5. Each swap > $1000 USD requires explicit user re-confirmation.\n"
    )

    def execute_swap_with_session_key(self, target: str, selector: str,
                                      calldata_hex: str, value_usd: float) -> dict:
        # Authorize via session key
        err = self.session_key.authorize(target, selector, value_usd)
        if err:
            return {"status": "rejected", "reason": err}
        # In production: build UserOperation, sign with SK, send via bundler
        # Here we stub the broadcast
        self.session_key.commit(value_usd)
        self._spent_usd += value_usd
        return {"status": "submitted", "tx_hash": "0x" + os.urandom(32).hex(),
                "remaining_daily_usd": self.session_key.max_per_day_usd - self.session_key.used_today_usd}

    def run(self, task: str, max_iter: int = 8):
        msgs = [{"role": "user", "content": task}]
        for i in range(max_iter):
            if self._spent_usd > self.task_budget_usd:
                return {"error": "task_budget_exceeded"}
            resp = self.client.messages.create(
                model="claude-opus-4-7",
                max_tokens=2048,
                system=self.SYSTEM,
                tools=[{"name":t.name,"description":t.description,
                        "input_schema":t.input_schema} for t in self.tools.values()],
                messages=msgs,
            )
            msgs.append({"role":"assistant","content":resp.content})
            if resp.stop_reason == "end_turn":
                final = "".join(b.text for b in resp.content if b.type == "text")
                return {"final": final, "spent_usd": self._spent_usd}
            if resp.stop_reason == "tool_use":
                tool_results = []
                for b in resp.content:
                    if b.type == "tool_use":
                        try:
                            out = self.tools[b.name].handler(b.input)
                            tool_results.append({"type":"tool_result","tool_use_id":b.id,
                                                  "content":json.dumps(out)})
                        except Exception as e:
                            tool_results.append({"type":"tool_result","tool_use_id":b.id,
                                                  "content":f"error: {e}", "is_error": True})
                msgs.append({"role":"user","content":tool_results})
        return {"error": "max_iter"}

# ====================================================================
# Demo
# ====================================================================
if __name__ == "__main__":
    sk = SessionKey.create(
        smart_account="0x" + "0" * 40,
        allowed_targets=["0x1111" + "1" * 36],   # uniswap router placeholder
        allowed_selectors=["0xb6f9de95"],          # swapExactETHForTokens (example)
        max_per_call_usd=500,
        max_per_day_usd=2000,
        valid_days=7,
    )
    print("Created session key:", sk.address)
    print("  expires:", time.strftime("%Y-%m-%d", time.localtime(sk.expires_ts)))

    agent = OnchainAgent(session_key=sk, task_budget_usd=2.0)
    out = agent.run("Check the ETH balance of 0x0000000000000000000000000000000000000001 and tell me if it's > 1 ETH.")
    print(json.dumps(out, indent=2, default=str))

    # Demo session key denial
    err = sk.authorize(target="0xdeadbeef" + "0"*32, selector="0xdead0000", value_usd=10000)
    print("Denial demo:", err)

七、金融领域应用

7.1 链上财富管理 agent

  • 用户给 session key(仅 swap、单笔 $5k,每日 $20k)
  • Agent 跑策略:rebalance / yield optimize / DCA
  • 主钱包永远在 cold storage,agent 只能动 session 范围

7.2 自动化稳定币运营

  • 跨多个 yield 协议比较 APY
  • Agent 自动 move funds(限于 USDC、限于白名单协议)
  • x402 调用 yield oracle

7.3 RWA 流动性 routing

  • 链上代币化美债 + 链上稳定币 + DEX
  • Agent 监控价差,动态分配
  • 合规约束写进 session key(只能调白名单合约 → 已 KYC 的协议)

八、生产经验与陷阱

  1. 私钥保管失误 Session key private 也是钱——泄漏者可用满范围+limit。最少:HSM / KMS / encrypted at rest + IAM。理想:threshold signing(MPC)。

  2. Simulate 与实际不一致 Block N simulate 通过,N+1 才 broadcast,状态变了 revert(前面有 large swap 改 price)。措施:simulate 时机离 broadcast 最近 + 链上 minOut 强约束。

  3. x402 价格欺诈 恶意 server 发 402 amount=$1 实际服务值 $0.001。客户端必须有 max_per_call cap + 信誉机制。

  4. Session key permission 失效 主账户撤销了 session 但 agent 不知道,反复尝试。Agent 收到 revert 后要识别 "permission revoked" 并停止。

  5. Bundler 拒绝 gas estimation 偏低 / Paymaster 拒付。需要 fallback 路径(换 bundler,或降级到 EOA send)。

  6. 重放攻击 x402 nonce 重复使用,server 重复扣钱。EIP-3009 nonce 必须 random + server 缓存检查。

  7. MEV / 三明治 agent 在 mempool 暴露 swap 被夹。措施:private mempool(Flashbots)、TWAP、或用 CoW Protocol(intent-based)。

  8. 跨链状态 Agent 读 chain A 状态,到 chain B 行动,桥延迟期间状态变。措施:单链 atomic 优先,跨链用 7683 intent。


九、Cost & Latency

操作成本
LLM iter(opus 4-7)$0.03-0.10
RPC read免费/一次
Bundler simulate免费(链下)
ERC-4337 UserOpgas + paymaster fee(10-50% 溢价)
x402 micro call$0.0001-$0.01 + ~50ms USDC settle
Session key creation1 笔交易 + ~$0.5-3 gas(L2)
延迟数值
LLM iter5-15s
Bundler submit2-5s
L2 finalize5-15s
x402 settle50-200ms

完整一次 "agent 决定 + 链上执行" 30-60s。生产里大量动作可批量到一笔 UserOp。


十、关键速查

Session key scope 推荐设置(不同任务)

任务推荐 scope
自动 yield rebalance协议白名单 + 单笔 $5k + 日 $50k + 7 天
自动 DCAswap target 白名单 + 固定金额 + 每天 1 次
风控自动平仓单笔金额大但仅 sell 方向 + 短期(24h)
试运行 / 测试主网 small 金额 + 严格白名单 + 1 天

Onchain agent 安全 checklist

  • 主账户私钥不接触 agent runtime
  • Session key 范围最小化
  • 每个 destructive call simulate first
  • 单笔 / 日累 USD cap
  • Task USD budget cap
  • Audit log every onchain action
  • 异常 revert 触发立刻停止 + 通知
  • x402 amount cap
  • 大额(> threshold)人工 re-confirm

十一、面试题

Q1: 为什么不能直接给 agent 主钱包私钥?

A: 安全上不可接受。Agent runtime 含 LLM + tool 调用 + 网络,攻击面巨大(prompt injection / RCE / dependency 漏洞)。一旦 runtime 被攻陷,主钱包全部资产丢失。Session key(ERC-7715)+ smart account(ERC-4337)允许"仅授权 agent 在范围内动钱",损失上限明确。这与传统软件"least privilege"原则同构。

Q2: x402 解决什么问题?为什么不用 Stripe?

A: ① No-KYC——agent 没法过 Stripe KYC;② Sub-cent——Stripe 最低 $0.30,x402 可以 $0.0001;③ Atomic——支付与服务一个 HTTP 往返;④ 机器友好——agent 钱包就是 ID;⑤ 跨链可移植。Stripe 适合人类买东西,x402 适合 agent 间机器消费。

Q3: 一个 agent 用 session key 跑了一周后,最大风险是什么?

A: ① Smart contract 漏洞——session key 本身没漏,但 agent 调的协议被黑(agent 资金在该协议中);② 预言机操纵——agent 据 price 决策,price 被操纵;③ MEV/三明治——swap 被夹,每次损失;④ session key 私钥泄漏——HSM / MPC 必要;⑤ 错误持续触发——agent 每天都做错事但在 limit 内,不报警。Mitigation:每日预算 + 异常告警 + 人工 review。

Q4: 设计一个 RWA 自动运营 agent,session key scope 怎么设?

A: ① 资产侧:白名单稳定币(USDC/PYUSD)+ 白名单 RWA token(已合规);② 协议侧:白名单 yield 协议(已审计 + 监管友好);③ 金额:单笔 ≤ AUM 的 5%,日 ≤ 20%;④ 方法:仅 deposit/withdraw/swap,不能 borrow;⑤ 时间:30 天 expiry;⑥ 接收方:仅 self-account;⑦ 强制 simulate;⑧ 大额(> 10% AUM)必须人工二次签。

Q5: Virtuals / ElizaOS / GOAT,企业 PM 应该选哪个?

A: 取决于产品。① 想要 token 化 agent + 社交 → Virtuals(但 token 化在很多司法区受限);② 自定义 character/plugin、TypeScript 团队 → ElizaOS;③ 想给现有 LLM stack(LangChain / Vercel AI)加 onchain action → GOAT;④ 企业内部不暴露公开 → 自建,不要 lock-in 任何框架。"用 framework"不等于"成功",PM 要关注:合规、可审计、能被金融团队信任。


十二、深入:x402 流程实战

12.1 完整 HTTP 序列

Request 1 (no payment):
  GET https://data.api/quote?symbol=BTC HTTP/1.1
  Accept: application/json

Response 1:
  HTTP/1.1 402 Payment Required
  Content-Type: application/json

  {
    "x402Version": 1,
    "accepts": [{
      "scheme": "exact",
      "network": "base",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "maxAmountRequired": "1000",   // 0.001 USDC (6 decimals)
      "resource": "/quote?symbol=BTC",
      "description": "Real-time BTC quote",
      "mimeType": "application/json",
      "payTo": "0xRecipient...",
      "maxTimeoutSeconds": 60,
      "extra": {"name": "USD Coin", "version": "2"}
    }]
  }

Request 2 (with payment):
  GET https://data.api/quote?symbol=BTC HTTP/1.1
  X-PAYMENT: <base64(scheme="exact", signature, message)>

Response 2:
  HTTP/1.1 200 OK
  X-PAYMENT-RESPONSE: <base64(facilitator_settlement_proof)>
  Content-Type: application/json

  {"symbol": "BTC", "price": 105_320, "ts": 1733...}

12.2 Facilitator 的角色

  • 验证 EIP-3009 签名
  • broadcast settlement 上链
  • 给 server 一个"已收到钱"凭证
  • Server 不需要自己跑节点

12.3 为什么不直接 settle 在 server?

  • Server 通常是 SaaS / API provider,无意维护链节点
  • Facilitator 提供 settlement-as-a-service,类似 Stripe 之于卡支付
  • 缺点:信任 facilitator(但 settlement 本身上链可审)

十三、Session Key 的链下管理设计

13.1 私钥生命周期

[Create]   主账户签授权 tx → onchain registry 记 SK 公钥 + scope
[Store]    SK 私钥加密存 KMS / HSM
[Use]      Agent runtime 取 SK 私钥(in-memory)→ 签 UserOp
[Rotate]   每 N 天创建新 SK,回收旧 SK
[Revoke]   主账户签 revoke tx → registry 标记 SK 失效

13.2 KMS 集成示例(AWS)

import boto3
kms = boto3.client("kms")

def sign_with_kms(key_id: str, message_hash: bytes) -> bytes:
    resp = kms.sign(
        KeyId=key_id,
        Message=message_hash,
        MessageType="DIGEST",
        SigningAlgorithm="ECDSA_SHA_256",
    )
    return resp["Signature"]

私钥永远不离开 KMS。Agent runtime 只能 request signing。即使容器被攻陷,攻击者拿不到私钥本体(只能在 IAM 允许范围内签)。

13.3 紧急 kill switch

// Smart account with kill switch
function emergencyRevokeAll() external onlyMainKey {
    sessionKeys.revokeAll();
}

主账户随时可一键 revoke 所有 SK。结合监控:异常 swap 大小、异常频率触发自动 alarm + 人工 kill。


十四、链上 agent 经济模型

14.1 Agent 的角色谱

角色例子商业模式
服务商:agent 提供服务收钱trading bot、data agentx402 / 订阅
代理人:代表 user 行动财富管理 agent用户付订阅 / 业绩分成
市场参与者:自营资产管理"agent token" funds治理 token 升值
协调者:撮合多 agentOlas mech分润

14.2 Agent token 模型(Virtuals 风格)

  • 每个 agent 发行 token
  • Token holder 共享 agent 收入(10-30% airdrop / 收入分配)
  • Agent 性能 → token 升值
  • 风险:监管不确定(多数司法区视为 security)

14.3 实际企业部署

传统金融机构通常用 agent token。常见模式:

  • Agent 内部部署,给客户经理用
  • 收入按服务套餐而非 token
  • 监管友好

十五、扩展练习

  1. 实现 paymaster 集成——用 USDC 付 gas 而非 ETH
  2. 加 EIP-7702 临时智能账户——让普通 EOA 用 session key
  3. 实现 batch transactions——多个 swap 打包成 1 笔 UserOp
  4. 加 simulation against forked mainnet——hardhat fork + simulate
  5. 写 monitoring dashboard——session key usage / 余额 / 失败率
  6. 实现 multi-sig session key——agent 提案,多个 sig 才执行
  7. 接 CoW Protocol——用 intent-based 避免 MEV
  8. 写 emergency revoke flow——异常时主账户一键 kill all SK

明日预告

Day 162: Week 24 复习——Multi-agent 系统整合 v1

  • 把 Day 149-161 的所有概念整合
  • 一个完整的"金融研究 + 链上执行"multi-agent v1
  • Phase 3 中段总结