You sign once. The agent runs for a week. You can kill it with one button.
An autonomous AI trading team on BNB Smart Chain β funding carry + DEX momentum + mean-reversion, gated by a single EIP-191-signed policy.
Built for the BNB HACK 2026 (CoinMarketCap Γ Trust Wallet Γ BNB Chain β $36K prize pool).
By Blaze Β· MIT License
Real-time market data via x402 microcharges at $0.01 USDC per call (EIP-3009 transferWithAuthorization on Base). 3-tier selector β CMC Pro β x402 β Binance fallback β switchable from the dashboard Config pane. Daily cap with an amber banner at 80%.
- Visible evidence: live CMC ledger on the dashboard, every cost line deep-linked to BaseScan.
Self-custody local signing. AES-256-GCM keystore + PBKDF2 200k iters at ~/.twak/wallet.json. Every BSC transaction is signed locally β keys never leave the host.
- Visible evidence: live TWAK-signed tx list on the dashboard with BscScan deep links.
BSC mainnet, PancakeSwap v3 swaps, plus two on-chain standards:
- ERC-8004 identity NFT β agent wallet, tokenId, IPFS metadata, traits.
- ERC-8183 job escrow β PnL deliverables as jobs (Open β Funded β Submitted β Completed).
- Visible evidence: live identity panel + jobs lifecycle on the dashboard.
| Sleeve | Capital | Strategy | Target |
|---|---|---|---|
| A β Funding carry | 70% | Long spot + short perp on PCS v3 | Ξ-neutral, ~+0.5% APR |
| B β DEX momentum | 20% | CMC volume-spike + 4h breakout | Capped at 1% per trade |
| C β Mean reversion | 10% | Fades 1h drops >2.0Ο | Capped at 0.5% per trade |
- 5% daily loss circuit breaker (vs 30% contest disqualification = 6Γ safer)
- 1% per-trade risk cap Β· 2Γ max leverage Β· 15% max single position
- 3-layer LLM safety team (advisor + reviewer + chat) β they can only tighten your policy, never loosen it
- Kill switch in the right rail β halts all new orders instantly
- 149 BEP-20 eligible tokens pinned to the BNB HACK Track 1 list
- You sign once. The agent runs for a week. You can kill it with one button.
bash install.sh # creates venv, installs deps, signs a dev policy
bash bnbagent # starts agent + dashboard on http://localhost:8000BNB Agent is an autonomous BSC trading agent plus a 3-layer LLM agent team (advisor / reviewer / chat) plus a Token Module (deploy + landing-page generator) plus a Skills registry plus an MCP server exposing all of the above to other agents.
It runs three strategies in parallel on BNB Smart Chain, pays for its own market data with USDC via x402, signs its own transactions with Trust Wallet's Agent Kit (TWAK), registers its own identity NFT via ERC-8004, and escrows its own PnL deliverables via ERC-8183 jobs β all gated by a single user-signed policy.
- Quick start
- What it does
- Architecture
- The 3-LLM agent team
- Sponsor integration
- Token Module
- Skills registry
- MCP server
- Risk engine
- Dashboard
- Configuration
- Environment variables
- Repository layout
- Documentation
- Testing
- Security model
- Deployment
- Contributing
- License
git clone <your-private-repo> bnbagent && cd bnbagent
bash install.sh # one command β venv, deps, signed dev policy
export OPENROUTER_API_KEY=sk-or-... # any one of 5 supported providers (optional)
bash bnbagent # agent + dashboard on http://localhost:8000That's it. The dashboard auto-loads; first-time users land in the Setup wizard (Network β Wallet β Sign Policy β Data source β Ready). After the wizard, the dashboard switches to the Live pane. The Setup wizard has a new 'Data source' step (CMC Pro / x402 / Binance).
v2.1.1: the wizard writes your choices to config/local.yaml (gitignored), not the tracked config/config.yaml. The shipped defaults file stays clean; your CMC Pro API key and custom RPCs never accidentally land in a commit. See core/config_paths.py for the merge semantics.
v2.1.2: every runtime write lands in a gitignored file. The operator-signed config/policy.yaml, the Token Module's agents/token_module.yaml, and the TWAK keystore at ~/.twak/ are all gitignored. The repo state is reproducible from git clone β the only thing that varies between operators is the local.yaml shadow and the runtime state in ~/.bnbagent/. The contract is pinned by tests/unit/test_repo_cleanliness.py (36 tests).
v2.1.3: dashboard UI gaps closed. The Config pane now has an LLM API key section (Set + Test buttons, writes to .env, restart-to-apply) and a Personas section listing all 4 personas (View / Edit / Reset). The Token Module has inline name + symbol form fields (replacing the old window.prompt() dialogs) plus a prominent network notice (green for testnet, red for mainnet) that updates when you change the dropdown.
v2.1.4: BNB HACK 2026 compliance. The contest page publishes a fixed 149-BEP-20 eligible list, requires on-chain registration before June 22, and demands 1 trade/day for 7 days. This release pins the eligible list (data/eligible_tokens.json), filters every trade universe against it (sleeves + risk engine), wraps npx twak compete register as a script + MCP tool + dashboard button, and adds a daily trade floor that fires a 0.1%-of-equity rebalance at 23:30 UTC if no sleeve traded that day. 47 new tests, full audit at docs/compliance.md.
v2.1.5: test infra + Sharpe annualization fix. Two cleanups ahead of submission. (1) tests/conftest.py now auto-generates a dev-signed config/policy.yaml (via policy.policy_sign --dev) if the file is missing at the start of a test session, and cleans it up afterward. This is a belt-and-suspenders for the canonical bash install.sh path β fresh clones and CI can run pytest directly without manually copying the example. (2) Backtest Sharpe / Sortino were annualized with the default 365*24*60 (minute samples) even though the replay equity curve has only ~200 points across 7 days (~36k samples/year, not 525k). The previous replay_bull.json Sharpe of 41 was real arithmetic, just annualizing the wrong sample frequency β Sharpe now reflects the actual sample count and is reported in the JSON's samples_per_year field for transparency. The same fix is applied to core/portfolio.py:sharpe() (the live-path version) which now accepts an explicit samples_per_year parameter.
| Command | What it does |
|---|---|
bash bnbagent |
start the agent + dashboard, Ctrl+C stops both |
bash bnbagent --replay |
run a 7-day synthetic replay; HTML report at data/reports/replay.html |
bash bnbagent --repl |
open a Python REPL with p = boot(...) pre-loaded |
bash scripts/mcp_serve.sh |
opt-in β run the MCP server (stdio, for Claude Code / Goose) as a separate process |
bash scripts/mcp_serve_sse.sh |
opt-in β run the MCP server (SSE, port 8765) for remote agents |
Reproducibility / judges: the backtest table in
docs/demo-script.mdis generated bypython -m scripts.run_both_regimes(3 regimes Γ 2 tape intervals,equity=1000).bash bnbagent --replayruns a single 7-day synthetic regime with the defaultequity=100β useful as a quick smoke test, but its numbers won't match the table (different position sizing β different trade count β different Sharpe). To audit the math, open the JSON indata/reports/and check thesamples_per_yearfield β that's the actual annualization denominator (v2.1.5: was hardcoded to 525,600, now computed from the tape duration / equity-curve length).
Requires Python 3.10+ and (optionally) Node 18+ for the TWAK CLI fallback. The dashboard works offline; the only required network access is to BSC RPCs and (if LLM is enabled) to your LLM provider.
| Sleeve | Capital | Strategy | Expected PnL | Drawdown |
|---|---|---|---|---|
| A β Funding carry | 70% | Long spot on PancakeSwap v3 + short perp on a BSC venue. Delta-neutral. Collects funding every 8h. | +0.5% APR baseline | very low |
| B β DEX momentum | 20% | CMC signals (volume spike + 4h breakout) β 1β4h long with ATR stop and 3% TP. Quarter-Kelly sizing. | positive alpha | capped at 1%/trade |
| C β Mean reversion | 10% | Fades 1h drops >2.5Ο on top-20 BSC tokens. 2% stop, 1% target. | positive alpha | capped at 0.5%/trade |
70% of capital is hedged (delta-neutral carry), with a 5% daily circuit breaker + 1% per-trade cap + 2Γ leverage cap. The agent is designed for low drawdown β see data/reports/replay_{bull,bear,chop}.json for the honest backtest (max DD < 2% in all three synthetic regimes).
- Daily loss circuit breaker: 3%
- Per-trade risk cap: 1%
- Max gross leverage: 2Γ
- Max single position: 15%
- Curated token allowlist (top-50 CMC + vetted BSC DEX list)
- Per-symbol post-loss cool-off (4h for momentum, 6h for mean-rev) to prevent revenge trades
- Signed User Policy β
policy.yamlis the only file the user signs (EIP-191). Every order is checked against it viacircuit_breaker_check()before going on-chain. - Dashboard kill switch β halts all new orders, leaves open positions to TP/stop themselves
A 10-item trading-logic audit pass before the live window, all fixes applied. See docs/audit-2026-06-05.md.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β USER signs policy.yaml ONCE (EIP-191) β
ββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BNB AGENT (Python, asyncio) β
β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ ββββββββββββββββββββββ β
β β Sleeve A β β Sleeve B β β Sleeve C β β AI Agent Team β β
β β 70% carry β β 20% momentumβ β 10% meanrev β β (3 LLM layers) β β
β ββββββββ¬βββββββ ββββββββ¬βββββββ ββββββββ¬βββββββ βββββββββββ¬βββββββββββ β
β βββββββββββββββββββΌβββββββββββββββββββ β β
β βΌ β β
β ββββββββββββββββββββββββββββββββββββββββ βββββββββΌβββββββββ β
β β core/risk.py β β Advisor β β
β β circuit_breaker_check() β β (5-min loop, β β
β β + Agent.review_trade() L2 β β can only β β
β ββββββββββββββββ¬ββββββββββββββββββββββββ β TIGHTEN) β β
β β ββββββββββββββββββ€ β
β ββββββββββββββββΌββββββββββββββββββββββββ β Reviewer β β
β β core/portfolio.py β β (per-trade, β β
β β equity, peak, PnL, DD β β can only β β
β ββββββββββββββββ¬ββββββββββββββββββββββββ β VETO) β β
β β ββββββββββββββββββ€ β
β β ββββββββββββββββββββ β Chat β β
β β β Token Module ββββββ€ (conversationalβ β
β β β + Token Website β β + 9 tools) β β
β β ββββββββββββββββββββ ββββββββββββββββββ β
β β ββββββββββββββββββ β
β β β Skills Reg. β β
β β β (6 built-ins) β β
β β ββββββββββββββββββ β
ββββββ¬ββββββββββββββββββββ¬ββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β β β
ββββββΌββββββββββ ββββββββΌβββββββ βββββββββββΌβββββββββ ββββββββββββββββββββ
β CoinMarketCapβ β Trust β β BNB AI Agent β β Agent MCP β
β Agent Hub β β Wallet β β SDK (bnbagent- β β Server β
β Data API + β β Agent Kit β β sdk) β β (stdio + SSE) β
β x402 ($0.01)β β (TWAK) β β BSC + PCS v3 β β 11 MCP tools β
β + Skills β β AES-256- β β + perps β β for other agents β
β β β GCM β β + ERC-8004 β β (Claude Code, β
β β β + PBKDF2 β β + ERC-8183 β β Goose, Cursor) β
ββββββββββββββββ βββββββββββββββ ββββββββββββββββββββ ββββββββββββββββββββ
The 3 sponsor layers are deeply integrated:
| Layer | Sponsor | What BNB Agent uses it for | Visible evidence |
|---|---|---|---|
| L1 | CoinMarketCap Agent Hub | Data API + Data MCP + Skills + x402 ($0.01 USDC/request via EIP-3009 transferWithAuthorization) |
Live x402 microcharge ledger on the dashboard, every cost line, BscScan-deep-linked |
| L2 | Trust Wallet Agent Kit (TWAK) | Self-custody local signing, AES-256-GCM keystore, PBKDF2 200k iters, at ~/.twak/wallet.json |
Live TWAK-signed tx list with BscScan deep links; "keys never left the host" |
| L3 | BNB AI Agent SDK | BSC mainnet, PancakeSwap v3, BSC perps, ERC-8004 identity NFT, ERC-8183 job escrow, x402 finality <200ms | Live identity panel (tokenId + IPFS metadata + 8004scan link) and jobs lifecycle (Open β Funded β Submitted β Completed) |
BNB Agent runs an LLM in three distinct roles. Each is strictly constrained so the LLM is pure additive value on top of the deterministic trading engine.
| Layer | Role | Loop | Can do | Cannot do |
|---|---|---|---|---|
| 1 β Advisor | Recommends TIGHTENING risk changes based on recent state | every 5 min | Lower risk caps, disable sleeves, all in core.control.write_control (same audit path as dashboard) |
Loosen any cap, raise per-trade risk, enable a disabled sleeve |
| 2 β Reviewer | Vetoes a trade before it goes on-chain | per-trade, 0.5s timeout | Veto, falls back to heuristic in <1ms | Raise risk, override circuit-breaker, bypass the policy |
| 3 β Chat | Conversational interface for the operator | on user input | Read state, dispatch 9 tools, recommend policy changes | Apply any policy change β user must re-sign in Setup wizard |
Hard safety envelope (all enforced in code, never delegated to the LLM):
- The advisor's
_apply()comparesnew < oldfor every numeric cap. Even a hostile LLM cannot raise a cap. - The reviewer's
_heuristic_vetoalways runs after the LLM and checks: sleeve drawdown > 50% of cap, win-rate < 20%, post-loss cooldown active. - The chat's
recommend_risk_changereturns a recommendation and a UI prompt to the Setup wizard β it never writes to the policy or the control file.
agents/providers.yaml (5 adapters, no third-party SDKs):
default: openrouter
providers:
anthropic: { base: https://api.anthropic.com, key: $ANTHROPIC_API_KEY }
openai: { base: https://api.openai.com, key: $OPENAI_API_KEY }
openrouter: { base: https://openrouter.ai/api, key: $OPENROUTER_API_KEY }
oai_compat: { base: $OAI_BASE, key: $OAI_KEY }
local: { base: $LOCAL_LLM_BASE, key: "" } # llama.cpp / ollama
agents:
advisor: { provider: openrouter, model: anthropic/claude-3.5-haiku, max_tokens: 512, temperature: 0.1 }
reviewer: { provider: openrouter, model: anthropic/claude-3.5-haiku, max_tokens: 256, temperature: 0.0 }
chat: { provider: openrouter, model: anthropic/claude-3.5-sonnet, max_tokens: 2048, temperature: 0.4 }
token_module: { provider: openrouter, model: anthropic/claude-3.5-haiku, max_tokens: 8000, temperature: 0.7 }All 4 agents can use different providers. The agent still runs as a deterministic bot if no provider is configured.
4 personas in markdown under agents/_pro_defaults/:
advisor.mdβ strict tightening-only personareviewer.mdβ strict veto-in-doubt personachat.mdβ operator-facing persona with the 9-tool listtoken_module.mdβ token deploy + website generation
Each persona is editable from the dashboard (Chat pane β "view persona" β edit β "save") and resettable to the pro default ("reset to pro"). The dashboard shows a "diverged" warning when the user-edited copy drifts from the pro default.
Full details: docs/agents.md.
Every market-data call (quotes, OHLCV, listings, info) goes through x402. The agent pays for its own data with USDC stablecoins, no API key required, $0.01/request. The flow:
agent β GET /v1/quotes/latest β 402 Payment Required
agent β EIP-3009 sign USDC transferWithAuthorization
agent β X-PAYMENT header (base64) β retry β 200 OK
Settlement is on Base (chain 8453) via native USDC 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 with the x402 exact-EVM scheme. The retry header is PAYMENT-SIGNATURE. The dashboard shows the full microcharge ledger (/api/cmc-charges) with BaseScan-deep-linkable tx hashes. Daily spend is capped by policy.fees.x402_max_usdc_per_day (default $10).
Every BSC transaction is signed locally with TWAK. The keystore at ~/.twak/wallet.json is encrypted with AES-256-GCM (12-byte IV, 16-byte auth tag) and a key derived from the password with PBKDF2-HMAC-SHA256 (200k iterations). The Setup wizard in the dashboard creates/imports the wallet, encrypts it, and signs the policy with it.
The private key never leaves the host process. The dashboard never has it. The browser never sees it.
The agent uses the bnbagent-sdk (or its connector equivalents):
BSCClientβ connection-pooled, RPC-rotating BSC clientPancakeV3β swap + quote helpersPerpsβ multi-venue funding/OI/position adapterERC8004β identity NFT registrationERC8183β job escrow lifecycle
The agent mints its own ERC-8004 identity NFT at startup (pinned to IPFS) and opens ERC-8183 jobs per evaluation window β one per sleeve + an aggregator. The user is the evaluator; they sign complete() at window end. USDC releases to the agent on-chain.
Full details: docs/onchain.md, docs/x402.md, docs/architecture.md.
A first-class dashboard tab (not a Skill). Deploys ERC-20 / BEP-20 / OpenZeppelin tokens on BSC, with optional single-file HTML landing-page generation.
Chat: "create a token called Mooncoin with symbol MOON and supply 1B"
β TokenModule.create_token(name, symbol, supply, ...)
β x402-pays CMC for token metadata (logged to microcharge ledger)
β TWAK-signs the contract-creation tx
β BNB SDK broadcasts; rcpt.contract_address is the new token's address
β metadata pinned to IPFS
β if create_website=true β LLM generates a single-file HTML page
(sanitized against eval/document.write, no external resources)
β returns { contract_address, tx_hash, explorer_url, website_html }
Mainnet deploy requires the user to type the token name in a confirmation dialog in the dashboard. The MCP tool also requires confirm_mainnet: true. Both are belt-and-suspenders.
Full details: docs/TOKEN_MODULE.md.
6 built-in Skills, discoverable, hot-toggled:
| Skill | Category | Effect |
|---|---|---|
telegram_alert |
notification | DM on every trade close (TELEGRAM_BOT_TOKEN + TELEGRAM_CHAT_ID) |
farcaster_post |
notification | Auto-post PnL updates (WARPCAST_KEY, rate-limited 1/h) |
webhook_dispatch |
notification | POST every event to a user-configured URL (WEBHOOK_URL) |
x_sentiment |
data | Sentiment score for top BSC tokens (X API primary, CMC trending fallback) |
cmc_global_filter |
data | The only Skill that writes β pauses all sleeves on bear regime |
glassnode_onchain |
data | Stub for the contest; deterministic score for the UI |
State persisted to ~/.bnbagent/skills.json. The chat can enable_skill(name) / disable_skill(name) directly. The dashboard's Skills tab lists all + their enabled state.
Full details: docs/SKILLS.md.
Heads up: the MCP server is not started by
bash bnbagent. It's an opt-in service for when you want other agents to call into the BNB Agent. Run it as a separate process. This is intentional β the defaultbnbagentrun is a self-contained agent + dashboard, with nothing listening for outside MCP clients.
agent_mcp/mcp_server.py exposes the BNB Agent as 11 MCP tools over stdio or SSE:
| Tool | What it does |
|---|---|
bnbagent_get_pnl |
Live portfolio stats |
bnbagent_list_positions |
Open positions across all sleeves |
bnbagent_list_trades(n) |
Recent closed trades |
bnbagent_get_policy |
Current signed policy summary |
bnbagent_recommend_risk_change |
Recommendation only β never writes |
bnbagent_deploy_token |
TokenModule deploy (mainnet requires confirm_mainnet=true + confirm_symbol match) |
bnbagent_chat |
Talk to the LLM in natural language |
bnbagent_list_skills |
List all Skills + enabled state |
bnbagent_enable_skill / bnbagent_disable_skill |
Toggle Skills |
Run the server (separate from bnbagent):
# stdio β for Claude Code / Goose / Cursor (configure in their mcp_servers.json)
bash scripts/mcp_serve.sh
# SSE β for remote agents, port 8765 by default
bash scripts/mcp_serve_sse.shIntegrate with any MCP client β the server speaks stdio, so any MCP-compatible client can drive the BNB Agent. Example configs:
Claude Code (~/.claude/mcp_servers.json):
{
"mcpServers": {
"bnbagent": {
"command": "bash",
"args": ["/home/style/bnbagent/scripts/mcp_serve.sh"],
"env": { "PYTHONPATH": "/home/style/bnbagent" }
}
}
}Goose / Cursor / Continue / any other MCP client β same shape: a
stdio command that runs scripts/mcp_serve.sh (or directly
python -m agent_mcp.mcp_server --transport stdio). Check your client's
docs for the exact config-file location and JSON schema; the keys
are always mcpServers.<name>.command + args + env.
Restart the client, then it will discover the 10 bnbagent tools
(bnbagent_get_pnl, bnbagent_deploy_token, bnbagent_chat, etc).
The integration test (tests/integration/test_mcp.py) spawns the
server and calls every tool end-to-end.
Full details: docs/MCP.md.
The risk engine is the only enforcement of the signed User Policy. Every order is gated by circuit_breaker_check() in core/risk.py.
| Check | Refuses if | Default |
|---|---|---|
| 0. Cooldown | now < day_breach_active_until |
60min after a daily breach |
| 1. Daily loss | (day_start - equity) / day_start β₯ daily_loss_circuit_breaker_pct |
3% |
| 2. Max drawdown | (peak - equity) / peak β₯ max_drawdown_pct |
8% |
| 3. Per-trade risk | risk / equity > per_trade_risk_pct |
1% |
| 4. Single position | notional / equity > max_single_position_pct |
15% |
| 5. Gross leverage | gross / equity > max_gross_leverage |
2Γ |
| 6. Allowlist | symbol not in policy.allowlist.bsc_tokens |
top-50 CMC + BSC DEX |
| 7. Sleeve cap | notional / equity > sleeves[X].max_position_pct |
per-sleeve |
| 8. Sleeve enabled | sleeves[X].enabled == false |
β |
| 9. Kill switch (added in v2.0) | policy._kill_switch == true |
dashboard button |
Layer 2 (per-trade reviewer) runs after the circuit breaker and before sign_transaction. Hard-coded timeout (0.5s) β heuristic-only fallback.
Full details: docs/agents.md, docs/audit-2026-06-05.md.
Single-page app (vanilla HTML/CSS/JS, no build step, no framework, ~1800 lines) at http://localhost:8000. Mission-control aesthetic β Inter for display, JetBrains Mono for numerics, hand-drawn SVG equity chart with gradient fill, animated live-status pulse, acid-lime accent on near-black.
| Pane | Source | Refresh | Purpose |
|---|---|---|---|
| Setup | setup files |
β | First-time user wizard (Network β Wallet β Sign Policy β Data source β Ready) |
| Live | /api/stats, /api/equity-series |
1.5s | Hero strip (equity, PnL, DD, Sharpe), SVG equity chart, sleeve cards, x402 ledger, TWAK txs, identity, jobs, trades |
| Chat | /api/chat, /api/agent/advisor, /api/agent/reviewer |
per message | Talk to the LLM; persona modal; recent decisions table |
| Tokens | /api/tokens/* |
β | Token Module config form + deploy button + result card with explorer link + website download |
| Config | /api/control, /api/llm/status |
on change | Sleeve toggles, risk overrides, LLM provider config |
| Logs | /api/logs/stream (SSE) |
live | Live agent log; color-coded by level |
| Replay | β | β | Pointer to bash bnbagent --replay |
Right rail (always visible):
- System status (mode, chain, address, wallet, last update)
- Sleeve toggles
- Control log (advisor + dashboard edits)
- Kill switch (red button, also in the Setup wizard)
Full details: docs/operations.md.
Two config files, both externalized so the agent can be configured without code changes:
| File | What | Who edits |
|---|---|---|
config/config.yaml |
Network, RPCs, gas, token registry, DEX/perps endpoints, CMC, tick intervals | operator (or via the Setup wizard) |
config/policy.yaml |
The signed User Policy (EIP-191) | operator (or via the Setup wizard) |
A third file, agents/providers.yaml, configures the LLM provider routing. The Setup wizard writes a default; the LLM Status page in the dashboard lets you change it.
A fourth file, agents/token_module.yaml, configures the Token Module (default protocol, default supply, default network, website theme).
A fifth file, agents/mcp.yaml (auto-generated if missing), configures the MCP server transport.
See .env.example for the full list. All optional.
| Var | Default | Notes |
|---|---|---|
BNBAGENT_DASHBOARD_PORT |
8000 |
dashboard HTTP port |
BNBAGENT_EQUITY |
100 |
starting USDC equity |
BNBAGENT_LOG_LEVEL |
INFO |
agent log level |
BNBAGENT_CONTROL_FILE |
~/.bnbagent/control.json |
dashboard β agent IPC |
BNBAGENT_MCP_HOST |
0.0.0.0 |
MCP SSE host |
BNBAGENT_MCP_PORT |
8765 |
MCP SSE port |
TWAK_KEYSTORE |
β | TWAK JSON keystore path |
TWAK_PWD |
β | TWAK keystore password |
BNBAGENT_PRIVATE_KEY |
β | dev-only fallback (do not use in prod) |
OPENROUTER_API_KEY |
β | easiest LLM provider (covers all 4 agents) |
ANTHROPIC_API_KEY |
β | direct Anthropic |
OPENAI_API_KEY |
β | direct OpenAI |
OAI_BASE / OAI_KEY |
β | generic OAI-compatible |
LOCAL_LLM_BASE |
http://127.0.0.1:8080 |
llama.cpp / ollama |
TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID |
β | telegram_alert skill |
WARPCAST_KEY |
β | farcaster_post skill |
WEBHOOK_URL |
β | webhook_dispatch skill |
CMC_API_KEY |
β | optional Pro API key (x402 otherwise) |
BASE_RPCS |
https://mainnet.base.org,https://base.publicnode.com,https://1rpc.io/base |
comma-separated Base mainnet RPC URLs (x402 funding detection polls all of them in rotation) |
bnbagent/
βββ README.md β you are here
βββ LICENSE β MIT
βββ install.sh β one-command installer
βββ bnbagent β one-command runner
βββ pyproject.toml β Python deps + setuptools packages
βββ package.json β Node deps (@trustwallet/cli)
βββ .env.example β every env var, all optional
β
βββ config/ β externalized configs
β βββ config.yaml β network/RPCs/tokens/DEX/perps/CMC/ticks
β βββ policy.yaml β signed User Policy
β βββ policy.schema.json β JSON schema
β βββ allowlist.yaml β curated top-50 CMC + BSC DEX
β βββ perps_venues.yaml β Aster/KiloEx/ApolloX/MUX
β βββ tokens.mainnet.yaml
β
βββ core/ β the agent loop
β βββ boot.py β load configs, init wallet, register identity
β βββ main.py β entry point (3 sleeves + advisor)
β βββ portfolio.py β equity, peak, PnL, DD, drawdown_pct
β βββ risk.py β circuit_breaker_check()
β βββ tick.py β TickLoop, Agent, review_trade hook
β βββ control.py β dashboard β agent IPC
β βββ setup.py β Setup wizard backend
β βββ utils.py β shared helpers
β
βββ connectors/ β sponsor adapters
β βββ cmc.py β CoinMarketCap Data API + x402
β βββ x402.py β EIP-3009 transferWithAuthorization
β βββ twak.py β Trust Wallet Agent Kit (signing)
β βββ bnb_sdk.py β BSC + PCS v3 + Perps + ERC-8004 + ERC-8183
β βββ ipfs.py β local IPFS pinning
β βββ keystore.py β AES-256-GCM + PBKDF2 wallet encryption
β
βββ strategies/ β the 3 sleeves
β βββ sleeve_a_carry.py
β βββ sleeve_b_momentum.py
β βββ sleeve_c_meanrev.py
β
βββ agents/ β AI Agent Team
β βββ providers.py β LLMClient Protocol + 5 adapters + LLMRouter
β βββ providers.yaml β per-agent provider+model routing
β βββ base.py β PersonaLoader + llm_complete + llm_stream
β βββ advisor.py β Layer 1: 5-min tightening loop
β βββ reviewer.py β Layer 2: per-trade veto
β βββ chat.py β Layer 3: conversational + 9 tools
β βββ token_module.py β TokenModule (deploy + website)
β βββ _pro_defaults/ β canonical pro personas (resettable)
β β βββ advisor.md
β β βββ reviewer.md
β β βββ chat.md
β β βββ token_module.md
β βββ personas/ β live user-editable personas
β βββ prompts/ β user-prompt templates
β
βββ agent_mcp/ β MCP server (stdio + SSE)
β βββ __init__.py
β βββ mcp_server.py β 11 MCP tools
β
βββ skills/ β discoverable, hot-toggled modules
β βββ base.py β Skill abstract base
β βββ registry.py β SkillRegistry (discover / enable / disable)
β βββ notification/ β telegram_alert, farcaster_post, webhook_dispatch
β βββ data/ β x_sentiment, cmc_global_filter, glassnode_onchain
β
βββ policy/ β EIP-191 sign + verify + version bump
βββ identity/ β ERC-8004 metadata + registration
βββ jobs/ β ERC-8183 open / submit / finalize
β
βββ dashboard/
β βββ backend/ β FastAPI
β β βββ main.py β all API endpoints (40+)
β β βββ metrics.py
β β βββ stream.py
β βββ frontend/ β single HTML file, ~1800 lines
β βββ index.html
β
βββ backtest/ β replay harness + metrics
β βββ fetch_history.py
β βββ metrics.py
β βββ replay.py
β
βββ tests/ β 683/697 passing (enforced by CI)
β βββ unit/ β ~13 files
β βββ integration/ β 1 file (MCP)
β βββ fixtures/ β llm.py, wallets.py, skills.py
β
βββ scripts/ β the granular launchers
β βββ first_run.sh β 5-command sanity check
β βββ sign_policy.sh
β βββ register_agent.sh
β βββ open_window.sh
β βββ replay_week.sh
β βββ start_agent.sh
β βββ start_dashboard.sh
β βββ finalize_window.sh
β βββ mcp_serve.sh β MCP stdio launcher
β βββ mcp_serve_sse.sh β MCP SSE launcher
β
βββ docs/ β full documentation
β βββ agents.md
β βββ architecture.md
β βββ audit-2026-06-05.md
β βββ API.md β every endpoint
β βββ CHANGELOG.md
β βββ CONTRIBUTING.md
β βββ demo-script.md
β βββ install.md
β βββ MCP.md
β βββ onchain.md
β βββ operations.md
β βββ PERSONAS.md
β βββ policy.md
β βββ SECURITY.md
β βββ setup-wizard.md
β βββ SKILLS.md
β βββ strategy.md
β βββ submission.md
β βββ TOKEN_MODULE.md
β βββ x402.md
β
βββ infra/ β docker, systemd (optional)
| File | Topic |
|---|---|
docs/architecture.md |
Architecture diagram + data flow + key design decisions |
docs/strategy.md |
The 3 sleeves in plain English, plus the scoring rationale |
docs/onchain.md |
ERC-8004 identity + ERC-8183 job lifecycle |
docs/x402.md |
x402 pay-per-request protocol, EIP-3009, daily spend cap |
docs/policy.md |
The signed User Policy, how signing works, how verification works |
docs/POLICY_CHANGELOG.md |
Per-version policy change log β every relaxation of a safety threshold with the rationale, the backtest tape, and the worst-case DD observed. v2.0.8-M1. |
docs/install.md |
One-command install + every env var |
docs/operations.md |
Dashboard pane reference + kill switch + control log |
docs/setup-wizard.md |
The 5-step Setup wizard (Network β Wallet β Sign Policy β Data source β Ready) |
docs/agents.md |
The 3-LLM agent team in depth (advisor / reviewer / chat) |
docs/TOKEN_MODULE.md |
Token deploy + landing-page generation + mainnet guard |
docs/SKILLS.md |
Skills registry + 6 built-ins + the cmc_global_filter pause rule |
docs/MCP.md |
MCP server transport, 11 tools, generic MCP-client integration |
docs/PERSONAS.md |
Persona format + reset semantics + diverged flag |
docs/API.md |
Every HTTP endpoint (40+) with request/response examples |
docs/SECURITY.md |
Threat model, signing, key mgmt, MCP exposure, audit trail |
docs/CONTRIBUTING.md |
Dev setup, code style, testing, PR process |
docs/CHANGELOG.md |
v1.0 β v2.0 history |
docs/audit-2026-06-05.md |
10-item trading-logic audit pass + fixes |
docs/submission.md |
Hackathon form fields pre-filled + pre-submission checklist |
docs/demo-script.md |
3-minute demo video script (judge-facing) |
salepitch.md |
One-page sales pitch + feature pitch |
pytest -q # 683/697 passing (~3:40 cold, ~12s unit-only)
# 2 pre-existing failures: replay JSON drift (test_meta)
# + IPC identity drift (test_dashboard_state_ipc) β non-blocking
pytest tests/unit/ # fast unit tests
pytest tests/integration/ # MCP end-to-end
pytest tests/unit/test_risk.py -v # 1 fileTest layout:
tests/unit/β 13 files, ~140 unit teststests/integration/β 1 file (MCP subprocess + tool calls)tests/fixtures/llm.pyβFakeLLMClient(records calls, returns scripted responses)tests/fixtures/wallets.pyβ shared dev wallets
Coverage of critical invariants:
test_advisor.py::test_cannot_loosen_with_higher_valueβ hostile LLM cannot raiseper_trade_risk_pctto 5.0test_reviewer.py::test_heuristic_overrides_llmβ LLM says allow, heuristic vetoes on win_rate < 20%test_reviewer.py::test_llm_timeout_falls_back_to_heuristicβ slow LLM doesn't block the sleeve looptest_chat.py::test_recommend_risk_change_does_not_writeβ chat's recommend never writes to policytest_token_module.py::test_sanitize_website_strips_evalβ generated HTML can'teval/document.writetest_skill_registry.py::test_enable_missing_env_blocksβ can't enable a Skill without its API keystest_mcp.py::test_deploy_token_mainnet_without_confirm_rejectedβ mainnet deploys always require explicit confirmation
| Concern | Mitigation |
|---|---|
| Private key on disk | AES-256-GCM at ~/.twak/wallet.json, PBKDF2 200k iters, chmod 600. Password supplied via TWAK_PWD env var. |
| Private key over the wire | Never. The dashboard receives only the address. The browser never sees the key. The browser POSTs the password to the dashboard, which decrypts the keystore in-process. |
| LLM agent team | Layer 1 can only TIGHTEN. Layer 2 can only VETO. Layer 3 can only RECOMMEND. All three safety envelopes are enforced in code, never delegated to the LLM. |
| Mainnet token deploy | Requires confirm_mainnet: true in the API. Frontend requires the user to type the token name in a dialog. Pre-flight check: policy signed, wallet set, mode == "mainnet". |
| x402 spend blow-up | fees.x402_max_usdc_per_day (default $10) caps daily CMC spend. |
| Mainnet gas blow-up | gas.max_gwei: 5 plus max_gas_price_gwei in policy. |
| Perps venue rug | Daily venue re-selection ranks 4 candidates; auto-switch on OI drop or withdrawals_paused=True. |
| BSC RPC outage | 3-RPC rotation in BSCClient; sleeves hold positions if all fail. |
| MCP exposure | The MCP server reads core.main.DASHBOARD_STATE; it has no filesystem or network access of its own. Mainnet deploys through MCP require the same confirm_mainnet guard as the dashboard. |
| Skill side effects | cmc_global_filter is the only Skill that writes; its writes are tagged _source: "skill:cmc_global_filter" and visible in the Control Log. |
| Adversarial personas | Persona files are loaded into the system prompt but the BaseAgent machinery is the same regardless. Reset to pro is one click. |
| Replay safety | The replay harness runs the strategies against a synthetic tape; no real txs are signed. The replay mode in BSCClient.broadcast returns deterministic stubs. |
| Token Module during contest | Hard date lock: refuses to deploy before 2026-07-07 00:00 UTC. After the window, requires BNBAGENT_ALLOW_TOKEN_DEPLOY=true in env. The contest forbids launches 2026-06-03β2026-07-06; this is enforced in code (TokenModule.is_deploy_unlocked), not in docs. |
| Mnemonic export on the public dashboard | /api/wallet/export-mnemonic returns 403 unless BNBAGENT_ALLOW_WALLET_EXPORT=true is set in the server env. Defense-in-depth: a judge who learns the admin password still cannot dump the operator's seed phrase unless they also have SSH access + restart capability. |
| Wallet swap on the public dashboard | /api/setup/wallet/import returns 403 unless BNBAGENT_ALLOW_WALLET_IMPORT=true is set. A judge who gets the admin password still cannot replace the operator's wallet with their own (which would let them drain funds or register a fake identity). |
Full details: docs/SECURITY.md.
A focused security review was performed in v2.0.8 covering the wallet
keystore, BSC RPC layer, gas pricing, CMC data dependency, MCP server
surface, and vol-pause logic. The review identified 0 Critical,
4 High, 7 Medium, 6 Low, 4 Info findings. All 4 Highs + 2 of the
Mediums were fixed in v2.0.8 (H1βH4, M3, M4). The full review is
private to the operator and is not committed to this public
repo. A summary of what was fixed (and what is deferred to
post-hackathon hardening) is in docs/SECURITY.md
under "v2.0.8 security review".
The hardening commits are:
| Commit | ID | What it fixes |
|---|---|---|
1ea07b8 |
H-4 | Gas-price cap from policy; refuse stuck-tx window |
4973b9d |
H-3 | resync_nonce to reconcile local cache from chain |
04719cb |
H-2 | Add pycryptodome>=3.18 to deps + hoist AES imports |
a4924ec |
H-1 | Gate BNBAGENT_PRIVATE_KEY env var behind explicit opt-in |
2366d68 |
M-4 | Vol filter fallback above pause threshold |
bd9cb93 |
M-3 | MCP SSE default bind 127.0.0.1 + optional Bearer auth |
bash install.sh && bash bnbagentBNBAGENT_AUTH_MODE defaults to disabled, so no password is required. The dashboard is open. Use this on your laptop.
One env var, BNBAGENT_AUTH_MODE, picks the mode. The legacy
BNBAGENT_AUTH_ENABLED flag still works as a fallback
(true β password, false/unset β disabled); BNBAGENT_AUTH_MODE
wins when both are set.
| Mode | When to use | Password? | Mutations? |
|---|---|---|---|
disabled (default) |
Local dev on your laptop | No | β all allowed |
password |
Coolify with operator-on-VPS | Yes (judge / admin) | β with admin cookie |
readonly |
Public contest URL (DoraHacks) | No | β 403 on all POSTs |
For the Coolify contest URL (recommended): set
BNBAGENT_AUTH_MODE=readonly. Judges hit the URL with no
password prompt, see the live agent (live state, sleeves, holdings,
chat, replay), but every mutation route returns 403. The
π’ DEMO MODE banner in the topbar makes it obvious. Defense in
depth: even forging an admin cookie doesn't help in readonly mode
(the cookie is bypassed entirely β everyone is judge).
For operator maintenance: switch to password mode temporarily
(see Phase 4 of coolify_runbook.md), log in as admin, do the
thing, switch back to readonly.
# Mode A: local dev (default, no env var)
# BNBAGENT_AUTH_MODE=disabled
# Mode B: contest public URL (recommended for Coolify)
BNBAGENT_AUTH_MODE=readonly
# Mode C: VPS with operator maintenance
BNBAGENT_AUTH_MODE=password
BNBAGENT_AUTH_SECRET=$(openssl rand -hex 32) # stable across restarts
JUDGE_PASSWORD=see-the-agent-running
ADMIN_PASSWORD=operate-the-agent
BNBAGENT_AUTH_COOKIE_SECURE=true # required when behind TLS
MINIMAX_API_KEY=sk-cp-... # the AI brainTwo roles are enforced by FastAPI dependency injection (in password mode):
judgeβ can see Live, Chat, Replay, Tokens (read), and use the chat agent. Cannot edit policy, sign, run registration, change personas, or hit the kill switch.adminβ full operator access (judge + setup + sign + register + kill switch + wallet export).
The cookie is HMAC-SHA256 signed (stdlib only, no new dep), 1-day expiry, httponly + samesite=strict. The signature uses BNBAGENT_AUTH_SECRET; if you forget to set it the dev fallback is used and you'll see a warning at startup. Sessions are invalidated on every restart without a real secret.
cp .env.example .env
$EDITOR .env # fill in the keys
docker compose up -d # builds Dockerfile, runs on :8000The Dockerfile ships a single Python 3.12 image that runs the dashboard backend (FastAPI on :8000) + the MCP SSE server (on :8765 if BNBAGENT_MCP_PORT=8765). Healthcheck is GET /api/healthz every 30s. bnbagent_data and bnbagent_logs named volumes persist runtime state across container rebuilds.
For Coolify: point it at the repo, set the env vars in the service UI, expose port 8000. Coolify's reverse proxy handles TLS termination in front.
Caddy:
bnbagent.example {
reverse_proxy 127.0.0.1:8000
}
BNBAGENT_AUTH_COOKIE_SECURE=true is required when running behind TLS so the browser keeps the cookie.
- Re-signed
config/policy.yamlwith the production evaluator's key - Wallet has real BNB (gas) + real USDC (trading)
-
mode: mainnetinconfig/config.yaml - ERC-8004 identity NFT minted on mainnet
- At least 1 ERC-8183 job in
Completedstate on mainnet - Backtest report
data/reports/replay.htmlis committed - Dashboard reachable at a public URL with TLS + auth
-
BNBAGENT_AUTH_MODE=readonlyset (contest URL) orpassword+ non-defaultJUDGE_PASSWORD/ADMIN_PASSWORD(operator-on-VPS) -
BNBAGENT_AUTH_SECRETset to a stable value (openssl rand -hex 32) if usingpasswordmode - BscScan + 8004scan deep links work
Full details: docs/operations.md.
PRs welcome. See docs/CONTRIBUTING.md for:
- Dev setup (venv, pre-commit, linting)
- Code style (ruff, type hints, docstrings)
- Test conventions (class-based, replay-tape fixtures, FakeLLMClient)
- PR review process
For the contest: please open issues for any bugs you find in the live PnL-replay window. Speed matters; we'll triage and patch.
MIT β see LICENSE. Copyright (c) 2026 Blaze.
__ ___
/ |/ / by Blaze Β· built for the BNB HACK 2026
/ /|_/ / CoinMarketCap Γ Trust Wallet Γ BNB Chain
/_/ /_/ $36K prize pool Β· live PnL-replay 2026-06-22 β 2026-06-28