bnbagent

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

BNBAgent SDK

BNBAgent SDK

Python SDK (
pip install bnbagent
, Python 3.10+) for on-chain AI agents on BNB Chain. Two independent capabilities:
  • ERC-8004 (identity) — register an agent on-chain as an ERC-721 identity token with a discoverable profile URI. Gas-free on BSC Testnet via MegaFuel paymaster.
  • ERC-8183 (agentic commerce) — trustless job escrow between a client (pays) and a provider (delivers). Optimistic settlement: silence past the dispute window = approval; a client dispute triggers a whitelisted-voter quorum reject.
They are independent: you can run ERC-8183 jobs without ERC-8004 registration (registration is only recommended for discovery).
Active development — breaking changes possible. Tested with
bnbagent==0.4.0
; verify install with
python -c "import bnbagent; print(bnbagent.__version__)"
. Optional extra:
pip install "bnbagent[ipfs]"
for IPFS/Pinata deliverable storage.
面向BNB Chain链上AI Agent的Python SDK(
pip install bnbagent
,要求Python 3.10+),具备两项独立功能:
  • ERC-8004(身份协议) — 将Agent作为带有可发现配置文件URI的ERC-721身份代币在链上注册。在BSC测试网可通过MegaFuel支付方实现免Gas费。
  • ERC-8183(Agent商业协议) — 实现客户(付费方)与服务提供者(交付方)之间的无信任任务托管。采用乐观结算机制:争议窗口期过后无异议即视为批准;客户发起争议则触发白名单投票者的多数否决机制。
两项功能相互独立:无需完成ERC-8004注册即可运行ERC-8183任务(仅推荐用于Agent发现场景时进行注册)。
项目处于活跃开发阶段——可能存在破坏性变更。已基于
bnbagent==0.4.0
测试;可通过
python -c "import bnbagent; print(bnbagent.__version__)"
验证安装版本。可选扩展:执行
pip install "bnbagent[ipfs]"
以支持IPFS/Pinata交付物存储。

⚠️ Mainnet economics — read BEFORE any mainnet commerce

⚠️ 主网经济规则 — 开展主网交易前必读

  • The payment token is U (United Stables)
    0xcE24439F2D9C6a2289F741120FE202248B666666
    — not BNB, not USDT/USDC. There is no faucet for it: acquire U on PancakeSwap (a WBNB–U pair exists). The client must hold U before calling
    fund()
    . Fetch decimals at runtime via
    erc8183.token_decimals()
    — don't assume.
  • ERC-8183 writes on mainnet are never gas-sponsored. Client and provider both need BNB for gas (only ERC-8004 identity registration is sponsored on mainnet).
  • The mainnet dispute window is 604800s (7 days). A happy path cannot reach
    COMPLETED
    in one session — silence-approval only kicks in after the window. Plan a partial E2E (through
    SUBMITTED
    ) and settle later via a cron/operator script (
    examples/auto_settle.py
    ).
    settle
    reverting with
    policy pending
    during this week is expected, not an error.
  • 支付代币为U(United Stables)
    0xcE24439F2D9C6a2289F741120FE202248B666666
    — 并非BNB、USDT或USDC。目前没有该代币的水龙头:需在PancakeSwap上获取U(存在WBNB-U交易对)。客户在调用
    fund()
    前必须持有U。请通过
    erc8183.token_decimals()
    在运行时获取小数位数——不要自行假设。
  • ERC-8183主网写入操作永远不提供Gas赞助。客户和服务提供者都需要BNB支付Gas费(仅ERC-8004身份注册在主网提供赞助)。
  • 主网争议窗口期为604800秒(7天)。正常流程无法在一次会话中达到
    COMPLETED
    状态——只有窗口期过后无异议才会触发批准。建议规划部分端到端流程(执行到
    SUBMITTED
    状态),之后通过定时任务/操作员脚本(
    examples/auto_settle.py
    )完成结算。在此周内
    settle
    返回
    policy pending
    属于预期情况,并非错误。

Preflight balance checklist (mainnet)

主网预飞行余额检查清单

PartyNeedsWhy
ClientBNBgas for
createJob
/
registerJob
/
setBudget
/
approve
/
fund
(+ optional swap gas)
ClientUthe job budget escrowed by
fund
(+ small residual for retries)
ProviderBNBgas for
submit
— not sponsored on mainnet
Settler (anyone)BNBgas for
settle
after the window
角色所需资产原因
客户BNB支付
createJob
/
registerJob
/
setBudget
/
approve
/
fund
的Gas费(+ 可选的兑换Gas费)
客户U
fund
托管的任务预算(+ 少量备用金用于重试)
服务提供者BNB支付
submit
的Gas费——主网不提供赞助
结算者(任意角色)BNB窗口期过后支付
settle
的Gas费

Decide what you're doing

确定你的使用场景

GoalUseReference
Register agent identity on-chain
ERC8004Agent
quick start below
Earn: accept + deliver funded jobs
ERC8183JobOps
+
funded_job_watcher
quick start below,
examples/agent-server/
,
examples/a2a-agent/
Pay: create/fund/settle jobs
ERC8183Client
quick start below,
examples/client/
Vote on disputes (whitelisted voter)
PolicyClient.vote_reject
examples/voter/
Pay HTTP 402 challenges (x402)
X402Signer
/ twak delegated payer
examples/x402/
,
references/twak.md
Understand internals / extend
references/architecture.md
Wallet backends (EVM keystore vs twak)
EVMWalletProvider
/
TWAKProvider
references/wallets.md
,
references/twak.md
目标使用组件参考资源
在链上注册Agent身份
ERC8004Agent
下方快速开始指南
赚取报酬:接受并交付已资助任务
ERC8183JobOps
+
funded_job_watcher
下方快速开始指南、
examples/agent-server/
examples/a2a-agent/
支付费用:创建/资助/结算任务
ERC8183Client
下方快速开始指南、
examples/client/
对争议进行投票(白名单投票者)
PolicyClient.vote_reject
examples/voter/
支付HTTP 402挑战(x402)
X402Signer
/ twak委托支付方
examples/x402/
references/twak.md
理解内部机制/扩展功能
references/architecture.md
钱包后端(EVM密钥库 vs twak)
EVMWalletProvider
/
TWAKProvider
references/wallets.md
references/twak.md

Quick start: register an agent (ERC-8004)

快速开始:注册Agent(ERC-8004)

One-time setup. Needs a private key (auto-generated if omitted) and
WALLET_PASSWORD
.
python
import os
from bnbagent import ERC8004Agent, AgentEndpoint, EVMWalletProvider

wallet = EVMWalletProvider(
    password=os.getenv("WALLET_PASSWORD"),
    private_key=os.getenv("PRIVATE_KEY"),  # only needed on first run; keystore persists to ~/.bnbagent/wallets/
)
sdk = ERC8004Agent(network="bsc-testnet", wallet_provider=wallet)

agent_uri = sdk.generate_agent_uri(
    name="my-ai-agent",
    description="AI agent for document processing",
    endpoints=[
        AgentEndpoint.a2a("https://my-agent.example.com"),                      # A2A first (discovery doc URL)
        AgentEndpoint.mcp("https://my-agent.example.com/mcp", version="2025-06-18"),  # MCP second, if served
    ],
)
result = sdk.register_agent(agent_uri=agent_uri)
一次性设置。需要私钥(若省略则自动生成)和
WALLET_PASSWORD
python
import os
from bnbagent import ERC8004Agent, AgentEndpoint, EVMWalletProvider

wallet = EVMWalletProvider(
    password=os.getenv("WALLET_PASSWORD"),
    private_key=os.getenv("PRIVATE_KEY"),  # 仅首次运行需要;密钥库将持久化到~/.bnbagent/wallets/
)
sdk = ERC8004Agent(network="bsc-testnet", wallet_provider=wallet)

agent_uri = sdk.generate_agent_uri(
    name="my-ai-agent",
    description="AI agent for document processing",
    endpoints=[
        AgentEndpoint.a2a("https://my-agent.example.com"),                      # 优先设置A2A(发现文档URL)
        AgentEndpoint.mcp("https://my-agent.example.com/mcp", version="2025-06-18"),  # 若提供MCP服务则其次设置
    ],
)
result = sdk.register_agent(agent_uri=agent_uri)

result["agentId"], result["transactionHash"]

result["agentId"], result["transactionHash"]

undefined
undefined

Quick start: provider (earn loop, headless)

快速开始:服务提供者(赚取报酬循环,无头模式)

No server needed. Watch for funded jobs, do the work, submit:
python
import asyncio
from bnbagent import EVMWalletProvider
from bnbagent.erc8183 import ERC8183JobOps, funded_job_watcher
from bnbagent.storage import LocalStorageProvider

wallet = EVMWalletProvider(password="...", private_key="0x...")
ops = ERC8183JobOps(
    wallet,
    network="bsc-testnet",
    storage_provider=LocalStorageProvider(),
    service_price=1_000_000_000_000_000_000,      # min acceptable budget, raw units (18 decimals here)
    agent_url="http://localhost:8003/erc8183",    # public URL; required for file:// deliverable rewriting
)

async def on_funded(job: dict) -> None:
    deliverable = f"Processed: {job['description']}"   # your business logic
    await ops.submit_result(job["jobId"], deliverable)

asyncio.run(funded_job_watcher(ops, on_funded, interval=30))
  • submit_result
    handles verification (FUNDED status, assignment, expiry, budget ≥ service_price), deliverable upload, manifest hashing, and the
    submit
    tx.
  • The watcher never submits or settles by itself. Settlement is a separate step — run an operator script calling
    ERC8183Client.settle(job_id)
    after the dispute window elapses (
    examples/auto_settle.py
    ,
    examples/agent-server/scripts/settle.py
    ).
  • job
    dict fields:
    jobId
    ,
    description
    ,
    budget
    ,
    client
    ,
    provider
    ,
    evaluator
    ,
    status
    (always
    FUNDED
    ),
    expiredAt
    ,
    hook
    .
  • Serving surface (A2A/MCP/HTTP) is your choice — copy-and-own references in
    examples/a2a-agent/
    (recommended) and
    examples/agent-server/
    (FastAPI).
  • Deliverable storage: placeholder URLs like
    https://example.invalid/manifest.json
    (as in
    examples/client/happy.py
    ) are chain-only demos — voters cannot verify the deliverable. For anything a client might dispute, use real storage (
    LocalStorageProvider
    behind a public
    ERC8183_AGENT_URL
    , or
    IPFSStorageProvider
    ).
无需服务器。监听已资助任务,完成工作并提交成果:
python
import asyncio
from bnbagent import EVMWalletProvider
from bnbagent.erc8183 import ERC8183JobOps, funded_job_watcher
from bnbagent.storage import LocalStorageProvider

wallet = EVMWalletProvider(password="...", private_key="0x...")
ops = ERC8183JobOps(
    wallet,
    network="bsc-testnet",
    storage_provider=LocalStorageProvider(),
    service_price=1_000_000_000_000_000_000,      # 最低可接受预算,原始单位(此处为18位小数)
    agent_url="http://localhost:8003/erc8183",    # 公共URL;重写file://交付物URL时必需
)

async def on_funded(job: dict) -> None:
    deliverable = f"Processed: {job['description']}"   # 你的业务逻辑
    await ops.submit_result(job["jobId"], deliverable)

asyncio.run(funded_job_watcher(ops, on_funded, interval=30))
  • submit_result
    会处理验证(FUNDED状态、任务分配、过期时间、预算≥service_price)、交付物上传、清单哈希计算以及
    submit
    交易。
  • 监听器不会自动提交或结算任务。结算是独立步骤——争议窗口期过后,运行调用
    ERC8183Client.settle(job_id)
    的操作员脚本(
    examples/auto_settle.py
    examples/agent-server/scripts/settle.py
    )。
  • job
    字典字段:
    jobId
    description
    budget
    client
    provider
    evaluator
    status
    (始终为
    FUNDED
    )、
    expiredAt
    hook
  • 服务接口(A2A/MCP/HTTP)可自行选择——推荐复制并定制
    examples/a2a-agent/
    (推荐)和
    examples/agent-server/
    (FastAPI)中的参考实现。
  • 交付物存储:
    https://example.invalid/manifest.json
    这类占位符URL(如
    examples/client/happy.py
    中所示)仅为链上演示——投票者无法验证交付物。对于客户可能发起争议的场景,请使用真实存储(公共
    ERC8183_AGENT_URL
    后端的
    LocalStorageProvider
    ,或
    IPFSStorageProvider
    )。

Quick start: client (create and pay for a job)

快速开始:客户(创建并支付任务)

python
import time
from bnbagent.erc8183 import ERC8183Client, JobStatus
from bnbagent.wallets import EVMWalletProvider

wallet = EVMWalletProvider(password="...", private_key="0x...")
erc8183 = ERC8183Client(wallet, network="bsc-testnet")

budget = 1 * (10 ** erc8183.token_decimals())   # DEMO-SCALE (1 full token). On MAINNET use tiny
                                                # budgets, e.g. (10 ** dec) // 100 for 0.01 U.
expired_at = int(time.time()) + 65 * 60

job_id = erc8183.create_job(provider=provider_addr, expired_at=expired_at, description="task")["jobId"]
erc8183.register_job(job_id)          # bind default policy (OptimisticPolicy)
erc8183.set_budget(job_id, budget)
erc8183.fund(job_id, budget)          # escrows; auto-approves payment token with 100-token floor
python
import time
from bnbagent.erc8183 import ERC8183Client, JobStatus
from bnbagent.wallets import EVMWalletProvider

wallet = EVMWalletProvider(password="...", private_key="0x...")
erc8183 = ERC8183Client(wallet, network="bsc-testnet")

budget = 1 * (10 ** erc8183.token_decimals())   # 演示规模(1个完整代币)。主网请使用小额预算,例如(10 ** dec) // 100表示0.01 U。
expired_at = int(time.time()) + 65 * 60

job_id = erc8183.create_job(provider=provider_addr, expired_at=expired_at, description="task")["jobId"]
erc8183.register_job(job_id)          # 绑定默认策略(OptimisticPolicy)
erc8183.set_budget(job_id, budget)
erc8183.fund(job_id, budget)          # 托管资金;自动以100代币为下限批准支付代币

... provider submits ... dispute window elapses ...

... 服务提供者提交成果 ... 争议窗口期结束 ...

erc8183.settle(job_id) # permissionless — anyone can call assert erc8183.get_job_status(job_id) == JobStatus.COMPLETED

Disputes and escape hatch:

```python
erc8183.dispute(job_id)        # client only, within dispute window after submit
erc8183.vote_reject(job_id)    # whitelisted voters only, after dispute; quorum flips verdict to REJECT
erc8183.claim_refund(job_id)   # anyone, after expiredAt if never settled — non-pausable escape hatch
fund(job_id, amount, approve_floor=None)
: default approves
max(amount, 100 * 10**decimals)
to avoid re-approving across job streams;
approve_floor=0
approves exactly
amount
; no approve is sent if allowance already covers it.
erc8183.settle(job_id) # 无权限限制——任意角色均可调用 assert erc8183.get_job_status(job_id) == JobStatus.COMPLETED

争议处理与应急方案:

```python
erc8183.dispute(job_id)        # 仅客户可在提交后争议窗口期内调用
erc8183.vote_reject(job_id)    # 仅白名单投票者可在争议发起后调用;多数票会将裁决结果改为REJECT
erc8183.claim_refund(job_id)   # 任意角色均可在expiredAt过后且未结算时调用——不可暂停的应急方案
fund(job_id, amount, approve_floor=None)
:默认批准
max(amount, 100 * 10**decimals)
以避免跨任务流重复批准;
approve_floor=0
则仅批准精确的
amount
;若当前余额已覆盖所需额度,则不会发送批准请求。

Job lifecycle

任务生命周期

OPEN ──► FUNDED ──► SUBMITTED ──┬─ silence past window ──► COMPLETED (provider paid, minus platform fee)
  │         │                   ├─ dispute + quorum reject ──► REJECTED (client refunded)
  │         │                   └─ no verdict + past expiredAt ──► EXPIRED (client claimRefund)
  │         └─ past expiredAt ──► EXPIRED (claimRefund)
  └─ client reject() before funding ──► REJECTED
OPEN ──► FUNDED ──► SUBMITTED ──┬─ 窗口期过后无异议 ──► COMPLETED(服务提供者获得报酬,扣除平台手续费)
  │         │                   ├─ 发起争议 + 多数票否决 ──► REJECTED(客户获得退款)
  │         │                   └─ 无裁决结果 + 超过expiredAt ──► EXPIRED(客户可claimRefund)
  │         └─ 超过expiredAt ──► EXPIRED(可claimRefund)
  └─ 客户在资助前调用reject() ──► REJECTED

Gas sponsorship matrix

Gas赞助矩阵

Protocol / writeBSC TestnetBSC Mainnet
ERC-8004
register_agent
✅ sponsored (MegaFuel)✅ sponsored (MegaFuel) — works with a zero-BNB wallet
ERC-8183 create/fund/submit/settle🟡 per-call: MegaFuel decides (
fund
/
settle
sponsored today); declined calls self-pay
❌ never sponsored — all writes self-pay BNB
ERC-20
approve
of payment token (sent inside
fund
when allowance short)
❌ always self-pays — fresh testnet buyer needs a little tBNB❌ self-pays
twak wallet ops❌ twak self-pays (twak-internal, SDK has no control)✅ twak auto-sponsors — see
references/twak.md
协议 / 写入操作BSC测试网BSC主网
ERC-8004
register_agent
✅ 赞助(MegaFuel)✅ 赞助(MegaFuel)——零BNB钱包也可使用
ERC-8183 create/fund/submit/settle🟡 按调用决定:MegaFuel当前赞助
fund
/
settle
;被拒绝的调用需自行支付Gas费
❌ 从不赞助——所有写入操作需自行支付BNB
ERC-20支付代币
approve
(余额不足时在
fund
内触发)
❌ 始终需自行支付——新的测试网用户需要少量tBNB❌ 需自行支付
twak钱包操作❌ twak自行支付(twak内部流程,SDK无法控制)✅ twak自动赞助——详见
references/twak.md

Networks & contracts

网络与合约

BSC Testnet (chain 97) — faucets: tBNB, U tokens
ContractAddress
Identity Registry (ERC-8004)
0x8004A818BFB912233c491871b3d84c89A494BD9e
AgenticCommerce
0xa206c0517b6371c6638cd9e4a42cc9f02a33b0de
EvaluatorRouter
0xd7d36d66d2f1b608a0f943f722d27e3744f66f25
OptimisticPolicy
0x4f4678d4439fec812ac7674bb3efb4c8f5fb78a6
BSC Mainnet (chain 56)
ContractAddress
Identity Registry (ERC-8004)
0x8004A169FB4a3325136EB29fA0ceB6D2e539a432
AgenticCommerce
0xea4daa3100a767e86fded867729ae7446476eba6
EvaluatorRouter
0x51895229e12f9876011789b04f8698af06ccd6da
OptimisticPolicy
0x9c01845705b3078aa2e8cff7520a6376fd766de5
The payment token address is NOT configurable — it is read from the Commerce kernel at runtime (
ERC8183Client.payment_token
). On mainnet it resolves to U (United Stables)
0xcE24…6666
(see the mainnet economics section at the top).
Notes:
  • The SDK constructor defaults to
    network="bsc-testnet"
    — always pass
    network="bsc-mainnet"
    explicitly (or
    NETWORK=bsc-mainnet
    ) for mainnet work, and print
    bscscan.com
    (not
    testnet.bscscan.com
    ) explorer links; some example scripts hardcode testnet URLs.
  • Discovery/indexer lag: the registry index may show a generic name (e.g.
    Agent #198565
    ) even when your URI carries the real name. The on-chain URI is the source of truth; indexer names can lag or stay generic.
BSC测试网(链ID 97) — 水龙头:tBNBU代币
合约地址
身份注册表(ERC-8004)
0x8004A818BFB912233c491871b3d84c89A494BD9e
AgenticCommerce
0xa206c0517b6371c6638cd9e4a42cc9f02a33b0de
EvaluatorRouter
0xd7d36d66d2f1b608a0f943f722d27e3744f66f25
OptimisticPolicy
0x4f4678d4439fec812ac7674bb3efb4c8f5fb78a6
BSC主网(链ID 56)
合约地址
身份注册表(ERC-8004)
0x8004A169FB4a3325136EB29fA0ceB6D2e539a432
AgenticCommerce
0xea4daa3100a767e86fded867729ae7446476eba6
EvaluatorRouter
0x51895229e12f9876011789b04f8698af06ccd6da
OptimisticPolicy
0x9c01845705b3078aa2e8cff7520a6376fd766de5
支付代币地址不可配置——会在运行时从商业核心合约读取(
ERC8183Client.payment_token
)。主网支付代币为U(United Stables)
0xcE24…6666
(详见顶部主网经济规则部分)。
注意事项:
  • SDK构造函数默认
    network="bsc-testnet"
    ——主网工作时请显式传递
    network="bsc-mainnet"
    (或设置
    NETWORK=bsc-mainnet
    ),并打印
    bscscan.com
    (而非
    testnet.bscscan.com
    )浏览器链接;部分示例脚本硬编码了测试网URL。
  • 发现/索引器延迟:即使你的URI包含真实名称,注册表索引可能仍显示通用名称(例如
    Agent #198565
    )。链上URI为可信数据源;索引器名称可能存在延迟或保持通用。

Environment variables

环境变量

Full annotated reference:
references/env.example
. The essentials:
VariableRequiredNotes
WALLET_PASSWORD
YesEncrypts/decrypts the keystore at
~/.bnbagent/wallets/
.
PRIVATE_KEY
First run onlyImported and encrypted, then removable. Auto-generates a wallet if absent.
WALLET_ADDRESS
NoPick a keystore when several exist.
NETWORK
No (
bsc-testnet
)
Or
bsc-mainnet
.
RPC_URL
NoCustom RPC endpoint.
ERC8183_SERVICE_PRICE
No (
1e18
)
Provider's minimum budget, raw units.
ERC8183_AGENT_URL
If LocalStorageProviderPublic base URL incl.
/erc8183
;
file://
deliverable URLs get rewritten to it.
STORAGE_API_KEY
If IPFSStorageProviderPinata-compatible JWT.
STORAGE_LOCAL_PATH
No (
.agent-data
)
Local deliverable dir.
Storage backend is chosen in code (pass
storage_provider=
), not by env var.
完整带注释的参考:
references/env.example
。核心变量:
变量是否必填说明
WALLET_PASSWORD
加密/解密
~/.bnbagent/wallets/
下的密钥库。
PRIVATE_KEY
仅首次运行导入并加密后即可移除。若未提供则自动生成钱包。
WALLET_ADDRESS
存在多个钱包时指定使用的密钥库。
NETWORK
否(默认
bsc-testnet
可选
bsc-mainnet
RPC_URL
自定义RPC端点。
ERC8183_SERVICE_PRICE
否(默认
1e18
服务提供者的最低预算,原始单位。
ERC8183_AGENT_URL
使用LocalStorageProvider时必填包含
/erc8183
的公共基础URL;
file://
交付物URL会被重写为此地址。
STORAGE_API_KEY
使用IPFSStorageProvider时必填兼容Pinata的JWT。
STORAGE_LOCAL_PATH
否(默认
.agent-data
本地交付物存储目录。
存储后端通过代码指定(传递
storage_provider=
参数),而非环境变量。

Security rules (important for agent flows)

安全规则(Agent流程关键注意事项)

  • EIP-712 signing is policy-gated by default.
    EVMWalletProvider.sign_typed_data
    only accepts EIP-3009
    TransferWithAuthorization
    /
    ReceiveWithAuthorization
    against U-token on BSC 56/97. EIP-2612
    Permit
    and Permit2
    PermitSingle
    /
    PermitBatch
    are denylisted unconditionally (they grant unbounded allowances — a malicious 402 server could drain the wallet). Never try to bypass this in agent-reachable code;
    SigningPolicy.permissive()
    and
    _DANGEROUS_sign_typed_data_no_policy()
    are tests-only.
  • Never hand tool functions a raw
    WalletProvider
    .
    Give them a scoped
    X402Signer(wallet, max_value_per_call={token: ...}, session_budget={token: ...})
    and always pass
    expected_to
    from config/on-chain registry — never from the 402 challenge body.
  • Custom tokens/types:
    SigningPolicy.strict_default().extend(domain_allowlist={(chain_id, contract)}, primary_type_allowlist={"MyType"})
    — the Permit denylist still wins.
  • claimRefund
    is non-pausable and non-hookable: funds are always recoverable past
    expiredAt
    .
  • Throwaway/demo keys: use
    EVMWalletProvider(persist=False)
    so one-off keys never touch disk, and never reuse demo keys in production. Never paste production private keys into chat/logs — prefer the keystore +
    WALLET_PASSWORD
    flow.
Full rationale, decision tree, and examples:
references/sdk-readme.md
(Security section) and
examples/security/e2e.py
.
  • EIP-712签名默认受策略限制
    EVMWalletProvider.sign_typed_data
    仅接受BSC 56/97链上U代币的EIP-3009
    TransferWithAuthorization
    /
    ReceiveWithAuthorization
    签名。EIP-2612
    Permit
    和Permit2
    PermitSingle
    /
    PermitBatch
    无条件列入黑名单(它们授予无限制额度——恶意402服务器可能掏空钱包)。切勿在Agent可访问的代码中尝试绕过此限制;
    SigningPolicy.permissive()
    _DANGEROUS_sign_typed_data_no_policy()
    仅用于测试。
  • 切勿向工具函数传递原始
    WalletProvider
    。应提供限定范围的
    X402Signer(wallet, max_value_per_call={token: ...}, session_budget={token: ...})
    ,且始终从配置/链上注册表传递
    expected_to
    ——绝不要从402挑战体中获取。
  • 自定义代币/类型:
    SigningPolicy.strict_default().extend(domain_allowlist={(chain_id, contract)}, primary_type_allowlist={"MyType"})
    ——Permit黑名单仍优先生效。
  • claimRefund
    不可暂停且无钩子:超过
    expiredAt
    后资金始终可追回。
  • 一次性/演示密钥:使用
    EVMWalletProvider(persist=False)
    ,使一次性密钥永不写入磁盘,且切勿在生产环境中复用演示密钥。切勿将生产环境私钥粘贴到聊天/日志中——优先使用密钥库+
    WALLET_PASSWORD
    流程。
完整原理、决策树及示例:
references/sdk-readme.md
(安全章节)和
examples/security/e2e.py

Wallet backends

钱包后端

  • EVMWalletProvider
    (default) — Keystore V3 (MetaMask/Geth compatible), persistent at
    ~/.bnbagent/wallets/
    or in-memory with
    persist=False
    .
  • TWAKProvider
    (Trust Wallet Agent Kit) — self-custody, self-broadcasting; no raw-tx or generic EIP-712 signing; BSC only; x402 via delegated payer
    make_x402_payer()
    . Read
    references/twak.md
    before using
    — unsupported calls raise
    UnsupportedWalletOperation
    . Swap:
    TWAKProvider(chain="bsc")
    or
    WALLET_KIND=twak
    .
  • Custom (HSM, MPC, KMS): subclass
    WalletProvider
    . Details:
    references/wallets.md
    .
  • EVMWalletProvider
    (默认)——Keystore V3(兼容MetaMask/Geth),持久化存储在
    ~/.bnbagent/wallets/
    ,或通过
    persist=False
    实现内存存储。
  • TWAKProvider
    (Trust Wallet Agent Kit)——自托管、自广播;不支持原始交易或通用EIP-712签名;仅支持BSC链;通过委托支付方
    make_x402_payer()
    实现x402。使用前请阅读
    references/twak.md
    ——不支持的调用会抛出
    UnsupportedWalletOperation
    。切换方式:
    TWAKProvider(chain="bsc")
    或设置
    WALLET_KIND=twak
  • 自定义后端(HSM、MPC、KMS):继承
    WalletProvider
    类。详情:
    references/wallets.md

AA / self-broadcast wallets (Privy, ZeroDev, etc.) — known integration tax

AA / 自广播钱包(Privy、ZeroDev等)——已知集成限制

Account-abstraction wallets that submit Intents/UserOperations instead of raw signed transactions are not first-class in the SDK yet (field-tested on BSC mainnet with a Privy AA client,
bnbagent==0.4.0
). What to expect and the workarounds that worked:
  • ERC-20
    approve
    fails
    :
    approve_payment_token
    goes through
    _send_tx
    → raw
    sign_transaction
    , which AA wallets don't implement (
    sign.transaction: wallet does not implement raw-transaction signing
    ). Workaround: do the
    approve(commerce, amount)
    on the payment token manually through your AA stack, then call
    fund
    with
    fund_bundles_approval=True
    .
    create_job
    /
    set_budget
    /
    fund
    themselves work through a custom Intent executor (subclass the executor /
    WalletProvider
    ).
  • jobId
    comes back
    None
    after
    create_job
    : AA wallets return a
    user_operation_hash
    , not a tx hash, and
    create_job
    only parses
    jobId
    from receipt logs. Workaround: wait for inclusion, then scan
    jobCounter
    backwards (or index recent jobs by
    client
    +
    provider
    +
    description
    ) to find your job.
  • For a documented self-broadcasting wallet, use
    TWAKProvider
    (
    references/twak.md
    ); Privy-style adapters are currently build-your-own.
提交Intents/UserOperations而非原始签名交易的账户抽象钱包目前并非SDK一等公民(已在BSC主网使用Privy AA客户端、
bnbagent==0.4.0
进行实地测试)。预期问题及可行解决方案:
  • ERC-20
    approve
    失败
    approve_payment_token
    通过
    _send_tx
    调用原始
    sign_transaction
    ,而AA钱包未实现该方法(报错
    sign.transaction: wallet does not implement raw-transaction signing
    )。解决方案:通过你的AA栈手动对支付代币执行
    approve(commerce, amount)
    ,然后调用
    fund
    并设置
    fund_bundles_approval=True
    create_job
    /
    set_budget
    /
    fund
    本身可通过自定义Intent执行器(继承执行器/
    WalletProvider
    )实现。
  • create_job
    jobId
    返回
    None
    :AA钱包返回
    user_operation_hash
    而非交易哈希,而
    create_job
    仅从收据日志解析
    jobId
    。解决方案:等待交易上链,然后反向扫描
    jobCounter
    (或按
    client
    +
    provider
    +
    description
    索引近期任务)找到你的任务。
  • 如需文档化的自广播钱包,请使用
    TWAKProvider
    references/twak.md
    );Privy风格的适配器目前需自行构建。

Troubleshooting

故障排除

ErrorCause → Fix
No PRIVATE_KEY and no keystore found
New wallet auto-generated, or set
PRIVATE_KEY
to import.
Multiple wallets found
Set
WALLET_ADDRESS=0x...
.
403 Provider mismatch
Job assigned to a different provider — check
job.provider
.
409 Not FUNDED
Job already submitted/settled.
408 Job expired
Past
expiredAt
; client can
claimRefund
, create a new job.
402 Budget below service price
Client must fund ≥
ERC8183_SERVICE_PRICE
.
settle
reverts
policy pending
Dispute window not elapsed and no dispute — wait, then retry. On mainnet the window is 7 days.
voteReject
reverts
not voter
/
not disputed
Caller not whitelisted or no dispute — use
examples/voter/vote_reject.py
.
Revert selector
0xcdbc1d27
on
register_job
Job already bound to a policy — re-registering reverts by design. Treat as success if
job_policy(job_id)
is already set.
sign.transaction: wallet does not implement raw-transaction signing
AA/self-broadcast wallet hit the raw-tx
approve
path — see AA wallet section above.
jobId
is
None
after
create_job
AA wallet returned a user-op hash, no receipt to parse — scan
jobCounter
backwards for your job.
Allowance stays 0 after
fund
attempt
The bundled
approve
never landed (wrong wallet path) — manually
approve(commerce, amount)
, then
fund
.
错误原因 → 修复方案
No PRIVATE_KEY and no keystore found
自动生成了新钱包,或设置
PRIVATE_KEY
导入已有钱包。
Multiple wallets found
设置
WALLET_ADDRESS=0x...
指定钱包。
403 Provider mismatch
任务分配给了其他服务提供者——检查
job.provider
409 Not FUNDED
任务已提交/结算。
408 Job expired
已超过
expiredAt
;客户可
claimRefund
并创建新任务。
402 Budget below service price
客户必须资助≥
ERC8183_SERVICE_PRICE
的金额。
settle
返回
policy pending
争议窗口期未结束且无争议——等待后重试。主网窗口期为7天
voteReject
返回
not voter
/
not disputed
调用者不在白名单中或无争议——使用
examples/voter/vote_reject.py
register_job
返回回滚选择器
0xcdbc1d27
任务已绑定策略——重新注册会按设计回滚。若
job_policy(job_id)
已设置,则视为成功。
sign.transaction: wallet does not implement raw-transaction signing
AA/自广播钱包触发了原始交易
approve
流程——详见上方AA钱包章节。
create_job
jobId
None
AA钱包返回用户操作哈希,无收据可解析——反向扫描
jobCounter
找到你的任务。
fund
尝试后余额仍为0
绑定的
approve
未生效(钱包路径错误)——手动执行
approve(commerce, amount)
,然后调用
fund

Files in this skill

本技能包含的文件

  • references/sdk-readme.md
    — full upstream SDK README (deep detail on everything above)
  • references/architecture.md
    — code map, layering, invariants
  • references/twak.md
    — TWAK wallet support matrix and boundaries
  • references/wallets.md
    — wallet provider deep dive
  • references/env.example
    — annotated env var reference
  • examples/
    — copy-and-own scripts:
    client/
    (5 canonical job flows),
    a2a-agent/
    ,
    agent-server/
    ,
    voter/
    ,
    twak/
    ,
    x402/
    ,
    security/
    ,
    auto_settle.py
  • references/sdk-readme.md
    — 完整的上游SDK README(包含上述所有内容的详细说明)
  • references/architecture.md
    — 代码映射、分层结构、不变量
  • references/twak.md
    — TWAK钱包支持矩阵及边界
  • references/wallets.md
    — 钱包提供者深度解析
  • references/env.example
    — 带注释的环境变量参考
  • examples/
    — 可复制使用的脚本:
    client/
    (5种标准任务流程)、
    a2a-agent/
    agent-server/
    voter/
    twak/
    x402/
    security/
    auto_settle.py