BNB Agent
Buy an OptimAI Search result through the ERC-8183 provider on BSC mainnet.
BNB Agent is an escrowed onchain payment flow. It is separate from the HTTP API: the buyer creates and funds an ERC-8183 job, the provider runs OptimAI Search, and the buyer verifies the public deliverable before settlement.
Before you start
- Use a dedicated buyer wallet. Never use the provider wallet as the buyer.
- Fund the wallet with BNB for BSC transaction gas and U for the job budget.
- Keep the buyer private key out of source code, committed
.envfiles, logs, prompts, and support chats. - Use a hardware wallet or encrypted keystore for real mainnet use.
Mainnet warning: this guide creates real BSC transactions. Verify every network, address, policy, provider, and budget value before signing.
Provider details
| Item | Value |
|---|---|
| Network | BSC mainnet, chain ID 56 |
| Provider wallet | 0x0936686CBaF6fF410AFE042B297D299afB46bfb0 |
| Commerce contract | 0xea4daa3100a767e86fded867729ae7446476eba6 |
| Evaluator router | 0x51895229e12f9876011789b04f8698af06ccd6da |
| Optimistic policy | 0x9c01845705b3078aa2e8cff7520a6376fd766de5 |
| Payment token | U: 0xcE24439F2D9C6a2289F741120FE202248B666666 |
| Minimum budget | 0.001 U (1000000000000000 base units) |
U has 18 decimals. The budget is held in ERC-8183 escrow; it is not sent directly to the provider when the job is funded.
Install the client
Install the current BNBAgent client SDK in an isolated environment:
python -m venv .venv
. .venv/bin/activate
pip install bnbagent requestsCreate and fund a job
The following example shows the ERC-8183 lifecycle. It uses a simple private key signer only to make the example readable. Replace it with your wallet or keystore integration in production.
import json
import os
import time
from bnbagent.erc8183 import ERC8183Client
from bnbagent.wallets import EVMWalletProvider
PROVIDER = "0x0936686CBaF6fF410AFE042B297D299afB46bfb0"
COMMERCE = "0xea4daa3100a767e86fded867729ae7446476eba6"
ROUTER = "0x51895229e12f9876011789b04f8698af06ccd6da"
POLICY = "0x9c01845705b3078aa2e8cff7520a6376fd766de5"
BUDGET = 1_000_000_000_000_000 # 0.001 U
wallet = EVMWalletProvider(
password=os.environ["WALLET_PASSWORD"],
private_key=os.environ["PRIVATE_KEY"], # Demo only: do not commit this.
)
client = ERC8183Client(wallet, network="bsc-mainnet")
# Refuse to sign if the SDK's current BSC preset differs from this provider.
assert client.commerce.address.lower() == COMMERCE.lower()
assert client.router.address.lower() == ROUTER.lower()
assert client.policy.address.lower() == POLICY.lower()
description = json.dumps(
{
"task": "optimai_search",
"query": "What is OptimAI Search? Give a concise answer.",
"options": {"timeout_seconds": 60},
},
separators=(",", ":"),
)
# The job must remain open beyond the policy dispute window plus a buffer.
expires_at = int(time.time()) + client.policy.dispute_window() + 86_400
created = client.create_job(
provider=PROVIDER,
expired_at=expires_at,
description=description,
)
job_id = created["jobId"]
client.register_job(job_id, policy=POLICY)
client.set_budget(job_id, BUDGET)
# Use an exact approval for a one-job test. The default SDK floor can approve
# a larger reusable allowance for convenience.
client.fund(job_id, BUDGET, approve_floor=0)
print(f"Funded job: {job_id}")The transaction sequence is:
- Create the job with the provider, expiry, and search description.
- Register the OptimisticPolicy.
- Set a budget of at least
0.001U. - Approve the exact U amount for a one-job smoke test when needed.
- Fund the job. Funding locks U in escrow and lets the provider begin work.
Every write consumes BNB gas. Set the expiry beyond the live dispute window with a safe buffer.
Describe the search
Use a clear query with a timeframe, market, company, or domain when it matters. The provider accepts a structured description such as:
{
"task": "optimai_search",
"query": "Analyze the latest OptimAI ecosystem and crypto market news",
"options": {
"timeout_seconds": 60
}
}query is required and accepts up to 1,000 characters. timeout_seconds is
optional and must be between 10 and 300. A plain-text description also works
and is treated as the search query. min_sources is a rejection threshold,
not a guarantee: if the completed Search has fewer citations than requested,
the provider does not submit a successful ERC-8183 deliverable. The job then
remains subject to ERC-8183 expiry/refund or dispute handling. Do not set
min_sources for the first smoke test: a valid search can have zero citations.
Do not put credentials or confidential information in the job description.
Retrieve the result
After the provider submits a result, retrieve the public manifest by job ID:
curl --fail-with-body \
https://bnbagent.optimai.network/erc8183/job/{job_id}/responseThe provider also exposes GET /erc8183/health. Read the job status, budget,
and escrow state onchain with the ERC-8183 client or a BSC explorer.
Provider route surface
The provider application defines these routes:
| Route | Intended use |
|---|---|
GET /erc8183/job/{job_id}/response | Buyer-facing public deliverable. |
GET /erc8183/job/{job_id}/verify | Check the deliverable hash when the route is exposed. |
GET /erc8183/job/{job_id} | Provider/operator job inspection. |
GET /erc8183/health | Liveness check. |
GET /erc8183/ready | Readiness check for funded-job discovery. |
GET /erc8183/status | Provider configuration and service status. |
POST /erc8183/negotiate | Provider negotiation protocol; normally operator/integration traffic. |
A reverse proxy or hosted deployment may intentionally publish only the public response and health routes. Do not assume every route is internet-facing; the on-chain ERC-8183 job state remains authoritative for escrow and settlement.
Results are public: anyone can retrieve a V1 result. Never include private queries, credentials, or other secrets in the job description.
Verify the deliverable
ERC-8183 stores the Keccak-256 hash of the canonical manifest onchain. Remove
the transport-only success field, serialize the remaining object with sorted
keys and compact separators, and compare its hash with job.deliverable:
import json
import requests
from web3 import Web3
payload = requests.get(
f"https://bnbagent.optimai.network/erc8183/job/{job_id}/response",
timeout=30,
).json()
payload.pop("success", None)
canonical = json.dumps(payload, sort_keys=True, separators=(",", ":"))
manifest_hash = Web3.keccak(text=canonical).hex()
job = client.get_job(job_id)
assert manifest_hash.lower() == Web3.to_hex(job.deliverable).lower()Settlement and disputes
After submission, payment remains in escrow during the OptimisticPolicy dispute window. A buyer may dispute during that period. If there is no valid rejection, settle only after the window ends:
client.settle(job_id)Read the policy's live dispute_window and the job's submitted_at before
settling. Do not settle immediately after receiving the manifest.
Support checklist
When reporting a problem, share only public information:
- Job ID
- BSC transaction hashes
- Buyer public address
- Public job status or error message
Never share a seed phrase, private key, wallet password, or internal OptimAI API key.