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 .env files, 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

ItemValue
NetworkBSC mainnet, chain ID 56
Provider wallet0x0936686CBaF6fF410AFE042B297D299afB46bfb0
Commerce contract0xea4daa3100a767e86fded867729ae7446476eba6
Evaluator router0x51895229e12f9876011789b04f8698af06ccd6da
Optimistic policy0x9c01845705b3078aa2e8cff7520a6376fd766de5
Payment tokenU: 0xcE24439F2D9C6a2289F741120FE202248B666666
Minimum budget0.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 requests

Create 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:

  1. Create the job with the provider, expiry, and search description.
  2. Register the OptimisticPolicy.
  3. Set a budget of at least 0.001 U.
  4. Approve the exact U amount for a one-job smoke test when needed.
  5. 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.

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}/response

The 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:

RouteIntended use
GET /erc8183/job/{job_id}/responseBuyer-facing public deliverable.
GET /erc8183/job/{job_id}/verifyCheck the deliverable hash when the route is exposed.
GET /erc8183/job/{job_id}Provider/operator job inspection.
GET /erc8183/healthLiveness check.
GET /erc8183/readyReadiness check for funded-job discovery.
GET /erc8183/statusProvider configuration and service status.
POST /erc8183/negotiateProvider 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.